1 //========================================================================
5 // Copyright 1996 Derek B. Noonburg
7 //========================================================================
10 #pragma implementation
26 #include "OutputDev.h"
31 //------------------------------------------------------------------------
33 //------------------------------------------------------------------------
35 Operator Gfx::opTab[] = {
36 {"\"", 3, {tchkNum, tchkNum, tchkString},
37 &Gfx::opMoveSetShowText},
38 {"'", 1, {tchkString},
39 &Gfx::opMoveShowText},
43 &Gfx::opEOFillStroke},
44 {"BDC", 2, {tchkName, tchkProps},
45 &Gfx::opBeginMarkedContent},
48 {"BMC", 1, {tchkName},
49 &Gfx::opBeginMarkedContent},
53 &Gfx::opBeginIgnoreUndef},
55 &Gfx::opSetStrokeColorSpace},
56 {"DP", 2, {tchkName, tchkProps},
62 {"EMC", 0, {tchkNone},
63 &Gfx::opEndMarkedContent},
67 &Gfx::opEndIgnoreUndef},
71 &Gfx::opSetStrokeGray},
76 {"K", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
77 &Gfx::opSetStrokeCMYKColor},
79 &Gfx::opSetMiterLimit},
84 {"RG", 3, {tchkNum, tchkNum, tchkNum},
85 &Gfx::opSetStrokeRGBColor},
88 {"SC", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
89 &Gfx::opSetStrokeColor},
90 {"SCN", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
92 &Gfx::opSetStrokeColorN},
94 &Gfx::opTextNextLine},
95 {"TD", 2, {tchkNum, tchkNum},
97 {"TJ", 1, {tchkArray},
98 &Gfx::opShowSpaceText},
100 &Gfx::opSetTextLeading},
102 &Gfx::opSetCharSpacing},
103 {"Td", 2, {tchkNum, tchkNum},
105 {"Tf", 2, {tchkName, tchkNum},
107 {"Tj", 1, {tchkString},
109 {"Tm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
111 &Gfx::opSetTextMatrix},
113 &Gfx::opSetTextRender},
115 &Gfx::opSetTextRise},
117 &Gfx::opSetWordSpacing},
119 &Gfx::opSetHorizScaling},
122 {"W*", 0, {tchkNone},
125 &Gfx::opCloseFillStroke},
126 {"b*", 0, {tchkNone},
127 &Gfx::opCloseEOFillStroke},
128 {"c", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
131 {"cm", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
134 {"cs", 1, {tchkName},
135 &Gfx::opSetFillColorSpace},
136 {"d", 2, {tchkArray, tchkNum},
138 {"d0", 2, {tchkNum, tchkNum},
139 &Gfx::opSetCharWidth},
140 {"d1", 6, {tchkNum, tchkNum, tchkNum, tchkNum,
142 &Gfx::opSetCacheDevice},
145 {"f*", 0, {tchkNone},
148 &Gfx::opSetFillGray},
149 {"gs", 1, {tchkName},
150 &Gfx::opSetExtGState},
156 &Gfx::opSetLineJoin},
157 {"k", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
158 &Gfx::opSetFillCMYKColor},
159 {"l", 2, {tchkNum, tchkNum},
161 {"m", 2, {tchkNum, tchkNum},
167 {"re", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
169 {"rg", 3, {tchkNum, tchkNum, tchkNum},
170 &Gfx::opSetFillRGBColor},
171 {"ri", 1, {tchkName},
172 &Gfx::opSetRenderingIntent},
174 &Gfx::opCloseStroke},
175 {"sc", -4, {tchkNum, tchkNum, tchkNum, tchkNum},
176 &Gfx::opSetFillColor},
177 {"scn", -5, {tchkSCN, tchkSCN, tchkSCN, tchkSCN,
179 &Gfx::opSetFillColorN},
180 {"sh", 1, {tchkName},
182 {"v", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
185 &Gfx::opSetLineWidth},
186 {"y", 4, {tchkNum, tchkNum, tchkNum, tchkNum},
190 #define numOps (sizeof(opTab) / sizeof(Operator))
192 //------------------------------------------------------------------------
194 GBool printCommands = gFalse;
196 //------------------------------------------------------------------------
198 //------------------------------------------------------------------------
200 GfxResources::GfxResources(Dict *resDict, GfxResources *next) {
205 // build font dictionary
207 resDict->lookup("Font", &obj1);
209 fonts = new GfxFontDict(obj1.getDict());
213 // get XObject dictionary
214 resDict->lookup("XObject", &xObjDict);
216 // get color space dictionary
217 resDict->lookup("ColorSpace", &colorSpaceDict);
219 // get pattern dictionary
220 resDict->lookup("Pattern", &patternDict);
222 // get graphics state parameter dictionary
223 resDict->lookup("ExtGState", &gStateDict);
228 colorSpaceDict.initNull();
229 patternDict.initNull();
230 gStateDict.initNull();
236 GfxResources::~GfxResources() {
241 colorSpaceDict.free();
246 GfxFont *GfxResources::lookupFont(char *name) {
248 GfxResources *resPtr;
250 for (resPtr = this; resPtr; resPtr = resPtr->next) {
252 if ((font = resPtr->fonts->lookup(name)))
256 error(-1, "Unknown font tag '%s'", name);
260 GBool GfxResources::lookupXObject(char *name, Object *obj) {
261 GfxResources *resPtr;
263 for (resPtr = this; resPtr; resPtr = resPtr->next) {
264 if (resPtr->xObjDict.isDict()) {
265 if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
270 error(-1, "XObject '%s' is unknown", name);
274 GBool GfxResources::lookupXObjectNF(char *name, Object *obj) {
275 GfxResources *resPtr;
277 for (resPtr = this; resPtr; resPtr = resPtr->next) {
278 if (resPtr->xObjDict.isDict()) {
279 if (!resPtr->xObjDict.dictLookupNF(name, obj)->isNull())
284 error(-1, "XObject '%s' is unknown", name);
288 void GfxResources::lookupColorSpace(char *name, Object *obj) {
289 GfxResources *resPtr;
291 for (resPtr = this; resPtr; resPtr = resPtr->next) {
292 if (resPtr->colorSpaceDict.isDict()) {
293 if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull()) {
302 GfxPattern *GfxResources::lookupPattern(char *name) {
303 GfxResources *resPtr;
307 for (resPtr = this; resPtr; resPtr = resPtr->next) {
308 if (resPtr->patternDict.isDict()) {
309 if (!resPtr->patternDict.dictLookup(name, &obj)->isNull()) {
310 pattern = GfxPattern::parse(&obj);
317 error(-1, "Unknown pattern '%s'", name);
321 GBool GfxResources::lookupGState(char *name, Object *obj) {
322 GfxResources *resPtr;
324 for (resPtr = this; resPtr; resPtr = resPtr->next) {
325 if (resPtr->gStateDict.isDict()) {
326 if (!resPtr->gStateDict.dictLookup(name, obj)->isNull()) {
332 error(-1, "ExtGState '%s' is unknown", name);
336 //------------------------------------------------------------------------
338 //------------------------------------------------------------------------
340 Gfx::Gfx(OutputDev *out1, int pageNum, Dict *resDict,
341 double dpi, double x1, double y1, double x2, double y2, GBool crop,
342 double cropX1, double cropY1, double cropX2, double cropY2,
346 // start the resource stack
347 res = new GfxResources(resDict, NULL);
351 state = new GfxState(dpi, x1, y1, x2, y2, rotate, out->upsideDown());
352 fontChanged = gFalse;
355 out->startPage(pageNum, state);
356 out->setDefaultCTM(state->getCTM());
357 out->updateAll(state);
358 for (i = 0; i < 6; ++i) {
359 baseMatrix[i] = state->getCTM()[i];
364 state->moveTo(cropX1, cropY1);
365 state->lineTo(cropX2, cropY1);
366 state->lineTo(cropX2, cropY2);
367 state->lineTo(cropX1, cropY2);
375 GfxResources *resPtr;
377 while (state->hasSaves()) {
378 state = state->restore();
379 out->restoreState(state);
383 resPtr = res->getNext();
391 void Gfx::display(Object *obj, GBool topLevel) {
395 if (obj->isArray()) {
396 for (i = 0; i < obj->arrayGetLength(); ++i) {
397 obj->arrayGet(i, &obj2);
398 if (!obj2.isStream()) {
399 error(-1, "Weird page contents");
405 } else if (!obj->isStream()) {
406 error(-1, "Weird page contents");
409 parser = new Parser(new Lexer(obj));
415 void Gfx::go(GBool topLevel) {
417 Object args[maxArgs];
418 int numCmds, numArgs;
421 // scan a sequence of objects
424 parser->getObj(&obj);
425 while (!obj.isEOF()) {
427 // got a command - execute it
431 for (i = 0; i < numArgs; ++i) {
433 args[i].print(stdout);
437 execOp(&obj, args, numArgs);
439 for (i = 0; i < numArgs; ++i)
443 // periodically update display
444 if (++numCmds == 200) {
449 // got an argument - save it
450 } else if (numArgs < maxArgs) {
451 args[numArgs++] = obj;
453 // too many arguments - something is wrong
455 error(getPos(), "Too many args in content stream");
457 printf("throwing away arg: ");
464 // grab the next object
465 parser->getObj(&obj);
469 // args at end with no command
471 error(getPos(), "Leftover args in content stream");
473 printf("%d leftovers:", numArgs);
474 for (i = 0; i < numArgs; ++i) {
476 args[i].print(stdout);
480 for (i = 0; i < numArgs; ++i)
485 if (topLevel && numCmds > 0) {
495 void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
501 name = cmd->getName();
502 if (!(op = findOp(name))) {
503 if (ignoreUndef == 0)
504 error(getPos(), "Unknown operator '%s'", name);
509 if (op->numArgs >= 0) {
510 if (numArgs != op->numArgs) {
511 error(getPos(), "Wrong number (%d) of args to '%s' operator",
516 if (numArgs > -op->numArgs) {
517 error(getPos(), "Too many (%d) args to '%s' operator",
522 for (i = 0; i < numArgs; ++i) {
523 if (!checkArg(&args[i], op->tchk[i])) {
524 error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
525 i, name, args[i].getTypeName());
531 (this->*op->func)(args, numArgs);
534 Operator *Gfx::findOp(char *name) {
539 // invariant: opTab[a] < name < opTab[b]
542 cmp = strcmp(opTab[m].name, name);
555 GBool Gfx::checkArg(Object *arg, TchkType type) {
557 case tchkBool: return arg->isBool();
558 case tchkInt: return arg->isInt();
559 case tchkNum: return arg->isNum();
560 case tchkString: return arg->isString();
561 case tchkName: return arg->isName();
562 case tchkArray: return arg->isArray();
563 case tchkProps: return arg->isDict() || arg->isName();
564 case tchkSCN: return arg->isNum() || arg->isName();
565 case tchkNone: return gFalse;
571 return parser ? parser->getPos() : -1;
574 //------------------------------------------------------------------------
575 // graphics state operators
576 //------------------------------------------------------------------------
578 void Gfx::opSave(Object args[], int numArgs) {
579 out->saveState(state);
580 state = state->save();
583 void Gfx::opRestore(Object args[], int numArgs) {
584 state = state->restore();
585 out->restoreState(state);
587 // Some PDF producers (Macromedia FreeHand) generate a save (q) and
588 // restore (Q) inside a path sequence. The PDF spec seems to imply
589 // that this is illegal. Calling clearPath() here implements the
590 // behavior apparently expected by this software.
594 void Gfx::opConcat(Object args[], int numArgs) {
595 state->concatCTM(args[0].getNum(), args[1].getNum(),
596 args[2].getNum(), args[3].getNum(),
597 args[4].getNum(), args[5].getNum());
598 out->updateCTM(state, args[0].getNum(), args[1].getNum(),
599 args[2].getNum(), args[3].getNum(),
600 args[4].getNum(), args[5].getNum());
604 void Gfx::opSetDash(Object args[], int numArgs) {
611 a = args[0].getArray();
612 length = a->getLength();
616 dash = (double *)gmalloc(length * sizeof(double));
617 for (i = 0; i < length; ++i) {
618 dash[i] = a->get(i, &obj)->getNum();
622 state->setLineDash(dash, length, args[1].getNum());
623 out->updateLineDash(state);
626 void Gfx::opSetFlat(Object args[], int numArgs) {
627 state->setFlatness((int)args[0].getNum());
628 out->updateFlatness(state);
631 void Gfx::opSetLineJoin(Object args[], int numArgs) {
632 state->setLineJoin(args[0].getInt());
633 out->updateLineJoin(state);
636 void Gfx::opSetLineCap(Object args[], int numArgs) {
637 state->setLineCap(args[0].getInt());
638 out->updateLineCap(state);
641 void Gfx::opSetMiterLimit(Object args[], int numArgs) {
642 state->setMiterLimit(args[0].getNum());
643 out->updateMiterLimit(state);
646 void Gfx::opSetLineWidth(Object args[], int numArgs) {
647 state->setLineWidth(args[0].getNum());
648 out->updateLineWidth(state);
651 void Gfx::opSetExtGState(Object args[], int numArgs) {
654 if (!res->lookupGState(args[0].getName(), &obj1)) {
657 if (!obj1.isDict()) {
658 error(getPos(), "ExtGState '%s' is wrong type", args[0].getName());
662 if (obj1.dictLookup("ca", &obj2)->isNum()) {
663 state->setFillOpacity(obj2.getNum());
664 out->updateFillOpacity(state);
667 if (obj1.dictLookup("CA", &obj2)->isNum()) {
668 state->setStrokeOpacity(obj2.getNum());
669 out->updateStrokeOpacity(state);
675 void Gfx::opSetRenderingIntent(Object args[], int numArgs) {
678 //------------------------------------------------------------------------
680 //------------------------------------------------------------------------
682 void Gfx::opSetFillGray(Object args[], int numArgs) {
685 state->setFillPattern(NULL);
686 state->setFillColorSpace(new GfxDeviceGrayColorSpace());
687 color.c[0] = args[0].getNum();
688 state->setFillColor(&color);
689 out->updateFillColor(state);
692 void Gfx::opSetStrokeGray(Object args[], int numArgs) {
695 state->setStrokePattern(NULL);
696 state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
697 color.c[0] = args[0].getNum();
698 state->setStrokeColor(&color);
699 out->updateStrokeColor(state);
702 void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
706 state->setFillPattern(NULL);
707 state->setFillColorSpace(new GfxDeviceCMYKColorSpace());
708 for (i = 0; i < 4; ++i) {
709 color.c[i] = args[i].getNum();
711 state->setFillColor(&color);
712 out->updateFillColor(state);
715 void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
719 state->setStrokePattern(NULL);
720 state->setStrokeColorSpace(new GfxDeviceCMYKColorSpace());
721 for (i = 0; i < 4; ++i) {
722 color.c[i] = args[i].getNum();
724 state->setStrokeColor(&color);
725 out->updateStrokeColor(state);
728 void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
732 state->setFillPattern(NULL);
733 state->setFillColorSpace(new GfxDeviceRGBColorSpace());
734 for (i = 0; i < 3; ++i) {
735 color.c[i] = args[i].getNum();
737 state->setFillColor(&color);
738 out->updateFillColor(state);
741 void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
745 state->setStrokePattern(NULL);
746 state->setStrokeColorSpace(new GfxDeviceRGBColorSpace());
747 for (i = 0; i < 3; ++i) {
748 color.c[i] = args[i].getNum();
750 state->setStrokeColor(&color);
751 out->updateStrokeColor(state);
754 void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
756 GfxColorSpace *colorSpace;
760 state->setFillPattern(NULL);
761 res->lookupColorSpace(args[0].getName(), &obj);
763 colorSpace = GfxColorSpace::parse(&args[0]);
765 colorSpace = GfxColorSpace::parse(&obj);
769 state->setFillColorSpace(colorSpace);
771 error(getPos(), "Bad color space");
773 for (i = 0; i < gfxColorMaxComps; ++i) {
776 state->setFillColor(&color);
777 out->updateFillColor(state);
780 void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
782 GfxColorSpace *colorSpace;
786 state->setStrokePattern(NULL);
787 res->lookupColorSpace(args[0].getName(), &obj);
789 colorSpace = GfxColorSpace::parse(&args[0]);
791 colorSpace = GfxColorSpace::parse(&obj);
795 state->setStrokeColorSpace(colorSpace);
797 error(getPos(), "Bad color space");
799 for (i = 0; i < gfxColorMaxComps; ++i) {
802 state->setStrokeColor(&color);
803 out->updateStrokeColor(state);
806 void Gfx::opSetFillColor(Object args[], int numArgs) {
810 state->setFillPattern(NULL);
811 for (i = 0; i < numArgs; ++i) {
812 color.c[i] = args[i].getNum();
814 state->setFillColor(&color);
815 out->updateFillColor(state);
818 void Gfx::opSetStrokeColor(Object args[], int numArgs) {
822 state->setStrokePattern(NULL);
823 for (i = 0; i < numArgs; ++i) {
824 color.c[i] = args[i].getNum();
826 state->setStrokeColor(&color);
827 out->updateStrokeColor(state);
830 void Gfx::opSetFillColorN(Object args[], int numArgs) {
835 if (state->getFillColorSpace()->getMode() == csPattern) {
837 for (i = 0; i < numArgs && i < 4; ++i) {
838 if (args[i].isNum()) {
839 color.c[i] = args[i].getNum();
842 state->setFillColor(&color);
843 out->updateFillColor(state);
845 if (args[numArgs-1].isName() &&
846 (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
847 state->setFillPattern(pattern);
851 state->setFillPattern(NULL);
852 for (i = 0; i < numArgs && i < 4; ++i) {
853 if (args[i].isNum()) {
854 color.c[i] = args[i].getNum();
857 state->setFillColor(&color);
858 out->updateFillColor(state);
862 void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
867 if (state->getStrokeColorSpace()->getMode() == csPattern) {
869 for (i = 0; i < numArgs && i < 4; ++i) {
870 if (args[i].isNum()) {
871 color.c[i] = args[i].getNum();
874 state->setStrokeColor(&color);
875 out->updateStrokeColor(state);
877 if (args[numArgs-1].isName() &&
878 (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
879 state->setStrokePattern(pattern);
883 state->setStrokePattern(NULL);
884 for (i = 0; i < numArgs && i < 4; ++i) {
885 if (args[i].isNum()) {
886 color.c[i] = args[i].getNum();
889 state->setStrokeColor(&color);
890 out->updateStrokeColor(state);
894 //------------------------------------------------------------------------
895 // path segment operators
896 //------------------------------------------------------------------------
898 void Gfx::opMoveTo(Object args[], int numArgs) {
899 state->moveTo(args[0].getNum(), args[1].getNum());
902 void Gfx::opLineTo(Object args[], int numArgs) {
903 if (!state->isCurPt()) {
904 error(getPos(), "No current point in lineto");
907 state->lineTo(args[0].getNum(), args[1].getNum());
910 void Gfx::opCurveTo(Object args[], int numArgs) {
911 double x1, y1, x2, y2, x3, y3;
913 if (!state->isCurPt()) {
914 error(getPos(), "No current point in curveto");
917 x1 = args[0].getNum();
918 y1 = args[1].getNum();
919 x2 = args[2].getNum();
920 y2 = args[3].getNum();
921 x3 = args[4].getNum();
922 y3 = args[5].getNum();
923 state->curveTo(x1, y1, x2, y2, x3, y3);
926 void Gfx::opCurveTo1(Object args[], int numArgs) {
927 double x1, y1, x2, y2, x3, y3;
929 if (!state->isCurPt()) {
930 error(getPos(), "No current point in curveto1");
933 x1 = state->getCurX();
934 y1 = state->getCurY();
935 x2 = args[0].getNum();
936 y2 = args[1].getNum();
937 x3 = args[2].getNum();
938 y3 = args[3].getNum();
939 state->curveTo(x1, y1, x2, y2, x3, y3);
942 void Gfx::opCurveTo2(Object args[], int numArgs) {
943 double x1, y1, x2, y2, x3, y3;
945 if (!state->isCurPt()) {
946 error(getPos(), "No current point in curveto2");
949 x1 = args[0].getNum();
950 y1 = args[1].getNum();
951 x2 = args[2].getNum();
952 y2 = args[3].getNum();
955 state->curveTo(x1, y1, x2, y2, x3, y3);
958 void Gfx::opRectangle(Object args[], int numArgs) {
961 x = args[0].getNum();
962 y = args[1].getNum();
963 w = args[2].getNum();
964 h = args[3].getNum();
966 state->lineTo(x + w, y);
967 state->lineTo(x + w, y + h);
968 state->lineTo(x, y + h);
972 void Gfx::opClosePath(Object args[], int numArgs) {
973 if (!state->isPath()) {
974 error(getPos(), "No current point in closepath");
980 //------------------------------------------------------------------------
981 // path painting operators
982 //------------------------------------------------------------------------
984 void Gfx::opEndPath(Object args[], int numArgs) {
988 void Gfx::opStroke(Object args[], int numArgs) {
989 if (!state->isCurPt()) {
990 //error(getPos(), "No path in stroke");
998 void Gfx::opCloseStroke(Object args[], int numArgs) {
999 if (!state->isCurPt()) {
1000 //error(getPos(), "No path in closepath/stroke");
1003 if (state->isPath()) {
1010 void Gfx::opFill(Object args[], int numArgs) {
1011 if (!state->isCurPt()) {
1012 //error(getPos(), "No path in fill");
1015 if (state->isPath()) {
1016 if (state->getFillColorSpace()->getMode() == csPattern) {
1017 doPatternFill(gFalse);
1025 void Gfx::opEOFill(Object args[], int numArgs) {
1026 if (!state->isCurPt()) {
1027 //error(getPos(), "No path in eofill");
1030 if (state->isPath()) {
1031 if (state->getFillColorSpace()->getMode() == csPattern) {
1032 doPatternFill(gTrue);
1040 void Gfx::opFillStroke(Object args[], int numArgs) {
1041 if (!state->isCurPt()) {
1042 //error(getPos(), "No path in fill/stroke");
1045 if (state->isPath()) {
1046 if (state->getFillColorSpace()->getMode() == csPattern) {
1047 doPatternFill(gFalse);
1056 void Gfx::opCloseFillStroke(Object args[], int numArgs) {
1057 if (!state->isCurPt()) {
1058 //error(getPos(), "No path in closepath/fill/stroke");
1061 if (state->isPath()) {
1063 if (state->getFillColorSpace()->getMode() == csPattern) {
1064 doPatternFill(gFalse);
1073 void Gfx::opEOFillStroke(Object args[], int numArgs) {
1074 if (!state->isCurPt()) {
1075 //error(getPos(), "No path in eofill/stroke");
1078 if (state->isPath()) {
1079 if (state->getFillColorSpace()->getMode() == csPattern) {
1080 doPatternFill(gTrue);
1089 void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
1090 if (!state->isCurPt()) {
1091 //error(getPos(), "No path in closepath/eofill/stroke");
1094 if (state->isPath()) {
1096 if (state->getFillColorSpace()->getMode() == csPattern) {
1097 doPatternFill(gTrue);
1106 void Gfx::opShFill(Object args[], int numArgs) {
1109 void Gfx::doPatternFill(GBool eoFill) {
1110 GfxPatternColorSpace *patCS;
1111 GfxPattern *pattern;
1112 GfxTilingPattern *tPat;
1115 GfxSubpath *subpath;
1116 double xMin, yMin, xMax, yMax, x, y, x1, y1;
1117 int xi0, yi0, xi1, yi1, xi, yi;
1118 double *ctm, *btm, *ptm;
1119 double m[6], ictm[6], m1[6], im[6];
1121 double xstep, ystep;
1125 patCS = (GfxPatternColorSpace *)state->getFillColorSpace();
1128 if (!(pattern = state->getFillPattern())) {
1131 if (pattern->getType() != 1) {
1134 tPat = (GfxTilingPattern *)pattern;
1136 // construct a (pattern space) -> (current space) transform matrix
1137 ctm = state->getCTM();
1139 ptm = tPat->getMatrix();
1140 // iCTM = invert CTM
1141 det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
1142 ictm[0] = ctm[3] * det;
1143 ictm[1] = -ctm[1] * det;
1144 ictm[2] = -ctm[2] * det;
1145 ictm[3] = ctm[0] * det;
1146 ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
1147 ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
1148 // m1 = PTM * BTM = PTM * base transform matrix
1149 m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
1150 m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
1151 m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
1152 m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
1153 m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
1154 m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
1155 // m = m1 * iCTM = (PTM * BTM) * (iCTM)
1156 m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
1157 m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
1158 m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
1159 m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
1160 m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
1161 m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
1163 // construct a (current space) -> (pattern space) transform matrix
1164 det = 1 / (m[0] * m[3] - m[1] * m[2]);
1166 im[1] = -m[1] * det;
1167 im[2] = -m[2] * det;
1169 im[4] = (m[2] * m[5] - m[3] * m[4]) * det;
1170 im[5] = (m[1] * m[4] - m[0] * m[5]) * det;
1172 // compute bounding box of current path, in pattern space
1173 xMin = xMax = yMin = yMax = 0; // make gcc happy
1174 path = state->getPath();
1175 for (i = 0; i < path->getNumSubpaths(); ++i) {
1176 subpath = path->getSubpath(i);
1177 for (j = 0; j < subpath->getNumPoints(); ++j) {
1178 x = subpath->getX(j);
1179 y = subpath->getY(j);
1180 x1 = x * im[0] + y * im[2] + im[4];
1181 y1 = x * im[1] + y * im[3] + im[5];
1182 if (i == 0 && j == 0) {
1188 } else if (x1 > xMax) {
1193 } else if (y1 > yMax) {
1200 // save current graphics state
1201 out->saveState(state);
1202 state = state->save();
1204 // set underlying color space (for uncolored tiling patterns)
1205 if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
1206 state->setFillColorSpace(cs->copy());
1208 state->setFillColorSpace(new GfxDeviceGrayColorSpace());
1210 state->setFillPattern(NULL);
1211 out->updateFillColor(state);
1213 // clip to current path
1222 //~ this should treat negative steps differently -- start at right/top
1223 //~ edge instead of left/bottom (?)
1224 xstep = fabs(tPat->getXStep());
1225 ystep = fabs(tPat->getYStep());
1226 xi0 = (int)floor(xMin / xstep);
1227 xi1 = (int)ceil(xMax / xstep);
1228 yi0 = (int)floor(yMin / ystep);
1229 yi1 = (int)ceil(yMax / ystep);
1230 for (i = 0; i < 4; ++i) {
1233 for (yi = yi0; yi < yi1; ++yi) {
1234 for (xi = xi0; xi < xi1; ++xi) {
1237 m1[4] = x * m[0] + y * m[2] + m[4];
1238 m1[5] = x * m[1] + y * m[3] + m[5];
1239 doForm1(tPat->getContentStream(), tPat->getResDict(),
1240 m1, tPat->getBBox());
1244 // restore graphics state
1245 state = state->restore();
1246 out->restoreState(state);
1249 void Gfx::doEndPath() {
1250 if (state->isPath()) {
1251 if (clip == clipNormal)
1253 else if (clip == clipEO)
1260 //------------------------------------------------------------------------
1261 // path clipping operators
1262 //------------------------------------------------------------------------
1264 void Gfx::opClip(Object args[], int numArgs) {
1268 void Gfx::opEOClip(Object args[], int numArgs) {
1272 //------------------------------------------------------------------------
1273 // text object operators
1274 //------------------------------------------------------------------------
1276 void Gfx::opBeginText(Object args[], int numArgs) {
1277 state->setTextMat(1, 0, 0, 1, 0, 0);
1278 state->textMoveTo(0, 0);
1279 out->updateTextMat(state);
1280 out->updateTextPos(state);
1281 fontChanged = gTrue;
1284 void Gfx::opEndText(Object args[], int numArgs) {
1287 //------------------------------------------------------------------------
1288 // text state operators
1289 //------------------------------------------------------------------------
1291 void Gfx::opSetCharSpacing(Object args[], int numArgs) {
1292 state->setCharSpace(args[0].getNum());
1293 out->updateCharSpace(state);
1296 void Gfx::opSetFont(Object args[], int numArgs) {
1299 if (!(font = res->lookupFont(args[0].getName()))) {
1302 if (printCommands) {
1303 printf(" font: '%s' %g\n",
1304 font->getName() ? font->getName()->getCString() : "???",
1307 state->setFont(font, args[1].getNum());
1308 fontChanged = gTrue;
1311 void Gfx::opSetTextLeading(Object args[], int numArgs) {
1312 state->setLeading(args[0].getNum());
1315 void Gfx::opSetTextRender(Object args[], int numArgs) {
1316 state->setRender(args[0].getInt());
1317 out->updateRender(state);
1320 void Gfx::opSetTextRise(Object args[], int numArgs) {
1321 state->setRise(args[0].getNum());
1322 out->updateRise(state);
1325 void Gfx::opSetWordSpacing(Object args[], int numArgs) {
1326 state->setWordSpace(args[0].getNum());
1327 out->updateWordSpace(state);
1330 void Gfx::opSetHorizScaling(Object args[], int numArgs) {
1331 state->setHorizScaling(args[0].getNum());
1332 out->updateHorizScaling(state);
1335 //------------------------------------------------------------------------
1336 // text positioning operators
1337 //------------------------------------------------------------------------
1339 void Gfx::opTextMove(Object args[], int numArgs) {
1342 tx = state->getLineX() + args[0].getNum();
1343 ty = state->getLineY() + args[1].getNum();
1344 state->textMoveTo(tx, ty);
1345 out->updateTextPos(state);
1348 void Gfx::opTextMoveSet(Object args[], int numArgs) {
1351 tx = state->getLineX() + args[0].getNum();
1352 ty = args[1].getNum();
1353 state->setLeading(-ty);
1354 ty += state->getLineY();
1355 state->textMoveTo(tx, ty);
1356 out->updateTextPos(state);
1359 void Gfx::opSetTextMatrix(Object args[], int numArgs) {
1360 state->setTextMat(args[0].getNum(), args[1].getNum(),
1361 args[2].getNum(), args[3].getNum(),
1362 args[4].getNum(), args[5].getNum());
1363 state->textMoveTo(0, 0);
1364 out->updateTextMat(state);
1365 out->updateTextPos(state);
1366 fontChanged = gTrue;
1369 void Gfx::opTextNextLine(Object args[], int numArgs) {
1372 tx = state->getLineX();
1373 ty = state->getLineY() - state->getLeading();
1374 state->textMoveTo(tx, ty);
1375 out->updateTextPos(state);
1378 //------------------------------------------------------------------------
1379 // text string operators
1380 //------------------------------------------------------------------------
1382 void Gfx::opShowText(Object args[], int numArgs) {
1383 if (!state->getFont()) {
1384 error(getPos(), "No font in show");
1387 doShowText(args[0].getString());
1390 void Gfx::opMoveShowText(Object args[], int numArgs) {
1393 if (!state->getFont()) {
1394 error(getPos(), "No font in move/show");
1397 tx = state->getLineX();
1398 ty = state->getLineY() - state->getLeading();
1399 state->textMoveTo(tx, ty);
1400 out->updateTextPos(state);
1401 doShowText(args[0].getString());
1404 void Gfx::opMoveSetShowText(Object args[], int numArgs) {
1407 if (!state->getFont()) {
1408 error(getPos(), "No font in move/set/show");
1411 state->setWordSpace(args[0].getNum());
1412 state->setCharSpace(args[1].getNum());
1413 tx = state->getLineX();
1414 ty = state->getLineY() - state->getLeading();
1415 state->textMoveTo(tx, ty);
1416 out->updateWordSpace(state);
1417 out->updateCharSpace(state);
1418 out->updateTextPos(state);
1419 doShowText(args[2].getString());
1422 void Gfx::opShowSpaceText(Object args[], int numArgs) {
1427 if (!state->getFont()) {
1428 error(getPos(), "No font in show/space");
1431 a = args[0].getArray();
1432 for (i = 0; i < a->getLength(); ++i) {
1435 state->textShift(-obj.getNum() * 0.001 * state->getFontSize());
1436 out->updateTextShift(state, obj.getNum());
1437 } else if (obj.isString()) {
1438 doShowText(obj.getString());
1440 error(getPos(), "Element of show/space array must be number or string");
1446 void Gfx::doShowText(GString *s) {
1448 GfxFontEncoding16 *enc;
1456 double dx, dy, width, height, w, h, x, y;
1457 double oldCTM[6], newCTM[6];
1463 double dx, dy, width, height, w, h, sWidth, sHeight;
1467 out->updateFont(state);
1468 fontChanged = gFalse;
1470 font = state->getFont();
1473 if (font->is16Bit()) {
1474 enc = font->getEncoding16();
1475 if (out->useDrawChar()) {
1476 out->beginString(state, s);
1479 s16 = new GString();
1481 sWidth = sHeight = 0;
1482 state->textTransformDelta(0, state->getRise(), &dx, &dy);
1483 p = (Guchar *)s->getCString();
1486 m = getNextChar16(enc, p, &c16);
1487 if (enc->wMode == 0) {
1488 width = state->getFontSize() * state->getHorizScaling() *
1489 font->getWidth16(c16) +
1490 state->getCharSpace();
1492 width += state->getWordSpace();
1497 height = state->getFontSize() * font->getHeight16(c16);
1499 state->textTransformDelta(width, height, &w, &h);
1500 if (out->useDrawChar()) {
1501 out->drawChar16(state, state->getCurX() + dx, state->getCurY() + dy,
1503 state->textShift(width, height);
1505 s16a[0] = (char)(c16 >> 8);
1506 s16a[1] = (char)c16;
1507 s16->append(s16a, 2);
1514 if (out->useDrawChar()) {
1515 out->endString(state);
1517 out->drawString16(state, s16);
1519 state->textShift(sWidth, sHeight);
1525 //~ also check out->renderType3()
1526 if (font->getType() == fontType3) {
1527 out->beginString(state, s);
1528 mat = state->getCTM();
1529 for (i = 0; i < 6; ++i) {
1532 mat = state->getTextMat();
1533 newCTM[0] = mat[0] * oldCTM[0] + mat[1] * oldCTM[2];
1534 newCTM[1] = mat[0] * oldCTM[1] + mat[1] * oldCTM[3];
1535 newCTM[2] = mat[2] * oldCTM[0] + mat[3] * oldCTM[2];
1536 newCTM[3] = mat[2] * oldCTM[1] + mat[3] * oldCTM[3];
1537 mat = font->getFontMatrix();
1538 newCTM[0] = mat[0] * newCTM[0] + mat[1] * newCTM[2];
1539 newCTM[1] = mat[0] * newCTM[1] + mat[1] * newCTM[3];
1540 newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2];
1541 newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3];
1542 newCTM[0] *= state->getFontSize();
1543 newCTM[3] *= state->getFontSize();
1544 newCTM[0] *= state->getHorizScaling();
1545 newCTM[2] *= state->getHorizScaling();
1546 state->textTransformDelta(0, state->getRise(), &dx, &dy);
1548 for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
1550 font->getCharProc(c8, &charProc);
1551 state->transform(state->getCurX() + dx, state->getCurY() + dy, &x, &y);
1552 state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
1553 //~ out->updateCTM(???)
1554 if (charProc.isStream()) {
1555 display(&charProc, gFalse);
1557 error(getPos(), "Missing or bad Type3 CharProc entry");
1559 state->setCTM(oldCTM[0], oldCTM[1], oldCTM[2],
1560 oldCTM[3], oldCTM[4], oldCTM[5]);
1561 //~ out->updateCTM(???) - use gsave/grestore instead?
1563 width = state->getFontSize() * state->getHorizScaling() *
1564 font->getWidth(c8) +
1565 state->getCharSpace();
1567 width += state->getWordSpace();
1569 state->textShift(width);
1572 out->endString(state);
1575 if (out->useDrawChar()) {
1576 out->beginString(state, s);
1577 state->textTransformDelta(0, state->getRise(), &dx, &dy);
1578 for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
1580 width = state->getFontSize() * state->getHorizScaling() *
1581 font->getWidth(c8) +
1582 state->getCharSpace();
1584 width += state->getWordSpace();
1585 state->textTransformDelta(width, 0, &w, &h);
1586 out->drawChar(state, state->getCurX() + dx, state->getCurY() + dy,
1588 state->textShift(width);
1590 out->endString(state);
1592 out->drawString(state, s);
1593 width = state->getFontSize() * state->getHorizScaling() *
1595 s->getLength() * state->getCharSpace();
1596 for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
1598 width += state->getWordSpace();
1600 state->textShift(width);
1605 int Gfx::getNextChar16(GfxFontEncoding16 *enc, Guchar *p, int *c16) {
1610 n = enc->codeLen[*p];
1612 *c16 = enc->map1[*p];
1614 code = (p[0] << 8) + p[1];
1617 // invariant: map2[2*a] <= code < map2[2*b]
1620 if (enc->map2[2*m] <= code)
1622 else if (enc->map2[2*m] > code)
1627 *c16 = enc->map2[2*a+1] + (code - enc->map2[2*a]);
1632 //------------------------------------------------------------------------
1633 // XObject operators
1634 //------------------------------------------------------------------------
1636 void Gfx::opXObject(Object args[], int numArgs) {
1637 Object obj1, obj2, refObj;
1642 if (!res->lookupXObject(args[0].getName(), &obj1)) {
1645 if (!obj1.isStream()) {
1646 error(getPos(), "XObject '%s' is wrong type", args[0].getName());
1651 obj1.streamGetDict()->lookup("OPI", &opiDict);
1652 if (opiDict.isDict()) {
1653 out->opiBegin(state, opiDict.getDict());
1656 obj1.streamGetDict()->lookup("Subtype", &obj2);
1657 if (obj2.isName("Image")) {
1658 res->lookupXObjectNF(args[0].getName(), &refObj);
1659 doImage(&refObj, obj1.getStream(), gFalse);
1661 } else if (obj2.isName("Form")) {
1663 } else if (obj2.isName()) {
1664 error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
1666 error(getPos(), "XObject subtype is missing or wrong type");
1670 if (opiDict.isDict()) {
1671 out->opiEnd(state, opiDict.getDict());
1678 void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
1684 GfxColorSpace *colorSpace;
1685 GfxImageColorMap *colorMap;
1689 dict = str->getDict();
1692 dict->lookup("Width", &obj1);
1693 if (obj1.isNull()) {
1695 dict->lookup("W", &obj1);
1699 width = obj1.getInt();
1701 dict->lookup("Height", &obj1);
1702 if (obj1.isNull()) {
1704 dict->lookup("H", &obj1);
1708 height = obj1.getInt();
1712 dict->lookup("ImageMask", &obj1);
1713 if (obj1.isNull()) {
1715 dict->lookup("IM", &obj1);
1719 mask = obj1.getBool();
1720 else if (!obj1.isNull())
1725 dict->lookup("BitsPerComponent", &obj1);
1726 if (obj1.isNull()) {
1728 dict->lookup("BPC", &obj1);
1732 bits = obj1.getInt();
1738 // check for inverted mask
1742 dict->lookup("Decode", &obj1);
1743 if (obj1.isNull()) {
1745 dict->lookup("D", &obj1);
1747 if (obj1.isArray()) {
1748 obj1.arrayGet(0, &obj2);
1749 if (obj2.isInt() && obj2.getInt() == 1)
1752 } else if (!obj1.isNull()) {
1758 out->drawImageMask(state, ref, str, width, height, invert, inlineImg);
1762 // get color space and color map
1763 dict->lookup("ColorSpace", &obj1);
1764 if (obj1.isNull()) {
1766 dict->lookup("CS", &obj1);
1768 if (obj1.isName()) {
1769 res->lookupColorSpace(obj1.getName(), &obj2);
1770 if (!obj2.isNull()) {
1777 colorSpace = GfxColorSpace::parse(&obj1);
1782 dict->lookup("Decode", &obj1);
1783 if (obj1.isNull()) {
1785 dict->lookup("D", &obj1);
1787 colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
1789 if (!colorMap->isOk()) {
1795 out->drawImage(state, ref, str, width, height, colorMap, inlineImg);
1805 error(getPos(), "Bad image parameters");
1808 void Gfx::doForm(Object *str) {
1810 Object matrixObj, bboxObj;
1811 double m[6], bbox[6];
1818 dict = str->streamGetDict();
1821 dict->lookup("FormType", &obj1);
1822 if (!(obj1.isInt() && obj1.getInt() == 1)) {
1823 error(getPos(), "Unknown form type");
1828 dict->lookup("BBox", &bboxObj);
1829 if (!bboxObj.isArray()) {
1832 error(getPos(), "Bad form bounding box");
1835 for (i = 0; i < 4; ++i) {
1836 bboxObj.arrayGet(i, &obj1);
1837 bbox[i] = obj1.getNum();
1843 dict->lookup("Matrix", &matrixObj);
1844 if (matrixObj.isArray()) {
1845 for (i = 0; i < 6; ++i) {
1846 matrixObj.arrayGet(i, &obj1);
1847 m[i] = obj1.getNum();
1858 dict->lookup("Resources", &resObj);
1859 resDict = resObj.isDict() ? resObj.getDict() : NULL;
1862 doForm1(str, resDict, m, bbox);
1867 void Gfx::doWidgetForm(Object *str, double xMin, double yMin,
1868 double xMax, double yMax) {
1869 Dict *dict, *resDict;
1870 Object matrixObj, bboxObj, resObj;
1872 double m[6], bbox[6];
1877 dict = str->streamGetDict();
1880 dict->lookup("BBox", &bboxObj);
1881 if (!bboxObj.isArray()) {
1883 error(getPos(), "Bad form bounding box");
1886 for (i = 0; i < 4; ++i) {
1887 bboxObj.arrayGet(i, &obj1);
1888 bbox[i] = obj1.getNum();
1894 dict->lookup("Matrix", &matrixObj);
1895 if (matrixObj.isArray()) {
1896 for (i = 0; i < 6; ++i) {
1897 matrixObj.arrayGet(i, &obj1);
1898 m[i] = obj1.getNum();
1908 // scale form bbox to widget rectangle
1909 sx = fabs((xMax - xMin) / (bbox[2] - bbox[0]));
1910 sy = fabs((yMax - yMin) / (bbox[3] - bbox[1]));
1911 m[0] *= sx; m[1] *= sy;
1912 m[2] *= sx; m[3] *= sy;
1913 m[4] *= sx; m[5] *= sy;
1915 // translate to widget rectangle
1920 dict->lookup("Resources", &resObj);
1921 resDict = resObj.isDict() ? resObj.getDict() : NULL;
1924 doForm1(str, resDict, m, bbox);
1930 void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) {
1932 double oldBaseMatrix[6];
1933 GfxResources *resPtr;
1936 // push new resources on stack
1937 res = new GfxResources(resDict, res);
1939 // save current graphics state
1940 out->saveState(state);
1941 state = state->save();
1943 // save current parser
1946 // set form transformation matrix
1947 state->concatCTM(matrix[0], matrix[1], matrix[2],
1948 matrix[3], matrix[4], matrix[5]);
1949 out->updateCTM(state, matrix[0], matrix[1], matrix[2],
1950 matrix[3], matrix[4], matrix[5]);
1952 // set new base matrix
1953 for (i = 0; i < 6; ++i) {
1954 oldBaseMatrix[i] = baseMatrix[i];
1955 baseMatrix[i] = state->getCTM()[i];
1958 // set form bounding box
1959 state->moveTo(bbox[0], bbox[1]);
1960 state->lineTo(bbox[2], bbox[1]);
1961 state->lineTo(bbox[2], bbox[3]);
1962 state->lineTo(bbox[0], bbox[3]);
1968 display(str, gFalse);
1970 // restore base matrix
1971 for (i = 0; i < 6; ++i) {
1972 baseMatrix[i] = oldBaseMatrix[i];
1978 // restore graphics state
1979 state = state->restore();
1980 out->restoreState(state);
1982 // pop resource stack
1983 resPtr = res->getNext();
1990 //------------------------------------------------------------------------
1991 // in-line image operators
1992 //------------------------------------------------------------------------
1994 void Gfx::opBeginImage(Object args[], int numArgs) {
1998 // build dict/stream
1999 str = buildImageStream();
2001 // display the image
2003 doImage(NULL, str, gTrue);
2006 c1 = str->getBaseStream()->getChar();
2007 c2 = str->getBaseStream()->getChar();
2008 while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
2010 c2 = str->getBaseStream()->getChar();
2016 Stream *Gfx::buildImageStream() {
2024 parser->getObj(&obj);
2025 while (!obj.isCmd("ID") && !obj.isEOF()) {
2026 if (!obj.isName()) {
2027 error(getPos(), "Inline image dictionary key must be a name object");
2029 parser->getObj(&obj);
2031 key = copyString(obj.getName());
2033 parser->getObj(&obj);
2034 if (obj.isEOF() || obj.isError())
2036 dict.dictAdd(key, &obj);
2038 parser->getObj(&obj);
2041 error(getPos(), "End of file in inline image");
2045 str = new EmbedStream(parser->getStream(), &dict);
2046 str = str->addFilters(&dict);
2051 void Gfx::opImageData(Object args[], int numArgs) {
2052 error(getPos(), "Internal: got 'ID' operator");
2055 void Gfx::opEndImage(Object args[], int numArgs) {
2056 error(getPos(), "Internal: got 'EI' operator");
2059 //------------------------------------------------------------------------
2060 // type 3 font operators
2061 //------------------------------------------------------------------------
2063 void Gfx::opSetCharWidth(Object args[], int numArgs) {
2064 error(getPos(), "Encountered 'd0' operator in content stream");
2067 void Gfx::opSetCacheDevice(Object args[], int numArgs) {
2068 error(getPos(), "Encountered 'd1' operator in content stream");
2071 //------------------------------------------------------------------------
2072 // compatibility operators
2073 //------------------------------------------------------------------------
2075 void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) {
2079 void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
2080 if (ignoreUndef > 0)
2084 //------------------------------------------------------------------------
2085 // marked content operators
2086 //------------------------------------------------------------------------
2088 void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
2089 if (printCommands) {
2090 printf(" marked content: %s ", args[0].getName());
2092 args[2].print(stdout);
2097 void Gfx::opEndMarkedContent(Object args[], int numArgs) {
2100 void Gfx::opMarkPoint(Object args[], int numArgs) {
2101 if (printCommands) {
2102 printf(" mark point: %s ", args[0].getName());
2104 args[2].print(stdout);