From d9f9a6449f377b4c933b75d57541b19c6d088994 Mon Sep 17 00:00:00 2001 From: Arturo Espinosa Date: Sat, 17 Apr 1999 02:59:58 +0000 Subject: Initial revision --- (limited to 'pdf/xpdf/GfxState.cc') 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 +#include +#include // 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; +} -- cgit v0.9.1