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