home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 110 / EnigmaAmiga110CD.iso / indispensabili / utility / apdf / xpdf-0.80 / xpdf / gfx.cc < prev    next >
C/C++ Source or Header  |  1999-04-27  |  38KB  |  1,574 lines

  1. //========================================================================
  2. //
  3. // Gfx.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8.  
  9. #ifdef __GNUC__
  10. #pragma implementation
  11. #endif
  12.  
  13. #include <stdio.h>
  14. #include <stddef.h>
  15. #include <string.h>
  16. #include "gmem.h"
  17. #include "Object.h"
  18. #include "Array.h"
  19. #include "Dict.h"
  20. #include "Stream.h"
  21. #include "Lexer.h"
  22. #include "Parser.h"
  23. #include "GfxFont.h"
  24. #include "GfxState.h"
  25. #include "OutputDev.h"
  26. #include "Params.h"
  27. #include "Error.h"
  28. #include "Gfx.h"
  29.  
  30. //------------------------------------------------------------------------
  31. // Operator table
  32. //------------------------------------------------------------------------
  33.  
  34. Operator Gfx::opTab[] = {
  35.   {"\"",  3, {tchkNum,    tchkNum,    tchkString},
  36.       &Gfx::opMoveSetShowText},
  37.   {"'",   1, {tchkString},
  38.       &Gfx::opMoveShowText},
  39.   {"B",   0, {tchkNone},
  40.       &Gfx::opFillStroke},
  41.   {"B*",  0, {tchkNone},
  42.       &Gfx::opEOFillStroke},
  43.   {"BDC", 2, {tchkName,   tchkProps},
  44.       &Gfx::opBeginMarkedContent},
  45.   {"BI",  0, {tchkNone},
  46.       &Gfx::opBeginImage},
  47.   {"BMC", 1, {tchkName},
  48.       &Gfx::opBeginMarkedContent},
  49.   {"BT",  0, {tchkNone},
  50.       &Gfx::opBeginText},
  51.   {"BX",  0, {tchkNone},
  52.       &Gfx::opBeginIgnoreUndef},
  53.   {"CS",  1, {tchkName},
  54.       &Gfx::opSetStrokeColorSpace},
  55.   {"DP",  2, {tchkName,   tchkProps},
  56.       &Gfx::opMarkPoint},
  57.   {"Do",  1, {tchkName},
  58.       &Gfx::opXObject},
  59.   {"EI",  0, {tchkNone},
  60.       &Gfx::opEndImage},
  61.   {"EMC", 0, {tchkNone},
  62.       &Gfx::opEndMarkedContent},
  63.   {"ET",  0, {tchkNone},
  64.       &Gfx::opEndText},
  65.   {"EX",  0, {tchkNone},
  66.       &Gfx::opEndIgnoreUndef},
  67.   {"F",   0, {tchkNone},
  68.       &Gfx::opFill},
  69.   {"G",   1, {tchkNum},
  70.       &Gfx::opSetStrokeGray},
  71.   {"ID",  0, {tchkNone},
  72.       &Gfx::opImageData},
  73.   {"J",   1, {tchkInt},
  74.       &Gfx::opSetLineCap},
  75.   {"K",   4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  76.       &Gfx::opSetStrokeCMYKColor},
  77.   {"M",   1, {tchkNum},
  78.       &Gfx::opSetMiterLimit},
  79.   {"MP",  1, {tchkName},
  80.       &Gfx::opMarkPoint},
  81.   {"Q",   0, {tchkNone},
  82.       &Gfx::opRestore},
  83.   {"RG",  3, {tchkNum,    tchkNum,    tchkNum},
  84.       &Gfx::opSetStrokeRGBColor},
  85.   {"S",   0, {tchkNone},
  86.       &Gfx::opStroke},
  87.   {"SC",  -4, {tchkNum,   tchkNum,    tchkNum,    tchkNum},
  88.       &Gfx::opSetStrokeColor},
  89.   {"SCN", -5, {tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
  90.            tchkSCN},
  91.       &Gfx::opSetStrokeColorN},
  92.   {"T*",  0, {tchkNone},
  93.       &Gfx::opTextNextLine},
  94.   {"TD",  2, {tchkNum,    tchkNum},
  95.       &Gfx::opTextMoveSet},
  96.   {"TJ",  1, {tchkArray},
  97.       &Gfx::opShowSpaceText},
  98.   {"TL",  1, {tchkNum},
  99.       &Gfx::opSetTextLeading},
  100.   {"Tc",  1, {tchkNum},
  101.       &Gfx::opSetCharSpacing},
  102.   {"Td",  2, {tchkNum,    tchkNum},
  103.       &Gfx::opTextMove},
  104.   {"Tf",  2, {tchkName,   tchkNum},
  105.       &Gfx::opSetFont},
  106.   {"Tj",  1, {tchkString},
  107.       &Gfx::opShowText},
  108.   {"Tm",  6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
  109.           tchkNum,    tchkNum},
  110.       &Gfx::opSetTextMatrix},
  111.   {"Tr",  1, {tchkInt},
  112.       &Gfx::opSetTextRender},
  113.   {"Ts",  1, {tchkNum},
  114.       &Gfx::opSetTextRise},
  115.   {"Tw",  1, {tchkNum},
  116.       &Gfx::opSetWordSpacing},
  117.   {"Tz",  1, {tchkNum},
  118.       &Gfx::opSetHorizScaling},
  119.   {"W",   0, {tchkNone},
  120.       &Gfx::opClip},
  121.   {"W*",  0, {tchkNone},
  122.       &Gfx::opEOClip},
  123.   {"b",   0, {tchkNone},
  124.       &Gfx::opCloseFillStroke},
  125.   {"b*",  0, {tchkNone},
  126.       &Gfx::opCloseEOFillStroke},
  127.   {"c",   6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
  128.           tchkNum,    tchkNum},
  129.       &Gfx::opCurveTo},
  130.   {"cm",  6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
  131.           tchkNum,    tchkNum},
  132.       &Gfx::opConcat},
  133.   {"cs",  1, {tchkName},
  134.       &Gfx::opSetFillColorSpace},
  135.   {"d",   2, {tchkArray,  tchkNum},
  136.       &Gfx::opSetDash},
  137.   {"d0",  2, {tchkNum,    tchkNum},
  138.       &Gfx::opSetCharWidth},
  139.   {"d1",  6, {tchkNum,    tchkNum,    tchkNum,    tchkNum,
  140.           tchkNum,    tchkNum},
  141.       &Gfx::opSetCacheDevice},
  142.   {"f",   0, {tchkNone},
  143.       &Gfx::opFill},
  144.   {"f*",  0, {tchkNone},
  145.       &Gfx::opEOFill},
  146.   {"g",   1, {tchkNum},
  147.       &Gfx::opSetFillGray},
  148.   {"gs",  1, {tchkName},
  149.       &Gfx::opSetExtGState},
  150.   {"h",   0, {tchkNone},
  151.       &Gfx::opClosePath},
  152.   {"i",   1, {tchkNum},
  153.       &Gfx::opSetFlat},
  154.   {"j",   1, {tchkInt},
  155.       &Gfx::opSetLineJoin},
  156.   {"k",   4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  157.       &Gfx::opSetFillCMYKColor},
  158.   {"l",   2, {tchkNum,    tchkNum},
  159.       &Gfx::opLineTo},
  160.   {"m",   2, {tchkNum,    tchkNum},
  161.       &Gfx::opMoveTo},
  162.   {"n",   0, {tchkNone},
  163.       &Gfx::opEndPath},
  164.   {"q",   0, {tchkNone},
  165.       &Gfx::opSave},
  166.   {"re",  4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  167.       &Gfx::opRectangle},
  168.   {"rg",  3, {tchkNum,    tchkNum,    tchkNum},
  169.       &Gfx::opSetFillRGBColor},
  170.   {"s",   0, {tchkNone},
  171.       &Gfx::opCloseStroke},
  172.   {"sc",  -4, {tchkNum,   tchkNum,    tchkNum,    tchkNum},
  173.       &Gfx::opSetFillColor},
  174.   {"scn", -5, {tchkSCN,   tchkSCN,    tchkSCN,    tchkSCN,
  175.            tchkSCN},
  176.       &Gfx::opSetFillColorN},
  177.   {"v",   4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  178.       &Gfx::opCurveTo1},
  179.   {"w",   1, {tchkNum},
  180.       &Gfx::opSetLineWidth},
  181.   {"y",   4, {tchkNum,    tchkNum,    tchkNum,    tchkNum},
  182.       &Gfx::opCurveTo2},
  183. };
  184.  
  185. #define numOps (sizeof(opTab) / sizeof(Operator))
  186.  
  187. //------------------------------------------------------------------------
  188. // Gfx
  189. //------------------------------------------------------------------------
  190.  
  191. Gfx::Gfx(OutputDev *out1, int pageNum, Dict *resDict,
  192.      int dpi, double x1, double y1, double x2, double y2, GBool crop,
  193.      double cropX1, double cropY1, double cropX2, double cropY2,
  194.      int rotate) {
  195.   Object obj1;
  196.  
  197.   // start the resource stack
  198.   res = new GfxResources(NULL);
  199.  
  200.   // build font dictionary
  201.   res->fonts = NULL;
  202.   if (resDict) {
  203.     resDict->lookup("Font", &obj1);
  204.     if (obj1.isDict())
  205.       res->fonts = new GfxFontDict(obj1.getDict());
  206.     obj1.free();
  207.   }
  208.  
  209.   // get XObject dictionary
  210.   if (resDict)
  211.     resDict->lookup("XObject", &res->xObjDict);
  212.   else
  213.     res->xObjDict.initNull();
  214.  
  215.   // get colorspace dictionary
  216.   if (resDict)
  217.     resDict->lookup("ColorSpace", &res->colorSpaceDict);
  218.   else
  219.     res->colorSpaceDict.initNull();
  220.  
  221.   // initialize
  222.   out = out1;
  223.   state = new GfxState(dpi, x1, y1, x2, y2, rotate, out->upsideDown());
  224.   fontChanged = gFalse;
  225.   clip = clipNone;
  226.   ignoreUndef = 0;
  227.   out->startPage(pageNum, state);
  228.   out->setDefaultCTM(state->getCTM());
  229.   out->updateAll(state);
  230.  
  231.   // set crop box
  232.   if (crop) {
  233.     state->moveTo(cropX1, cropY1);
  234.     state->lineTo(cropX2, cropY1);
  235.     state->lineTo(cropX2, cropY2);
  236.     state->lineTo(cropX1, cropY2);
  237.     state->closePath();
  238.     out->clip(state);
  239.     state->clearPath();
  240.   }
  241. }
  242.  
  243. Gfx::~Gfx() {
  244.   GfxResources *resPtr;
  245.  
  246.   while (state->hasSaves()) {
  247.     state = state->restore();
  248.     out->restoreState(state);
  249.   }
  250.   out->endPage();
  251.   while (res) {
  252.     resPtr = res->next;
  253.     delete res;
  254.     res = resPtr;
  255.   }
  256.   if (state)
  257.     delete state;
  258. }
  259.  
  260. GfxResources::~GfxResources() {
  261.   if (fonts)
  262.     delete fonts;
  263.   xObjDict.free();
  264.   colorSpaceDict.free();
  265. }
  266.  
  267. void Gfx::display(Object *obj) {
  268.   Object obj2;
  269.   int i;
  270.  
  271.   if (obj->isArray()) {
  272.     for (i = 0; i < obj->arrayGetLength(); ++i) {
  273.       obj->arrayGet(i, &obj2);
  274.       if (!obj2.isStream()) {
  275.     error(-1, "Weird page contents");
  276.     obj2.free();
  277.     return;
  278.       }
  279.       obj2.free();
  280.     }
  281.   } else if (!obj->isStream()) {
  282.     error(-1, "Weird page contents");
  283.     return;
  284.   }
  285.   parser = new Parser(new Lexer(obj));
  286.   go();
  287. }
  288.  
  289. void Gfx::go() {
  290.   Object obj;
  291.   Object args[maxArgs];
  292.   int numCmds, numArgs;
  293.   int i;
  294.  
  295.   // scan a sequence of objects
  296.   numCmds = 0;
  297.   numArgs = 0;
  298.   parser->getObj(&obj);
  299.   while (!obj.isEOF()) {
  300.  
  301.     // got a command - execute it
  302.     if (obj.isCmd()) {
  303.       if (printCommands) {
  304.     obj.print(stdout);
  305.     for (i = 0; i < numArgs; ++i) {
  306.       printf(" ");
  307.       args[i].print(stdout);
  308.     }
  309.     printf("\n");
  310.       }
  311.       execOp(&obj, args, numArgs);
  312.       obj.free();
  313.       for (i = 0; i < numArgs; ++i)
  314.     args[i].free();
  315.       numArgs = 0;
  316.  
  317.       // periodically update display
  318.       if (++numCmds == 200) {
  319.     out->dump();
  320.     numCmds = 0;
  321.       }
  322.  
  323.     // got an argument - save it
  324.     } else if (numArgs < maxArgs) {
  325.       args[numArgs++] = obj;
  326.  
  327.     // too many arguments - something is wrong
  328.     } else {
  329.       error(getPos(), "Too many args in content stream");
  330.       if (printCommands) {
  331.     printf("throwing away arg: ");
  332.     obj.print(stdout);
  333.     printf("\n");
  334.       }
  335.       obj.free();
  336.     }
  337.  
  338.     // grab the next object
  339.     parser->getObj(&obj);
  340.   }
  341.   obj.free();
  342.  
  343.   // args at end with no command
  344.   if (numArgs > 0) {
  345.     error(getPos(), "Leftover args in content stream");
  346.     if (printCommands) {
  347.       printf("%d leftovers:", numArgs);
  348.       for (i = 0; i < numArgs; ++i) {
  349.     printf(" ");
  350.     args[i].print(stdout);
  351.       }
  352.       printf("\n");
  353.     }
  354.     for (i = 0; i < numArgs; ++i)
  355.       args[i].free();
  356.   }
  357.  
  358.   // update display
  359.   if (numCmds > 0)
  360.     out->dump();
  361.  
  362.   // clean up
  363.   if (parser)
  364.     delete parser;
  365.   if (printCommands)
  366.     fflush(stdout);
  367. }
  368.  
  369. void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
  370.   Operator *op;
  371.   char *name;
  372.   int i;
  373.  
  374.   // find operator
  375.   name = cmd->getName();
  376.   if (!(op = findOp(name))) {
  377.     if (ignoreUndef == 0)
  378.       error(getPos(), "Unknown operator '%s'", name);
  379.     return;
  380.   }
  381.  
  382.   // type check args
  383.   if (op->numArgs >= 0) {
  384.     if (numArgs != op->numArgs) {
  385.       error(getPos(), "Wrong number (%d) of args to '%s' operator",
  386.         numArgs, name);
  387.       return;
  388.     }
  389.   } else {
  390.     if (numArgs > -op->numArgs) {
  391.       error(getPos(), "Too many (%d) args to '%s' operator",
  392.         numArgs, name);
  393.       return;
  394.     }
  395.   }
  396.   for (i = 0; i < numArgs; ++i) {
  397.     if (!checkArg(&args[i], op->tchk[i])) {
  398.       error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
  399.         i, name, args[i].getTypeName());
  400.       return;
  401.     }
  402.   }
  403.  
  404.   // do it
  405.   (this->*op->func)(args, numArgs);
  406. }
  407.  
  408. Operator *Gfx::findOp(char *name) {
  409.   int a, b, m, cmp;
  410.  
  411.   a = -1;
  412.   b = numOps;
  413.   // invariant: opTab[a] < name < opTab[b]
  414.   while (b - a > 1) {
  415.     m = (a + b) / 2;
  416.     cmp = strcmp(opTab[m].name, name);
  417.     if (cmp < 0)
  418.       a = m;
  419.     else if (cmp > 0)
  420.       b = m;
  421.     else
  422.       a = b = m;
  423.   }
  424.   if (cmp != 0)
  425.     return NULL;
  426.   return &opTab[a];
  427. }
  428.  
  429. GBool Gfx::checkArg(Object *arg, TchkType type) {
  430.   switch (type) {
  431.   case tchkBool:   return arg->isBool();
  432.   case tchkInt:    return arg->isInt();
  433.   case tchkNum:    return arg->isNum();
  434.   case tchkString: return arg->isString();
  435.   case tchkName:   return arg->isName();
  436.   case tchkArray:  return arg->isArray();
  437.   case tchkProps:  return arg->isDict() || arg->isName();
  438.   case tchkSCN:    return arg->isNum() || arg->isName();
  439.   case tchkNone:   return gFalse;
  440.   }
  441.   return gFalse;
  442. }
  443.  
  444. int Gfx::getPos() {
  445.   return parser->getPos();
  446. }
  447.  
  448. GfxFont *Gfx::lookupFont(char *name) {
  449.   GfxFont *font;
  450.   GfxResources *resPtr;
  451.  
  452.   for (resPtr = res; resPtr; resPtr = resPtr->next) {
  453.     if (resPtr->fonts) {
  454.       if ((font = resPtr->fonts->lookup(name)))
  455.     return font;
  456.     }
  457.   }
  458.   error(getPos(), "unknown font tag '%s'", name);
  459.   return NULL;
  460. }
  461.  
  462. GBool Gfx::lookupXObject(char *name, Object *obj) {
  463.   GfxResources *resPtr;
  464.  
  465.   for (resPtr = res; resPtr; resPtr = resPtr->next) {
  466.     if (resPtr->xObjDict.isDict()) {
  467.       if (!resPtr->xObjDict.dictLookup(name, obj)->isNull())
  468.     return gTrue;
  469.       obj->free();
  470.     }
  471.   }
  472.   error(getPos(), "XObject '%s' is unknown", name);
  473.   return gFalse;
  474. }
  475.  
  476. void Gfx::lookupColorSpace(char *name, Object *obj) {
  477.   GfxResources *resPtr;
  478.  
  479.   for (resPtr = res; resPtr; resPtr = resPtr->next) {
  480.     if (resPtr->colorSpaceDict.isDict()) {
  481.       if (!resPtr->colorSpaceDict.dictLookup(name, obj)->isNull())
  482.     return;
  483.       obj->free();
  484.     }
  485.   }
  486.   obj->initNull();
  487. }
  488.  
  489. //------------------------------------------------------------------------
  490. // graphics state operators
  491. //------------------------------------------------------------------------
  492.  
  493. void Gfx::opSave(Object args[], int numArgs) {
  494.   out->saveState(state);
  495.   state = state->save();
  496. }
  497.  
  498. void Gfx::opRestore(Object args[], int numArgs) {
  499.   state = state->restore();
  500.   out->restoreState(state);
  501. }
  502.  
  503. void Gfx::opConcat(Object args[], int numArgs) {
  504.   state->concatCTM(args[0].getNum(), args[1].getNum(),
  505.            args[2].getNum(), args[3].getNum(),
  506.            args[4].getNum(), args[5].getNum());
  507.   out->updateCTM(state, args[0].getNum(), args[1].getNum(),
  508.          args[2].getNum(), args[3].getNum(),
  509.          args[4].getNum(), args[5].getNum());
  510.   fontChanged = gTrue;
  511. }
  512.  
  513. void Gfx::opSetDash(Object args[], int numArgs) {
  514.   Array *a;
  515.   int length;
  516.   Object obj;
  517.   double *dash;
  518.   int i;
  519.  
  520.   a = args[0].getArray();
  521.   length = a->getLength();
  522.   if (length == 0) {
  523.     dash = NULL;
  524.   } else {
  525.     dash = (double *)gmalloc(length * sizeof(double));
  526.     for (i = 0; i < length; ++i) {
  527.       dash[i] = a->get(i, &obj)->getNum();
  528.       obj.free();
  529.     }
  530.   }
  531.   state->setLineDash(dash, length, args[1].getNum());
  532.   out->updateLineDash(state);
  533. }
  534.  
  535. void Gfx::opSetFlat(Object args[], int numArgs) {
  536.   state->setFlatness((int)args[0].getNum());
  537.   out->updateFlatness(state);
  538. }
  539.  
  540. void Gfx::opSetLineJoin(Object args[], int numArgs) {
  541.   state->setLineJoin(args[0].getInt());
  542.   out->updateLineJoin(state);
  543. }
  544.  
  545. void Gfx::opSetLineCap(Object args[], int numArgs) {
  546.   state->setLineCap(args[0].getInt());
  547.   out->updateLineCap(state);
  548. }
  549.  
  550. void Gfx::opSetMiterLimit(Object args[], int numArgs) {
  551.   state->setMiterLimit(args[0].getNum());
  552.   out->updateMiterLimit(state);
  553. }
  554.  
  555. void Gfx::opSetLineWidth(Object args[], int numArgs) {
  556.   state->setLineWidth(args[0].getNum());
  557.   out->updateLineWidth(state);
  558. }
  559.  
  560. void Gfx::opSetExtGState(Object args[], int numArgs) {
  561. }
  562.  
  563. //------------------------------------------------------------------------
  564. // color operators
  565. //------------------------------------------------------------------------
  566.  
  567. void Gfx::opSetFillGray(Object args[], int numArgs) {
  568.   state->setFillColorSpace(new GfxColorSpace(colorGray));
  569.   state->setFillGray(args[0].getNum());
  570.   out->updateFillColor(state);
  571. }
  572.  
  573. void Gfx::opSetStrokeGray(Object args[], int numArgs) {
  574.   state->setStrokeColorSpace(new GfxColorSpace(colorGray));
  575.   state->setStrokeGray(args[0].getNum());
  576.   out->updateStrokeColor(state);
  577. }
  578.  
  579. void Gfx::opSetFillCMYKColor(Object args[], int numArgs) {
  580.   state->setFillColorSpace(new GfxColorSpace(colorCMYK));
  581.   state->setFillCMYK(args[0].getNum(), args[1].getNum(),
  582.              args[2].getNum(), args[3].getNum());
  583.   out->updateFillColor(state);
  584. }
  585.  
  586. void Gfx::opSetStrokeCMYKColor(Object args[], int numArgs) {
  587.   state->setStrokeColorSpace(new GfxColorSpace(colorCMYK));
  588.   state->setStrokeCMYK(args[0].getNum(), args[1].getNum(),
  589.                args[2].getNum(), args[3].getNum());
  590.   out->updateStrokeColor(state);
  591. }
  592.  
  593. void Gfx::opSetFillRGBColor(Object args[], int numArgs) {
  594.   state->setFillColorSpace(new GfxColorSpace(colorRGB));
  595.   state->setFillRGB(args[0].getNum(), args[1].getNum(), args[2].getNum());
  596.   out->updateFillColor(state);
  597. }
  598.  
  599. void Gfx::opSetStrokeRGBColor(Object args[], int numArgs) {
  600.   state->setStrokeColorSpace(new GfxColorSpace(colorRGB));
  601.   state->setStrokeRGB(args[0].getNum(), args[1].getNum(), args[2].getNum());
  602.   out->updateStrokeColor(state);
  603. }
  604.  
  605. void Gfx::opSetFillColorSpace(Object args[], int numArgs) {
  606.   Object obj;
  607.   GfxColorSpace *colorSpace;
  608.   double x[4];
  609.  
  610.   lookupColorSpace(args[0].getName(), &obj);
  611.   if (obj.isNull())
  612.     colorSpace = new GfxColorSpace(&args[0]);
  613.   else
  614.     colorSpace = new GfxColorSpace(&obj);
  615.   obj.free();
  616.   if (colorSpace->isOk()) {
  617.     state->setFillColorSpace(colorSpace);
  618.   } else {
  619.     delete colorSpace;
  620.     error(getPos(), "Bad colorspace");
  621.   }
  622.   x[0] = x[1] = x[2] = x[3] = 0;
  623.   state->setFillColor(x);
  624.   out->updateFillColor(state);
  625. }
  626.  
  627. void Gfx::opSetStrokeColorSpace(Object args[], int numArgs) {
  628.   Object obj;
  629.   GfxColorSpace *colorSpace;
  630.   double x[4];
  631.  
  632.   lookupColorSpace(args[0].getName(), &obj);
  633.   if (obj.isNull())
  634.     colorSpace = new GfxColorSpace(&args[0]);
  635.   else
  636.     colorSpace = new GfxColorSpace(&obj);
  637.   obj.free();
  638.   if (colorSpace->isOk()) {
  639.     state->setStrokeColorSpace(colorSpace);
  640.   } else {
  641.     delete colorSpace;
  642.     error(getPos(), "Bad colorspace");
  643.   }
  644.   x[0] = x[1] = x[2] = x[3] = 0;
  645.   state->setStrokeColor(x);
  646.   out->updateStrokeColor(state);
  647. }
  648.  
  649. void Gfx::opSetFillColor(Object args[], int numArgs) {
  650.   double x[4];
  651.   int i;
  652.  
  653.   x[0] = x[1] = x[2] = x[3] = 0;
  654.   for (i = 0; i < numArgs; ++i)
  655.     x[i] = args[i].getNum();
  656.   state->setFillColor(x);
  657.   out->updateFillColor(state);
  658. }
  659.  
  660. void Gfx::opSetStrokeColor(Object args[], int numArgs) {
  661.   double x[4];
  662.   int i;
  663.  
  664.   x[0] = x[1] = x[2] = x[3] = 0;
  665.   for (i = 0; i < numArgs; ++i)
  666.     x[i] = args[i].getNum();
  667.   state->setStrokeColor(x);
  668.   out->updateStrokeColor(state);
  669. }
  670.  
  671. void Gfx::opSetFillColorN(Object args[], int numArgs) {
  672.   double x[4];
  673.   int i;
  674.  
  675.   x[0] = x[1] = x[2] = x[3] = 0;
  676.   for (i = 0; i < numArgs && i < 4; ++i) {
  677.     if (args[i].isNum())
  678.       x[i] = args[i].getNum();
  679.     else
  680.       break;
  681.   }
  682.   state->setFillColor(x);
  683.   out->updateFillColor(state);
  684. }
  685.  
  686. void Gfx::opSetStrokeColorN(Object args[], int numArgs) {
  687.   double x[4];
  688.   int i;
  689.  
  690.   x[0] = x[1] = x[2] = x[3] = 0;
  691.   for (i = 0; i < numArgs && i < 4; ++i) {
  692.     if (args[i].isNum())
  693.       x[i] = args[i].getNum();
  694.     else
  695.       break;
  696.   }
  697.   state->setStrokeColor(x);
  698.   out->updateStrokeColor(state);
  699. }
  700.  
  701. //------------------------------------------------------------------------
  702. // path segment operators
  703. //------------------------------------------------------------------------
  704.  
  705. void Gfx::opMoveTo(Object args[], int numArgs) {
  706.   state->moveTo(args[0].getNum(), args[1].getNum());
  707. }
  708.  
  709. void Gfx::opLineTo(Object args[], int numArgs) {
  710.   if (!state->isCurPt()) {
  711.     error(getPos(), "No current point in lineto");
  712.     return;
  713.   }
  714.   state->lineTo(args[0].getNum(), args[1].getNum());
  715. }
  716.  
  717. void Gfx::opCurveTo(Object args[], int numArgs) {
  718.   double x1, y1, x2, y2, x3, y3;
  719.  
  720.   if (!state->isCurPt()) {
  721.     error(getPos(), "No current point in curveto");
  722.     return;
  723.   }
  724.   x1 = args[0].getNum();
  725.   y1 = args[1].getNum();
  726.   x2 = args[2].getNum();
  727.   y2 = args[3].getNum();
  728.   x3 = args[4].getNum();
  729.   y3 = args[5].getNum();
  730.   state->curveTo(x1, y1, x2, y2, x3, y3);
  731. }
  732.  
  733. void Gfx::opCurveTo1(Object args[], int numArgs) {
  734.   double x1, y1, x2, y2, x3, y3;
  735.  
  736.   if (!state->isCurPt()) {
  737.     error(getPos(), "No current point in curveto1");
  738.     return;
  739.   }
  740.   x1 = state->getCurX();
  741.   y1 = state->getCurY();
  742.   x2 = args[0].getNum();
  743.   y2 = args[1].getNum();
  744.   x3 = args[2].getNum();
  745.   y3 = args[3].getNum();
  746.   state->curveTo(x1, y1, x2, y2, x3, y3);
  747. }
  748.  
  749. void Gfx::opCurveTo2(Object args[], int numArgs) {
  750.   double x1, y1, x2, y2, x3, y3;
  751.  
  752.   if (!state->isCurPt()) {
  753.     error(getPos(), "No current point in curveto2");
  754.     return;
  755.   }
  756.   x1 = args[0].getNum();
  757.   y1 = args[1].getNum();
  758.   x2 = args[2].getNum();
  759.   y2 = args[3].getNum();
  760.   x3 = x2;
  761.   y3 = y2;
  762.   state->curveTo(x1, y1, x2, y2, x3, y3);
  763. }
  764.  
  765. void Gfx::opRectangle(Object args[], int numArgs) {
  766.   double x, y, w, h;
  767.  
  768.   x = args[0].getNum();
  769.   y = args[1].getNum();
  770.   w = args[2].getNum();
  771.   h = args[3].getNum();
  772.   state->moveTo(x, y);
  773.   state->lineTo(x + w, y);
  774.   state->lineTo(x + w, y + h);
  775.   state->lineTo(x, y + h);
  776.   state->closePath();
  777. }
  778.  
  779. void Gfx::opClosePath(Object args[], int numArgs) {
  780.   if (!state->isPath()) {
  781.     error(getPos(), "No current point in closepath");
  782.     return;
  783.   }
  784.   state->closePath();
  785. }
  786.  
  787. //------------------------------------------------------------------------
  788. // path painting operators
  789. //------------------------------------------------------------------------
  790.  
  791. void Gfx::opEndPath(Object args[], int numArgs) {
  792.   doEndPath();
  793. }
  794.  
  795. void Gfx::opStroke(Object args[], int numArgs) {
  796.   if (!state->isCurPt()) {
  797.     //error(getPos(), "No path in stroke");
  798.     return;
  799.   }
  800.   if (state->isPath())
  801.     out->stroke(state);
  802.   doEndPath();
  803. }
  804.  
  805. void Gfx::opCloseStroke(Object args[], int numArgs) {
  806.   if (!state->isCurPt()) {
  807.     //error(getPos(), "No path in closepath/stroke");
  808.     return;
  809.   }
  810.   if (state->isPath()) {
  811.     state->closePath();
  812.     out->stroke(state);
  813.   }
  814.   doEndPath();
  815. }
  816.  
  817. void Gfx::opFill(Object args[], int numArgs) {
  818.   if (!state->isCurPt()) {
  819.     //error(getPos(), "No path in fill");
  820.     return;
  821.   }
  822.   if (state->isPath())
  823.     out->fill(state);
  824.   doEndPath();
  825. }
  826.  
  827. void Gfx::opEOFill(Object args[], int numArgs) {
  828.   if (!state->isCurPt()) {
  829.     //error(getPos(), "No path in eofill");
  830.     return;
  831.   }
  832.   if (state->isPath())
  833.     out->eoFill(state);
  834.   doEndPath();
  835. }
  836.  
  837. void Gfx::opFillStroke(Object args[], int numArgs) {
  838.   if (!state->isCurPt()) {
  839.     //error(getPos(), "No path in fill/stroke");
  840.     return;
  841.   }
  842.   if (state->isPath()) {
  843.     out->fill(state);
  844.     out->stroke(state);
  845.   }
  846.   doEndPath();
  847. }
  848.  
  849. void Gfx::opCloseFillStroke(Object args[], int numArgs) {
  850.   if (!state->isCurPt()) {
  851.     //error(getPos(), "No path in closepath/fill/stroke");
  852.     return;
  853.   }
  854.   if (state->isPath()) {
  855.     state->closePath();
  856.     out->fill(state);
  857.     out->stroke(state);
  858.   }
  859.   doEndPath();
  860. }
  861.  
  862. void Gfx::opEOFillStroke(Object args[], int numArgs) {
  863.   if (!state->isCurPt()) {
  864.     //error(getPos(), "No path in eofill/stroke");
  865.     return;
  866.   }
  867.   if (state->isPath()) {
  868.     out->eoFill(state);
  869.     out->stroke(state);
  870.   }
  871.   doEndPath();
  872. }
  873.  
  874. void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
  875.   if (!state->isCurPt()) {
  876.     //error(getPos(), "No path in closepath/eofill/stroke");
  877.     return;
  878.   }
  879.   if (state->isPath()) {
  880.     state->closePath();
  881.     out->eoFill(state);
  882.     out->stroke(state);
  883.   }
  884.   doEndPath();
  885. }
  886.  
  887. void Gfx::doEndPath() {
  888.   if (state->isPath()) {
  889.     if (clip == clipNormal)
  890.       out->clip(state);
  891.     else if (clip == clipEO)
  892.       out->eoClip(state);
  893.   }
  894.   clip = clipNone;
  895.   state->clearPath();
  896. }
  897.  
  898. //------------------------------------------------------------------------
  899. // path clipping operators
  900. //------------------------------------------------------------------------
  901.  
  902. void Gfx::opClip(Object args[], int numArgs) {
  903.   clip = clipNormal;
  904. }
  905.  
  906. void Gfx::opEOClip(Object args[], int numArgs) {
  907.   clip = clipEO;
  908. }
  909.  
  910. //------------------------------------------------------------------------
  911. // text object operators
  912. //------------------------------------------------------------------------
  913.  
  914. void Gfx::opBeginText(Object args[], int numArgs) {
  915.   state->setTextMat(1, 0, 0, 1, 0, 0);
  916.   state->textMoveTo(0, 0);
  917.   out->updateTextMat(state);
  918.   out->updateTextPos(state);
  919.   fontChanged = gTrue;
  920. }
  921.  
  922. void Gfx::opEndText(Object args[], int numArgs) {
  923. }
  924.  
  925. //------------------------------------------------------------------------
  926. // text state operators
  927. //------------------------------------------------------------------------
  928.  
  929. void Gfx::opSetCharSpacing(Object args[], int numArgs) {
  930.   state->setCharSpace(args[0].getNum());
  931.   out->updateCharSpace(state);
  932. }
  933.  
  934. void Gfx::opSetFont(Object args[], int numArgs) {
  935.   GfxFont *font;
  936.  
  937.   if (!(font = lookupFont(args[0].getName())))
  938.     return;
  939.   if (printCommands) {
  940.     printf("  font: '%s' %g\n",
  941.        font->getName() ? font->getName()->getCString() : "???",
  942.        args[1].getNum());
  943.   }
  944.   state->setFont(font, args[1].getNum());
  945.   fontChanged = gTrue;
  946. }
  947.  
  948. void Gfx::opSetTextLeading(Object args[], int numArgs) {
  949.   state->setLeading(args[0].getNum());
  950. }
  951.  
  952. void Gfx::opSetTextRender(Object args[], int numArgs) {
  953.   state->setRender(args[0].getInt());
  954.   out->updateRender(state);
  955. }
  956.  
  957. void Gfx::opSetTextRise(Object args[], int numArgs) {
  958.   state->setRise(args[0].getNum());
  959.   out->updateRise(state);
  960. }
  961.  
  962. void Gfx::opSetWordSpacing(Object args[], int numArgs) {
  963.   state->setWordSpace(args[0].getNum());
  964.   out->updateWordSpace(state);
  965. }
  966.  
  967. void Gfx::opSetHorizScaling(Object args[], int numArgs) {
  968.   state->setHorizScaling(args[0].getNum());
  969.   out->updateHorizScaling(state);
  970. }
  971.  
  972. //------------------------------------------------------------------------
  973. // text positioning operators
  974. //------------------------------------------------------------------------
  975.  
  976. void Gfx::opTextMove(Object args[], int numArgs) {
  977.   double tx, ty;
  978.  
  979.   tx = state->getLineX() + args[0].getNum();
  980.   ty = state->getLineY() + args[1].getNum();
  981.   state->textMoveTo(tx, ty);
  982.   out->updateTextPos(state);
  983. }
  984.  
  985. void Gfx::opTextMoveSet(Object args[], int numArgs) {
  986.   double tx, ty;
  987.  
  988.   tx = state->getLineX() + args[0].getNum();
  989.   ty = args[1].getNum();
  990.   state->setLeading(-ty);
  991.   ty += state->getLineY();
  992.   state->textMoveTo(tx, ty);
  993.   out->updateTextPos(state);
  994. }
  995.  
  996. void Gfx::opSetTextMatrix(Object args[], int numArgs) {
  997.   state->setTextMat(args[0].getNum(), args[1].getNum(),
  998.             args[2].getNum(), args[3].getNum(),
  999.             args[4].getNum(), args[5].getNum());
  1000.   state->textMoveTo(0, 0);
  1001.   out->updateTextMat(state);
  1002.   out->updateTextPos(state);
  1003.   fontChanged = gTrue;
  1004. }
  1005.  
  1006. void Gfx::opTextNextLine(Object args[], int numArgs) {
  1007.   double tx, ty;
  1008.  
  1009.   tx = state->getLineX();
  1010.   ty = state->getLineY() - state->getLeading();
  1011.   state->textMoveTo(tx, ty);
  1012.   out->updateTextPos(state);
  1013. }
  1014.  
  1015. //------------------------------------------------------------------------
  1016. // text string operators
  1017. //------------------------------------------------------------------------
  1018.  
  1019. void Gfx::opShowText(Object args[], int numArgs) {
  1020.   if (!state->getFont()) {
  1021.     error(getPos(), "No font in show");
  1022.     return;
  1023.   }
  1024.   doShowText(args[0].getString());
  1025. }
  1026.  
  1027. void Gfx::opMoveShowText(Object args[], int numArgs) {
  1028.   double tx, ty;
  1029.  
  1030.   if (!state->getFont()) {
  1031.     error(getPos(), "No font in move/show");
  1032.     return;
  1033.   }
  1034.   tx = state->getLineX();
  1035.   ty = state->getLineY() - state->getLeading();
  1036.   state->textMoveTo(tx, ty);
  1037.   out->updateTextPos(state);
  1038.   doShowText(args[0].getString());
  1039. }
  1040.  
  1041. void Gfx::opMoveSetShowText(Object args[], int numArgs) {
  1042.   double tx, ty;
  1043.  
  1044.   if (!state->getFont()) {
  1045.     error(getPos(), "No font in move/set/show");
  1046.     return;
  1047.   }
  1048.   state->setWordSpace(args[0].getNum());
  1049.   state->setCharSpace(args[1].getNum());
  1050.   tx = state->getLineX();
  1051.   ty = state->getLineY() - state->getLeading();
  1052.   state->textMoveTo(tx, ty);
  1053.   out->updateWordSpace(state);
  1054.   out->updateCharSpace(state);
  1055.   out->updateTextPos(state);
  1056.   doShowText(args[2].getString());
  1057. }
  1058.  
  1059. void Gfx::opShowSpaceText(Object args[], int numArgs) {
  1060.   Array *a;
  1061.   Object obj;
  1062.   int i;
  1063.  
  1064.   if (!state->getFont()) {
  1065.     error(getPos(), "No font in show/space");
  1066.     return;
  1067.   }
  1068.   a = args[0].getArray();
  1069.   for (i = 0; i < a->getLength(); ++i) {
  1070.     a->get(i, &obj);
  1071.     if (obj.isNum()) {
  1072.       state->textShift(-obj.getNum() * 0.001 * state->getFontSize());
  1073.       out->updateTextShift(state, obj.getNum());
  1074.     } else if (obj.isString()) {
  1075.       doShowText(obj.getString());
  1076.     } else {
  1077.       error(getPos(), "Element of show/space array must be number or string");
  1078.     }
  1079.     obj.free();
  1080.   }
  1081. }
  1082.  
  1083. void Gfx::doShowText(GString *s) {
  1084.   GfxFont *font;
  1085.   GfxFontEncoding16 *enc;
  1086.   Guchar *p;
  1087.   Guchar c8;
  1088.   int c16;
  1089.   GString *s16;
  1090.   int m, n;
  1091.   double dx, dy, width, w, h;
  1092.  
  1093.   if (fontChanged) {
  1094.     out->updateFont(state);
  1095.     fontChanged = gFalse;
  1096.   }
  1097.   font = state->getFont();
  1098.  
  1099.   //----- 16-bit font
  1100.   if (font->is16Bit()) {
  1101.     enc = font->getEncoding16();
  1102.     if (out->useDrawChar()) {
  1103.       out->beginString(state, s);
  1104.       s16 = NULL;
  1105.     } else {
  1106.       s16 = new GString("  ");
  1107.     }
  1108.     state->textTransformDelta(0, state->getRise(), &dx, &dy);
  1109.     p = (Guchar *)s->getCString();
  1110.     n = s->getLength();
  1111.     while (n > 0) {
  1112.       m = getNextChar16(enc, p, &c16);
  1113.       width = state->getFontSize() * state->getHorizScaling() *
  1114.           font->getWidth16(c16) +
  1115.           state->getCharSpace();
  1116.       if (c16 == ' ')
  1117.     width += state->getWordSpace();
  1118.       state->textTransformDelta(width, 0, &w, &h);
  1119.       if (out->useDrawChar()) {
  1120.     out->drawChar16(state, state->getCurX() + dx, state->getCurY() + dy,
  1121.             w, h, c16);
  1122.       } else {
  1123.     s16->setChar(0, (char)(c16 >> 8));
  1124.     s16->setChar(1, (char)c16);
  1125.     out->drawString16(state, s16);
  1126.       }
  1127.       state->textShift(width);
  1128.       n -= m;
  1129.       p += m;
  1130.     }
  1131.     if (out->useDrawChar())
  1132.       out->endString(state);
  1133.     else
  1134.       delete s16;
  1135.  
  1136.   //----- 8-bit font
  1137.   } else {
  1138.     if (out->useDrawChar()) {
  1139.       out->beginString(state, s);
  1140.       state->textTransformDelta(0, state->getRise(), &dx, &dy);
  1141.       for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
  1142.     c8 = *p;
  1143.     width = state->getFontSize() * state->getHorizScaling() *
  1144.         font->getWidth(c8) +
  1145.         state->getCharSpace();
  1146.     if (c8 == ' ')
  1147.       width += state->getWordSpace();
  1148.     state->textTransformDelta(width, 0, &w, &h);
  1149.     out->drawChar(state, state->getCurX() + dx, state->getCurY() + dy,
  1150.               w, h, c8);
  1151.     state->textShift(width);
  1152.       }
  1153.       out->endString(state);
  1154.     } else {
  1155.       out->drawString(state, s);
  1156.       width = state->getFontSize() * state->getHorizScaling() *
  1157.           font->getWidth(s) +
  1158.           s->getLength() * state->getCharSpace();
  1159.       for (p = (Guchar *)s->getCString(), n = s->getLength(); n; ++p, --n) {
  1160.     if (*p == ' ')
  1161.       width += state->getWordSpace();
  1162.       }
  1163.       state->textShift(width);
  1164.     }
  1165.   }
  1166. }
  1167.  
  1168. int Gfx::getNextChar16(GfxFontEncoding16 *enc, Guchar *p, int *c16) {
  1169.   int n;
  1170.   int code;
  1171.   int a, b, m;
  1172.  
  1173.   n = enc->codeLen[*p];
  1174.   if (n == 1) {
  1175.     *c16 = enc->map1[*p];
  1176.   } else {
  1177.     code = (p[0] << 8) + p[1];
  1178.     a = 0;
  1179.     b = enc->map2Len;
  1180.     // invariant: map2[2*a] <= code < map2[2*b]
  1181.     while (b - a > 1) {
  1182.       m = (a + b) / 2;
  1183.       if (enc->map2[2*m] <= code)
  1184.     a = m;
  1185.       else if (enc->map2[2*m] > code)
  1186.     b = m;
  1187.       else
  1188.     break;
  1189.     }
  1190.     *c16 = enc->map2[2*a+1] + (code - enc->map2[2*a]);
  1191.   }
  1192.   return n;
  1193. }
  1194.  
  1195. //------------------------------------------------------------------------
  1196. // XObject operators
  1197. //------------------------------------------------------------------------
  1198.  
  1199. void Gfx::opXObject(Object args[], int numArgs) {
  1200.   Object obj1, obj2;
  1201.  
  1202.   if (!lookupXObject(args[0].getName(), &obj1))
  1203.     return;
  1204.   if (!obj1.isStream("XObject")) {
  1205.     error(getPos(), "XObject '%s' is wrong type", args[0].getName());
  1206.     obj1.free();
  1207.     return;
  1208.   }
  1209.   obj1.streamGetDict()->lookup("Subtype", &obj2);
  1210.   if (obj2.isName("Image"))
  1211.     doImage(obj1.getStream(), gFalse);
  1212.   else if (obj2.isName("Form"))
  1213.     doForm(&obj1);
  1214.   else if (obj2.isName())
  1215.     error(getPos(), "Unknown XObject subtype '%s'", obj2.getName());
  1216.   else
  1217.     error(getPos(), "XObject subtype is missing or wrong type");
  1218.   obj2.free();
  1219.   obj1.free();
  1220. }
  1221.  
  1222. void Gfx::doImage(Stream *str, GBool inlineImg) {
  1223.   Dict *dict;
  1224.   Object obj1, obj2;
  1225.   int width, height;
  1226.   int bits;
  1227.   GBool mask;
  1228.   GfxColorSpace *colorSpace;
  1229.   GfxImageColorMap *colorMap;
  1230.   GBool invert;
  1231.  
  1232.   // get stream dict
  1233.   dict = str->getDict();
  1234.  
  1235.   // get size
  1236.   dict->lookup("Width", &obj1);
  1237.   if (obj1.isNull()) {
  1238.     obj1.free();
  1239.     dict->lookup("W", &obj1);
  1240.   }
  1241.   if (!obj1.isInt())
  1242.     goto err2;
  1243.   width = obj1.getInt();
  1244.   obj1.free();
  1245.   dict->lookup("Height", &obj1);
  1246.   if (obj1.isNull()) {
  1247.     obj1.free();
  1248.     dict->lookup("H", &obj1);
  1249.   }
  1250.   if (!obj1.isInt())
  1251.     goto err2;
  1252.   height = obj1.getInt();
  1253.   obj1.free();
  1254.  
  1255.   // image or mask?
  1256.   dict->lookup("ImageMask", &obj1);
  1257.   if (obj1.isNull()) {
  1258.     obj1.free();
  1259.     dict->lookup("IM", &obj1);
  1260.   }
  1261.   mask = gFalse;
  1262.   if (obj1.isBool())
  1263.     mask = obj1.getBool();
  1264.   else if (!obj1.isNull())
  1265.     goto err2;
  1266.   obj1.free();
  1267.  
  1268.   // bit depth
  1269.   dict->lookup("BitsPerComponent", &obj1);
  1270.   if (obj1.isNull()) {
  1271.     obj1.free();
  1272.     dict->lookup("BPC", &obj1);
  1273.   }
  1274.   if (!obj1.isInt())
  1275.     goto err2;
  1276.   bits = obj1.getInt();
  1277.   obj1.free();
  1278.  
  1279.   // display a mask
  1280.   if (mask) {
  1281.  
  1282.     // check for inverted mask
  1283.     if (bits != 1)
  1284.       goto err1;
  1285.     invert = gFalse;
  1286.     dict->lookup("Decode", &obj1);
  1287.     if (obj1.isNull()) {
  1288.       obj1.free();
  1289.       dict->lookup("D", &obj1);
  1290.     }
  1291.     if (obj1.isArray()) {
  1292.       obj1.arrayGet(0, &obj2);
  1293.       if (obj2.isInt() && obj2.getInt() == 1)
  1294.     invert = gTrue;
  1295.       obj2.free();
  1296.     } else if (!obj1.isNull()) {
  1297.       goto err2;
  1298.     }
  1299.     obj1.free();
  1300.  
  1301.     // draw it
  1302.     out->drawImageMask(state, str, width, height, invert, inlineImg);
  1303.  
  1304.   } else {
  1305.  
  1306.     // get color space and color map
  1307.     dict->lookup("ColorSpace", &obj1);
  1308.     if (obj1.isNull()) {
  1309.       obj1.free();
  1310.       dict->lookup("CS", &obj1);
  1311.     }
  1312.     if (obj1.isName()) {
  1313.       lookupColorSpace(obj1.getName(), &obj2);
  1314.       if (!obj2.isNull()) {
  1315.     obj1.free();
  1316.     obj1 = obj2;
  1317.       } else {
  1318.     obj2.free();
  1319.       }
  1320.     }
  1321.     colorSpace = new GfxColorSpace(&obj1);
  1322.     obj1.free();
  1323.     if (!colorSpace->isOk()) {
  1324.       delete colorSpace;
  1325.       goto err1;
  1326.     }
  1327.     dict->lookup("Decode", &obj1);
  1328.     if (obj1.isNull()) {
  1329.       obj1.free();
  1330.       dict->lookup("D", &obj1);
  1331.     }
  1332.     colorMap = new GfxImageColorMap(bits, &obj1, colorSpace);
  1333.     obj1.free();
  1334.     if (!colorMap->isOk()) {
  1335.       delete colorSpace;
  1336.       goto err1;
  1337.     }
  1338.  
  1339.     // draw it
  1340.     out->drawImage(state, str, width, height, colorMap, inlineImg);
  1341.     delete colorMap;
  1342.   }
  1343.  
  1344.   return;
  1345.  
  1346.  err2:
  1347.   obj1.free();
  1348.  err1:
  1349.   error(getPos(), "Bad image parameters");
  1350. }
  1351.  
  1352. void Gfx::doForm(Object *str) {
  1353.   Parser *oldParser;
  1354.   GfxResources *resPtr;
  1355.   Dict *dict;
  1356.   Dict *resDict;
  1357.   Object matrixObj, bboxObj;
  1358.   double m[6];
  1359.   Object obj1, obj2;
  1360.   int i;
  1361.  
  1362.   // get stream dict
  1363.   dict = str->streamGetDict();
  1364.  
  1365.   // check form type
  1366.   dict->lookup("FormType", &obj1);
  1367.   if (!(obj1.isInt() && obj1.getInt() == 1)) {
  1368.     obj1.free();
  1369.     error(getPos(), "Unknown form type");
  1370.     return;
  1371.   }
  1372.   obj1.free();
  1373.  
  1374.   // get matrix and bounding box
  1375.   dict->lookup("Matrix", &matrixObj);
  1376.   if (!matrixObj.isArray()) {
  1377.     matrixObj.free();
  1378.     error(getPos(), "Bad form matrix");
  1379.     return;
  1380.   }
  1381.   dict->lookup("BBox", &bboxObj);
  1382.   if (!bboxObj.isArray()) {
  1383.     matrixObj.free();
  1384.     bboxObj.free();
  1385.     error(getPos(), "Bad form bounding box");
  1386.     return;
  1387.   }
  1388.  
  1389.   // push new resources on stack
  1390.   dict->lookup("Resources", &obj1);
  1391.   if (obj1.isDict()) {
  1392.     resDict = obj1.getDict();
  1393.     res = new GfxResources(res);
  1394.     res->fonts = NULL;
  1395.     resDict->lookup("Font", &obj2);
  1396.     if (obj2.isDict())
  1397.       res->fonts = new GfxFontDict(obj2.getDict());
  1398.     obj2.free();
  1399.     resDict->lookup("XObject", &res->xObjDict);
  1400.     resDict->lookup("ColorSpace", &res->colorSpaceDict);
  1401.     obj1.free();
  1402.   }
  1403.  
  1404.   // save current graphics state
  1405.   out->saveState(state);
  1406.   state = state->save();
  1407.  
  1408.   // save current parser
  1409.   oldParser = parser;
  1410.  
  1411.   // set form transformation matrix
  1412.   for (i = 0; i < 6; ++i) {
  1413.     matrixObj.arrayGet(i, &obj1);
  1414.     m[i] = obj1.getNum();
  1415.     obj1.free();
  1416.   }
  1417.   state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
  1418.   out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]);
  1419.  
  1420.   // set form bounding box
  1421.   for (i = 0; i < 4; ++i) {
  1422.     bboxObj.arrayGet(i, &obj1);
  1423.     m[i] = obj1.getNum();
  1424.     obj1.free();
  1425.   }
  1426.   state->moveTo(m[0], m[1]);
  1427.   state->lineTo(m[0]+m[2], m[1]);
  1428.   state->lineTo(m[0]+m[2], m[1]+m[3]);
  1429.   state->lineTo(m[0], m[1]+m[3]);
  1430.   state->closePath();
  1431.   out->clip(state);
  1432.   state->clearPath();
  1433.  
  1434.   // draw the form
  1435.   display(str);
  1436.  
  1437.   // free matrix and bounding box
  1438.   matrixObj.free();
  1439.   bboxObj.free();
  1440.  
  1441.   // restore parser
  1442.   parser = oldParser;
  1443.  
  1444.   // restore graphics state
  1445.   state = state->restore();
  1446.   out->restoreState(state);
  1447.  
  1448.   // pop resource stack
  1449.   resPtr = res->next;
  1450.   delete res;
  1451.   res = resPtr;
  1452.  
  1453.   return;
  1454. }
  1455.  
  1456. //------------------------------------------------------------------------
  1457. // in-line image operators
  1458. //------------------------------------------------------------------------
  1459.  
  1460. void Gfx::opBeginImage(Object args[], int numArgs) {
  1461.   Stream *str;
  1462.   int c1, c2;
  1463.  
  1464.   // build dict/stream
  1465.   str = buildImageStream();
  1466.  
  1467.   // display the image
  1468.   if (str) {
  1469.     doImage(str, gTrue);
  1470.   
  1471.     // skip 'EI' tag
  1472.     c1 = str->getBaseStream()->getChar();
  1473.     c2 = str->getBaseStream()->getChar();
  1474.     while (!(c1 == 'E' && c2 == 'I') && c2 != EOF) {
  1475.       c1 = c2;
  1476.       c2 = str->getBaseStream()->getChar();
  1477.     }
  1478.     delete str;
  1479.   }
  1480. }
  1481.  
  1482. Stream *Gfx::buildImageStream() {
  1483.   Object dict;
  1484.   Object obj;
  1485.   char *key;
  1486.   Stream *str;
  1487.  
  1488.   // build dictionary
  1489.   dict.initDict();
  1490.   parser->getObj(&obj);
  1491.   while (!obj.isCmd("ID") && !obj.isEOF()) {
  1492.     if (!obj.isName()) {
  1493.       error(getPos(), "Inline image dictionary key must be a name object");
  1494.       obj.free();
  1495.       parser->getObj(&obj);
  1496.     } else {
  1497.       key = copyString(obj.getName());
  1498.       obj.free();
  1499.       parser->getObj(&obj);
  1500.       if (obj.isEOF() || obj.isError())
  1501.     break;
  1502.       dict.dictAdd(key, &obj);
  1503.     }
  1504.     parser->getObj(&obj);
  1505.   }
  1506.   if (obj.isEOF())
  1507.     error(getPos(), "End of file in inline image");
  1508.   obj.free();
  1509.  
  1510.   // make stream
  1511.   str = new SubStream(parser->getStream(), &dict);
  1512.   str = str->addFilters(&dict);
  1513.  
  1514.   return str;
  1515. }
  1516.  
  1517. void Gfx::opImageData(Object args[], int numArgs) {
  1518.   error(getPos(), "Internal: got 'ID' operator");
  1519. }
  1520.  
  1521. void Gfx::opEndImage(Object args[], int numArgs) {
  1522.   error(getPos(), "Internal: got 'EI' operator");
  1523. }
  1524.  
  1525. //------------------------------------------------------------------------
  1526. // type 3 font operators
  1527. //------------------------------------------------------------------------
  1528.  
  1529. void Gfx::opSetCharWidth(Object args[], int numArgs) {
  1530.   error(getPos(), "Encountered 'd0' operator in content stream");
  1531. }
  1532.  
  1533. void Gfx::opSetCacheDevice(Object args[], int numArgs) {
  1534.   error(getPos(), "Encountered 'd1' operator in content stream");
  1535. }
  1536.  
  1537. //------------------------------------------------------------------------
  1538. // compatibility operators
  1539. //------------------------------------------------------------------------
  1540.  
  1541. void Gfx::opBeginIgnoreUndef(Object args[], int numArgs) {
  1542.   ++ignoreUndef;
  1543. }
  1544.  
  1545. void Gfx::opEndIgnoreUndef(Object args[], int numArgs) {
  1546.   if (ignoreUndef > 0)
  1547.     --ignoreUndef;
  1548. }
  1549.  
  1550. //------------------------------------------------------------------------
  1551. // marked content operators
  1552. //------------------------------------------------------------------------
  1553.  
  1554. void Gfx::opBeginMarkedContent(Object args[], int numArgs) {
  1555.     if (printCommands) {
  1556.     printf("  marked content: %s ", args[0].getName());
  1557.     if (numArgs == 2)
  1558.       args[2].print(stdout);
  1559.     printf("\n");
  1560.   }
  1561. }
  1562.  
  1563. void Gfx::opEndMarkedContent(Object args[], int numArgs) {
  1564. }
  1565.  
  1566. void Gfx::opMarkPoint(Object args[], int numArgs) {
  1567.     if (printCommands) {
  1568.     printf("  mark point: %s ", args[0].getName());
  1569.     if (numArgs == 2)
  1570.       args[2].print(stdout);
  1571.     printf("\n");
  1572.   }
  1573. }
  1574.