summaryrefslogtreecommitdiff
path: root/noncore/unsupported/qpdf/xpdf/Gfx.cc
Unidiff
Diffstat (limited to 'noncore/unsupported/qpdf/xpdf/Gfx.cc') (more/less context) (ignore whitespace changes)
-rw-r--r--noncore/unsupported/qpdf/xpdf/Gfx.cc589
1 files changed, 444 insertions, 145 deletions
diff --git a/noncore/unsupported/qpdf/xpdf/Gfx.cc b/noncore/unsupported/qpdf/xpdf/Gfx.cc
index c19971c..17d613e 100644
--- a/noncore/unsupported/qpdf/xpdf/Gfx.cc
+++ b/noncore/unsupported/qpdf/xpdf/Gfx.cc
@@ -2,7 +2,7 @@
2// 2//
3// Gfx.cc 3// Gfx.cc
4// 4//
5// Copyright 1996 Derek B. Noonburg 5// Copyright 1996-2002 Glyph & Cog, LLC
6// 6//
7//======================================================================== 7//========================================================================
8 8
@@ -30,6 +30,11 @@
30#include "Error.h" 30#include "Error.h"
31#include "Gfx.h" 31#include "Gfx.h"
32 32
33// the MSVC math.h doesn't define this
34#ifndef M_PI
35#define M_PI 3.14159265358979323846
36#endif
37
33//------------------------------------------------------------------------ 38//------------------------------------------------------------------------
34// constants 39// constants
35//------------------------------------------------------------------------ 40//------------------------------------------------------------------------
@@ -40,6 +45,12 @@
40// Max delta allowed in any color component for an axial shading fill. 45// Max delta allowed in any color component for an axial shading fill.
41#define axialColorDelta (1 / 256.0) 46#define axialColorDelta (1 / 256.0)
42 47
48// Max number of splits along the t axis for a radial shading fill.
49#define radialMaxSplits 256
50
51// Max delta allowed in any color component for a radial shading fill.
52#define radialColorDelta (1 / 256.0)
53
43//------------------------------------------------------------------------ 54//------------------------------------------------------------------------
44// Operator table 55// Operator table
45//------------------------------------------------------------------------ 56//------------------------------------------------------------------------
@@ -374,6 +385,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, fouble dpi,
374 int i; 385 int i;
375 386
376 xref = xrefA; 387 xref = xrefA;
388 subPage = gFalse;
377 printCommands = printCommandsA; 389 printCommands = printCommandsA;
378 390
379 // start the resource stack 391 // start the resource stack
@@ -405,21 +417,54 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, fouble dpi,
405 } 417 }
406} 418}
407 419
408Gfx::~Gfx() { 420Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
409 GfxResources *resPtr; 421 PDFRectangle *box, GBool crop, PDFRectangle *cropBox) {
422 int i;
410 423
424 xref = xrefA;
425 subPage = gTrue;
426 printCommands = gFalse;
427
428 // start the resource stack
429 res = new GfxResources(xref, resDict, NULL);
430
431 // initialize
432 out = outA;
433 state = new GfxState(72, box, 0, gFalse);
434 fontChanged = gFalse;
435 clip = clipNone;
436 ignoreUndef = 0;
437 for (i = 0; i < 6; ++i) {
438 baseMatrix[i] = state->getCTM()[i];
439 }
440
441 // set crop box
442 if (crop) {
443 state->moveTo(cropBox->x1, cropBox->y1);
444 state->lineTo(cropBox->x2, cropBox->y1);
445 state->lineTo(cropBox->x2, cropBox->y2);
446 state->lineTo(cropBox->x1, cropBox->y2);
447 state->closePath();
448 state->clip();
449 out->clip(state);
450 state->clearPath();
451 }
452}
453
454Gfx::~Gfx() {
411 while (state->hasSaves()) { 455 while (state->hasSaves()) {
412 state = state->restore(); 456 state = state->restore();
413 out->restoreState(state); 457 out->restoreState(state);
414 } 458 }
415 out->endPage(); 459 if (!subPage) {
460 out->endPage();
461 }
416 while (res) { 462 while (res) {
417 resPtr = res->getNext(); 463 popResources();
418 delete res;
419 res = resPtr;
420 } 464 }
421 if (state) 465 if (state) {
422 delete state; 466 delete state;
467 }
423} 468}
424 469
425void Gfx::display(Object *obj, GBool topLevel) { 470void Gfx::display(Object *obj, GBool topLevel) {
@@ -449,11 +494,11 @@ void Gfx::display(Object *obj, GBool topLevel) {
449void Gfx::go(GBool topLevel) { 494void Gfx::go(GBool topLevel) {
450 Object obj; 495 Object obj;
451 Object args[maxArgs]; 496 Object args[maxArgs];
452 int numCmds, numArgs; 497 int numArgs;
453 int i; 498 int i;
454 499
455 // scan a sequence of objects 500 // scan a sequence of objects
456 numCmds = 0; 501 updateLevel = 0;
457 numArgs = 0; 502 numArgs = 0;
458 parser->getObj(&obj); 503 parser->getObj(&obj);
459 while (!obj.isEOF()) { 504 while (!obj.isEOF()) {
@@ -476,9 +521,9 @@ void Gfx::go(GBool topLevel) {
476 numArgs = 0; 521 numArgs = 0;
477 522
478 // periodically update display 523 // periodically update display
479 if (++numCmds == 200) { 524 if (++updateLevel >= 20000) {
480 out->dump(); 525 out->dump();
481 numCmds = 0; 526 updateLevel = 0;
482 } 527 }
483 528
484 // got an argument - save it 529 // got an argument - save it
@@ -519,7 +564,7 @@ void Gfx::go(GBool topLevel) {
519 } 564 }
520 565
521 // update display 566 // update display
522 if (topLevel && numCmds > 0) { 567 if (topLevel && updateLevel > 0) {
523 out->dump(); 568 out->dump();
524 } 569 }
525} 570}
@@ -1138,7 +1183,7 @@ void Gfx::doPatternFill(GBool eoFill) {
1138 fouble cxMin, cyMin, cxMax, cyMax; 1183 fouble cxMin, cyMin, cxMax, cyMax;
1139 int xi0, yi0, xi1, yi1, xi, yi; 1184 int xi0, yi0, xi1, yi1, xi, yi;
1140 fouble *ctm, *btm, *ptm; 1185 fouble *ctm, *btm, *ptm;
1141 fouble m[6], ictm[6], m1[6], im[6], imb[6]; 1186 fouble m[6], ictm[6], m1[6], imb[6];
1142 fouble det; 1187 fouble det;
1143 fouble xstep, ystep; 1188 fouble xstep, ystep;
1144 int i; 1189 int i;
@@ -1189,15 +1234,6 @@ void Gfx::doPatternFill(GBool eoFill) {
1189 m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4]; 1234 m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
1190 m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5]; 1235 m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
1191 1236
1192 // construct a (current space) -> (pattern space) transform matrix
1193 det = 1 / (m[0] * m[3] - m[1] * m[2]);
1194 im[0] = m[3] * det;
1195 im[1] = -m[1] * det;
1196 im[2] = -m[2] * det;
1197 im[3] = m[0] * det;
1198 im[4] = (m[2] * m[5] - m[3] * m[4]) * det;
1199 im[5] = (m[1] * m[4] - m[0] * m[5]) * det;
1200
1201 // construct a (base space) -> (pattern space) transform matrix 1237 // construct a (base space) -> (pattern space) transform matrix
1202 det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]); 1238 det = 1 / (m1[0] * m1[3] - m1[1] * m1[2]);
1203 imb[0] = m1[3] * det; 1239 imb[0] = m1[3] * det;
@@ -1331,6 +1367,9 @@ void Gfx::opShFill(Object args[], int numArgs) {
1331 case 2: 1367 case 2:
1332 doAxialShFill((GfxAxialShading *)shading); 1368 doAxialShFill((GfxAxialShading *)shading);
1333 break; 1369 break;
1370 case 3:
1371 doRadialShFill((GfxRadialShading *)shading);
1372 break;
1334 } 1373 }
1335 1374
1336 // restore graphics state 1375 // restore graphics state
@@ -1343,9 +1382,6 @@ void Gfx::opShFill(Object args[], int numArgs) {
1343void Gfx::doAxialShFill(GfxAxialShading *shading) { 1382void Gfx::doAxialShFill(GfxAxialShading *shading) {
1344 fouble xMin, yMin, xMax, yMax; 1383 fouble xMin, yMin, xMax, yMax;
1345 fouble x0, y0, x1, y1; 1384 fouble x0, y0, x1, y1;
1346 fouble det;
1347 fouble *ctm;
1348 fouble ictm[6];
1349 fouble dx, dy, mul; 1385 fouble dx, dy, mul;
1350 fouble tMin, tMax, t, tx, ty; 1386 fouble tMin, tMax, t, tx, ty;
1351 fouble s[4], sMin, sMax, tmp; 1387 fouble s[4], sMin, sMax, tmp;
@@ -1357,54 +1393,8 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
1357 int nComps; 1393 int nComps;
1358 int i, j, k, kk; 1394 int i, j, k, kk;
1359 1395
1360 // get clip region bbox and transform to current user space 1396 // get the clip region bbox
1361 state->getClipBBox(&x0, &y0, &x1, &y1); 1397 state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
1362 ctm = state->getCTM();
1363 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
1364 ictm[0] = ctm[3] * det;
1365 ictm[1] = -ctm[1] * det;
1366 ictm[2] = -ctm[2] * det;
1367 ictm[3] = ctm[0] * det;
1368 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
1369 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
1370 xMin = xMax = x0 * ictm[0] + y0 * ictm[2] + ictm[4];
1371 yMin = yMax = x0 * ictm[1] + y0 * ictm[3] + ictm[5];
1372 tx = x0 * ictm[0] + y1 * ictm[2] + ictm[4];
1373 ty = x0 * ictm[1] + y1 * ictm[3] + ictm[5];
1374 if (tx < xMin) {
1375 xMin = tx;
1376 } else if (tx > xMax) {
1377 xMax = tx;
1378 }
1379 if (ty < yMin) {
1380 yMin = ty;
1381 } else if (ty > yMax) {
1382 yMax = ty;
1383 }
1384 tx = x1 * ictm[0] + y0 * ictm[2] + ictm[4];
1385 ty = x1 * ictm[1] + y0 * ictm[3] + ictm[5];
1386 if (tx < xMin) {
1387 xMin = tx;
1388 } else if (tx > xMax) {
1389 xMax = tx;
1390 }
1391 if (ty < yMin) {
1392 yMin = ty;
1393 } else if (ty > yMax) {
1394 yMax = ty;
1395 }
1396 tx = x1 * ictm[0] + y1 * ictm[2] + ictm[4];
1397 ty = x1 * ictm[1] + y1 * ictm[3] + ictm[5];
1398 if (tx < xMin) {
1399 xMin = tx;
1400 } else if (tx > xMax) {
1401 xMax = tx;
1402 }
1403 if (ty < yMin) {
1404 yMin = ty;
1405 } else if (ty > yMax) {
1406 yMax = ty;
1407 }
1408 1398
1409 // compute min and max t values, based on the four corners of the 1399 // compute min and max t values, based on the four corners of the
1410 // clip region bbox 1400 // clip region bbox
@@ -1619,6 +1609,202 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
1619 } 1609 }
1620} 1610}
1621 1611
1612void Gfx::doRadialShFill(GfxRadialShading *shading) {
1613 fouble sMin, sMax, xMin, yMin, xMax, yMax;
1614 fouble x0, y0, r0, x1, y1, r1, t0, t1;
1615 int nComps;
1616 GfxColor colorA, colorB;
1617 fouble xa, ya, xb, yb, ra, rb;
1618 fouble ta, tb, sa, sb;
1619 int ia, ib, k, n;
1620 fouble *ctm;
1621 fouble angle, t;
1622
1623 // get the shading info
1624 shading->getCoords(&x0, &y0, &r0, &x1, &y1, &r1);
1625 t0 = shading->getDomain0();
1626 t1 = shading->getDomain1();
1627 nComps = shading->getColorSpace()->getNComps();
1628
1629 // compute the (possibly extended) s range
1630 sMin = 0;
1631 sMax = 1;
1632 if (shading->getExtend0()) {
1633 if (r0 < r1) {
1634 // extend the smaller end
1635 sMin = -r0 / (r1 - r0);
1636 } else {
1637 // extend the larger end
1638 //~ this computes the diagonal of the bounding box -- we should
1639 //~ really compute the intersection of the moving/expanding
1640 //~ circles with each of the four corners and look for the max
1641 //~ radius
1642 state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
1643 sMin = (sqrt((xMax - xMin) * (xMax - xMin) +
1644 (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
1645 if (sMin > 0) {
1646 sMin = 0;
1647 } else if (sMin < -20) {
1648 // sanity check
1649 sMin = -20;
1650 }
1651 }
1652 }
1653 if (shading->getExtend1()) {
1654 if (r1 < r0) {
1655 // extend the smaller end
1656 sMax = -r0 / (r1 - r0);
1657 } else if (r1 > r0) {
1658 // extend the larger end
1659 state->getUserClipBBox(&xMin, &yMin, &xMax, &yMax);
1660 sMax = (sqrt((xMax - xMin) * (xMax - xMin) +
1661 (yMax - yMin) * (yMax - yMin)) - r0) / (r1 - r0);
1662 if (sMax < 1) {
1663 sMin = 1;
1664 } else if (sMax > 20) {
1665 // sanity check
1666 sMax = 20;
1667 }
1668 }
1669 }
1670
1671 // compute the number of steps into which circles must be divided to
1672 // achieve a curve flatness of 0.1 pixel in device space for the
1673 // largest circle (note that "device space" is 72 dpi when generating
1674 // PostScript, hence the relatively small 0.1 pixel accuracy)
1675 ctm = state->getCTM();
1676 t = fabs(ctm[0]);
1677 if (fabs(ctm[1]) > t) {
1678 t = fabs(ctm[1]);
1679 }
1680 if (fabs(ctm[2]) > t) {
1681 t = fabs(ctm[2]);
1682 }
1683 if (fabs(ctm[3]) > t) {
1684 t = fabs(ctm[3]);
1685 }
1686 if (r0 > r1) {
1687 t *= r0;
1688 } else {
1689 t *= r1;
1690 }
1691 if (t < 1) {
1692 n = 3;
1693 } else {
1694 n = (int)(M_PI / acos(1 - 0.1 / t));
1695 if (n < 3) {
1696 n = 3;
1697 } else if (n > 200) {
1698 n = 200;
1699 }
1700 }
1701
1702 // Traverse the t axis and do the shading.
1703 //
1704 // This generates and fills a series of rings. Each ring is defined
1705 // by two circles:
1706 // sa, ta, xa, ya, ra, colorA
1707 // sb, tb, xb, yb, rb, colorB
1708 //
1709 // The s/t axis is divided into radialMaxSplits parts; these parts
1710 // are combined as much as possible while respecting the
1711 // radialColorDelta parameter.
1712
1713 // setup for the start circle
1714 ia = 0;
1715 sa = sMin;
1716 ta = t0 + sa * (t1 - t0);
1717 xa = x0 + sa * (x1 - x0);
1718 ya = y0 + sa * (y1 - y0);
1719 ra = r0 + sa * (r1 - r0);
1720 if (ta < t0) {
1721 shading->getColor(t0, &colorA);
1722 } else if (ta > t1) {
1723 shading->getColor(t1, &colorA);
1724 } else {
1725 shading->getColor(ta, &colorA);
1726 }
1727
1728 while (ia < radialMaxSplits) {
1729
1730 // go as far along the t axis (toward t1) as we can, such that the
1731 // color difference is within the tolerance (radialColorDelta) --
1732 // this uses bisection (between the current value, t, and t1),
1733 // limited to radialMaxSplits points along the t axis
1734 ib = radialMaxSplits;
1735 sb = sMin + ((fouble)ib / (fouble)radialMaxSplits) * (sMax - sMin);
1736 tb = t0 + sb * (t1 - t0);
1737 if (tb < t0) {
1738 shading->getColor(t0, &colorB);
1739 } else if (tb > t1) {
1740 shading->getColor(t1, &colorB);
1741 } else {
1742 shading->getColor(tb, &colorB);
1743 }
1744 while (ib - ia > 1) {
1745 for (k = 0; k < nComps; ++k) {
1746 if (fabs(colorB.c[k] - colorA.c[k]) > radialColorDelta) {
1747 break;
1748 }
1749 }
1750 if (k == nComps) {
1751 break;
1752 }
1753 ib = (ia + ib) / 2;
1754 sb = sMin + ((fouble)ib / (fouble)radialMaxSplits) * (sMax - sMin);
1755 tb = t0 + sb * (t1 - t0);
1756 if (tb < t0) {
1757 shading->getColor(t0, &colorB);
1758 } else if (tb > t1) {
1759 shading->getColor(t1, &colorB);
1760 } else {
1761 shading->getColor(tb, &colorB);
1762 }
1763 }
1764
1765 // compute center and radius of the circle
1766 xb = x0 + sb * (x1 - x0);
1767 yb = y0 + sb * (y1 - y0);
1768 rb = r0 + sb * (r1 - r0);
1769
1770 // use the average of the colors at the two circles
1771 for (k = 0; k < nComps; ++k) {
1772 colorA.c[k] = 0.5 * (colorA.c[k] + colorB.c[k]);
1773 }
1774 state->setFillColor(&colorA);
1775 out->updateFillColor(state);
1776
1777 // construct path for first circle
1778 state->moveTo(xa + ra, ya);
1779 for (k = 1; k < n; ++k) {
1780 angle = ((fouble)k / (fouble)n) * 2 * M_PI;
1781 state->lineTo(xa + ra * cos(angle), ya + ra * sin(angle));
1782 }
1783 state->closePath();
1784
1785 // construct and append path for second circle
1786 state->moveTo(xb + rb, yb);
1787 for (k = 1; k < n; ++k) {
1788 angle = ((fouble)k / (fouble)n) * 2 * M_PI;
1789 state->lineTo(xb + rb * cos(angle), yb + rb * sin(angle));
1790 }
1791 state->closePath();
1792
1793 // fill the ring
1794 out->eoFill(state);
1795 state->clearPath();
1796
1797 // step to the next value of t
1798 ia = ib;
1799 sa = sb;
1800 ta = tb;
1801 xa = xb;
1802 ya = yb;
1803 ra = rb;
1804 colorA = colorB;
1805 }
1806}
1807
1622void Gfx::doEndPath() { 1808void Gfx::doEndPath() {
1623 if (state->isPath() && clip != clipNone) { 1809 if (state->isPath() && clip != clipNone) {
1624 state->clip(); 1810 state->clip();
@@ -1800,17 +1986,23 @@ void Gfx::opMoveSetShowText(Object args[], int numArgs) {
1800void Gfx::opShowSpaceText(Object args[], int numArgs) { 1986void Gfx::opShowSpaceText(Object args[], int numArgs) {
1801 Array *a; 1987 Array *a;
1802 Object obj; 1988 Object obj;
1989 int wMode;
1803 int i; 1990 int i;
1804 1991
1805 if (!state->getFont()) { 1992 if (!state->getFont()) {
1806 error(getPos(), "No font in show/space"); 1993 error(getPos(), "No font in show/space");
1807 return; 1994 return;
1808 } 1995 }
1996 wMode = state->getFont()->getWMode();
1809 a = args[0].getArray(); 1997 a = args[0].getArray();
1810 for (i = 0; i < a->getLength(); ++i) { 1998 for (i = 0; i < a->getLength(); ++i) {
1811 a->get(i, &obj); 1999 a->get(i, &obj);
1812 if (obj.isNum()) { 2000 if (obj.isNum()) {
1813 state->textShift(-obj.getNum() * 0.001 * state->getFontSize()); 2001 if (wMode) {
2002 state->textShift(0, -obj.getNum() * 0.001 * state->getFontSize());
2003 } else {
2004 state->textShift(-obj.getNum() * 0.001 * state->getFontSize(), 0);
2005 }
1814 out->updateTextShift(state, obj.getNum()); 2006 out->updateTextShift(state, obj.getNum());
1815 } else if (obj.isString()) { 2007 } else if (obj.isString()) {
1816 doShowText(obj.getString()); 2008 doShowText(obj.getString());
@@ -1823,31 +2015,33 @@ void Gfx::opShowSpaceText(Object args[], int numArgs) {
1823 2015
1824void Gfx::doShowText(GString *s) { 2016void Gfx::doShowText(GString *s) {
1825 GfxFont *font; 2017 GfxFont *font;
2018 int wMode;
1826 fouble riseX, riseY; 2019 fouble riseX, riseY;
1827 CharCode code; 2020 CharCode code;
1828 Unicode u[8]; 2021 Unicode u[8];
1829 fouble dx, dy, dx2, dy2, tdx, tdy; 2022 fouble x, y, dx, dy, dx2, dy2, curX, curY, tdx, tdy;
1830 fouble originX, originY, tOriginX, tOriginY; 2023 fouble originX, originY, tOriginX, tOriginY;
2024 fouble oldCTM[6], newCTM[6];
2025 fouble *mat;
2026 Object charProc;
2027 Dict *resDict;
2028 Parser *oldParser;
1831 char *p; 2029 char *p;
1832 int len, n, uLen, nChars, nSpaces; 2030 int len, n, uLen, nChars, nSpaces, i;
1833 2031
1834 if (fontChanged) { 2032 if (fontChanged) {
1835 out->updateFont(state); 2033 out->updateFont(state);
1836 fontChanged = gFalse; 2034 fontChanged = gFalse;
1837 } 2035 }
1838 font = state->getFont(); 2036 font = state->getFont();
2037 wMode = font->getWMode();
1839 2038
1840#if 0 //~type3 2039 if (out->useDrawChar()) {
1841 fouble x, y;
1842 fouble oldCTM[6], newCTM[6];
1843 fouble *mat;
1844 Object charProc;
1845 Parser *oldParser;
1846 int i;
1847
1848 //~ also check out->renderType3()
1849 if (font->getType() == fontType3) {
1850 out->beginString(state, s); 2040 out->beginString(state, s);
2041 }
2042
2043 // handle a Type 3 char
2044 if (font->getType() == fontType3 && out->interpretType3Chars()) {
1851 mat = state->getCTM(); 2045 mat = state->getCTM();
1852 for (i = 0; i < 6; ++i) { 2046 for (i = 0; i < 6; ++i) {
1853 oldCTM[i] = mat[i]; 2047 oldCTM[i] = mat[i];
@@ -1867,6 +2061,8 @@ void Gfx::doShowText(GString *s) {
1867 newCTM[0] *= state->getHorizScaling(); 2061 newCTM[0] *= state->getHorizScaling();
1868 newCTM[2] *= state->getHorizScaling(); 2062 newCTM[2] *= state->getHorizScaling();
1869 state->textTransformDelta(0, state->getRise(), &riseX, &riseY); 2063 state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
2064 curX = state->getCurX();
2065 curY = state->getCurY();
1870 oldParser = parser; 2066 oldParser = parser;
1871 p = s->getCString(); 2067 p = s->getCString();
1872 len = s->getLength(); 2068 len = s->getLength();
@@ -1874,21 +2070,6 @@ void Gfx::doShowText(GString *s) {
1874 n = font->getNextChar(p, len, &code, 2070 n = font->getNextChar(p, len, &code,
1875 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, 2071 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
1876 &dx, &dy, &originX, &originY); 2072 &dx, &dy, &originX, &originY);
1877 state->transform(state->getCurX() + riseX, state->getCurY() + riseY,
1878 &x, &y);
1879 out->saveState(state);
1880 state = state->save();
1881 state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
1882 //~ out->updateCTM(???)
1883 ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
1884 if (charProc.isStream()) {
1885 display(&charProc, gFalse);
1886 } else {
1887 error(getPos(), "Missing or bad Type3 CharProc entry");
1888 }
1889 state = state->restore();
1890 out->restoreState(state);
1891 charProc.free();
1892 dx = dx * state->getFontSize() + state->getCharSpace(); 2073 dx = dx * state->getFontSize() + state->getCharSpace();
1893 if (n == 1 && *p == ' ') { 2074 if (n == 1 && *p == ' ') {
1894 dx += state->getWordSpace(); 2075 dx += state->getWordSpace();
@@ -1896,31 +2077,61 @@ void Gfx::doShowText(GString *s) {
1896 dx *= state->getHorizScaling(); 2077 dx *= state->getHorizScaling();
1897 dy *= state->getFontSize(); 2078 dy *= state->getFontSize();
1898 state->textTransformDelta(dx, dy, &tdx, &tdy); 2079 state->textTransformDelta(dx, dy, &tdx, &tdy);
1899 state->shift(tdx, tdy); 2080 state->transform(curX + riseX, curY + riseY, &x, &y);
2081 out->saveState(state);
2082 state = state->save();
2083 state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
2084 //~ out->updateCTM(???)
2085 if (!out->beginType3Char(state, code, u, uLen)) {
2086 ((Gfx8BitFont *)font)->getCharProc(code, &charProc);
2087 if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
2088 pushResources(resDict);
2089 }
2090 if (charProc.isStream()) {
2091 display(&charProc, gFalse);
2092 } else {
2093 error(getPos(), "Missing or bad Type3 CharProc entry");
2094 }
2095 out->endType3Char(state);
2096 if (resDict) {
2097 popResources();
2098 }
2099 charProc.free();
2100 }
2101 state = state->restore();
2102 out->restoreState(state);
2103 // GfxState::restore() does *not* restore the current position,
2104 // so we track it here with (curX, curY)
2105 curX += tdx;
2106 curY += tdy;
2107 state->moveTo(curX, curY);
1900 p += n; 2108 p += n;
1901 len -= n; 2109 len -= n;
1902 } 2110 }
1903 parser = oldParser; 2111 parser = oldParser;
1904 out->endString(state);
1905 return;
1906 }
1907#endif
1908 2112
1909 if (out->useDrawChar()) { 2113 } else if (out->useDrawChar()) {
1910 state->textTransformDelta(0, state->getRise(), &riseX, &riseY); 2114 state->textTransformDelta(0, state->getRise(), &riseX, &riseY);
1911 out->beginString(state, s);
1912 p = s->getCString(); 2115 p = s->getCString();
1913 len = s->getLength(); 2116 len = s->getLength();
1914 while (len > 0) { 2117 while (len > 0) {
1915 n = font->getNextChar(p, len, &code, 2118 n = font->getNextChar(p, len, &code,
1916 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen, 2119 u, (int)(sizeof(u) / sizeof(Unicode)), &uLen,
1917 &dx, &dy, &originX, &originY); 2120 &dx, &dy, &originX, &originY);
1918 dx = dx * state->getFontSize() + state->getCharSpace(); 2121 if (wMode) {
1919 if (n == 1 && *p == ' ') { 2122 dx *= state->getFontSize();
1920 dx += state->getWordSpace(); 2123 dy = dy * state->getFontSize() + state->getCharSpace();
2124 if (n == 1 && *p == ' ') {
2125 dy += state->getWordSpace();
2126 }
2127 } else {
2128 dx = dx * state->getFontSize() + state->getCharSpace();
2129 if (n == 1 && *p == ' ') {
2130 dx += state->getWordSpace();
2131 }
2132 dx *= state->getHorizScaling();
2133 dy *= state->getFontSize();
1921 } 2134 }
1922 dx *= state->getHorizScaling();
1923 dy *= state->getFontSize();
1924 state->textTransformDelta(dx, dy, &tdx, &tdy); 2135 state->textTransformDelta(dx, dy, &tdx, &tdy);
1925 originX *= state->getFontSize(); 2136 originX *= state->getFontSize();
1926 originY *= state->getFontSize(); 2137 originY *= state->getFontSize();
@@ -1931,7 +2142,6 @@ void Gfx::doShowText(GString *s) {
1931 p += n; 2142 p += n;
1932 len -= n; 2143 len -= n;
1933 } 2144 }
1934 out->endString(state);
1935 2145
1936 } else { 2146 } else {
1937 dx = dy = 0; 2147 dx = dy = 0;
@@ -1951,15 +2161,28 @@ void Gfx::doShowText(GString *s) {
1951 p += n; 2161 p += n;
1952 len -= n; 2162 len -= n;
1953 } 2163 }
1954 dx = dx * state->getFontSize() 2164 if (wMode) {
1955 + nChars * state->getCharSpace() 2165 dx *= state->getFontSize();
1956 + nSpaces * state->getWordSpace(); 2166 dy = dy * state->getFontSize()
1957 dx *= state->getHorizScaling(); 2167 + nChars * state->getCharSpace()
1958 dy *= state->getFontSize(); 2168 + nSpaces * state->getWordSpace();
2169 } else {
2170 dx = dx * state->getFontSize()
2171 + nChars * state->getCharSpace()
2172 + nSpaces * state->getWordSpace();
2173 dx *= state->getHorizScaling();
2174 dy *= state->getFontSize();
2175 }
1959 state->textTransformDelta(dx, dy, &tdx, &tdy); 2176 state->textTransformDelta(dx, dy, &tdx, &tdy);
1960 out->drawString(state, s); 2177 out->drawString(state, s);
1961 state->shift(tdx, tdy); 2178 state->shift(tdx, tdy);
1962 } 2179 }
2180
2181 if (out->useDrawChar()) {
2182 out->endString(state);
2183 }
2184
2185 updateLevel += 10 * s->getLength();
1963} 2186}
1964 2187
1965//------------------------------------------------------------------------ 2188//------------------------------------------------------------------------
@@ -1967,7 +2190,7 @@ void Gfx::doShowText(GString *s) {
1967//------------------------------------------------------------------------ 2190//------------------------------------------------------------------------
1968 2191
1969void Gfx::opXObject(Object args[], int numArgs) { 2192void Gfx::opXObject(Object args[], int numArgs) {
1970 Object obj1, obj2, refObj; 2193 Object obj1, obj2, obj3, refObj;
1971#if OPI_SUPPORT 2194#if OPI_SUPPORT
1972 Object opiDict; 2195 Object opiDict;
1973#endif 2196#endif
@@ -1993,6 +2216,10 @@ void Gfx::opXObject(Object args[], int numArgs) {
1993 refObj.free(); 2216 refObj.free();
1994 } else if (obj2.isName("Form")) { 2217 } else if (obj2.isName("Form")) {
1995 doForm(&obj1); 2218 doForm(&obj1);
2219 } else if (obj2.isName("PS")) {
2220 obj1.streamGetDict()->lookup("Level1", &obj3);
2221 out->psXObject(obj1.getStream(),
2222 obj3.isStream() ? obj3.getStream() : (Stream *)NULL);
1996 } else if (obj2.isName()) { 2223 } else if (obj2.isName()) {
1997 error(getPos(), "Unknown XObject subtype '%s'", obj2.getName()); 2224 error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
1998 } else { 2225 } else {
@@ -2148,6 +2375,11 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
2148 maskObj.free(); 2375 maskObj.free();
2149 } 2376 }
2150 2377
2378 if ((i = width * height) > 1000) {
2379 i = 1000;
2380 }
2381 updateLevel += i;
2382
2151 return; 2383 return;
2152 2384
2153 err2: 2385 err2:
@@ -2215,19 +2447,22 @@ void Gfx::doForm(Object *str) {
2215 resObj.free(); 2447 resObj.free();
2216} 2448}
2217 2449
2218void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin, 2450void Gfx::doAnnot(Object *str, fouble xMin, fouble yMin,
2219 fouble xMax, fouble yMax) { 2451 fouble xMax, fouble yMax) {
2220 Dict *dict, *resDict; 2452 Dict *dict, *resDict;
2221 Object matrixObj, bboxObj, resObj; 2453 Object matrixObj, bboxObj, resObj;
2222 Object obj1; 2454 Object obj1;
2223 fouble m[6], bbox[6]; 2455 fouble m[6], bbox[6], ictm[6];
2224 fouble sx, sy; 2456 fouble *ctm;
2457 fouble formX0, formY0, formX1, formY1;
2458 fouble annotX0, annotY0, annotX1, annotY1;
2459 fouble det, x, y, sx, sy;
2225 int i; 2460 int i;
2226 2461
2227 // get stream dict 2462 // get stream dict
2228 dict = str->streamGetDict(); 2463 dict = str->streamGetDict();
2229 2464
2230 // get bounding box 2465 // get the form bounding box
2231 dict->lookup("BBox", &bboxObj); 2466 dict->lookup("BBox", &bboxObj);
2232 if (!bboxObj.isArray()) { 2467 if (!bboxObj.isArray()) {
2233 bboxObj.free(); 2468 bboxObj.free();
@@ -2241,7 +2476,7 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin,
2241 } 2476 }
2242 bboxObj.free(); 2477 bboxObj.free();
2243 2478
2244 // get matrix 2479 // get the form matrix
2245 dict->lookup("Matrix", &matrixObj); 2480 dict->lookup("Matrix", &matrixObj);
2246 if (matrixObj.isArray()) { 2481 if (matrixObj.isArray()) {
2247 for (i = 0; i < 6; ++i) { 2482 for (i = 0; i < 6; ++i) {
@@ -2256,16 +2491,64 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin,
2256 } 2491 }
2257 matrixObj.free(); 2492 matrixObj.free();
2258 2493
2259 // scale form bbox to widget rectangle 2494 // transform the form bbox from form space to user space
2260 sx = fabs((xMax - xMin) / (bbox[2] - bbox[0])); 2495 formX0 = bbox[0] * m[0] + bbox[1] * m[2] + m[4];
2261 sy = fabs((yMax - yMin) / (bbox[3] - bbox[1])); 2496 formY0 = bbox[0] * m[1] + bbox[1] * m[3] + m[5];
2262 m[0] *= sx; m[1] *= sy; 2497 formX1 = bbox[2] * m[0] + bbox[3] * m[2] + m[4];
2263 m[2] *= sx; m[3] *= sy; 2498 formY1 = bbox[2] * m[1] + bbox[3] * m[3] + m[5];
2264 m[4] *= sx; m[5] *= sy; 2499
2500 // transform the annotation bbox from default user space to user
2501 // space: (bbox * baseMatrix) * iCTM
2502 ctm = state->getCTM();
2503 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
2504 ictm[0] = ctm[3] * det;
2505 ictm[1] = -ctm[1] * det;
2506 ictm[2] = -ctm[2] * det;
2507 ictm[3] = ctm[0] * det;
2508 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
2509 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
2510 x = baseMatrix[0] * xMin + baseMatrix[2] * yMin + baseMatrix[4];
2511 y = baseMatrix[1] * xMin + baseMatrix[3] * yMin + baseMatrix[5];
2512 annotX0 = ictm[0] * x + ictm[2] * y + ictm[4];
2513 annotY0 = ictm[1] * x + ictm[3] * y + ictm[5];
2514 x = baseMatrix[0] * xMax + baseMatrix[2] * yMax + baseMatrix[4];
2515 y = baseMatrix[1] * xMax + baseMatrix[3] * yMax + baseMatrix[5];
2516 annotX1 = ictm[0] * x + ictm[2] * y + ictm[4];
2517 annotY1 = ictm[1] * x + ictm[3] * y + ictm[5];
2518
2519 // swap min/max coords
2520 if (formX0 > formX1) {
2521 x = formX0; formX0 = formX1; formX1 = x;
2522 }
2523 if (formY0 > formY1) {
2524 y = formY0; formY0 = formY1; formY1 = y;
2525 }
2526 if (annotX0 > annotX1) {
2527 x = annotX0; annotX0 = annotX1; annotX1 = x;
2528 }
2529 if (annotY0 > annotY1) {
2530 y = annotY0; annotY0 = annotY1; annotY1 = y;
2531 }
2265 2532
2266 // translate to widget rectangle 2533 // scale the form to fit the annotation bbox
2267 m[4] += xMin; 2534 if (formX1 == formX0) {
2268 m[5] += yMin; 2535 // this shouldn't happen
2536 sx = 1;
2537 } else {
2538 sx = (annotX1 - annotX0) / (formX1 - formX0);
2539 }
2540 if (formY1 == formY0) {
2541 // this shouldn't happen
2542 sy = 1;
2543 } else {
2544 sy = (annotY1 - annotY0) / (formY1 - formY0);
2545 }
2546 m[0] *= sx;
2547 m[2] *= sx;
2548 m[4] = (m[4] - formX0) * sx + annotX0;
2549 m[1] *= sy;
2550 m[3] *= sy;
2551 m[5] = (m[5] - formY0) * sy + annotY0;
2269 2552
2270 // get resources 2553 // get resources
2271 dict->lookup("Resources", &resObj); 2554 dict->lookup("Resources", &resObj);
@@ -2281,11 +2564,10 @@ void Gfx::doWidgetForm(Object *str, fouble xMin, fouble yMin,
2281void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) { 2564void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) {
2282 Parser *oldParser; 2565 Parser *oldParser;
2283 fouble oldBaseMatrix[6]; 2566 fouble oldBaseMatrix[6];
2284 GfxResources *resPtr;
2285 int i; 2567 int i;
2286 2568
2287 // push new resources on stack 2569 // push new resources on stack
2288 res = new GfxResources(xref, resDict, res); 2570 pushResources(resDict);
2289 2571
2290 // save current graphics state 2572 // save current graphics state
2291 out->saveState(state); 2573 out->saveState(state);
@@ -2332,11 +2614,21 @@ void Gfx::doForm1(Object *str, Dict *resDict, fouble *matrix, fouble *bbox) {
2332 out->restoreState(state); 2614 out->restoreState(state);
2333 2615
2334 // pop resource stack 2616 // pop resource stack
2617 popResources();
2618
2619 return;
2620}
2621
2622void Gfx::pushResources(Dict *resDict) {
2623 res = new GfxResources(xref, resDict, res);
2624}
2625
2626void Gfx::popResources() {
2627 GfxResources *resPtr;
2628
2335 resPtr = res->getNext(); 2629 resPtr = res->getNext();
2336 delete res; 2630 delete res;
2337 res = resPtr; 2631 res = resPtr;
2338
2339 return;
2340} 2632}
2341 2633
2342//------------------------------------------------------------------------ 2634//------------------------------------------------------------------------
@@ -2378,19 +2670,24 @@ Stream *Gfx::buildImageStream() {
2378 if (!obj.isName()) { 2670 if (!obj.isName()) {
2379 error(getPos(), "Inline image dictionary key must be a name object"); 2671 error(getPos(), "Inline image dictionary key must be a name object");
2380 obj.free(); 2672 obj.free();
2381 parser->getObj(&obj);
2382 } else { 2673 } else {
2383 key = copyString(obj.getName()); 2674 key = copyString(obj.getName());
2384 obj.free(); 2675 obj.free();
2385 parser->getObj(&obj); 2676 parser->getObj(&obj);
2386 if (obj.isEOF() || obj.isError()) 2677 if (obj.isEOF() || obj.isError()) {
2678 gfree(key);
2387 break; 2679 break;
2680 }
2388 dict.dictAdd(key, &obj); 2681 dict.dictAdd(key, &obj);
2389 } 2682 }
2390 parser->getObj(&obj); 2683 parser->getObj(&obj);
2391 } 2684 }
2392 if (obj.isEOF()) 2685 if (obj.isEOF()) {
2393 error(getPos(), "End of file in inline image"); 2686 error(getPos(), "End of file in inline image");
2687 obj.free();
2688 dict.free();
2689 return NULL;
2690 }
2394 obj.free(); 2691 obj.free();
2395 2692
2396 // make stream 2693 // make stream
@@ -2413,11 +2710,13 @@ void Gfx::opEndImage(Object args[], int numArgs) {
2413//------------------------------------------------------------------------ 2710//------------------------------------------------------------------------
2414 2711
2415void Gfx::opSetCharWidth(Object args[], int numArgs) { 2712void Gfx::opSetCharWidth(Object args[], int numArgs) {
2416 error(getPos(), "Encountered 'd0' operator in content stream"); 2713 out->type3D0(state, args[0].getNum(), args[1].getNum());
2417} 2714}
2418 2715
2419void Gfx::opSetCacheDevice(Object args[], int numArgs) { 2716void Gfx::opSetCacheDevice(Object args[], int numArgs) {
2420 error(getPos(), "Encountered 'd1' operator in content stream"); 2717 out->type3D1(state, args[0].getNum(), args[1].getNum(),
2718 args[2].getNum(), args[3].getNum(),
2719 args[4].getNum(), args[5].getNum());
2421} 2720}
2422 2721
2423//------------------------------------------------------------------------ 2722//------------------------------------------------------------------------