]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/GfxState.cc
Lots of cvsignores
[evince.git] / pdf / xpdf / GfxState.cc
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 <stddef.h>
14 #include <math.h>
15 #include <string.h> // for memcpy()
16 #include "gmem.h"
17 #include "Error.h"
18 #include "Object.h"
19 #include "GfxState.h"
20
21 //------------------------------------------------------------------------
22 // GfxColor
23 //------------------------------------------------------------------------
24
25 void GfxColor::setCMYK(double c, double m, double y, double k) {
26   if ((r = 1 - (c + k)) < 0)
27     r = 0;
28   if ((g = 1 - (m + k)) < 0)
29     g = 0;
30   if ((b = 1 - (y + k)) < 0)
31     b = 0;
32 }
33
34 //------------------------------------------------------------------------
35 // GfxColorSpace
36 //------------------------------------------------------------------------
37
38 GfxColorSpace::GfxColorSpace(Object *colorSpace) {
39   Object csObj;
40   Object obj, obj2;
41   char *s;
42   int x;
43   int i, j;
44
45   ok = gTrue;
46   lookup = NULL;
47
48   // check for Separation colorspace
49   colorSpace->copy(&csObj);
50   sepFunc = NULL;
51   if (colorSpace->isArray()) {
52     colorSpace->arrayGet(0, &obj);
53     if (obj.isName("Separation")) {
54       csObj.free();
55       colorSpace->arrayGet(2, &csObj);
56       sepFunc = new Function(colorSpace->arrayGet(3, &obj2));
57       obj2.free();
58       if (!sepFunc->isOk()) {
59         delete sepFunc;
60         sepFunc = NULL;
61       }
62     }
63     obj.free();
64   }
65
66   // get mode
67   indexed = gFalse;
68   if (csObj.isName()) {
69     setMode(&csObj);
70   } else if (csObj.isArray()) {
71     csObj.arrayGet(0, &obj);
72     if (obj.isName("Indexed") || obj.isName("I")) {
73       indexed = gTrue;
74       setMode(csObj.arrayGet(1, &obj2));
75       obj2.free();
76     } else {
77       setMode(&csObj);
78     }
79     obj.free();
80   } else {
81     goto err1;
82   }
83   if (!ok)
84     return;
85
86   // get lookup table for indexed colorspace
87   if (indexed) {
88     csObj.arrayGet(2, &obj);
89     if (!obj.isInt())
90       goto err2;
91     indexHigh = obj.getInt();
92     obj.free();
93     lookup = (Guchar (*)[4])gmalloc((indexHigh + 1) * 4 * sizeof(Guchar));
94     csObj.arrayGet(3, &obj);
95     if (obj.isStream()) {
96       obj.streamReset();
97       for (i = 0; i <= indexHigh; ++i) {
98         for (j = 0; j < numComps; ++j) {
99           if ((x = obj.streamGetChar()) == EOF)
100             goto err2;
101           lookup[i][j] = (Guchar)x;
102         }
103       }
104     } else if (obj.isString()) {
105       s = obj.getString()->getCString();
106       for (i = 0; i <= indexHigh; ++i)
107         for (j = 0; j < numComps; ++j)
108           lookup[i][j] = (Guchar)*s++;
109     } else {
110       goto err2;
111     }
112     obj.free();
113   }
114
115   csObj.free();
116   return;
117
118  err2:
119   obj.free();
120  err1:
121   csObj.free();
122   ok = gFalse;
123 }
124
125 GfxColorSpace::GfxColorSpace(GfxColorMode mode1) {
126   sepFunc = NULL;
127   mode = mode1;
128   indexed = gFalse;
129   switch (mode) {
130   case colorGray: numComps = 1; break;
131   case colorCMYK: numComps = 4; break;
132   case colorRGB:  numComps = 3; break;
133   }
134   lookup = NULL;
135   ok = gTrue;
136 }
137
138 GfxColorSpace::~GfxColorSpace() {
139   if (sepFunc)
140     delete sepFunc;
141   gfree(lookup);
142 }
143
144 GfxColorSpace::GfxColorSpace(GfxColorSpace *colorSpace) {
145   int size;
146
147   if (colorSpace->sepFunc)
148     sepFunc = colorSpace->sepFunc->copy();
149   else
150     sepFunc = NULL;
151   mode = colorSpace->mode;
152   indexed = colorSpace->indexed;
153   numComps = colorSpace->numComps;
154   indexHigh = colorSpace->indexHigh;
155   if (indexed) {
156     size = (indexHigh + 1) * 4 * sizeof(Guchar);
157     lookup = (Guchar (*)[4])gmalloc(size);
158     memcpy(lookup, colorSpace->lookup, size);
159   } else {
160     lookup = NULL;
161   }
162   ok = gTrue;
163 }
164
165 void GfxColorSpace::setMode(Object *colorSpace) {
166   Object obj;
167
168   if (colorSpace->isName("DeviceGray") || colorSpace->isName("G")) {
169     mode = colorGray;
170     numComps = 1;
171   } else if (colorSpace->isName("DeviceRGB") || colorSpace->isName("RGB")) {
172     mode = colorRGB;
173     numComps = 3;
174   } else if (colorSpace->isName("DeviceCMYK") || colorSpace->isName("CMYK")) {
175     mode = colorCMYK;
176     numComps = 4;
177   } else if (colorSpace->isArray()) {
178     colorSpace->arrayGet(0, &obj);
179     if (obj.isName("CalGray")) {
180       mode = colorGray;
181       numComps = 1;
182     } else if (obj.isName("CalRGB")) {
183       mode = colorRGB;
184       numComps = 3;
185     } else if (obj.isName("CalCMYK")) {
186       mode = colorCMYK;
187       numComps = 4;
188     } else {
189       ok = gFalse;
190     }
191     obj.free();
192   } else {
193     ok = gFalse;
194   }
195 }
196
197 void GfxColorSpace::getColor(double x[4], GfxColor *color) {
198   double y[4];
199   Guchar *p;
200
201   if (sepFunc) {
202     sepFunc->transform(x, y);
203   } else {
204     y[0] = x[0];
205     y[1] = x[1];
206     y[2] = x[2];
207     y[3] = x[3];
208   }
209   if (indexed) {
210     p = lookup[(int)(y[0] + 0.5)];
211     switch (mode) {
212     case colorGray:
213       color->setGray(p[0] / 255.0);
214       break;
215     case colorCMYK:
216       color->setCMYK(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0, p[3] / 255.0);
217       break;
218     case colorRGB:
219       color->setRGB(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0);
220       break;
221     }
222   } else {
223     switch (mode) {
224     case colorGray:
225       color->setGray(y[0]);
226       break;
227     case colorCMYK:
228       color->setCMYK(y[0], y[1], y[2], y[3]);
229       break;
230     case colorRGB:
231       color->setRGB(y[0], y[1], y[2]);
232       break;
233     }
234   }
235 }
236
237 //------------------------------------------------------------------------
238 // Function
239 //------------------------------------------------------------------------
240
241 Function::Function(Object *funcObj) {
242   Stream *str;
243   Dict *dict;
244   int nSamples, sampleBits;
245   double sampleMul;
246   Object obj1, obj2;
247   Guint buf, bitMask;
248   int bits;
249   int s;
250   int i;
251
252   ok = gFalse;
253   samples = NULL;
254
255   if (!funcObj->isStream()) {
256     error(-1, "Expected function dictionary");
257     goto err3;
258   }
259   str = funcObj->getStream();
260   dict = str->getDict();
261
262   //----- FunctionType
263   if (!dict->lookup("FunctionType", &obj1)->isInt() ||
264       obj1.getInt() != 0) {
265     error(-1, "Unknown function type");
266     goto err2;
267   }
268   obj1.free();
269
270   //----- Domain
271   if (!dict->lookup("Domain", &obj1)->isArray()) {
272     error(-1, "Function is missing domain");
273     goto err2;
274   }
275   m = obj1.arrayGetLength() / 2;
276   if (m > 4) {
277     error(-1, "Functions with more than 1 input are unsupported");
278     goto err2;
279   }
280   for (i = 0; i < m; ++i) {
281     obj1.arrayGet(2*i, &obj2);
282     if (!obj2.isNum()) {
283       error(-1, "Illegal value in function domain array");
284       goto err1;
285     }
286     domain[i][0] = obj2.getNum();
287     obj2.free();
288     obj1.arrayGet(2*i+1, &obj2);
289     if (!obj2.isNum()) {
290       error(-1, "Illegal value in function domain array");
291       goto err1;
292     }
293     domain[i][1] = obj2.getNum();
294     obj2.free();
295   }
296   obj1.free();
297
298   //----- Range
299   if (!dict->lookup("Range", &obj1)->isArray()) {
300     error(-1, "Function is missing range");
301     goto err2;
302   }
303   n = obj1.arrayGetLength() / 2;
304   if (n > 4) {
305     error(-1, "Functions with more than 4 outputs are unsupported");
306     goto err2;
307   }
308   for (i = 0; i < n; ++i) {
309     obj1.arrayGet(2*i, &obj2);
310     if (!obj2.isNum()) {
311       error(-1, "Illegal value in function range array");
312       goto err1;
313     }
314     range[i][0] = obj2.getNum();
315     obj2.free();
316     obj1.arrayGet(2*i+1, &obj2);
317     if (!obj2.isNum()) {
318       error(-1, "Illegal value in function range array");
319       goto err1;
320     }
321     range[i][1] = obj2.getNum();
322     obj2.free();
323   }
324   obj1.free();
325
326   //----- Size
327   if (!dict->lookup("Size", &obj1)->isArray() ||
328       obj1.arrayGetLength() != m) {
329     error(-1, "Function has missing or invalid size array");
330     goto err2;
331   }
332   for (i = 0; i < m; ++i) {
333     obj1.arrayGet(i, &obj2);
334     if (!obj2.isInt()) {
335       error(-1, "Illegal value in function size array");
336       goto err1;
337     }
338     sampleSize[i] = obj2.getInt();
339     obj2.free();
340   }
341   obj1.free();
342
343   //----- BitsPerSample
344   if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
345     error(-1, "Function has missing or invalid BitsPerSample");
346     goto err2;
347   }
348   sampleBits = obj1.getInt();
349   sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
350   obj1.free();
351
352   //----- Encode
353   if (dict->lookup("Encode", &obj1)->isArray() &&
354       obj1.arrayGetLength() == 2*m) {
355     for (i = 0; i < m; ++i) {
356       obj1.arrayGet(2*i, &obj2);
357       if (!obj2.isNum()) {
358         error(-1, "Illegal value in function encode array");
359         goto err1;
360       }
361       encode[i][0] = obj2.getNum();
362       obj2.free();
363       obj1.arrayGet(2*i+1, &obj2);
364       if (!obj2.isNum()) {
365         error(-1, "Illegal value in function encode array");
366         goto err1;
367       }
368       encode[i][1] = obj2.getNum();
369       obj2.free();
370     }
371   } else {
372     for (i = 0; i < m; ++i) {
373       encode[i][0] = 0;
374       encode[i][1] = sampleSize[i] - 1;
375     }
376   }
377   obj1.free();
378
379   //----- Decode
380   if (dict->lookup("Decode", &obj1)->isArray() &&
381       obj1.arrayGetLength() == 2*n) {
382     for (i = 0; i < n; ++i) {
383       obj1.arrayGet(2*i, &obj2);
384       if (!obj2.isNum()) {
385         error(-1, "Illegal value in function decode array");
386         goto err1;
387       }
388       decode[i][0] = obj2.getNum();
389       obj2.free();
390       obj1.arrayGet(2*i+1, &obj2);
391       if (!obj2.isNum()) {
392         error(-1, "Illegal value in function decode array");
393         goto err1;
394       }
395       decode[i][1] = obj2.getNum();
396       obj2.free();
397     }
398   } else {
399     for (i = 0; i < n; ++i) {
400       decode[i][0] = range[i][0];
401       decode[i][1] = range[i][1];
402     }
403   }
404   obj1.free();
405
406   //----- samples
407   nSamples = n;
408   for (i = 0; i < m; ++i)
409     nSamples *= sampleSize[i];
410   samples = (double *)gmalloc(nSamples * sizeof(double));
411   buf = 0;
412   bits = 0;
413   bitMask = (1 << sampleBits) - 1;
414   str->reset();
415   for (i = 0; i < nSamples; ++i) {
416     if (sampleBits == 8) {
417       s = str->getChar();
418     } else if (sampleBits == 16) {
419       s = str->getChar();
420       s = (s << 8) + str->getChar();
421     } else if (sampleBits == 32) {
422       s = str->getChar();
423       s = (s << 8) + str->getChar();
424       s = (s << 8) + str->getChar();
425       s = (s << 8) + str->getChar();
426     } else {
427       while (bits < sampleBits) {
428         buf = (buf << 8) | (str->getChar() & 0xff);
429         bits += 8;
430       }
431       s = (buf >> (bits - sampleBits)) & bitMask;
432       bits -= sampleBits;
433     }
434     samples[i] = (double)s * sampleMul;
435   }
436
437   ok = gTrue;
438   return;
439
440  err1:
441   obj2.free();
442  err2:
443   obj1.free();
444  err3:
445   return;
446 }
447
448 Function::Function(Function *func) {
449   int nSamples, i;
450
451   m = func->m;
452   n = func->n;
453   memcpy(domain, func->domain, sizeof(domain));
454   memcpy(range, func->range, sizeof(range));
455   memcpy(sampleSize, func->sampleSize, sizeof(sampleSize));
456   memcpy(encode, func->encode, sizeof(encode));
457   memcpy(decode, func->decode, sizeof(decode));
458
459   nSamples = n;
460   for (i = 0; i < m; ++i)
461     nSamples *= sampleSize[i];
462   samples = (double *)gmalloc(nSamples * sizeof(double));
463   memcpy(samples, func->samples, nSamples * sizeof(double));
464
465   ok = gTrue;
466 }
467
468 Function::~Function() {
469   if (samples)
470     gfree(samples);
471 }
472
473 void Function::transform(double *in, double *out) {
474   double e[4];
475   double s;
476   double x0, x1;
477   int e0, e1;
478   double efrac;
479   int i;
480
481   // map input values into sample array
482   for (i = 0; i < m; ++i) {
483     e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
484            (encode[i][1] - encode[i][0]) + encode[i][0];
485     if (e[i] < 0)
486       e[i] = 0;
487     else if (e[i] > sampleSize[i] - 1)
488       e[i] = sampleSize[i] - 1;
489   }
490
491   for (i = 0; i < n; ++i) {
492
493     // m-linear interpolation
494     // (only m=1 is currently supported)
495     e0 = (int)floor(e[0]);
496     e1 = (int)ceil(e[0]);
497     efrac = e[0] - e0;
498     x0 = samples[e0 * n + i];
499     x1 = samples[e1 * n + i];
500     s = (1 - efrac) * x0 + efrac * x1;
501
502     // map output values to range
503     out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
504     if (out[i] < range[i][0])
505       out[i] = range[i][0];
506     else if (out[i] > range[i][1])
507       out[i] = range[i][1];
508   }
509 }
510
511 //------------------------------------------------------------------------
512 // GfxImageColorMap
513 //------------------------------------------------------------------------
514
515 GfxImageColorMap::GfxImageColorMap(int bits1, Object *decode,
516                                    GfxColorSpace *colorSpace1) {
517   GfxColor color;
518   double x[4];
519   int maxPixel;
520   Object obj;
521   int i, j;
522
523   ok = gTrue;
524
525   // bits per component and colorspace
526   bits = bits1;
527   maxPixel = (1 << bits) - 1;
528   colorSpace = colorSpace1;
529   mode = colorSpace->getMode();
530
531   // get decode map
532   if (decode->isNull()) {
533     if (colorSpace->isIndexed()) {
534       indexed = gTrue;
535       numComps = 1;
536       decodeLow[0] = 0;
537       decodeRange[0] = maxPixel;
538     } else {
539       indexed = gFalse;
540       numComps = colorSpace->getNumPixelComps();
541       for (i = 0; i < numComps; ++i) {
542         decodeLow[i] = 0;
543         decodeRange[i] = 1;
544       }
545     }
546   } else if (decode->isArray()) {
547     numComps = decode->arrayGetLength() / 2;
548     if (numComps != colorSpace->getNumPixelComps())
549       goto err1;
550     indexed = colorSpace->isIndexed();
551     for (i = 0; i < numComps; ++i) {
552       decode->arrayGet(2*i, &obj);
553       if (!obj.isNum())
554         goto err2;
555       decodeLow[i] = obj.getNum();
556       obj.free();
557       decode->arrayGet(2*i+1, &obj);
558       if (!obj.isNum())
559         goto err2;
560       decodeRange[i] = obj.getNum() - decodeLow[i];
561       obj.free();
562     }
563   } else {
564     goto err1;
565   }
566
567   // construct lookup table
568   lookup = (double (*)[4])gmalloc((maxPixel + 1) * 4 * sizeof(double));
569   if (indexed) {
570     for (i = 0; i <= maxPixel; ++i) {
571       x[0] = (double)i;
572       colorSpace->getColor(x, &color);
573       lookup[i][0] = color.getR();
574       lookup[i][1] = color.getG();
575       lookup[i][2] = color.getB();
576     }
577   } else {
578     for (i = 0; i <= maxPixel; ++i)
579       for (j = 0; j < numComps; ++j)
580         lookup[i][j] = decodeLow[j] + (i * decodeRange[j]) / maxPixel;
581   }
582
583   return;
584
585  err2:
586   obj.free();
587  err1:
588   ok = gFalse;
589 }
590
591 GfxImageColorMap::~GfxImageColorMap() {
592   delete colorSpace;
593   gfree(lookup);
594 }
595
596 void GfxImageColorMap::getColor(Guchar x[4], GfxColor *color) {
597   double *p;
598
599   if (indexed) {
600     p = lookup[x[0]];
601     color->setRGB(p[0], p[1], p[2]);
602   } else {
603     switch (mode) {
604     case colorGray:
605       color->setGray(lookup[x[0]][0]);
606       break;
607     case colorCMYK:
608       color->setCMYK(lookup[x[0]][0], lookup[x[1]][1],
609                      lookup[x[2]][2], lookup[x[3]][3]);
610       break;
611     case colorRGB:
612       color->setRGB(lookup[x[0]][0], lookup[x[1]][1], lookup[x[2]][2]);
613       break;
614     }
615   }
616 }
617
618 //------------------------------------------------------------------------
619 // GfxSubpath and GfxPath
620 //------------------------------------------------------------------------
621
622 GfxSubpath::GfxSubpath(double x1, double y1) {
623   size = 16;
624   x = (double *)gmalloc(size * sizeof(double));
625   y = (double *)gmalloc(size * sizeof(double));
626   curve = (GBool *)gmalloc(size * sizeof(GBool));
627   n = 1;
628   x[0] = x1;
629   y[0] = y1;
630   curve[0] = gFalse;
631 }
632
633 GfxSubpath::~GfxSubpath() {
634   gfree(x);
635   gfree(y);
636   gfree(curve);
637 }
638
639 // Used for copy().
640 GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
641   size = subpath->size;
642   n = subpath->n;
643   x = (double *)gmalloc(size * sizeof(double));
644   y = (double *)gmalloc(size * sizeof(double));
645   curve = (GBool *)gmalloc(size * sizeof(GBool));
646   memcpy(x, subpath->x, n * sizeof(double));
647   memcpy(y, subpath->y, n * sizeof(double));
648   memcpy(curve, subpath->curve, n * sizeof(GBool));
649 }
650
651 void GfxSubpath::lineTo(double x1, double y1) {
652   if (n >= size) {
653     size += 16;
654     x = (double *)grealloc(x, size * sizeof(double));
655     y = (double *)grealloc(y, size * sizeof(double));
656     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
657   }
658   x[n] = x1;
659   y[n] = y1;
660   curve[n] = gFalse;
661   ++n;
662 }
663
664 void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
665                          double x3, double y3) {
666   if (n+3 > size) {
667     size += 16;
668     x = (double *)grealloc(x, size * sizeof(double));
669     y = (double *)grealloc(y, size * sizeof(double));
670     curve = (GBool *)grealloc(curve, size * sizeof(GBool));
671   }
672   x[n] = x1;
673   y[n] = y1;
674   x[n+1] = x2;
675   y[n+1] = y2;
676   x[n+2] = x3;
677   y[n+2] = y3;
678   curve[n] = curve[n+1] = gTrue;
679   curve[n+2] = gFalse;
680   n += 3;
681 }
682
683 GfxPath::GfxPath() {
684   justMoved = gFalse;
685   size = 16;
686   n = 0;
687   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
688 }
689
690 GfxPath::~GfxPath() {
691   int i;
692
693   for (i = 0; i < n; ++i)
694     delete subpaths[i];
695   gfree(subpaths);
696 }
697
698 // Used for copy().
699 GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
700                  GfxSubpath **subpaths1, int n1, int size1) {
701   int i;
702
703   justMoved = justMoved1;
704   firstX = firstX1;
705   firstY = firstY1;
706   size = size1;
707   n = n1;
708   subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
709   for (i = 0; i < n; ++i)
710     subpaths[i] = subpaths1[i]->copy();
711 }
712
713 void GfxPath::moveTo(double x, double y) {
714   justMoved = gTrue;
715   firstX = x;
716   firstY = y;
717 }
718
719 void GfxPath::lineTo(double x, double y) {
720   if (justMoved) {
721     if (n >= size) {
722       size += 16;
723       subpaths = (GfxSubpath **)
724                    grealloc(subpaths, size * sizeof(GfxSubpath *));
725     }
726     subpaths[n] = new GfxSubpath(firstX, firstY);
727     ++n;
728     justMoved = gFalse;
729   }
730   subpaths[n-1]->lineTo(x, y);
731 }
732
733 void GfxPath::curveTo(double x1, double y1, double x2, double y2,
734              double x3, double y3) {
735   if (justMoved) {
736     if (n >= size) {
737       size += 16;
738       subpaths = (GfxSubpath **)
739                    grealloc(subpaths, size * sizeof(GfxSubpath *));
740     }
741     subpaths[n] = new GfxSubpath(firstX, firstY);
742     ++n;
743     justMoved = gFalse;
744   }
745   subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
746 }
747
748
749 //------------------------------------------------------------------------
750 // GfxState
751 //------------------------------------------------------------------------
752
753 GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a,
754                    int rotate, GBool upsideDown) {
755   double k;
756
757   px1 = px1a;
758   py1 = py1a;
759   px2 = px2a;
760   py2 = py2a;
761   k = (double)dpi / 72.0;
762   if (rotate == 90) {
763     ctm[0] = 0;
764     ctm[1] = upsideDown ? k : -k;
765     ctm[2] = k;
766     ctm[3] = 0;
767     ctm[4] = -k * py1;
768     ctm[5] = k * (upsideDown ? -px1 : px2);
769     pageWidth = (int)(k * (py2 - py1));
770     pageHeight = (int)(k * (px2 - px1));
771   } else if (rotate == 180) {
772     ctm[0] = -k;
773     ctm[1] = 0;
774     ctm[2] = 0;
775     ctm[3] = upsideDown ? k : -k;
776     ctm[4] = k * px2;
777     ctm[5] = k * (upsideDown ? -py1 : py2);
778     pageWidth = (int)(k * (px2 - px1));
779     pageHeight = (int)(k * (py2 - py1));
780   } else if (rotate == 270) {
781     ctm[0] = 0;
782     ctm[1] = upsideDown ? -k : k;
783     ctm[2] = -k;
784     ctm[3] = 0;
785     ctm[4] = k * py2;
786     ctm[5] = k * (upsideDown ? px2 : -px1);
787     pageWidth = (int)(k * (py2 - py1));
788     pageHeight = (int)(k * (px2 - px1));
789   } else {
790     ctm[0] = k;
791     ctm[1] = 0;
792     ctm[2] = 0;
793     ctm[3] = upsideDown ? -k : k;
794     ctm[4] = -k * px1;
795     ctm[5] = k * (upsideDown ? py2 : -py1);
796     pageWidth = (int)(k * (px2 - px1));
797     pageHeight = (int)(k * (py2 - py1));
798   }
799
800   fillColorSpace = new GfxColorSpace(colorGray);
801   strokeColorSpace = new GfxColorSpace(colorGray);
802   fillColor.setGray(0);
803   strokeColor.setGray(0);
804
805   lineWidth = 1;
806   lineDash = NULL;
807   lineDashLength = 0;
808   lineDashStart = 0;
809   flatness = 0;
810   lineJoin = 0;
811   lineCap = 0;
812   miterLimit = 10;
813
814   font = NULL;
815   fontSize = 0;
816   textMat[0] = 1; textMat[1] = 0;
817   textMat[2] = 0; textMat[3] = 1;
818   textMat[4] = 0; textMat[5] = 0;
819   charSpace = 0;
820   wordSpace = 0;
821   horizScaling = 1;
822   leading = 0;
823   rise = 0;
824   render = 0;
825
826   path = new GfxPath();
827   curX = curY = 0;
828   lineX = lineY = 0;
829
830   saved = NULL;
831 }
832
833 GfxState::~GfxState() {
834   if (fillColorSpace)
835     delete fillColorSpace;
836   if (strokeColorSpace)
837     delete strokeColorSpace;
838   gfree(lineDash);
839   delete path;
840   if (saved)
841     delete saved;
842 }
843
844 // Used for copy();
845 GfxState::GfxState(GfxState *state) {
846   memcpy(this, state, sizeof(GfxState));
847   if (fillColorSpace)
848     fillColorSpace = state->fillColorSpace->copy();
849   if (strokeColorSpace)
850     strokeColorSpace = state->strokeColorSpace->copy();
851   if (lineDashLength > 0) {
852     lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
853     memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
854   }
855   path = state->path->copy();
856   saved = NULL;
857 }
858
859 double GfxState::transformWidth(double w) {
860   double x, y;
861
862   x = ctm[0] + ctm[2];
863   y = ctm[1] + ctm[3];
864   return w * sqrt(0.5 * (x * x + y * y));
865 }
866
867 double GfxState::getTransformedFontSize() {
868   double x1, y1, x2, y2;
869
870   x1 = textMat[2] * fontSize;
871   y1 = textMat[3] * fontSize;
872   x2 = ctm[0] * x1 + ctm[2] * y1;
873   y2 = ctm[1] * x1 + ctm[3] * y1;
874   return sqrt(x2 * x2 + y2 * y2);
875 }
876
877 void GfxState::getFontTransMat(double *m11, double *m12,
878                                double *m21, double *m22) {
879   *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
880   *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
881   *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
882   *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
883 }
884
885 void GfxState::concatCTM(double a, double b, double c,
886                          double d, double e, double f) {
887   double a1 = ctm[0];
888   double b1 = ctm[1];
889   double c1 = ctm[2];
890   double d1 = ctm[3];
891
892   ctm[0] = a * a1 + b * c1;
893   ctm[1] = a * b1 + b * d1;
894   ctm[2] = c * a1 + d * c1;
895   ctm[3] = c * b1 + d * d1;
896   ctm[4] = e * a1 + f * c1 + ctm[4];
897   ctm[5] = e * b1 + f * d1 + ctm[5];
898 }
899
900 void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
901   if (fillColorSpace)
902     delete fillColorSpace;
903   fillColorSpace = colorSpace;
904 }
905
906 void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
907   if (strokeColorSpace)
908     delete strokeColorSpace;
909   strokeColorSpace = colorSpace;
910 }
911
912 void GfxState::setLineDash(double *dash, int length, double start) {
913   if (lineDash)
914     gfree(lineDash);
915   lineDash = dash;
916   lineDashLength = length;
917   lineDashStart = start;
918 }
919
920 void GfxState::clearPath() {
921   delete path;
922   path = new GfxPath();
923 }
924
925 void GfxState::textShift(double tx) {
926   double dx, dy;
927
928   textTransformDelta(tx, 0, &dx, &dy);
929   curX += dx;
930   curY += dy;
931 }
932
933 GfxState *GfxState::save() {
934   GfxState *newState;
935
936   newState = copy();
937   newState->saved = this;
938   return newState;
939 }
940
941 GfxState *GfxState::restore() {
942   GfxState *oldState;
943
944   if (saved) {
945     oldState = saved;
946     saved = NULL;
947     delete this;
948   } else {
949     oldState = this;
950   }
951   return oldState;
952 }