summaryrefslogtreecommitdiff
path: root/noncore/unsupported/qpdf/xpdf/GfxState.cc
Unidiff
Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/GfxState.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/unsupported/qpdf/xpdf/GfxState.cc2097
1 files changed, 2097 insertions, 0 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/GfxState.cc b/noncore/unsupported/qpdf/xpdf/GfxState.cc
new file mode 100644
index 0000000..af4e0d4
--- a/dev/null
+++ b/noncore/unsupported/qpdf/xpdf/GfxState.cc
@@ -0,0 +1,2097 @@
1//========================================================================
2//
3// GfxState.cc
4//
5// Copyright 1996 Derek B. Noonburg
6//
7//========================================================================
8
9#ifdef __GNUC__
10#pragma implementation
11#endif
12
13#include <aconf.h>
14#include <stddef.h>
15#include <math.h>
16#include <string.h> // for memcpy()
17#include "gmem.h"
18#include "Error.h"
19#include "Object.h"
20#include "Array.h"
21#include "Page.h"
22#include "GfxState.h"
23
24//------------------------------------------------------------------------
25
26static inline fouble clip01(fouble x) {
27 return (x < 0) ? fouble(0) : ((x > 1) ? fouble(1) : x);
28}
29
30//------------------------------------------------------------------------
31// GfxColorSpace
32//------------------------------------------------------------------------
33
34GfxColorSpace::GfxColorSpace() {
35}
36
37GfxColorSpace::~GfxColorSpace() {
38}
39
40GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
41 GfxColorSpace *cs;
42 Object obj1;
43
44 cs = NULL;
45 if (csObj->isName()) {
46 if (csObj->isName("DeviceGray") || csObj->isName("G")) {
47 cs = new GfxDeviceGrayColorSpace();
48 } else if (csObj->isName("DeviceRGB") || csObj->isName("RGB")) {
49 cs = new GfxDeviceRGBColorSpace();
50 } else if (csObj->isName("DeviceCMYK") || csObj->isName("CMYK")) {
51 cs = new GfxDeviceCMYKColorSpace();
52 } else if (csObj->isName("Pattern")) {
53 cs = new GfxPatternColorSpace(NULL);
54 } else {
55 error(-1, "Bad color space '%s'", csObj->getName());
56 }
57 } else if (csObj->isArray()) {
58 csObj->arrayGet(0, &obj1);
59 if (obj1.isName("DeviceGray") || obj1.isName("G")) {
60 cs = new GfxDeviceGrayColorSpace();
61 } else if (obj1.isName("DeviceRGB") || obj1.isName("RGB")) {
62 cs = new GfxDeviceRGBColorSpace();
63 } else if (obj1.isName("DeviceCMYK") || obj1.isName("CMYK")) {
64 cs = new GfxDeviceCMYKColorSpace();
65 } else if (obj1.isName("CalGray")) {
66 cs = GfxCalGrayColorSpace::parse(csObj->getArray());
67 } else if (obj1.isName("CalRGB")) {
68 cs = GfxCalRGBColorSpace::parse(csObj->getArray());
69 } else if (obj1.isName("Lab")) {
70 cs = GfxLabColorSpace::parse(csObj->getArray());
71 } else if (obj1.isName("ICCBased")) {
72 cs = GfxICCBasedColorSpace::parse(csObj->getArray());
73 } else if (obj1.isName("Indexed") || obj1.isName("I")) {
74 cs = GfxIndexedColorSpace::parse(csObj->getArray());
75 } else if (obj1.isName("Separation")) {
76 cs = GfxSeparationColorSpace::parse(csObj->getArray());
77 } else if (obj1.isName("DeviceN")) {
78 cs = GfxDeviceNColorSpace::parse(csObj->getArray());
79 } else if (obj1.isName("Pattern")) {
80 cs = GfxPatternColorSpace::parse(csObj->getArray());
81 } else {
82 error(-1, "Bad color space '%s'", csObj->getName());
83 }
84 obj1.free();
85 } else {
86 error(-1, "Bad color space - expected name or array");
87 }
88 return cs;
89}
90
91void GfxColorSpace::getDefaultRanges(fouble *decodeLow, fouble *decodeRange,
92 int maxImgPixel) {
93 int i;
94
95 for (i = 0; i < getNComps(); ++i) {
96 decodeLow[i] = 0;
97 decodeRange[i] = 1;
98 }
99}
100
101//------------------------------------------------------------------------
102// GfxDeviceGrayColorSpace
103//------------------------------------------------------------------------
104
105GfxDeviceGrayColorSpace::GfxDeviceGrayColorSpace() {
106}
107
108GfxDeviceGrayColorSpace::~GfxDeviceGrayColorSpace() {
109}
110
111GfxColorSpace *GfxDeviceGrayColorSpace::copy() {
112 return new GfxDeviceGrayColorSpace();
113}
114
115void GfxDeviceGrayColorSpace::getGray(GfxColor *color, fouble *gray) {
116 *gray = clip01(color->c[0]);
117}
118
119void GfxDeviceGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
120 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
121}
122
123void GfxDeviceGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
124 cmyk->c = cmyk->m = cmyk->y = 0;
125 cmyk->k = clip01(1 - color->c[0]);
126}
127
128//------------------------------------------------------------------------
129// GfxCalGrayColorSpace
130//------------------------------------------------------------------------
131
132GfxCalGrayColorSpace::GfxCalGrayColorSpace() {
133 whiteX = whiteY = whiteZ = 1;
134 blackX = blackY = blackZ = 0;
135 gamma = 1;
136}
137
138GfxCalGrayColorSpace::~GfxCalGrayColorSpace() {
139}
140
141GfxColorSpace *GfxCalGrayColorSpace::copy() {
142 GfxCalGrayColorSpace *cs;
143
144 cs = new GfxCalGrayColorSpace();
145 cs->whiteX = whiteX;
146 cs->whiteY = whiteY;
147 cs->whiteZ = whiteZ;
148 cs->blackX = blackX;
149 cs->blackY = blackY;
150 cs->blackZ = blackZ;
151 cs->gamma = gamma;
152 return cs;
153}
154
155GfxColorSpace *GfxCalGrayColorSpace::parse(Array *arr) {
156 GfxCalGrayColorSpace *cs;
157 Object obj1, obj2, obj3;
158
159 arr->get(1, &obj1);
160 if (!obj1.isDict()) {
161 error(-1, "Bad CalGray color space");
162 obj1.free();
163 return NULL;
164 }
165 cs = new GfxCalGrayColorSpace();
166 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
167 obj2.arrayGetLength() == 3) {
168 obj2.arrayGet(0, &obj3);
169 cs->whiteX = obj3.getNum();
170 obj3.free();
171 obj2.arrayGet(1, &obj3);
172 cs->whiteY = obj3.getNum();
173 obj3.free();
174 obj2.arrayGet(2, &obj3);
175 cs->whiteZ = obj3.getNum();
176 obj3.free();
177 }
178 obj2.free();
179 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
180 obj2.arrayGetLength() == 3) {
181 obj2.arrayGet(0, &obj3);
182 cs->blackX = obj3.getNum();
183 obj3.free();
184 obj2.arrayGet(1, &obj3);
185 cs->blackY = obj3.getNum();
186 obj3.free();
187 obj2.arrayGet(2, &obj3);
188 cs->blackZ = obj3.getNum();
189 obj3.free();
190 }
191 obj2.free();
192 if (obj1.dictLookup("Gamma", &obj2)->isNum()) {
193 cs->gamma = obj2.getNum();
194 }
195 obj2.free();
196 obj1.free();
197 return cs;
198}
199
200void GfxCalGrayColorSpace::getGray(GfxColor *color, fouble *gray) {
201 *gray = clip01(color->c[0]);
202}
203
204void GfxCalGrayColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
205 rgb->r = rgb->g = rgb->b = clip01(color->c[0]);
206}
207
208void GfxCalGrayColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
209 cmyk->c = cmyk->m = cmyk->y = 0;
210 cmyk->k = clip01(1 - color->c[0]);
211}
212
213//------------------------------------------------------------------------
214// GfxDeviceRGBColorSpace
215//------------------------------------------------------------------------
216
217GfxDeviceRGBColorSpace::GfxDeviceRGBColorSpace() {
218}
219
220GfxDeviceRGBColorSpace::~GfxDeviceRGBColorSpace() {
221}
222
223GfxColorSpace *GfxDeviceRGBColorSpace::copy() {
224 return new GfxDeviceRGBColorSpace();
225}
226
227void GfxDeviceRGBColorSpace::getGray(GfxColor *color, fouble *gray) {
228 *gray = clip01(0.299 * color->c[0] +
229 0.587 * color->c[1] +
230 0.114 * color->c[2]);
231}
232
233void GfxDeviceRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
234 rgb->r = clip01(color->c[0]);
235 rgb->g = clip01(color->c[1]);
236 rgb->b = clip01(color->c[2]);
237}
238
239void GfxDeviceRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
240 fouble c, m, y, k;
241
242 c = clip01(1 - color->c[0]);
243 m = clip01(1 - color->c[1]);
244 y = clip01(1 - color->c[2]);
245 k = c;
246 if (m < k) {
247 k = m;
248 }
249 if (y < k) {
250 k = y;
251 }
252 cmyk->c = c - k;
253 cmyk->m = m - k;
254 cmyk->y = y - k;
255 cmyk->k = k;
256}
257
258//------------------------------------------------------------------------
259// GfxCalRGBColorSpace
260//------------------------------------------------------------------------
261
262GfxCalRGBColorSpace::GfxCalRGBColorSpace() {
263 whiteX = whiteY = whiteZ = 1;
264 blackX = blackY = blackZ = 0;
265 gammaR = gammaG = gammaB = 1;
266 mat[0] = 1; mat[1] = 0; mat[2] = 0;
267 mat[3] = 0; mat[4] = 1; mat[5] = 0;
268 mat[6] = 0; mat[7] = 0; mat[8] = 1;
269}
270
271GfxCalRGBColorSpace::~GfxCalRGBColorSpace() {
272}
273
274GfxColorSpace *GfxCalRGBColorSpace::copy() {
275 GfxCalRGBColorSpace *cs;
276 int i;
277
278 cs = new GfxCalRGBColorSpace();
279 cs->whiteX = whiteX;
280 cs->whiteY = whiteY;
281 cs->whiteZ = whiteZ;
282 cs->blackX = blackX;
283 cs->blackY = blackY;
284 cs->blackZ = blackZ;
285 cs->gammaR = gammaR;
286 cs->gammaG = gammaG;
287 cs->gammaB = gammaB;
288 for (i = 0; i < 9; ++i) {
289 cs->mat[i] = mat[i];
290 }
291 return cs;
292}
293
294GfxColorSpace *GfxCalRGBColorSpace::parse(Array *arr) {
295 GfxCalRGBColorSpace *cs;
296 Object obj1, obj2, obj3;
297 int i;
298
299 arr->get(1, &obj1);
300 if (!obj1.isDict()) {
301 error(-1, "Bad CalRGB color space");
302 obj1.free();
303 return NULL;
304 }
305 cs = new GfxCalRGBColorSpace();
306 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
307 obj2.arrayGetLength() == 3) {
308 obj2.arrayGet(0, &obj3);
309 cs->whiteX = obj3.getNum();
310 obj3.free();
311 obj2.arrayGet(1, &obj3);
312 cs->whiteY = obj3.getNum();
313 obj3.free();
314 obj2.arrayGet(2, &obj3);
315 cs->whiteZ = obj3.getNum();
316 obj3.free();
317 }
318 obj2.free();
319 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
320 obj2.arrayGetLength() == 3) {
321 obj2.arrayGet(0, &obj3);
322 cs->blackX = obj3.getNum();
323 obj3.free();
324 obj2.arrayGet(1, &obj3);
325 cs->blackY = obj3.getNum();
326 obj3.free();
327 obj2.arrayGet(2, &obj3);
328 cs->blackZ = obj3.getNum();
329 obj3.free();
330 }
331 obj2.free();
332 if (obj1.dictLookup("Gamma", &obj2)->isArray() &&
333 obj2.arrayGetLength() == 3) {
334 obj2.arrayGet(0, &obj3);
335 cs->gammaR = obj3.getNum();
336 obj3.free();
337 obj2.arrayGet(1, &obj3);
338 cs->gammaG = obj3.getNum();
339 obj3.free();
340 obj2.arrayGet(2, &obj3);
341 cs->gammaB = obj3.getNum();
342 obj3.free();
343 }
344 obj2.free();
345 if (obj1.dictLookup("Matrix", &obj2)->isArray() &&
346 obj2.arrayGetLength() == 9) {
347 for (i = 0; i < 9; ++i) {
348 obj2.arrayGet(i, &obj3);
349 cs->mat[i] = obj3.getNum();
350 obj3.free();
351 }
352 }
353 obj2.free();
354 obj1.free();
355 return cs;
356}
357
358void GfxCalRGBColorSpace::getGray(GfxColor *color, fouble *gray) {
359 *gray = clip01(0.299 * color->c[0] +
360 0.587 * color->c[1] +
361 0.114 * color->c[2]);
362}
363
364void GfxCalRGBColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
365 rgb->r = clip01(color->c[0]);
366 rgb->g = clip01(color->c[1]);
367 rgb->b = clip01(color->c[2]);
368}
369
370void GfxCalRGBColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
371 fouble c, m, y, k;
372
373 c = clip01(1 - color->c[0]);
374 m = clip01(1 - color->c[1]);
375 y = clip01(1 - color->c[2]);
376 k = c;
377 if (m < k) {
378 k = m;
379 }
380 if (y < k) {
381 k = y;
382 }
383 cmyk->c = c - k;
384 cmyk->m = m - k;
385 cmyk->y = y - k;
386 cmyk->k = k;
387}
388
389//------------------------------------------------------------------------
390// GfxDeviceCMYKColorSpace
391//------------------------------------------------------------------------
392
393GfxDeviceCMYKColorSpace::GfxDeviceCMYKColorSpace() {
394}
395
396GfxDeviceCMYKColorSpace::~GfxDeviceCMYKColorSpace() {
397}
398
399GfxColorSpace *GfxDeviceCMYKColorSpace::copy() {
400 return new GfxDeviceCMYKColorSpace();
401}
402
403void GfxDeviceCMYKColorSpace::getGray(GfxColor *color, fouble *gray) {
404 *gray = clip01(1 - color->c[3]
405 - 0.299 * color->c[0]
406 - 0.587 * color->c[1]
407 - 0.114 * color->c[2]);
408}
409
410void GfxDeviceCMYKColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
411 rgb->r = clip01(1 - (color->c[0] + color->c[3]));
412 rgb->g = clip01(1 - (color->c[1] + color->c[3]));
413 rgb->b = clip01(1 - (color->c[2] + color->c[3]));
414}
415
416void GfxDeviceCMYKColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
417 cmyk->c = clip01(color->c[0]);
418 cmyk->m = clip01(color->c[1]);
419 cmyk->y = clip01(color->c[2]);
420 cmyk->k = clip01(color->c[3]);
421}
422
423//------------------------------------------------------------------------
424// GfxLabColorSpace
425//------------------------------------------------------------------------
426
427// This is the inverse of MatrixLMN in Example 4.10 from the PostScript
428// Language Reference, Third Edition.
429static fouble xyzrgb[3][3] = {
430 { 3.240449, -1.537136, -0.498531 },
431 { -0.969265, 1.876011, 0.041556 },
432 { 0.055643, -0.204026, 1.057229 }
433};
434
435GfxLabColorSpace::GfxLabColorSpace() {
436 whiteX = whiteY = whiteZ = 1;
437 blackX = blackY = blackZ = 0;
438 aMin = bMin = -100;
439 aMax = bMax = 100;
440}
441
442GfxLabColorSpace::~GfxLabColorSpace() {
443}
444
445GfxColorSpace *GfxLabColorSpace::copy() {
446 GfxLabColorSpace *cs;
447
448 cs = new GfxLabColorSpace();
449 cs->whiteX = whiteX;
450 cs->whiteY = whiteY;
451 cs->whiteZ = whiteZ;
452 cs->blackX = blackX;
453 cs->blackY = blackY;
454 cs->blackZ = blackZ;
455 cs->aMin = aMin;
456 cs->aMax = aMax;
457 cs->bMin = bMin;
458 cs->bMax = bMax;
459 cs->kr = kr;
460 cs->kg = kg;
461 cs->kb = kb;
462 return cs;
463}
464
465GfxColorSpace *GfxLabColorSpace::parse(Array *arr) {
466 GfxLabColorSpace *cs;
467 Object obj1, obj2, obj3;
468
469 arr->get(1, &obj1);
470 if (!obj1.isDict()) {
471 error(-1, "Bad Lab color space");
472 obj1.free();
473 return NULL;
474 }
475 cs = new GfxLabColorSpace();
476 if (obj1.dictLookup("WhitePoint", &obj2)->isArray() &&
477 obj2.arrayGetLength() == 3) {
478 obj2.arrayGet(0, &obj3);
479 cs->whiteX = obj3.getNum();
480 obj3.free();
481 obj2.arrayGet(1, &obj3);
482 cs->whiteY = obj3.getNum();
483 obj3.free();
484 obj2.arrayGet(2, &obj3);
485 cs->whiteZ = obj3.getNum();
486 obj3.free();
487 }
488 obj2.free();
489 if (obj1.dictLookup("BlackPoint", &obj2)->isArray() &&
490 obj2.arrayGetLength() == 3) {
491 obj2.arrayGet(0, &obj3);
492 cs->blackX = obj3.getNum();
493 obj3.free();
494 obj2.arrayGet(1, &obj3);
495 cs->blackY = obj3.getNum();
496 obj3.free();
497 obj2.arrayGet(2, &obj3);
498 cs->blackZ = obj3.getNum();
499 obj3.free();
500 }
501 obj2.free();
502 if (obj1.dictLookup("Range", &obj2)->isArray() &&
503 obj2.arrayGetLength() == 4) {
504 obj2.arrayGet(0, &obj3);
505 cs->aMin = obj3.getNum();
506 obj3.free();
507 obj2.arrayGet(1, &obj3);
508 cs->aMax = obj3.getNum();
509 obj3.free();
510 obj2.arrayGet(2, &obj3);
511 cs->bMin = obj3.getNum();
512 obj3.free();
513 obj2.arrayGet(3, &obj3);
514 cs->bMax = obj3.getNum();
515 obj3.free();
516 }
517 obj2.free();
518 obj1.free();
519
520 cs->kr = 1 / (xyzrgb[0][0] * cs->whiteX +
521 xyzrgb[0][1] * cs->whiteY +
522 xyzrgb[0][2] * cs->whiteZ);
523 cs->kg = 1 / (xyzrgb[1][0] * cs->whiteX +
524 xyzrgb[1][1] * cs->whiteY +
525 xyzrgb[1][2] * cs->whiteZ);
526 cs->kb = 1 / (xyzrgb[2][0] * cs->whiteX +
527 xyzrgb[2][1] * cs->whiteY +
528 xyzrgb[2][2] * cs->whiteZ);
529
530 return cs;
531}
532
533void GfxLabColorSpace::getGray(GfxColor *color, fouble *gray) {
534 GfxRGB rgb;
535
536 getRGB(color, &rgb);
537 *gray = clip01(0.299 * rgb.r +
538 0.587 * rgb.g +
539 0.114 * rgb.b);
540}
541
542void GfxLabColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
543 fouble X, Y, Z;
544 fouble t1, t2;
545 fouble r, g, b;
546
547 // convert L*a*b* to CIE 1931 XYZ color space
548 t1 = (color->c[0] + 16) / 116;
549 t2 = t1 + color->c[1] / 500;
550 if (t2 >= (6.0 / 29.0)) {
551 X = t2 * t2 * t2;
552 } else {
553 X = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
554 }
555 X *= whiteX;
556 if (t1 >= (6.0 / 29.0)) {
557 Y = t1 * t1 * t1;
558 } else {
559 Y = (108.0 / 841.0) * (t1 - (4.0 / 29.0));
560 }
561 Y *= whiteY;
562 t2 = t1 - color->c[2] / 200;
563 if (t2 >= (6.0 / 29.0)) {
564 Z = t2 * t2 * t2;
565 } else {
566 Z = (108.0 / 841.0) * (t2 - (4.0 / 29.0));
567 }
568 Z *= whiteZ;
569
570 // convert XYZ to RGB, including gamut mapping and gamma correction
571 r = xyzrgb[0][0] * X + xyzrgb[0][1] * Y + xyzrgb[0][2] * Z;
572 g = xyzrgb[1][0] * X + xyzrgb[1][1] * Y + xyzrgb[1][2] * Z;
573 b = xyzrgb[2][0] * X + xyzrgb[2][1] * Y + xyzrgb[2][2] * Z;
574 rgb->r = pow(clip01(r * kr), 0.5);
575 rgb->g = pow(clip01(g * kg), 0.5);
576 rgb->b = pow(clip01(b * kb), 0.5);
577}
578
579void GfxLabColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
580 GfxRGB rgb;
581 fouble c, m, y, k;
582
583 getRGB(color, &rgb);
584 c = clip01(1 - rgb.r);
585 m = clip01(1 - rgb.g);
586 y = clip01(1 - rgb.b);
587 k = c;
588 if (m < k) {
589 k = m;
590 }
591 if (y < k) {
592 k = y;
593 }
594 cmyk->c = c - k;
595 cmyk->m = m - k;
596 cmyk->y = y - k;
597 cmyk->k = k;
598}
599
600void GfxLabColorSpace::getDefaultRanges(fouble *decodeLow, fouble *decodeRange,
601 int maxImgPixel) {
602 decodeLow[0] = 0;
603 decodeRange[0] = 100;
604 decodeLow[1] = aMin;
605 decodeRange[1] = aMax - aMin;
606 decodeLow[2] = bMin;
607 decodeRange[2] = bMax - bMin;
608}
609
610//------------------------------------------------------------------------
611// GfxICCBasedColorSpace
612//------------------------------------------------------------------------
613
614GfxICCBasedColorSpace::GfxICCBasedColorSpace(int nCompsA, GfxColorSpace *altA,
615 Ref *iccProfileStreamA) {
616 nComps = nCompsA;
617 alt = altA;
618 iccProfileStream = *iccProfileStreamA;
619 rangeMin[0] = rangeMin[1] = rangeMin[2] = rangeMin[3] = 0;
620 rangeMax[0] = rangeMax[1] = rangeMax[2] = rangeMax[3] = 1;
621}
622
623GfxICCBasedColorSpace::~GfxICCBasedColorSpace() {
624 delete alt;
625}
626
627GfxColorSpace *GfxICCBasedColorSpace::copy() {
628 GfxICCBasedColorSpace *cs;
629 int i;
630
631 cs = new GfxICCBasedColorSpace(nComps, alt->copy(), &iccProfileStream);
632 for (i = 0; i < 4; ++i) {
633 cs->rangeMin[i] = rangeMin[i];
634 cs->rangeMax[i] = rangeMax[i];
635 }
636 return cs;
637}
638
639GfxColorSpace *GfxICCBasedColorSpace::parse(Array *arr) {
640 GfxICCBasedColorSpace *cs;
641 Ref iccProfileStreamA;
642 int nCompsA;
643 GfxColorSpace *altA;
644 Dict *dict;
645 Object obj1, obj2, obj3;
646 int i;
647
648 arr->getNF(1, &obj1);
649 if (obj1.isRef()) {
650 iccProfileStreamA = obj1.getRef();
651 } else {
652 iccProfileStreamA.num = 0;
653 iccProfileStreamA.gen = 0;
654 }
655 obj1.free();
656 arr->get(1, &obj1);
657 if (!obj1.isStream()) {
658 error(-1, "Bad ICCBased color space (stream)");
659 obj1.free();
660 return NULL;
661 }
662 dict = obj1.streamGetDict();
663 if (!dict->lookup("N", &obj2)->isInt()) {
664 error(-1, "Bad ICCBased color space (N)");
665 obj2.free();
666 obj1.free();
667 return NULL;
668 }
669 nCompsA = obj2.getInt();
670 obj2.free();
671 if (dict->lookup("Alternate", &obj2)->isNull() ||
672 !(altA = GfxColorSpace::parse(&obj2))) {
673 switch (nCompsA) {
674 case 1:
675 altA = new GfxDeviceGrayColorSpace();
676 break;
677 case 3:
678 altA = new GfxDeviceRGBColorSpace();
679 break;
680 case 4:
681 altA = new GfxDeviceCMYKColorSpace();
682 break;
683 default:
684 error(-1, "Bad ICCBased color space - invalid N");
685 obj2.free();
686 obj1.free();
687 return NULL;
688 }
689 }
690 obj2.free();
691 cs = new GfxICCBasedColorSpace(nCompsA, altA, &iccProfileStreamA);
692 if (dict->lookup("Range", &obj2)->isArray() &&
693 obj2.arrayGetLength() == 2 * nCompsA) {
694 for (i = 0; i < nCompsA; ++i) {
695 obj2.arrayGet(2*i, &obj3);
696 cs->rangeMin[i] = obj3.getNum();
697 obj3.free();
698 obj2.arrayGet(2*i+1, &obj3);
699 cs->rangeMax[i] = obj3.getNum();
700 obj3.free();
701 }
702 }
703 obj2.free();
704 obj1.free();
705 return cs;
706}
707
708void GfxICCBasedColorSpace::getGray(GfxColor *color, fouble *gray) {
709 alt->getGray(color, gray);
710}
711
712void GfxICCBasedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
713 alt->getRGB(color, rgb);
714}
715
716void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
717 alt->getCMYK(color, cmyk);
718}
719
720void GfxICCBasedColorSpace::getDefaultRanges(fouble *decodeLow,
721 fouble *decodeRange,
722 int maxImgPixel) {
723 int i;
724
725 for (i = 0; i < nComps; ++i) {
726 decodeLow[i] = rangeMin[i];
727 decodeRange[i] = rangeMax[i] - rangeMin[i];
728 }
729}
730
731//------------------------------------------------------------------------
732// GfxIndexedColorSpace
733//------------------------------------------------------------------------
734
735GfxIndexedColorSpace::GfxIndexedColorSpace(GfxColorSpace *baseA,
736 int indexHighA) {
737 base = baseA;
738 indexHigh = indexHighA;
739 lookup = (Guchar *)gmalloc((indexHigh + 1) * base->getNComps() *
740 sizeof(Guchar));
741}
742
743GfxIndexedColorSpace::~GfxIndexedColorSpace() {
744 delete base;
745 gfree(lookup);
746}
747
748GfxColorSpace *GfxIndexedColorSpace::copy() {
749 GfxIndexedColorSpace *cs;
750
751 cs = new GfxIndexedColorSpace(base->copy(), indexHigh);
752 memcpy(cs->lookup, lookup,
753 (indexHigh + 1) * base->getNComps() * sizeof(Guchar));
754 return cs;
755}
756
757GfxColorSpace *GfxIndexedColorSpace::parse(Array *arr) {
758 GfxIndexedColorSpace *cs;
759 GfxColorSpace *baseA;
760 int indexHighA;
761 Object obj1;
762 int x;
763 char *s;
764 int n, i, j;
765
766 if (arr->getLength() != 4) {
767 error(-1, "Bad Indexed color space");
768 goto err1;
769 }
770 arr->get(1, &obj1);
771 if (!(baseA = GfxColorSpace::parse(&obj1))) {
772 error(-1, "Bad Indexed color space (base color space)");
773 goto err2;
774 }
775 obj1.free();
776 if (!arr->get(2, &obj1)->isInt()) {
777 error(-1, "Bad Indexed color space (hival)");
778 goto err2;
779 }
780 indexHighA = obj1.getInt();
781 obj1.free();
782 cs = new GfxIndexedColorSpace(baseA, indexHighA);
783 arr->get(3, &obj1);
784 n = baseA->getNComps();
785 if (obj1.isStream()) {
786 obj1.streamReset();
787 for (i = 0; i <= indexHighA; ++i) {
788 for (j = 0; j < n; ++j) {
789 if ((x = obj1.streamGetChar()) == EOF) {
790 error(-1, "Bad Indexed color space (lookup table stream too short)");
791 goto err3;
792 }
793 cs->lookup[i*n + j] = (Guchar)x;
794 }
795 }
796 obj1.streamClose();
797 } else if (obj1.isString()) {
798 if (obj1.getString()->getLength() < (indexHighA + 1) * n) {
799 error(-1, "Bad Indexed color space (lookup table string too short)");
800 goto err3;
801 }
802 s = obj1.getString()->getCString();
803 for (i = 0; i <= indexHighA; ++i) {
804 for (j = 0; j < n; ++j) {
805 cs->lookup[i*n + j] = (Guchar)*s++;
806 }
807 }
808 } else {
809 error(-1, "Bad Indexed color space (lookup table)");
810 goto err3;
811 }
812 obj1.free();
813 return cs;
814
815 err3:
816 delete cs;
817 err2:
818 obj1.free();
819 err1:
820 return NULL;
821}
822
823void GfxIndexedColorSpace::getGray(GfxColor *color, fouble *gray) {
824 Guchar *p;
825 GfxColor color2;
826 int n, i;
827
828 n = base->getNComps();
829 p = &lookup[(int)(color->c[0] + 0.5) * n];
830 for (i = 0; i < n; ++i) {
831 color2.c[i] = p[i] / 255.0;
832 }
833 base->getGray(&color2, gray);
834}
835
836void GfxIndexedColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
837 Guchar *p;
838 GfxColor color2;
839 int n, i;
840
841 n = base->getNComps();
842 p = &lookup[(int)(color->c[0] + 0.5) * n];
843 for (i = 0; i < n; ++i) {
844 color2.c[i] = p[i] / 255.0;
845 }
846 base->getRGB(&color2, rgb);
847}
848
849void GfxIndexedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
850 Guchar *p;
851 GfxColor color2;
852 int n, i;
853
854 n = base->getNComps();
855 p = &lookup[(int)(color->c[0] + 0.5) * n];
856 for (i = 0; i < n; ++i) {
857 color2.c[i] = p[i] / 255.0;
858 }
859 base->getCMYK(&color2, cmyk);
860}
861
862void GfxIndexedColorSpace::getDefaultRanges(fouble *decodeLow,
863 fouble *decodeRange,
864 int maxImgPixel) {
865 decodeLow[0] = 0;
866 decodeRange[0] = maxImgPixel;
867}
868
869//------------------------------------------------------------------------
870// GfxSeparationColorSpace
871//------------------------------------------------------------------------
872
873GfxSeparationColorSpace::GfxSeparationColorSpace(GString *nameA,
874 GfxColorSpace *altA,
875 Function *funcA) {
876 name = nameA;
877 alt = altA;
878 func = funcA;
879}
880
881GfxSeparationColorSpace::~GfxSeparationColorSpace() {
882 delete name;
883 delete alt;
884 delete func;
885}
886
887GfxColorSpace *GfxSeparationColorSpace::copy() {
888 return new GfxSeparationColorSpace(name->copy(), alt->copy(), func->copy());
889}
890
891//~ handle the 'All' and 'None' colorants
892GfxColorSpace *GfxSeparationColorSpace::parse(Array *arr) {
893 GfxSeparationColorSpace *cs;
894 GString *nameA;
895 GfxColorSpace *altA;
896 Function *funcA;
897 Object obj1;
898
899 if (arr->getLength() != 4) {
900 error(-1, "Bad Separation color space");
901 goto err1;
902 }
903 if (!arr->get(1, &obj1)->isName()) {
904 error(-1, "Bad Separation color space (name)");
905 goto err2;
906 }
907 nameA = new GString(obj1.getName());
908 obj1.free();
909 arr->get(2, &obj1);
910 if (!(altA = GfxColorSpace::parse(&obj1))) {
911 error(-1, "Bad Separation color space (alternate color space)");
912 goto err3;
913 }
914 obj1.free();
915 arr->get(3, &obj1);
916 if (!(funcA = Function::parse(&obj1))) {
917 goto err4;
918 }
919 obj1.free();
920 cs = new GfxSeparationColorSpace(nameA, altA, funcA);
921 return cs;
922
923 err4:
924 delete altA;
925 err3:
926 delete nameA;
927 err2:
928 obj1.free();
929 err1:
930 return NULL;
931}
932
933void GfxSeparationColorSpace::getGray(GfxColor *color, fouble *gray) {
934 GfxColor color2;
935
936 func->transform(color->c, color2.c);
937 alt->getGray(&color2, gray);
938}
939
940void GfxSeparationColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
941 GfxColor color2;
942
943 func->transform(color->c, color2.c);
944 alt->getRGB(&color2, rgb);
945}
946
947void GfxSeparationColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
948 GfxColor color2;
949
950 func->transform(color->c, color2.c);
951 alt->getCMYK(&color2, cmyk);
952}
953
954//------------------------------------------------------------------------
955// GfxDeviceNColorSpace
956//------------------------------------------------------------------------
957
958GfxDeviceNColorSpace::GfxDeviceNColorSpace(int nCompsA,
959 GfxColorSpace *altA,
960 Function *funcA) {
961 nComps = nCompsA;
962 alt = altA;
963 func = funcA;
964}
965
966GfxDeviceNColorSpace::~GfxDeviceNColorSpace() {
967 int i;
968
969 for (i = 0; i < nComps; ++i) {
970 delete names[i];
971 }
972 delete alt;
973 delete func;
974}
975
976GfxColorSpace *GfxDeviceNColorSpace::copy() {
977 GfxDeviceNColorSpace *cs;
978 int i;
979
980 cs = new GfxDeviceNColorSpace(nComps, alt->copy(), func->copy());
981 for (i = 0; i < nComps; ++i) {
982 cs->names[i] = names[i]->copy();
983 }
984 return cs;
985}
986
987//~ handle the 'None' colorant
988GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) {
989 GfxDeviceNColorSpace *cs;
990 int nCompsA;
991 GString *namesA[gfxColorMaxComps];
992 GfxColorSpace *altA;
993 Function *funcA;
994 Object obj1, obj2;
995 int i;
996
997 if (arr->getLength() != 4 && arr->getLength() != 5) {
998 error(-1, "Bad DeviceN color space");
999 goto err1;
1000 }
1001 if (!arr->get(1, &obj1)->isArray()) {
1002 error(-1, "Bad DeviceN color space (names)");
1003 goto err2;
1004 }
1005 nCompsA = obj1.arrayGetLength();
1006 for (i = 0; i < nCompsA; ++i) {
1007 if (!obj1.arrayGet(i, &obj2)->isName()) {
1008 error(-1, "Bad DeviceN color space (names)");
1009 obj2.free();
1010 goto err2;
1011 }
1012 namesA[i] = new GString(obj2.getName());
1013 obj2.free();
1014 }
1015 obj1.free();
1016 arr->get(2, &obj1);
1017 if (!(altA = GfxColorSpace::parse(&obj1))) {
1018 error(-1, "Bad DeviceN color space (alternate color space)");
1019 goto err3;
1020 }
1021 obj1.free();
1022 arr->get(3, &obj1);
1023 if (!(funcA = Function::parse(&obj1))) {
1024 goto err4;
1025 }
1026 obj1.free();
1027 cs = new GfxDeviceNColorSpace(nCompsA, altA, funcA);
1028 for (i = 0; i < nCompsA; ++i) {
1029 cs->names[i] = namesA[i];
1030 }
1031 return cs;
1032
1033 err4:
1034 delete altA;
1035 err3:
1036 for (i = 0; i < nCompsA; ++i) {
1037 delete namesA[i];
1038 }
1039 err2:
1040 obj1.free();
1041 err1:
1042 return NULL;
1043}
1044
1045void GfxDeviceNColorSpace::getGray(GfxColor *color, fouble *gray) {
1046 GfxColor color2;
1047
1048 func->transform(color->c, color2.c);
1049 alt->getGray(&color2, gray);
1050}
1051
1052void GfxDeviceNColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1053 GfxColor color2;
1054
1055 func->transform(color->c, color2.c);
1056 alt->getRGB(&color2, rgb);
1057}
1058
1059void GfxDeviceNColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1060 GfxColor color2;
1061
1062 func->transform(color->c, color2.c);
1063 alt->getCMYK(&color2, cmyk);
1064}
1065
1066//------------------------------------------------------------------------
1067// GfxPatternColorSpace
1068//------------------------------------------------------------------------
1069
1070GfxPatternColorSpace::GfxPatternColorSpace(GfxColorSpace *underA) {
1071 under = underA;
1072}
1073
1074GfxPatternColorSpace::~GfxPatternColorSpace() {
1075 if (under) {
1076 delete under;
1077 }
1078}
1079
1080GfxColorSpace *GfxPatternColorSpace::copy() {
1081 return new GfxPatternColorSpace(under ? under->copy() :
1082 (GfxColorSpace *)NULL);
1083}
1084
1085GfxColorSpace *GfxPatternColorSpace::parse(Array *arr) {
1086 GfxPatternColorSpace *cs;
1087 GfxColorSpace *underA;
1088 Object obj1;
1089
1090 if (arr->getLength() != 1 && arr->getLength() != 2) {
1091 error(-1, "Bad Pattern color space");
1092 return NULL;
1093 }
1094 underA = NULL;
1095 if (arr->getLength() == 2) {
1096 arr->get(1, &obj1);
1097 if (!(underA = GfxColorSpace::parse(&obj1))) {
1098 error(-1, "Bad Pattern color space (underlying color space)");
1099 obj1.free();
1100 return NULL;
1101 }
1102 obj1.free();
1103 }
1104 cs = new GfxPatternColorSpace(underA);
1105 return cs;
1106}
1107
1108void GfxPatternColorSpace::getGray(GfxColor *color, fouble *gray) {
1109 *gray = 0;
1110}
1111
1112void GfxPatternColorSpace::getRGB(GfxColor *color, GfxRGB *rgb) {
1113 rgb->r = rgb->g = rgb->b = 0;
1114}
1115
1116void GfxPatternColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) {
1117 cmyk->c = cmyk->m = cmyk->y = 0;
1118 cmyk->k = 1;
1119}
1120
1121//------------------------------------------------------------------------
1122// Pattern
1123//------------------------------------------------------------------------
1124
1125GfxPattern::GfxPattern(int typeA) {
1126 type = typeA;
1127}
1128
1129GfxPattern::~GfxPattern() {
1130}
1131
1132GfxPattern *GfxPattern::parse(Object *obj) {
1133 GfxPattern *pattern;
1134 Dict *dict;
1135 Object obj1;
1136
1137 pattern = NULL;
1138 if (obj->isStream()) {
1139 dict = obj->streamGetDict();
1140 dict->lookup("PatternType", &obj1);
1141 if (obj1.isInt() && obj1.getInt() == 1) {
1142 pattern = new GfxTilingPattern(dict, obj);
1143 }
1144 obj1.free();
1145 }
1146 return pattern;
1147}
1148
1149//------------------------------------------------------------------------
1150// GfxTilingPattern
1151//------------------------------------------------------------------------
1152
1153GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
1154 GfxPattern(1)
1155{
1156 Object obj1, obj2;
1157 int i;
1158
1159 if (streamDict->lookup("PaintType", &obj1)->isInt()) {
1160 paintType = obj1.getInt();
1161 } else {
1162 paintType = 1;
1163 error(-1, "Invalid or missing PaintType in pattern");
1164 }
1165 obj1.free();
1166 if (streamDict->lookup("TilingType", &obj1)->isInt()) {
1167 tilingType = obj1.getInt();
1168 } else {
1169 tilingType = 1;
1170 error(-1, "Invalid or missing TilingType in pattern");
1171 }
1172 obj1.free();
1173 bbox[0] = bbox[1] = 0;
1174 bbox[2] = bbox[3] = 1;
1175 if (streamDict->lookup("BBox", &obj1)->isArray() &&
1176 obj1.arrayGetLength() == 4) {
1177 for (i = 0; i < 4; ++i) {
1178 if (obj1.arrayGet(i, &obj2)->isNum()) {
1179 bbox[i] = obj2.getNum();
1180 }
1181 obj2.free();
1182 }
1183 } else {
1184 error(-1, "Invalid or missing BBox in pattern");
1185 }
1186 obj1.free();
1187 if (streamDict->lookup("XStep", &obj1)->isNum()) {
1188 xStep = obj1.getNum();
1189 } else {
1190 xStep = 1;
1191 error(-1, "Invalid or missing XStep in pattern");
1192 }
1193 obj1.free();
1194 if (streamDict->lookup("YStep", &obj1)->isNum()) {
1195 yStep = obj1.getNum();
1196 } else {
1197 yStep = 1;
1198 error(-1, "Invalid or missing YStep in pattern");
1199 }
1200 obj1.free();
1201 if (!streamDict->lookup("Resources", &resDict)->isDict()) {
1202 resDict.free();
1203 resDict.initNull();
1204 error(-1, "Invalid or missing Resources in pattern");
1205 }
1206 matrix[0] = 1; matrix[1] = 0;
1207 matrix[2] = 0; matrix[3] = 1;
1208 matrix[4] = 0; matrix[5] = 0;
1209 if (streamDict->lookup("Matrix", &obj1)->isArray() &&
1210 obj1.arrayGetLength() == 6) {
1211 for (i = 0; i < 6; ++i) {
1212 if (obj1.arrayGet(i, &obj2)->isNum()) {
1213 matrix[i] = obj2.getNum();
1214 }
1215 obj2.free();
1216 }
1217 }
1218 obj1.free();
1219 stream->copy(&contentStream);
1220}
1221
1222GfxTilingPattern::~GfxTilingPattern() {
1223 resDict.free();
1224 contentStream.free();
1225}
1226
1227GfxPattern *GfxTilingPattern::copy() {
1228 return new GfxTilingPattern(this);
1229}
1230
1231GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
1232 GfxPattern(1)
1233{
1234 memcpy(this, pat, sizeof(GfxTilingPattern));
1235 pat->resDict.copy(&resDict);
1236 pat->contentStream.copy(&contentStream);
1237}
1238
1239//------------------------------------------------------------------------
1240// GfxShading
1241//------------------------------------------------------------------------
1242
1243GfxShading::GfxShading() {
1244}
1245
1246GfxShading::~GfxShading() {
1247 delete colorSpace;
1248}
1249
1250GfxShading *GfxShading::parse(Object *obj) {
1251 GfxShading *shading;
1252 int typeA;
1253 GfxColorSpace *colorSpaceA;
1254 GfxColor backgroundA;
1255 GBool hasBackgroundA;
1256 fouble xMinA, yMinA, xMaxA, yMaxA;
1257 GBool hasBBoxA;
1258 Object obj1, obj2;
1259 int i;
1260
1261 shading = NULL;
1262 if (obj->isDict()) {
1263
1264 if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
1265 error(-1, "Invalid ShadingType in shading dictionary");
1266 obj1.free();
1267 goto err1;
1268 }
1269 typeA = obj1.getInt();
1270 obj1.free();
1271 if (typeA != 2) {
1272 error(-1, "Unimplemented shading type %d", typeA);
1273 goto err1;
1274 }
1275
1276 obj->dictLookup("ColorSpace", &obj1);
1277 if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
1278 error(-1, "Bad color space in shading dictionary");
1279 obj1.free();
1280 goto err1;
1281 }
1282 obj1.free();
1283
1284 for (i = 0; i < gfxColorMaxComps; ++i) {
1285 backgroundA.c[i] = 0;
1286 }
1287 hasBackgroundA = gFalse;
1288 if (obj->dictLookup("Background", &obj1)->isArray()) {
1289 if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
1290 hasBackgroundA = gTrue;
1291 for (i = 0; i < colorSpaceA->getNComps(); ++i) {
1292 backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
1293 obj2.free();
1294 }
1295 } else {
1296 error(-1, "Bad Background in shading dictionary");
1297 }
1298 }
1299 obj1.free();
1300
1301 xMinA = yMinA = xMaxA = yMaxA = 0;
1302 hasBBoxA = gFalse;
1303 if (obj->dictLookup("BBox", &obj1)->isArray()) {
1304 if (obj1.arrayGetLength() == 4) {
1305 hasBBoxA = gTrue;
1306 xMinA = obj1.arrayGet(0, &obj2)->getNum();
1307 obj2.free();
1308 yMinA = obj1.arrayGet(1, &obj2)->getNum();
1309 obj2.free();
1310 xMaxA = obj1.arrayGet(2, &obj2)->getNum();
1311 obj2.free();
1312 yMaxA = obj1.arrayGet(3, &obj2)->getNum();
1313 obj2.free();
1314 } else {
1315 error(-1, "Bad BBox in shading dictionary");
1316 }
1317 }
1318 obj1.free();
1319
1320 shading = GfxAxialShading::parse(obj->getDict());
1321
1322 if (shading) {
1323 shading->type = typeA;
1324 shading->colorSpace = colorSpaceA;
1325 shading->background = backgroundA;
1326 shading->hasBackground = hasBackgroundA;
1327 shading->xMin = xMinA;
1328 shading->yMin = yMinA;
1329 shading->xMax = xMaxA;
1330 shading->yMax = yMaxA;
1331 shading->hasBBox = hasBBoxA;
1332 } else {
1333 delete colorSpaceA;
1334 }
1335 }
1336
1337 return shading;
1338
1339 err1:
1340 return NULL;
1341}
1342
1343//------------------------------------------------------------------------
1344// GfxAxialShading
1345//------------------------------------------------------------------------
1346
1347GfxAxialShading::GfxAxialShading(fouble x0A, fouble y0A,
1348 fouble x1A, fouble y1A,
1349 fouble t0A, fouble t1A,
1350 Function **funcsA, int nFuncsA,
1351 GBool extend0A, GBool extend1A) {
1352 int i;
1353
1354 x0 = x0A;
1355 y0 = y0A;
1356 x1 = x1A;
1357 y1 = y1A;
1358 t0 = t0A;
1359 t1 = t1A;
1360 nFuncs = nFuncsA;
1361 for (i = 0; i < nFuncs; ++i) {
1362 funcs[i] = funcsA[i];
1363 }
1364 extend0 = extend0A;
1365 extend1 = extend1A;
1366}
1367
1368GfxAxialShading::~GfxAxialShading() {
1369 int i;
1370
1371 for (i = 0; i < nFuncs; ++i) {
1372 delete funcs[i];
1373 }
1374}
1375
1376GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
1377 fouble x0A, y0A, x1A, y1A;
1378 fouble t0A, t1A;
1379 Function *funcsA[gfxColorMaxComps];
1380 int nFuncsA;
1381 GBool extend0A, extend1A;
1382 Object obj1, obj2;
1383 int i;
1384
1385 x0A = y0A = x1A = y1A = 0;
1386 if (dict->lookup("Coords", &obj1)->isArray() &&
1387 obj1.arrayGetLength() == 4) {
1388 x0A = obj1.arrayGet(0, &obj2)->getNum();
1389 obj2.free();
1390 y0A = obj1.arrayGet(1, &obj2)->getNum();
1391 obj2.free();
1392 x1A = obj1.arrayGet(2, &obj2)->getNum();
1393 obj2.free();
1394 y1A = obj1.arrayGet(3, &obj2)->getNum();
1395 obj2.free();
1396 } else {
1397 error(-1, "Missing or invalid Coords in shading dictionary");
1398 goto err1;
1399 }
1400 obj1.free();
1401
1402 t0A = 0;
1403 t1A = 1;
1404 if (dict->lookup("Domain", &obj1)->isArray() &&
1405 obj1.arrayGetLength() == 2) {
1406 t0A = obj1.arrayGet(0, &obj2)->getNum();
1407 obj2.free();
1408 t1A = obj1.arrayGet(1, &obj2)->getNum();
1409 obj2.free();
1410 }
1411 obj1.free();
1412
1413 dict->lookup("Function", &obj1);
1414 if (obj1.isArray()) {
1415 nFuncsA = obj1.arrayGetLength();
1416 for (i = 0; i < nFuncsA; ++i) {
1417 obj1.arrayGet(i, &obj2);
1418 if (!(funcsA[i] = Function::parse(&obj2))) {
1419 obj1.free();
1420 obj2.free();
1421 goto err1;
1422 }
1423 obj2.free();
1424 }
1425 } else {
1426 nFuncsA = 1;
1427 if (!(funcsA[0] = Function::parse(&obj1))) {
1428 obj1.free();
1429 goto err1;
1430 }
1431 }
1432 obj1.free();
1433
1434 extend0A = extend1A = gFalse;
1435 if (dict->lookup("Extend", &obj1)->isArray() &&
1436 obj1.arrayGetLength() == 2) {
1437 extend0A = obj1.arrayGet(0, &obj2)->getBool();
1438 obj2.free();
1439 extend1A = obj1.arrayGet(1, &obj2)->getBool();
1440 obj2.free();
1441 }
1442 obj1.free();
1443
1444 return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
1445 funcsA, nFuncsA, extend0A, extend1A);
1446
1447 err1:
1448 return NULL;
1449}
1450
1451void GfxAxialShading::getColor(fouble t, GfxColor *color) {
1452 int i;
1453
1454 for (i = 0; i < nFuncs; ++i) {
1455 funcs[i]->transform(&t, &color->c[i]);
1456 }
1457}
1458
1459//------------------------------------------------------------------------
1460// GfxImageColorMap
1461//------------------------------------------------------------------------
1462
1463GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
1464 GfxColorSpace *colorSpaceA) {
1465 GfxIndexedColorSpace *indexedCS;
1466 GfxSeparationColorSpace *sepCS;
1467 int maxPixel, indexHigh;
1468 Guchar *lookup2;
1469 Function *sepFunc;
1470 Object obj;
1471 fouble x[gfxColorMaxComps];
1472 fouble y[gfxColorMaxComps];
1473 int i, j, k;
1474
1475 ok = gTrue;
1476
1477 // bits per component and color space
1478 bits = bitsA;
1479 maxPixel = (1 << bits) - 1;
1480 colorSpace = colorSpaceA;
1481
1482 // get decode map
1483 if (decode->isNull()) {
1484 nComps = colorSpace->getNComps();
1485 colorSpace->getDefaultRanges(decodeLow, decodeRange, maxPixel);
1486 } else if (decode->isArray()) {
1487 nComps = decode->arrayGetLength() / 2;
1488 if (nComps != colorSpace->getNComps()) {
1489 goto err1;
1490 }
1491 for (i = 0; i < nComps; ++i) {
1492 decode->arrayGet(2*i, &obj);
1493 if (!obj.isNum()) {
1494 goto err2;
1495 }
1496 decodeLow[i] = obj.getNum();
1497 obj.free();
1498 decode->arrayGet(2*i+1, &obj);
1499 if (!obj.isNum()) {
1500 goto err2;
1501 }
1502 decodeRange[i] = obj.getNum() - decodeLow[i];
1503 obj.free();
1504 }
1505 } else {
1506 goto err1;
1507 }
1508
1509 // Construct a lookup table -- this stores pre-computed decoded
1510 // values for each component, i.e., the result of applying the
1511 // decode mapping to each possible image pixel component value.
1512 //
1513 // Optimization: for Indexed and Separation color spaces (which have
1514 // only one component), we store color values in the lookup table
1515 // rather than component values.
1516 colorSpace2 = NULL;
1517 nComps2 = 0;
1518 if (colorSpace->getMode() == csIndexed) {
1519 // Note that indexHigh may not be the same as maxPixel --
1520 // Distiller will remove unused palette entries, resulting in
1521 // indexHigh < maxPixel.
1522 indexedCS = (GfxIndexedColorSpace *)colorSpace;
1523 colorSpace2 = indexedCS->getBase();
1524 indexHigh = indexedCS->getIndexHigh();
1525 nComps2 = colorSpace2->getNComps();
1526 lookup = (fouble *)gmalloc((indexHigh + 1) * nComps2 * sizeof(fouble));
1527 lookup2 = indexedCS->getLookup();
1528 for (i = 0; i <= indexHigh; ++i) {
1529 j = (int)(decodeLow[0] +(i * decodeRange[0]) / maxPixel + 0.5);
1530 for (k = 0; k < nComps2; ++k) {
1531 lookup[i*nComps2 + k] = lookup2[i*nComps2 + k] / 255.0;
1532 }
1533 }
1534 } else if (colorSpace->getMode() == csSeparation) {
1535 sepCS = (GfxSeparationColorSpace *)colorSpace;
1536 colorSpace2 = sepCS->getAlt();
1537 nComps2 = colorSpace2->getNComps();
1538 lookup = (fouble *)gmalloc((maxPixel + 1) * nComps2 * sizeof(fouble));
1539 sepFunc = sepCS->getFunc();
1540 for (i = 0; i <= maxPixel; ++i) {
1541 x[0] = decodeLow[0] + (i * decodeRange[0]) / maxPixel;
1542 sepFunc->transform(x, y);
1543 for (k = 0; k < nComps2; ++k) {
1544 lookup[i*nComps2 + k] = y[k];
1545 }
1546 }
1547 } else {
1548 lookup = (fouble *)gmalloc((maxPixel + 1) * nComps * sizeof(fouble));
1549 for (i = 0; i <= maxPixel; ++i) {
1550 for (k = 0; k < nComps; ++k) {
1551 lookup[i*nComps + k] = decodeLow[k] +
1552 (i * decodeRange[k]) / maxPixel;
1553 }
1554 }
1555 }
1556
1557 return;
1558
1559 err2:
1560 obj.free();
1561 err1:
1562 ok = gFalse;
1563}
1564
1565GfxImageColorMap::~GfxImageColorMap() {
1566 delete colorSpace;
1567 gfree(lookup);
1568}
1569
1570void GfxImageColorMap::getGray(Guchar *x, fouble *gray) {
1571 GfxColor color;
1572 fouble *p;
1573 int i;
1574
1575 if (colorSpace2) {
1576 p = &lookup[x[0] * nComps2];
1577 for (i = 0; i < nComps2; ++i) {
1578 color.c[i] = *p++;
1579 }
1580 colorSpace2->getGray(&color, gray);
1581 } else {
1582 for (i = 0; i < nComps; ++i) {
1583 color.c[i] = lookup[x[i] * nComps + i];
1584 }
1585 colorSpace->getGray(&color, gray);
1586 }
1587}
1588
1589void GfxImageColorMap::getRGB(Guchar *x, GfxRGB *rgb) {
1590 GfxColor color;
1591 fouble *p;
1592 int i;
1593
1594 if (colorSpace2) {
1595 p = &lookup[x[0] * nComps2];
1596 for (i = 0; i < nComps2; ++i) {
1597 color.c[i] = *p++;
1598 }
1599 colorSpace2->getRGB(&color, rgb);
1600 } else {
1601 for (i = 0; i < nComps; ++i) {
1602 color.c[i] = lookup[x[i] * nComps + i];
1603 }
1604 colorSpace->getRGB(&color, rgb);
1605 }
1606}
1607
1608void GfxImageColorMap::getCMYK(Guchar *x, GfxCMYK *cmyk) {
1609 GfxColor color;
1610 fouble *p;
1611 int i;
1612
1613 if (colorSpace2) {
1614 p = &lookup[x[0] * nComps2];
1615 for (i = 0; i < nComps2; ++i) {
1616 color.c[i] = *p++;
1617 }
1618 colorSpace2->getCMYK(&color, cmyk);
1619 } else {
1620 for (i = 0; i < nComps; ++i) {
1621 color.c[i] = lookup[x[i] * nComps + i];
1622 }
1623 colorSpace->getCMYK(&color, cmyk);
1624 }
1625}
1626
1627//------------------------------------------------------------------------
1628// GfxSubpath and GfxPath
1629//------------------------------------------------------------------------
1630
1631GfxSubpath::GfxSubpath(fouble x1, fouble y1) {
1632 size = 16;
1633 x = (fouble *)gmalloc(size * sizeof(fouble));
1634 y = (fouble *)gmalloc(size * sizeof(fouble));
1635 curve = (GBool *)gmalloc(size * sizeof(GBool));
1636 n = 1;
1637 x[0] = x1;
1638 y[0] = y1;
1639 curve[0] = gFalse;
1640 closed = gFalse;
1641}
1642
1643GfxSubpath::~GfxSubpath() {
1644 gfree(x);
1645 gfree(y);
1646 gfree(curve);
1647}
1648
1649// Used for copy().
1650GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
1651 size = subpath->size;
1652 n = subpath->n;
1653 x = (fouble *)gmalloc(size * sizeof(fouble));
1654 y = (fouble *)gmalloc(size * sizeof(fouble));
1655 curve = (GBool *)gmalloc(size * sizeof(GBool));
1656 memcpy(x, subpath->x, n * sizeof(fouble));
1657 memcpy(y, subpath->y, n * sizeof(fouble));
1658 memcpy(curve, subpath->curve, n * sizeof(GBool));
1659 closed = subpath->closed;
1660}
1661
1662void GfxSubpath::lineTo(fouble x1, fouble y1) {
1663 if (n >= size) {
1664 size += 16;
1665 x = (fouble *)grealloc(x, size * sizeof(fouble));
1666 y = (fouble *)grealloc(y, size * sizeof(fouble));
1667 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1668 }
1669 x[n] = x1;
1670 y[n] = y1;
1671 curve[n] = gFalse;
1672 ++n;
1673}
1674
1675void GfxSubpath::curveTo(fouble x1, fouble y1, fouble x2, fouble y2,
1676 fouble x3, fouble y3) {
1677 if (n+3 > size) {
1678 size += 16;
1679 x = (fouble *)grealloc(x, size * sizeof(fouble));
1680 y = (fouble *)grealloc(y, size * sizeof(fouble));
1681 curve = (GBool *)grealloc(curve, size * sizeof(GBool));
1682 }
1683 x[n] = x1;
1684 y[n] = y1;
1685 x[n+1] = x2;
1686 y[n+1] = y2;
1687 x[n+2] = x3;
1688 y[n+2] = y3;
1689 curve[n] = curve[n+1] = gTrue;
1690 curve[n+2] = gFalse;
1691 n += 3;
1692}
1693
1694void GfxSubpath::close() {
1695 if (x[n-1] != x[0] || y[n-1] != y[0]) {
1696 lineTo(x[0], y[0]);
1697 }
1698 closed = gTrue;
1699}
1700
1701GfxPath::GfxPath() {
1702 justMoved = gFalse;
1703 size = 16;
1704 n = 0;
1705 firstX = firstY = 0;
1706 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1707}
1708
1709GfxPath::~GfxPath() {
1710 int i;
1711
1712 for (i = 0; i < n; ++i)
1713 delete subpaths[i];
1714 gfree(subpaths);
1715}
1716
1717// Used for copy().
1718GfxPath::GfxPath(GBool justMoved1, fouble firstX1, fouble firstY1,
1719 GfxSubpath **subpaths1, int n1, int size1) {
1720 int i;
1721
1722 justMoved = justMoved1;
1723 firstX = firstX1;
1724 firstY = firstY1;
1725 size = size1;
1726 n = n1;
1727 subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
1728 for (i = 0; i < n; ++i)
1729 subpaths[i] = subpaths1[i]->copy();
1730}
1731
1732void GfxPath::moveTo(fouble x, fouble y) {
1733 justMoved = gTrue;
1734 firstX = x;
1735 firstY = y;
1736}
1737
1738void GfxPath::lineTo(fouble x, fouble y) {
1739 if (justMoved) {
1740 if (n >= size) {
1741 size += 16;
1742 subpaths = (GfxSubpath **)
1743 grealloc(subpaths, size * sizeof(GfxSubpath *));
1744 }
1745 subpaths[n] = new GfxSubpath(firstX, firstY);
1746 ++n;
1747 justMoved = gFalse;
1748 }
1749 subpaths[n-1]->lineTo(x, y);
1750}
1751
1752void GfxPath::curveTo(fouble x1, fouble y1, fouble x2, fouble y2,
1753 fouble x3, fouble y3) {
1754 if (justMoved) {
1755 if (n >= size) {
1756 size += 16;
1757 subpaths = (GfxSubpath **)
1758 grealloc(subpaths, size * sizeof(GfxSubpath *));
1759 }
1760 subpaths[n] = new GfxSubpath(firstX, firstY);
1761 ++n;
1762 justMoved = gFalse;
1763 }
1764 subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
1765}
1766
1767void GfxPath::close() {
1768 // this is necessary to handle the pathological case of
1769 // moveto/closepath/clip, which defines an empty clipping region
1770 if (justMoved) {
1771 if (n >= size) {
1772 size += 16;
1773 subpaths = (GfxSubpath **)
1774 grealloc(subpaths, size * sizeof(GfxSubpath *));
1775 }
1776 subpaths[n] = new GfxSubpath(firstX, firstY);
1777 ++n;
1778 justMoved = gFalse;
1779 }
1780 subpaths[n-1]->close();
1781}
1782
1783//------------------------------------------------------------------------
1784// GfxState
1785//------------------------------------------------------------------------
1786
1787GfxState::GfxState(fouble dpi, PDFRectangle *pageBox, int rotate,
1788 GBool upsideDown) {
1789 fouble k;
1790
1791 px1 = pageBox->x1;
1792 py1 = pageBox->y1;
1793 px2 = pageBox->x2;
1794 py2 = pageBox->y2;
1795 k = dpi / 72.0;
1796 if (rotate == 90) {
1797 ctm[0] = 0;
1798 ctm[1] = upsideDown ? k : -k;
1799 ctm[2] = k;
1800 ctm[3] = 0;
1801 ctm[4] = -k * py1;
1802 ctm[5] = k * (upsideDown ? -px1 : px2);
1803 pageWidth = k * (py2 - py1);
1804 pageHeight = k * (px2 - px1);
1805 } else if (rotate == 180) {
1806 ctm[0] = -k;
1807 ctm[1] = 0;
1808 ctm[2] = 0;
1809 ctm[3] = upsideDown ? k : -k;
1810 ctm[4] = k * px2;
1811 ctm[5] = k * (upsideDown ? -py1 : py2);
1812 pageWidth = k * (px2 - px1);
1813 pageHeight = k * (py2 - py1);
1814 } else if (rotate == 270) {
1815 ctm[0] = 0;
1816 ctm[1] = upsideDown ? -k : k;
1817 ctm[2] = -k;
1818 ctm[3] = 0;
1819 ctm[4] = k * py2;
1820 ctm[5] = k * (upsideDown ? px2 : -px1);
1821 pageWidth = k * (py2 - py1);
1822 pageHeight = k * (px2 - px1);
1823 } else {
1824 ctm[0] = k;
1825 ctm[1] = 0;
1826 ctm[2] = 0;
1827 ctm[3] = upsideDown ? -k : k;
1828 ctm[4] = -k * px1;
1829 ctm[5] = k * (upsideDown ? py2 : -py1);
1830 pageWidth = k * (px2 - px1);
1831 pageHeight = k * (py2 - py1);
1832 }
1833
1834 fillColorSpace = new GfxDeviceGrayColorSpace();
1835 strokeColorSpace = new GfxDeviceGrayColorSpace();
1836 fillColor.c[0] = 0;
1837 strokeColor.c[0] = 0;
1838 fillPattern = NULL;
1839 strokePattern = NULL;
1840 fillOpacity = 1;
1841 strokeOpacity = 1;
1842
1843 lineWidth = 1;
1844 lineDash = NULL;
1845 lineDashLength = 0;
1846 lineDashStart = 0;
1847 flatness = 0;
1848 lineJoin = 0;
1849 lineCap = 0;
1850 miterLimit = 10;
1851
1852 font = NULL;
1853 fontSize = 0;
1854 textMat[0] = 1; textMat[1] = 0;
1855 textMat[2] = 0; textMat[3] = 1;
1856 textMat[4] = 0; textMat[5] = 0;
1857 charSpace = 0;
1858 wordSpace = 0;
1859 horizScaling = 1;
1860 leading = 0;
1861 rise = 0;
1862 render = 0;
1863
1864 path = new GfxPath();
1865 curX = curY = 0;
1866 lineX = lineY = 0;
1867
1868 clipXMin = 0;
1869 clipYMin = 0;
1870 clipXMax = pageWidth;
1871 clipYMax = pageHeight;
1872
1873 saved = NULL;
1874}
1875
1876GfxState::~GfxState() {
1877 if (fillColorSpace) {
1878 delete fillColorSpace;
1879 }
1880 if (strokeColorSpace) {
1881 delete strokeColorSpace;
1882 }
1883 if (fillPattern) {
1884 delete fillPattern;
1885 }
1886 if (strokePattern) {
1887 delete strokePattern;
1888 }
1889 gfree(lineDash);
1890 if (path) {
1891 // this gets set to NULL by restore()
1892 delete path;
1893 }
1894 if (saved) {
1895 delete saved;
1896 }
1897}
1898
1899// Used for copy();
1900GfxState::GfxState(GfxState *state) {
1901 memcpy(this, state, sizeof(GfxState));
1902 if (fillColorSpace) {
1903 fillColorSpace = state->fillColorSpace->copy();
1904 }
1905 if (strokeColorSpace) {
1906 strokeColorSpace = state->strokeColorSpace->copy();
1907 }
1908 if (fillPattern) {
1909 fillPattern = state->fillPattern->copy();
1910 }
1911 if (strokePattern) {
1912 strokePattern = state->strokePattern->copy();
1913 }
1914 if (lineDashLength > 0) {
1915 lineDash = (fouble *)gmalloc(lineDashLength * sizeof(fouble));
1916 memcpy(lineDash, state->lineDash, lineDashLength * sizeof(fouble));
1917 }
1918 saved = NULL;
1919}
1920
1921fouble GfxState::transformWidth(fouble w) {
1922 fouble x, y;
1923
1924 x = ctm[0] + ctm[2];
1925 y = ctm[1] + ctm[3];
1926 return w * sqrt(0.5 * (x * x + y * y));
1927}
1928
1929fouble GfxState::getTransformedFontSize() {
1930 fouble x1, y1, x2, y2;
1931
1932 x1 = textMat[2] * fontSize;
1933 y1 = textMat[3] * fontSize;
1934 x2 = ctm[0] * x1 + ctm[2] * y1;
1935 y2 = ctm[1] * x1 + ctm[3] * y1;
1936 return sqrt(x2 * x2 + y2 * y2);
1937}
1938
1939void GfxState::getFontTransMat(fouble *m11, fouble *m12,
1940 fouble *m21, fouble *m22) {
1941 *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
1942 *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
1943 *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
1944 *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
1945}
1946
1947void GfxState::setCTM(fouble a, fouble b, fouble c,
1948 fouble d, fouble e, fouble f) {
1949 ctm[0] = a;
1950 ctm[1] = b;
1951 ctm[2] = c;
1952 ctm[3] = d;
1953 ctm[4] = e;
1954 ctm[5] = f;
1955}
1956
1957void GfxState::concatCTM(fouble a, fouble b, fouble c,
1958 fouble d, fouble e, fouble f) {
1959 fouble a1 = ctm[0];
1960 fouble b1 = ctm[1];
1961 fouble c1 = ctm[2];
1962 fouble d1 = ctm[3];
1963
1964 ctm[0] = a * a1 + b * c1;
1965 ctm[1] = a * b1 + b * d1;
1966 ctm[2] = c * a1 + d * c1;
1967 ctm[3] = c * b1 + d * d1;
1968 ctm[4] = e * a1 + f * c1 + ctm[4];
1969 ctm[5] = e * b1 + f * d1 + ctm[5];
1970}
1971
1972void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
1973 if (fillColorSpace) {
1974 delete fillColorSpace;
1975 }
1976 fillColorSpace = colorSpace;
1977}
1978
1979void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
1980 if (strokeColorSpace) {
1981 delete strokeColorSpace;
1982 }
1983 strokeColorSpace = colorSpace;
1984}
1985
1986void GfxState::setFillPattern(GfxPattern *pattern) {
1987 if (fillPattern) {
1988 delete fillPattern;
1989 }
1990 fillPattern = pattern;
1991}
1992
1993void GfxState::setStrokePattern(GfxPattern *pattern) {
1994 if (strokePattern) {
1995 delete strokePattern;
1996 }
1997 strokePattern = pattern;
1998}
1999
2000void GfxState::setLineDash(fouble *dash, int length, fouble start) {
2001 if (lineDash)
2002 gfree(lineDash);
2003 lineDash = dash;
2004 lineDashLength = length;
2005 lineDashStart = start;
2006}
2007
2008void GfxState::clearPath() {
2009 delete path;
2010 path = new GfxPath();
2011}
2012
2013void GfxState::clip() {
2014 fouble xMin, yMin, xMax, yMax, x, y;
2015 GfxSubpath *subpath;
2016 int i, j;
2017
2018 xMin = xMax = yMin = yMax = 0; // make gcc happy
2019 for (i = 0; i < path->getNumSubpaths(); ++i) {
2020 subpath = path->getSubpath(i);
2021 for (j = 0; j < subpath->getNumPoints(); ++j) {
2022 transform(subpath->getX(j), subpath->getY(j), &x, &y);
2023 if (i == 0 && j == 0) {
2024 xMin = xMax = x;
2025 yMin = yMax = y;
2026 } else {
2027 if (x < xMin) {
2028 xMin = x;
2029 } else if (x > xMax) {
2030 xMax = x;
2031 }
2032 if (y < yMin) {
2033 yMin = y;
2034 } else if (y > yMax) {
2035 yMax = y;
2036 }
2037 }
2038 }
2039 }
2040 if (xMin > clipXMin) {
2041 clipXMin = xMin;
2042 }
2043 if (yMin > clipYMin) {
2044 clipYMin = yMin;
2045 }
2046 if (xMax < clipXMax) {
2047 clipXMax = xMax;
2048 }
2049 if (yMax < clipYMax) {
2050 clipYMax = yMax;
2051 }
2052}
2053
2054void GfxState::textShift(fouble tx) {
2055 fouble dx, dy;
2056
2057 textTransformDelta(tx, 0, &dx, &dy);
2058 curX += dx;
2059 curY += dy;
2060}
2061
2062void GfxState::shift(fouble dx, fouble dy) {
2063 curX += dx;
2064 curY += dy;
2065}
2066
2067GfxState *GfxState::save() {
2068 GfxState *newState;
2069
2070 newState = copy();
2071 newState->saved = this;
2072 return newState;
2073}
2074
2075GfxState *GfxState::restore() {
2076 GfxState *oldState;
2077
2078 if (saved) {
2079 oldState = saved;
2080
2081 // these attributes aren't saved/restored by the q/Q operators
2082 oldState->path = path;
2083 oldState->curX = curX;
2084 oldState->curY = curY;
2085 oldState->lineX = lineX;
2086 oldState->lineY = lineY;
2087
2088 path = NULL;
2089 saved = NULL;
2090 delete this;
2091
2092 } else {
2093 oldState = this;
2094 }
2095
2096 return oldState;
2097}