Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pdf/xpdf/GfxState.cc
diff options
context:
space:
mode:
authorArturo Espinosa <unammx@src.gnome.org>1999-04-17 02:59:58 (GMT)
committer Arturo Espinosa <unammx@src.gnome.org>1999-04-17 02:59:58 (GMT)
commitd9f9a6449f377b4c933b75d57541b19c6d088994 (patch)
tree04f7f0c54447ef792fbf83bc5039174f4681b3bb /pdf/xpdf/GfxState.cc
Initial revision
Diffstat (limited to 'pdf/xpdf/GfxState.cc')
-rw-r--r--pdf/xpdf/GfxState.cc952
1 files changed, 952 insertions, 0 deletions
diff --git a/pdf/xpdf/GfxState.cc b/pdf/xpdf/GfxState.cc
new file mode 100644
index 0000000..bf0e4de
--- /dev/null
+++ b/pdf/xpdf/GfxState.cc
@@ -0,0 +1,952 @@
+//========================================================================
+//
+// GfxState.cc
+//
+// Copyright 1996 Derek B. Noonburg
+//
+//========================================================================
+
+#ifdef __GNUC__
+#pragma implementation
+#endif
+
+#include <stddef.h>
+#include <math.h>
+#include <string.h> // for memcpy()
+#include "gmem.h"
+#include "Error.h"
+#include "Object.h"
+#include "GfxState.h"
+
+//------------------------------------------------------------------------
+// GfxColor
+//------------------------------------------------------------------------
+
+void GfxColor::setCMYK(double c, double m, double y, double k) {
+ if ((r = 1 - (c + k)) < 0)
+ r = 0;
+ if ((g = 1 - (m + k)) < 0)
+ g = 0;
+ if ((b = 1 - (y + k)) < 0)
+ b = 0;
+}
+
+//------------------------------------------------------------------------
+// GfxColorSpace
+//------------------------------------------------------------------------
+
+GfxColorSpace::GfxColorSpace(Object *colorSpace) {
+ Object csObj;
+ Object obj, obj2;
+ char *s;
+ int x;
+ int i, j;
+
+ ok = gTrue;
+ lookup = NULL;
+
+ // check for Separation colorspace
+ colorSpace->copy(&csObj);
+ sepFunc = NULL;
+ if (colorSpace->isArray()) {
+ colorSpace->arrayGet(0, &obj);
+ if (obj.isName("Separation")) {
+ csObj.free();
+ colorSpace->arrayGet(2, &csObj);
+ sepFunc = new Function(colorSpace->arrayGet(3, &obj2));
+ obj2.free();
+ if (!sepFunc->isOk()) {
+ delete sepFunc;
+ sepFunc = NULL;
+ }
+ }
+ obj.free();
+ }
+
+ // get mode
+ indexed = gFalse;
+ if (csObj.isName()) {
+ setMode(&csObj);
+ } else if (csObj.isArray()) {
+ csObj.arrayGet(0, &obj);
+ if (obj.isName("Indexed") || obj.isName("I")) {
+ indexed = gTrue;
+ setMode(csObj.arrayGet(1, &obj2));
+ obj2.free();
+ } else {
+ setMode(&csObj);
+ }
+ obj.free();
+ } else {
+ goto err1;
+ }
+ if (!ok)
+ return;
+
+ // get lookup table for indexed colorspace
+ if (indexed) {
+ csObj.arrayGet(2, &obj);
+ if (!obj.isInt())
+ goto err2;
+ indexHigh = obj.getInt();
+ obj.free();
+ lookup = (Guchar (*)[4])gmalloc((indexHigh + 1) * 4 * sizeof(Guchar));
+ csObj.arrayGet(3, &obj);
+ if (obj.isStream()) {
+ obj.streamReset();
+ for (i = 0; i <= indexHigh; ++i) {
+ for (j = 0; j < numComps; ++j) {
+ if ((x = obj.streamGetChar()) == EOF)
+ goto err2;
+ lookup[i][j] = (Guchar)x;
+ }
+ }
+ } else if (obj.isString()) {
+ s = obj.getString()->getCString();
+ for (i = 0; i <= indexHigh; ++i)
+ for (j = 0; j < numComps; ++j)
+ lookup[i][j] = (Guchar)*s++;
+ } else {
+ goto err2;
+ }
+ obj.free();
+ }
+
+ csObj.free();
+ return;
+
+ err2:
+ obj.free();
+ err1:
+ csObj.free();
+ ok = gFalse;
+}
+
+GfxColorSpace::GfxColorSpace(GfxColorMode mode1) {
+ sepFunc = NULL;
+ mode = mode1;
+ indexed = gFalse;
+ switch (mode) {
+ case colorGray: numComps = 1; break;
+ case colorCMYK: numComps = 4; break;
+ case colorRGB: numComps = 3; break;
+ }
+ lookup = NULL;
+ ok = gTrue;
+}
+
+GfxColorSpace::~GfxColorSpace() {
+ if (sepFunc)
+ delete sepFunc;
+ gfree(lookup);
+}
+
+GfxColorSpace::GfxColorSpace(GfxColorSpace *colorSpace) {
+ int size;
+
+ if (colorSpace->sepFunc)
+ sepFunc = colorSpace->sepFunc->copy();
+ else
+ sepFunc = NULL;
+ mode = colorSpace->mode;
+ indexed = colorSpace->indexed;
+ numComps = colorSpace->numComps;
+ indexHigh = colorSpace->indexHigh;
+ if (indexed) {
+ size = (indexHigh + 1) * 4 * sizeof(Guchar);
+ lookup = (Guchar (*)[4])gmalloc(size);
+ memcpy(lookup, colorSpace->lookup, size);
+ } else {
+ lookup = NULL;
+ }
+ ok = gTrue;
+}
+
+void GfxColorSpace::setMode(Object *colorSpace) {
+ Object obj;
+
+ if (colorSpace->isName("DeviceGray") || colorSpace->isName("G")) {
+ mode = colorGray;
+ numComps = 1;
+ } else if (colorSpace->isName("DeviceRGB") || colorSpace->isName("RGB")) {
+ mode = colorRGB;
+ numComps = 3;
+ } else if (colorSpace->isName("DeviceCMYK") || colorSpace->isName("CMYK")) {
+ mode = colorCMYK;
+ numComps = 4;
+ } else if (colorSpace->isArray()) {
+ colorSpace->arrayGet(0, &obj);
+ if (obj.isName("CalGray")) {
+ mode = colorGray;
+ numComps = 1;
+ } else if (obj.isName("CalRGB")) {
+ mode = colorRGB;
+ numComps = 3;
+ } else if (obj.isName("CalCMYK")) {
+ mode = colorCMYK;
+ numComps = 4;
+ } else {
+ ok = gFalse;
+ }
+ obj.free();
+ } else {
+ ok = gFalse;
+ }
+}
+
+void GfxColorSpace::getColor(double x[4], GfxColor *color) {
+ double y[4];
+ Guchar *p;
+
+ if (sepFunc) {
+ sepFunc->transform(x, y);
+ } else {
+ y[0] = x[0];
+ y[1] = x[1];
+ y[2] = x[2];
+ y[3] = x[3];
+ }
+ if (indexed) {
+ p = lookup[(int)(y[0] + 0.5)];
+ switch (mode) {
+ case colorGray:
+ color->setGray(p[0] / 255.0);
+ break;
+ case colorCMYK:
+ color->setCMYK(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0, p[3] / 255.0);
+ break;
+ case colorRGB:
+ color->setRGB(p[0] / 255.0, p[1] / 255.0, p[2] / 255.0);
+ break;
+ }
+ } else {
+ switch (mode) {
+ case colorGray:
+ color->setGray(y[0]);
+ break;
+ case colorCMYK:
+ color->setCMYK(y[0], y[1], y[2], y[3]);
+ break;
+ case colorRGB:
+ color->setRGB(y[0], y[1], y[2]);
+ break;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// Function
+//------------------------------------------------------------------------
+
+Function::Function(Object *funcObj) {
+ Stream *str;
+ Dict *dict;
+ int nSamples, sampleBits;
+ double sampleMul;
+ Object obj1, obj2;
+ Guint buf, bitMask;
+ int bits;
+ int s;
+ int i;
+
+ ok = gFalse;
+ samples = NULL;
+
+ if (!funcObj->isStream()) {
+ error(-1, "Expected function dictionary");
+ goto err3;
+ }
+ str = funcObj->getStream();
+ dict = str->getDict();
+
+ //----- FunctionType
+ if (!dict->lookup("FunctionType", &obj1)->isInt() ||
+ obj1.getInt() != 0) {
+ error(-1, "Unknown function type");
+ goto err2;
+ }
+ obj1.free();
+
+ //----- Domain
+ if (!dict->lookup("Domain", &obj1)->isArray()) {
+ error(-1, "Function is missing domain");
+ goto err2;
+ }
+ m = obj1.arrayGetLength() / 2;
+ if (m > 4) {
+ error(-1, "Functions with more than 1 input are unsupported");
+ goto err2;
+ }
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function domain array");
+ goto err1;
+ }
+ domain[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function domain array");
+ goto err1;
+ }
+ domain[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- Range
+ if (!dict->lookup("Range", &obj1)->isArray()) {
+ error(-1, "Function is missing range");
+ goto err2;
+ }
+ n = obj1.arrayGetLength() / 2;
+ if (n > 4) {
+ error(-1, "Functions with more than 4 outputs are unsupported");
+ goto err2;
+ }
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function range array");
+ goto err1;
+ }
+ range[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function range array");
+ goto err1;
+ }
+ range[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- Size
+ if (!dict->lookup("Size", &obj1)->isArray() ||
+ obj1.arrayGetLength() != m) {
+ error(-1, "Function has missing or invalid size array");
+ goto err2;
+ }
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!obj2.isInt()) {
+ error(-1, "Illegal value in function size array");
+ goto err1;
+ }
+ sampleSize[i] = obj2.getInt();
+ obj2.free();
+ }
+ obj1.free();
+
+ //----- BitsPerSample
+ if (!dict->lookup("BitsPerSample", &obj1)->isInt()) {
+ error(-1, "Function has missing or invalid BitsPerSample");
+ goto err2;
+ }
+ sampleBits = obj1.getInt();
+ sampleMul = 1.0 / (double)((1 << sampleBits) - 1);
+ obj1.free();
+
+ //----- Encode
+ if (dict->lookup("Encode", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2*m) {
+ for (i = 0; i < m; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function encode array");
+ goto err1;
+ }
+ encode[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function encode array");
+ goto err1;
+ }
+ encode[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ for (i = 0; i < m; ++i) {
+ encode[i][0] = 0;
+ encode[i][1] = sampleSize[i] - 1;
+ }
+ }
+ obj1.free();
+
+ //----- Decode
+ if (dict->lookup("Decode", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 2*n) {
+ for (i = 0; i < n; ++i) {
+ obj1.arrayGet(2*i, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function decode array");
+ goto err1;
+ }
+ decode[i][0] = obj2.getNum();
+ obj2.free();
+ obj1.arrayGet(2*i+1, &obj2);
+ if (!obj2.isNum()) {
+ error(-1, "Illegal value in function decode array");
+ goto err1;
+ }
+ decode[i][1] = obj2.getNum();
+ obj2.free();
+ }
+ } else {
+ for (i = 0; i < n; ++i) {
+ decode[i][0] = range[i][0];
+ decode[i][1] = range[i][1];
+ }
+ }
+ obj1.free();
+
+ //----- samples
+ nSamples = n;
+ for (i = 0; i < m; ++i)
+ nSamples *= sampleSize[i];
+ samples = (double *)gmalloc(nSamples * sizeof(double));
+ buf = 0;
+ bits = 0;
+ bitMask = (1 << sampleBits) - 1;
+ str->reset();
+ for (i = 0; i < nSamples; ++i) {
+ if (sampleBits == 8) {
+ s = str->getChar();
+ } else if (sampleBits == 16) {
+ s = str->getChar();
+ s = (s << 8) + str->getChar();
+ } else if (sampleBits == 32) {
+ s = str->getChar();
+ s = (s << 8) + str->getChar();
+ s = (s << 8) + str->getChar();
+ s = (s << 8) + str->getChar();
+ } else {
+ while (bits < sampleBits) {
+ buf = (buf << 8) | (str->getChar() & 0xff);
+ bits += 8;
+ }
+ s = (buf >> (bits - sampleBits)) & bitMask;
+ bits -= sampleBits;
+ }
+ samples[i] = (double)s * sampleMul;
+ }
+
+ ok = gTrue;
+ return;
+
+ err1:
+ obj2.free();
+ err2:
+ obj1.free();
+ err3:
+ return;
+}
+
+Function::Function(Function *func) {
+ int nSamples, i;
+
+ m = func->m;
+ n = func->n;
+ memcpy(domain, func->domain, sizeof(domain));
+ memcpy(range, func->range, sizeof(range));
+ memcpy(sampleSize, func->sampleSize, sizeof(sampleSize));
+ memcpy(encode, func->encode, sizeof(encode));
+ memcpy(decode, func->decode, sizeof(decode));
+
+ nSamples = n;
+ for (i = 0; i < m; ++i)
+ nSamples *= sampleSize[i];
+ samples = (double *)gmalloc(nSamples * sizeof(double));
+ memcpy(samples, func->samples, nSamples * sizeof(double));
+
+ ok = gTrue;
+}
+
+Function::~Function() {
+ if (samples)
+ gfree(samples);
+}
+
+void Function::transform(double *in, double *out) {
+ double e[4];
+ double s;
+ double x0, x1;
+ int e0, e1;
+ double efrac;
+ int i;
+
+ // map input values into sample array
+ for (i = 0; i < m; ++i) {
+ e[i] = ((in[i] - domain[i][0]) / (domain[i][1] - domain[i][0])) *
+ (encode[i][1] - encode[i][0]) + encode[i][0];
+ if (e[i] < 0)
+ e[i] = 0;
+ else if (e[i] > sampleSize[i] - 1)
+ e[i] = sampleSize[i] - 1;
+ }
+
+ for (i = 0; i < n; ++i) {
+
+ // m-linear interpolation
+ // (only m=1 is currently supported)
+ e0 = (int)floor(e[0]);
+ e1 = (int)ceil(e[0]);
+ efrac = e[0] - e0;
+ x0 = samples[e0 * n + i];
+ x1 = samples[e1 * n + i];
+ s = (1 - efrac) * x0 + efrac * x1;
+
+ // map output values to range
+ out[i] = s * (decode[i][1] - decode[i][0]) + decode[i][0];
+ if (out[i] < range[i][0])
+ out[i] = range[i][0];
+ else if (out[i] > range[i][1])
+ out[i] = range[i][1];
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxImageColorMap
+//------------------------------------------------------------------------
+
+GfxImageColorMap::GfxImageColorMap(int bits1, Object *decode,
+ GfxColorSpace *colorSpace1) {
+ GfxColor color;
+ double x[4];
+ int maxPixel;
+ Object obj;
+ int i, j;
+
+ ok = gTrue;
+
+ // bits per component and colorspace
+ bits = bits1;
+ maxPixel = (1 << bits) - 1;
+ colorSpace = colorSpace1;
+ mode = colorSpace->getMode();
+
+ // get decode map
+ if (decode->isNull()) {
+ if (colorSpace->isIndexed()) {
+ indexed = gTrue;
+ numComps = 1;
+ decodeLow[0] = 0;
+ decodeRange[0] = maxPixel;
+ } else {
+ indexed = gFalse;
+ numComps = colorSpace->getNumPixelComps();
+ for (i = 0; i < numComps; ++i) {
+ decodeLow[i] = 0;
+ decodeRange[i] = 1;
+ }
+ }
+ } else if (decode->isArray()) {
+ numComps = decode->arrayGetLength() / 2;
+ if (numComps != colorSpace->getNumPixelComps())
+ goto err1;
+ indexed = colorSpace->isIndexed();
+ for (i = 0; i < numComps; ++i) {
+ decode->arrayGet(2*i, &obj);
+ if (!obj.isNum())
+ goto err2;
+ decodeLow[i] = obj.getNum();
+ obj.free();
+ decode->arrayGet(2*i+1, &obj);
+ if (!obj.isNum())
+ goto err2;
+ decodeRange[i] = obj.getNum() - decodeLow[i];
+ obj.free();
+ }
+ } else {
+ goto err1;
+ }
+
+ // construct lookup table
+ lookup = (double (*)[4])gmalloc((maxPixel + 1) * 4 * sizeof(double));
+ if (indexed) {
+ for (i = 0; i <= maxPixel; ++i) {
+ x[0] = (double)i;
+ colorSpace->getColor(x, &color);
+ lookup[i][0] = color.getR();
+ lookup[i][1] = color.getG();
+ lookup[i][2] = color.getB();
+ }
+ } else {
+ for (i = 0; i <= maxPixel; ++i)
+ for (j = 0; j < numComps; ++j)
+ lookup[i][j] = decodeLow[j] + (i * decodeRange[j]) / maxPixel;
+ }
+
+ return;
+
+ err2:
+ obj.free();
+ err1:
+ ok = gFalse;
+}
+
+GfxImageColorMap::~GfxImageColorMap() {
+ delete colorSpace;
+ gfree(lookup);
+}
+
+void GfxImageColorMap::getColor(Guchar x[4], GfxColor *color) {
+ double *p;
+
+ if (indexed) {
+ p = lookup[x[0]];
+ color->setRGB(p[0], p[1], p[2]);
+ } else {
+ switch (mode) {
+ case colorGray:
+ color->setGray(lookup[x[0]][0]);
+ break;
+ case colorCMYK:
+ color->setCMYK(lookup[x[0]][0], lookup[x[1]][1],
+ lookup[x[2]][2], lookup[x[3]][3]);
+ break;
+ case colorRGB:
+ color->setRGB(lookup[x[0]][0], lookup[x[1]][1], lookup[x[2]][2]);
+ break;
+ }
+ }
+}
+
+//------------------------------------------------------------------------
+// GfxSubpath and GfxPath
+//------------------------------------------------------------------------
+
+GfxSubpath::GfxSubpath(double x1, double y1) {
+ size = 16;
+ x = (double *)gmalloc(size * sizeof(double));
+ y = (double *)gmalloc(size * sizeof(double));
+ curve = (GBool *)gmalloc(size * sizeof(GBool));
+ n = 1;
+ x[0] = x1;
+ y[0] = y1;
+ curve[0] = gFalse;
+}
+
+GfxSubpath::~GfxSubpath() {
+ gfree(x);
+ gfree(y);
+ gfree(curve);
+}
+
+// Used for copy().
+GfxSubpath::GfxSubpath(GfxSubpath *subpath) {
+ size = subpath->size;
+ n = subpath->n;
+ x = (double *)gmalloc(size * sizeof(double));
+ y = (double *)gmalloc(size * sizeof(double));
+ curve = (GBool *)gmalloc(size * sizeof(GBool));
+ memcpy(x, subpath->x, n * sizeof(double));
+ memcpy(y, subpath->y, n * sizeof(double));
+ memcpy(curve, subpath->curve, n * sizeof(GBool));
+}
+
+void GfxSubpath::lineTo(double x1, double y1) {
+ if (n >= size) {
+ size += 16;
+ x = (double *)grealloc(x, size * sizeof(double));
+ y = (double *)grealloc(y, size * sizeof(double));
+ curve = (GBool *)grealloc(curve, size * sizeof(GBool));
+ }
+ x[n] = x1;
+ y[n] = y1;
+ curve[n] = gFalse;
+ ++n;
+}
+
+void GfxSubpath::curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3) {
+ if (n+3 > size) {
+ size += 16;
+ x = (double *)grealloc(x, size * sizeof(double));
+ y = (double *)grealloc(y, size * sizeof(double));
+ curve = (GBool *)grealloc(curve, size * sizeof(GBool));
+ }
+ x[n] = x1;
+ y[n] = y1;
+ x[n+1] = x2;
+ y[n+1] = y2;
+ x[n+2] = x3;
+ y[n+2] = y3;
+ curve[n] = curve[n+1] = gTrue;
+ curve[n+2] = gFalse;
+ n += 3;
+}
+
+GfxPath::GfxPath() {
+ justMoved = gFalse;
+ size = 16;
+ n = 0;
+ subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
+}
+
+GfxPath::~GfxPath() {
+ int i;
+
+ for (i = 0; i < n; ++i)
+ delete subpaths[i];
+ gfree(subpaths);
+}
+
+// Used for copy().
+GfxPath::GfxPath(GBool justMoved1, double firstX1, double firstY1,
+ GfxSubpath **subpaths1, int n1, int size1) {
+ int i;
+
+ justMoved = justMoved1;
+ firstX = firstX1;
+ firstY = firstY1;
+ size = size1;
+ n = n1;
+ subpaths = (GfxSubpath **)gmalloc(size * sizeof(GfxSubpath *));
+ for (i = 0; i < n; ++i)
+ subpaths[i] = subpaths1[i]->copy();
+}
+
+void GfxPath::moveTo(double x, double y) {
+ justMoved = gTrue;
+ firstX = x;
+ firstY = y;
+}
+
+void GfxPath::lineTo(double x, double y) {
+ if (justMoved) {
+ if (n >= size) {
+ size += 16;
+ subpaths = (GfxSubpath **)
+ grealloc(subpaths, size * sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->lineTo(x, y);
+}
+
+void GfxPath::curveTo(double x1, double y1, double x2, double y2,
+ double x3, double y3) {
+ if (justMoved) {
+ if (n >= size) {
+ size += 16;
+ subpaths = (GfxSubpath **)
+ grealloc(subpaths, size * sizeof(GfxSubpath *));
+ }
+ subpaths[n] = new GfxSubpath(firstX, firstY);
+ ++n;
+ justMoved = gFalse;
+ }
+ subpaths[n-1]->curveTo(x1, y1, x2, y2, x3, y3);
+}
+
+
+//------------------------------------------------------------------------
+// GfxState
+//------------------------------------------------------------------------
+
+GfxState::GfxState(int dpi, double px1a, double py1a, double px2a, double py2a,
+ int rotate, GBool upsideDown) {
+ double k;
+
+ px1 = px1a;
+ py1 = py1a;
+ px2 = px2a;
+ py2 = py2a;
+ k = (double)dpi / 72.0;
+ if (rotate == 90) {
+ ctm[0] = 0;
+ ctm[1] = upsideDown ? k : -k;
+ ctm[2] = k;
+ ctm[3] = 0;
+ ctm[4] = -k * py1;
+ ctm[5] = k * (upsideDown ? -px1 : px2);
+ pageWidth = (int)(k * (py2 - py1));
+ pageHeight = (int)(k * (px2 - px1));
+ } else if (rotate == 180) {
+ ctm[0] = -k;
+ ctm[1] = 0;
+ ctm[2] = 0;
+ ctm[3] = upsideDown ? k : -k;
+ ctm[4] = k * px2;
+ ctm[5] = k * (upsideDown ? -py1 : py2);
+ pageWidth = (int)(k * (px2 - px1));
+ pageHeight = (int)(k * (py2 - py1));
+ } else if (rotate == 270) {
+ ctm[0] = 0;
+ ctm[1] = upsideDown ? -k : k;
+ ctm[2] = -k;
+ ctm[3] = 0;
+ ctm[4] = k * py2;
+ ctm[5] = k * (upsideDown ? px2 : -px1);
+ pageWidth = (int)(k * (py2 - py1));
+ pageHeight = (int)(k * (px2 - px1));
+ } else {
+ ctm[0] = k;
+ ctm[1] = 0;
+ ctm[2] = 0;
+ ctm[3] = upsideDown ? -k : k;
+ ctm[4] = -k * px1;
+ ctm[5] = k * (upsideDown ? py2 : -py1);
+ pageWidth = (int)(k * (px2 - px1));
+ pageHeight = (int)(k * (py2 - py1));
+ }
+
+ fillColorSpace = new GfxColorSpace(colorGray);
+ strokeColorSpace = new GfxColorSpace(colorGray);
+ fillColor.setGray(0);
+ strokeColor.setGray(0);
+
+ lineWidth = 1;
+ lineDash = NULL;
+ lineDashLength = 0;
+ lineDashStart = 0;
+ flatness = 0;
+ lineJoin = 0;
+ lineCap = 0;
+ miterLimit = 10;
+
+ font = NULL;
+ fontSize = 0;
+ textMat[0] = 1; textMat[1] = 0;
+ textMat[2] = 0; textMat[3] = 1;
+ textMat[4] = 0; textMat[5] = 0;
+ charSpace = 0;
+ wordSpace = 0;
+ horizScaling = 1;
+ leading = 0;
+ rise = 0;
+ render = 0;
+
+ path = new GfxPath();
+ curX = curY = 0;
+ lineX = lineY = 0;
+
+ saved = NULL;
+}
+
+GfxState::~GfxState() {
+ if (fillColorSpace)
+ delete fillColorSpace;
+ if (strokeColorSpace)
+ delete strokeColorSpace;
+ gfree(lineDash);
+ delete path;
+ if (saved)
+ delete saved;
+}
+
+// Used for copy();
+GfxState::GfxState(GfxState *state) {
+ memcpy(this, state, sizeof(GfxState));
+ if (fillColorSpace)
+ fillColorSpace = state->fillColorSpace->copy();
+ if (strokeColorSpace)
+ strokeColorSpace = state->strokeColorSpace->copy();
+ if (lineDashLength > 0) {
+ lineDash = (double *)gmalloc(lineDashLength * sizeof(double));
+ memcpy(lineDash, state->lineDash, lineDashLength * sizeof(double));
+ }
+ path = state->path->copy();
+ saved = NULL;
+}
+
+double GfxState::transformWidth(double w) {
+ double x, y;
+
+ x = ctm[0] + ctm[2];
+ y = ctm[1] + ctm[3];
+ return w * sqrt(0.5 * (x * x + y * y));
+}
+
+double GfxState::getTransformedFontSize() {
+ double x1, y1, x2, y2;
+
+ x1 = textMat[2] * fontSize;
+ y1 = textMat[3] * fontSize;
+ x2 = ctm[0] * x1 + ctm[2] * y1;
+ y2 = ctm[1] * x1 + ctm[3] * y1;
+ return sqrt(x2 * x2 + y2 * y2);
+}
+
+void GfxState::getFontTransMat(double *m11, double *m12,
+ double *m21, double *m22) {
+ *m11 = (textMat[0] * ctm[0] + textMat[1] * ctm[2]) * fontSize;
+ *m12 = (textMat[0] * ctm[1] + textMat[1] * ctm[3]) * fontSize;
+ *m21 = (textMat[2] * ctm[0] + textMat[3] * ctm[2]) * fontSize;
+ *m22 = (textMat[2] * ctm[1] + textMat[3] * ctm[3]) * fontSize;
+}
+
+void GfxState::concatCTM(double a, double b, double c,
+ double d, double e, double f) {
+ double a1 = ctm[0];
+ double b1 = ctm[1];
+ double c1 = ctm[2];
+ double d1 = ctm[3];
+
+ ctm[0] = a * a1 + b * c1;
+ ctm[1] = a * b1 + b * d1;
+ ctm[2] = c * a1 + d * c1;
+ ctm[3] = c * b1 + d * d1;
+ ctm[4] = e * a1 + f * c1 + ctm[4];
+ ctm[5] = e * b1 + f * d1 + ctm[5];
+}
+
+void GfxState::setFillColorSpace(GfxColorSpace *colorSpace) {
+ if (fillColorSpace)
+ delete fillColorSpace;
+ fillColorSpace = colorSpace;
+}
+
+void GfxState::setStrokeColorSpace(GfxColorSpace *colorSpace) {
+ if (strokeColorSpace)
+ delete strokeColorSpace;
+ strokeColorSpace = colorSpace;
+}
+
+void GfxState::setLineDash(double *dash, int length, double start) {
+ if (lineDash)
+ gfree(lineDash);
+ lineDash = dash;
+ lineDashLength = length;
+ lineDashStart = start;
+}
+
+void GfxState::clearPath() {
+ delete path;
+ path = new GfxPath();
+}
+
+void GfxState::textShift(double tx) {
+ double dx, dy;
+
+ textTransformDelta(tx, 0, &dx, &dy);
+ curX += dx;
+ curY += dy;
+}
+
+GfxState *GfxState::save() {
+ GfxState *newState;
+
+ newState = copy();
+ newState->saved = this;
+ return newState;
+}
+
+GfxState *GfxState::restore() {
+ GfxState *oldState;
+
+ if (saved) {
+ oldState = saved;
+ saved = NULL;
+ delete this;
+ } else {
+ oldState = this;
+ }
+ return oldState;
+}