home *** CD-ROM | disk | FTP | other *** search
/ PSION CD 2 / PsionCDVol2.iso / Programs / 720 / PDF090B4-SorceCode / pdf / Gfx.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-30  |  44.4 KB  |  1,757 lines

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