home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 110 / EnigmaAmiga110CD.iso / indispensabili / utility / apdf / xpdf-0.80 / xpdf / aoutputdev.cc < prev    next >
C/C++ Source or Header  |  1999-06-10  |  57KB  |  2,358 lines

  1. //========================================================================
  2. //
  3. // AOutputDev.cc
  4. //
  5. // adapted from XOutputDev.cc - Copyright 1996 Derek B. Noonburg
  6. //
  7. // changes are copyright 1999 Emmanuel Lesueur
  8. //
  9. //========================================================================
  10.  
  11. #ifdef __GNUC__
  12. #pragma implementation
  13. #endif
  14.  
  15. #define DB(x) //x
  16.  
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <stddef.h>
  20. #include <string.h>
  21. #include <ctype.h>
  22. #include <math.h>
  23. #define Object ZZObject
  24. #include <graphics/gfx.h>
  25. #include <graphics/text.h>
  26. #undef Object
  27. #include "gmem.h"
  28. #include "GString.h"
  29. #include "Object.h"
  30. #include "Stream.h"
  31. #include "GfxState.h"
  32. #include "GfxFont.h"
  33. #include "Error.h"
  34. #include "TextOutputDev.h"
  35. #include "AOutputDev.h"
  36. #include "AGfx.h"
  37. #include "FontOutputDev.h"
  38.  
  39.  
  40. //------------------------------------------------------------------------
  41. // Constants and macros
  42. //------------------------------------------------------------------------
  43.  
  44. inline int xoutRound(double x) { return int(x + 0.5); }
  45.  
  46. const int maxCurveSplits=6;  // max number of splits when recursively
  47.                  //   drawing Bezier curves
  48.  
  49. PArea<short> xoutRound(const PArea<double>& a) {
  50.   PArea<short> r;
  51.   r.rule(PArea<short>::Rule(a.rule()));
  52.   r.reserve(a.size());
  53.   for(PArea<double>::const_iterator p(a.begin()); p != a.end(); ++p) {
  54.     Polygon<short> t;
  55.     t.reserve(p->size());
  56.     for(Polygon<double>::const_iterator v(p->begin()); v != p->end(); ++v)
  57.       t.push_back(Vertex<short>(xoutRound(v->x), xoutRound(v->y)));
  58.     r.push_back(t);
  59.   }
  60.   return r;
  61. }
  62.  
  63. //------------------------------------------------------------------------
  64. // Parameters
  65. //------------------------------------------------------------------------
  66.  
  67. extern int maxColors;
  68.  
  69. //------------------------------------------------------------------------
  70. // ColorTable
  71. //------------------------------------------------------------------------
  72.  
  73. Gulong ColorTable::add(Gulong x) {
  74.   if (num == maxEntries) {
  75.     maxEntries = (maxEntries * 3) / 2 + 16;
  76.     entries = (entry*) grealloc(entries, maxEntries*sizeof(entry));
  77.   }
  78.   Gulong n = num;
  79.   entry *p = entries;
  80.   while (n > 0) {
  81.     Gulong k = n / 2;
  82.     entry *q = p + k;
  83.     if (x > q->val) {
  84.       p = q + 1;
  85.       n -= k + 1;
  86.     } else if(x != q->val)
  87.       n = k;
  88.     else {
  89.       p = q;
  90.       break;
  91.     }
  92.   }
  93.   if (p != entries + num)
  94.     memmove(p+1, p, (entries+num-p)*sizeof(entry));
  95.   p->n = num;
  96.   p->val = x;
  97.   return num++;
  98. }
  99.  
  100. Gulong ColorTable::find(Gulong x) const {
  101.   Gulong n = num;
  102.   entry *p = entries;
  103.   while (n > 0) {
  104.     Gulong k = n / 2;
  105.     entry *q = p + k;
  106.     if (x > q->val) {
  107.       p = q + 1;
  108.       n -= k + 1;
  109.     } else if(x != q->val)
  110.       n = k;
  111.     else
  112.       return q->n;
  113.   }
  114.   return Gulong(-1);
  115. }
  116.  
  117. // find the RGB value of pen n
  118. // slow, but only used int drawImageMask...
  119. Gulong ColorTable::find_rgb(Gulong n) const {
  120.   if (n < num) {
  121.     entry *p = entries;
  122.     while (p->n != n)
  123.       ++p;
  124.     return p->val;
  125.   }
  126.   return 0; // should not happen...
  127. }
  128.  
  129. //------------------------------------------------------------------------
  130. // Constructed characters
  131. //------------------------------------------------------------------------
  132.  
  133. #define lastRegularChar 0x0ff
  134. #define firstSubstChar  0x100
  135. #define lastSubstChar   0x104
  136. #define firstConstrChar 0x105
  137. #define lastConstrChar  0x106
  138. #define firstMultiChar  0x107
  139. #define lastMultiChar   0x10d
  140.  
  141. // substituted chars
  142. static Guchar substChars[] = {
  143.   0x27,                         // 100: quotesingle --> quoteright
  144.   0x2d,                         // 101: emdash --> hyphen
  145.   0xad,                         // 102: hyphen --> endash
  146.   0x2f,                         // 103: fraction --> slash
  147.   0xb0,                         // 104: ring --> degree
  148. };
  149.  
  150. // constructed chars
  151. // 105: bullet
  152. // 106: trademark
  153.  
  154. // built-up chars
  155. static char *multiChars[] = {
  156.   "fi",                         // 107: fi
  157.   "fl",                         // 108: fl
  158.   "OE",                         // 109: OE
  159.   "oe",                         // 10a: oe
  160.   "...",                        // 10b: ellipsis
  161.   "``",                         // 10c: quotedblleft
  162.   "''"                          // 10d: quotedblright
  163. };
  164.  
  165. // ignored chars
  166. // 10c: Lslash
  167. // 10d: Scaron
  168. // 10e: Zcaron
  169. // 10f: Ydieresis
  170. // 110: breve
  171. // 111: caron
  172. // 112: circumflex
  173. // 113: dagger
  174. // 114: daggerdbl
  175. // 115: dotaccent
  176. // 116: dotlessi
  177. // 117: florin
  178. // 118: grave
  179. // 119: guilsinglleft
  180. // 11a: guilsinglright
  181. // 11b: hungarumlaut
  182. // 11c: lslash
  183. // 11d: ogonek
  184. // 11e: perthousand
  185. // 11f: quotedblbase
  186. // 120: quotesinglbase
  187. // 121: scaron
  188. // 122: tilde
  189. // 123: zcaron
  190.  
  191. //------------------------------------------------------------------------
  192. // AOutputFont
  193. //------------------------------------------------------------------------
  194.  
  195. int AOutputFont::xFontCount;
  196.  
  197. // Note: if real font is substantially narrower than substituted
  198. // font, the size is reduced accordingly.
  199. AOutputFont::AOutputFont(AGfx& gfx1, GfxFont *gfxFont, double m11, double m12,
  200.              double m21, double m22) : gfx(gfx1) {
  201.   GfxFontEncoding *encoding;
  202.   const char *fontName;
  203.   int fontStyle;
  204.   //GBool rotated;
  205.   double size;
  206.   int startSize, sz;
  207.   int index;
  208.   int code, code2;
  209.   char *charName;
  210.   int n;
  211.   double w1, w2;
  212.  
  213.   // init
  214.   id = gfxFont->getID();
  215.   mat11 = m11;
  216.   mat12 = m12;
  217.   mat21 = m21;
  218.   mat22 = m22;
  219.   xFont = NULL;
  220.   hex = gFalse;
  221.  
  222.   // construct X font name
  223.   fontName = getAFont(gfxFont, encoding, fontStyle, w1, w2);
  224.   m11 *= w1;
  225.   m12 *= w2;
  226.   m21 *= w1;
  227.   m22 *= w2;
  228.  
  229.   // Construct forward and reverse map.
  230.   // This tries to deal with font subset character names of the
  231.   // form 'Bxx', 'Cxx', 'Gxx', with decimal or hex numbering.
  232.  
  233.   for (code = 0; code < 256; ++code)
  234.     revMap[code] = 0;
  235.   if (encoding) {
  236.     for (code = 0; code < 256; ++code) {
  237.       if ((charName = gfxFont->getCharName(code))) {
  238.     if ((charName[0] == 'B' || charName[0] == 'C' ||
  239.          charName[0] == 'G') &&
  240.         strlen(charName) == 3 &&
  241.         ((charName[1] >= 'a' && charName[1] <= 'f') ||
  242.          (charName[1] >= 'A' && charName[1] <= 'F') ||
  243.          (charName[2] >= 'a' && charName[2] <= 'f') ||
  244.          (charName[2] >= 'A' && charName[2] <= 'F'))) {
  245.       hex = gTrue;
  246.       break;
  247.     }
  248.       }
  249.     }
  250.     for (code = 0; code < 256; ++code) {
  251.       if ((charName = gfxFont->getCharName(code))) {
  252.     if ((code2 = encoding->getCharCode(charName)) < 0) {
  253.       n = strlen(charName);
  254.       if (hex && n == 3 &&
  255.           (charName[0] == 'B' || charName[0] == 'C' ||
  256.            charName[0] == 'G') &&
  257.           isxdigit(charName[1]) && isxdigit(charName[2])) {
  258.         //sscanf(charName+1, "%x", &code2);
  259.         code2 = strtol(charName+1, NULL, 16);
  260.       } else if (!hex && n >= 2 && n <= 3 &&
  261.              isdigit(charName[0]) && isdigit(charName[1])) {
  262.         code2 = atoi(charName);
  263.         if (code2 >= 256)
  264.           code2 = -1;
  265.       } else if (!hex && n >= 3 && n <= 5 && isdigit(charName[1])) {
  266.         code2 = atoi(charName+1);
  267.         if (code2 >= 256)
  268.           code2 = -1;
  269.       }
  270.       //~ this is a kludge -- is there a standard internal encoding
  271.       //~ used by all/most Type 1 fonts?
  272.       if (code2 == 262)           // hyphen
  273.         code2 = 45;
  274.       else if (code2 == 266)      // emdash
  275.         code2 = 208;
  276.     }
  277.     if (code2 >= 0) {
  278.       map[code] = (Gushort)code2;
  279.       if (code2 < 256)
  280.         revMap[code2] = (Guchar)code;
  281.     } else {
  282.       map[code] = 0;
  283.     }
  284.       } else {
  285.     map[code] = 0;
  286.       }
  287.     }
  288.   } else {
  289.     code2 = 0; // to make gcc happy
  290.     //~ this is a hack to get around the fact that X won't draw
  291.     //~ chars 0..31; this works when the fonts have duplicate encodings
  292.     //~ for those chars
  293.     for (code = 0; code < 32; ++code) {
  294.       if ((charName = gfxFont->getCharName(code)) &&
  295.       (code2 = gfxFont->getCharCode(charName)) >= 0) {
  296.     map[code] = (Gushort)code2;
  297.     if (code2 < 256)
  298.       revMap[code2] = (Guchar)code;
  299.       }
  300.     }
  301.     for (code = 32; code < 256; ++code) {
  302.       map[code] = (Gushort)code;
  303.       revMap[code] = (Guchar)code;
  304.     }
  305.   }
  306.  
  307.   // compute size, normalize matrix
  308.   size = sqrt(m21*m21 + m22*m22);
  309.   m11 = m11 / size;
  310.   m12 = -m12 / size;
  311.   m21 = m21 / size;
  312.   m22 = -m22 / size;
  313.   startSize = (int)size;
  314.  
  315.   // try to get a rotated font?
  316.   /*rotated = !(mat11 > 0 && mat22 > 0 && fabs(mat11/mat22 - 1) < 0.2 &&
  317.           fabs(mat12) < 0.01 && fabs(mat21) < 0.01);
  318.  
  319.   // open X font -- if font is not found (which means the server can't
  320.   // scale fonts), try progressively smaller and then larger sizes
  321.   //~ This does a linear search -- it should get a list of fonts from
  322.   //~ the server and pick the closest.
  323.   if (rotated)
  324.     sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]",
  325.         m11<0 ? "~" : "", fabs(m11 * startSize),
  326.         m12<0 ? "~" : "", fabs(m12 * startSize),
  327.         m21<0 ? "~" : "", fabs(m21 * startSize),
  328.         m22<0 ? "~" : "", fabs(m22 * startSize));
  329.   else
  330.     sprintf(fontSize, "%d", startSize);*/
  331.  
  332.   xFont = xFontCount++;
  333.   gfx.openfont(xFont, fontName, startSize, fontStyle);
  334. }
  335.  
  336. AOutputFont::~AOutputFont() {
  337.   gfx.closefont(xFont);
  338. }
  339.  
  340. //------------------------------------------------------------------------
  341. // AOutputFontCache
  342. //------------------------------------------------------------------------
  343.  
  344. AOutputFontCache::AOutputFontCache(AGfx& g) : gfx(g) {
  345.   int i;
  346.  
  347.   for (i = 0; i < fontCacheSize; ++i)
  348.     fonts[i] = NULL;
  349.   numFonts = 0;
  350. }
  351.  
  352. AOutputFontCache::~AOutputFontCache() {
  353.   int i;
  354.  
  355.   for (i = 0; i < numFonts; ++i)
  356.     delete fonts[i];
  357. }
  358.  
  359. AOutputFont *AOutputFontCache::getFont(GfxFont *gfxFont,
  360.                        double m11, double m12,
  361.                        double m21, double m22) {
  362.   AOutputFont *font;
  363.   int i, j;
  364.  
  365.   // is it the most recently used font?
  366.   if (numFonts > 0 && fonts[0]->matches(gfxFont->getID(),
  367.                     m11, m12, m21, m22))
  368.     return fonts[0];
  369.  
  370.   // is it in the cache?
  371.   for (i = 1; i < numFonts; ++i) {
  372.     if (fonts[i]->matches(gfxFont->getID(), m11, m12, m21, m22)) {
  373.       font = fonts[i];
  374.       for (j = i; j > 0; --j)
  375.     fonts[j] = fonts[j-1];
  376.       fonts[0] = font;
  377.       return font;
  378.     }
  379.   }
  380.  
  381.   // make a new font
  382.   font = new AOutputFont(gfx, gfxFont, m11, m12, m21, m22);
  383.   /*if (!font->getTextFont()) {
  384.     delete font;
  385.     return NULL;
  386.   }*/
  387.  
  388.   // insert font in cache
  389.   if (numFonts == fontCacheSize) {
  390.     --numFonts;
  391.     delete fonts[numFonts];
  392.   }
  393.   for (j = numFonts; j > 0; --j)
  394.     fonts[j] = fonts[j-1];
  395.   fonts[0] = font;
  396.   ++numFonts;
  397.  
  398.   // return it
  399.   return font;
  400. }
  401.  
  402. //------------------------------------------------------------------------
  403. // AOutputDev
  404. //------------------------------------------------------------------------
  405.  
  406. AOutputDev::AOutputDev(AGfx& gfx1, Guint depth1, ColorMap* colormap1)
  407.     : gfx(gfx1) {
  408.   Gulong mask;
  409.   int r, g, b, n, m, i;
  410.   GBool ok;
  411.  
  412.   // get display/pixmap info
  413.   depth = depth1;
  414.   colormap = colormap1;
  415.  
  416.   rShift = 4;
  417.   gShift = 4;
  418.   bShift = 4;
  419.   rMul = (1 << rShift) - 1;
  420.   gMul = (1 << gShift) - 1;
  421.   bMul = (1 << bShift) - 1;
  422.   colorMask = 0x00f0f0f0;
  423.  
  424.   // check for TrueColor visual
  425.   trueColor = depth>8;
  426.  
  427.   // set up the font cache and fonts
  428.   gfxFont = NULL;
  429.   font = NULL;
  430.   fontCache = new AOutputFontCache(gfx);
  431.  
  432.   // create text object
  433.   text = new TextPage(gFalse);
  434. }
  435.  
  436. AOutputDev::~AOutputDev() {
  437.   delete fontCache;
  438.   delete text;
  439. }
  440.  
  441. void AOutputDev::startPage(int pageNum, GfxState *state) {
  442.   GfxColor color;
  443.  
  444.   capStyle = CapButt;
  445.   joinStyle = JoinBevel;
  446.   curColor = penColor;
  447.   strokeColor = curColor;
  448.   fillColor = curColor;
  449.   linkColor = Gulong(-1);
  450.  
  451.   clipRegion.clear();
  452.   installClip();
  453.   Polygon<double> p;
  454.   p.reserve(4);
  455.   p.push_back(Vertex<double>(0,0));
  456.   p.push_back(Vertex<double>(10000,0));
  457.   p.push_back(Vertex<double>(10000,10000));
  458.   p.push_back(Vertex<double>(0,10000));
  459.   clipRegion.push_back(p);
  460.   clipStack.clear();
  461.  
  462.   // default line flatness
  463.   flatness = 0;
  464.  
  465.   // clear font
  466.   gfxFont = NULL;
  467.   font = NULL;
  468.  
  469.   // clear text object
  470.   text->clear();
  471.  
  472.   gfx.init();
  473.   gfx.start_page();
  474.   colorTable.clear();
  475.   colorTable.add(0x000000UL);
  476.   colorTable.add(0xf0f0f0UL);
  477. }
  478.  
  479. void AOutputDev::endPage() {
  480.   gfx.end_page();
  481.   gfx.flush();
  482.   text->coalesce();
  483. }
  484.  
  485. void AOutputDev::drawLinkBorder(double x1, double y1, double x2, double y2,
  486.                 double w) {
  487.   int x, y;
  488.   DB(printf("\ndrawlink(%f,%f,%f,%f,%f)\n",x1,y1,x2,y2,w);)
  489.   if (linkColor == Gulong(-1)) {
  490.       GfxColor color;
  491.       color.setRGB(0, 0, 1);
  492.       linkColor = findColor(&color);
  493.   }
  494.   if (curColor != linkColor) {
  495.       curColor = linkColor;
  496.       gfx.setapen(curColor);
  497.   }
  498.   //XSetLineAttributes(display, strokeGC, xoutRound(w),
  499.   //                   LineSolid, CapRound, JoinRound);
  500.   Polygon<short> points;
  501.   points.reserve(5);
  502.   cvtUserToDev(x1, y1, &x, &y);
  503.   Vertex<short> orig(x,y);
  504.   points.push_back(orig);
  505.   cvtUserToDev(x2, y1, &x, &y);
  506.   points.push_back(Vertex<short>(x,y));
  507.   cvtUserToDev(x2, y2, &x, &y);
  508.   points.push_back(Vertex<short>(x,y));
  509.   cvtUserToDev(x1, y2, &x, &y);
  510.   points.push_back(Vertex<short>(x,y));
  511.   points.push_back(orig);
  512.   gfx.polydraw(points);
  513. }
  514.  
  515. void AOutputDev::saveState(GfxState *state) {
  516.   DB(printf("\nsave state\n");)
  517.   clipStack.push_back(clipRegion);
  518. }
  519.  
  520. void AOutputDev::restoreState(GfxState *state) {
  521.   DB(printf("\nrestore state\n");)
  522.   clipRegion = clipStack.back();
  523.   clipStack.pop_back();
  524.   curColor = Gulong(-1);
  525.   updateAll(state);
  526.   installClip();
  527. }
  528.  
  529. void AOutputDev::updateAll(GfxState *state) {
  530.   updateLineAttrs(state, gTrue);
  531.   updateFlatness(state);
  532.   updateMiterLimit(state);
  533.   updateFillColor(state);
  534.   updateStrokeColor(state);
  535.   updateFont(state);
  536. }
  537.  
  538. void AOutputDev::updateCTM(GfxState *state, double m11, double m12,
  539.                double m21, double m22, double m31, double m32) {
  540.   updateLineAttrs(state, gTrue);
  541. }
  542.  
  543. void AOutputDev::updateLineDash(GfxState *state) {
  544.   updateLineAttrs(state, gTrue);
  545. }
  546.  
  547. void AOutputDev::updateFlatness(GfxState *state) {
  548.   flatness = state->getFlatness();
  549. }
  550.  
  551. void AOutputDev::updateLineJoin(GfxState *state) {
  552.   updateLineAttrs(state, gFalse);
  553. }
  554.  
  555. void AOutputDev::updateLineCap(GfxState *state) {
  556.   updateLineAttrs(state, gFalse);
  557. }
  558.  
  559. // unimplemented
  560. void AOutputDev::updateMiterLimit(GfxState *state) {
  561. }
  562.  
  563. void AOutputDev::updateLineWidth(GfxState *state) {
  564.   updateLineAttrs(state, gFalse);
  565. }
  566.  
  567. void AOutputDev::updateLineAttrs(GfxState *state, GBool updateDash) {
  568.   CapStyle cap;
  569.   JoinStyle join;
  570.   double *dashPattern;
  571.   int dashLength;
  572.   double dashStart;
  573.   int i;
  574.  
  575.   lineWidth = state->getTransformedLineWidth();
  576.   switch (state->getLineCap()) {
  577.   case 0: cap = CapButt; break;
  578.   case 1: cap = CapRound; break;
  579.   case 2: cap = CapProjecting; break;
  580.   default:
  581.     error(-1, "Bad line cap style (%d)", state->getLineCap());
  582.     cap = CapButt;
  583.     break;
  584.   }
  585.   capStyle = cap;
  586.   switch (state->getLineJoin()) {
  587.   case 0: join = JoinMiter; break;
  588.   case 1: join = JoinRound; break;
  589.   case 2: join = JoinBevel; break;
  590.   default:
  591.     error(-1, "Bad line join style (%d)", state->getLineJoin());
  592.     join = JoinMiter;
  593.     break;
  594.   }
  595.   joinStyle = join;
  596.   state->getLineDash(&dashPattern, &dashLength, &dashStart);
  597.   /*XSetLineAttributes(display, strokeGC, xoutRound(width),
  598.              dashLength > 0 ? LineOnOffDash : LineSolid,
  599.              cap, join);*/
  600.   if (updateDash) {
  601.     unsigned mask = 0xffff;
  602.     short start = 0;
  603.     if (dashLength > 0) {
  604.       int n = 16;
  605.       for (i = 0; i < dashLength; ++i) {
  606.     int k = xoutRound(state->transformWidth(dashPattern[i]));
  607.     if (k < n) {
  608.       mask ^= (1 << n-k) - 1;
  609.       n -= k;
  610.     } else
  611.       break;
  612.       }
  613.       start = xoutRound(dashStart);
  614.     }
  615.     gfx.set_line_ptrn(mask, start);
  616.   }
  617. }
  618.  
  619. void AOutputDev::updateFillColor(GfxState *state) {
  620.   fillColor = findColor(state->getFillColor());
  621.   DB(printf("\nfill color=%d\n",fillColor);)
  622. }
  623.  
  624. void AOutputDev::updateStrokeColor(GfxState *state) {
  625.   strokeColor = findColor(state->getStrokeColor());
  626.   DB(printf("\nstroke color=%d\n",strokeColor);)
  627. }
  628.  
  629. void AOutputDev::updateFont(GfxState *state) {
  630.   double m11, m12, m21, m22;
  631.  
  632.   if (!(gfxFont = state->getFont())) {
  633.     font = NULL;
  634.     return;
  635.   }
  636.   state->getFontTransMat(&m11, &m12, &m21, &m22);
  637.   m11 *= state->getHorizScaling();
  638.   m21 *= state->getHorizScaling();
  639.   font = fontCache->getFont(gfxFont, m11, m12, m21, m22);
  640.   if (font)
  641.     gfx.setfont(font->getTextFont());
  642.   else {
  643.       DB(printf("\nupdateFont failed.\n");)
  644.   }
  645. }
  646.  
  647. void AOutputDev::stroke(GfxState *state) {
  648.  
  649.   if (curColor != strokeColor) {
  650.     curColor = strokeColor;
  651.     gfx.setapen(curColor);
  652.   }
  653.  
  654.   // transform points
  655.   PArea<double> area(convertPath(state));
  656.  
  657.   // draw each subpath
  658.   if (lineWidth <= 1.5) {
  659.  
  660.     PArea<short> iarea(xoutRound(area));
  661.     for (PArea<short>::const_iterator p(iarea.begin()); p != iarea.end(); ++p)
  662.       if(!p->empty()) {
  663.     DB(printf("\nstroke(%d)\n",p->size());)
  664.     gfx.polydraw(*p);
  665.       }
  666.  
  667.   } else {
  668.  
  669.     for (PArea<double>::const_iterator q(area.begin()); q != area.end(); ++q) {
  670.       Polygon<double>::const_iterator p(q->begin());
  671.       for (int k = 1; k < q->size(); ++k, ++p) {
  672.     if (floor(p[0].x + 0.5) == floor(p[1].x + 0.5)) {
  673.       DB(printf("\nthickVstroke\n");)
  674.       short x1 = xoutRound(p[0].x - lineWidth/2);
  675.       short x2 = xoutRound(p[0].x + lineWidth/2);
  676.       short y1 = xoutRound(p[0].y);
  677.       short y2 = xoutRound(p[1].y);
  678.       if (y1 > y2) {
  679.           short t = y1;
  680.           y1 = y2;
  681.           y2 = t;
  682.       }
  683.       gfx.rectfill(x1,y1,x2,y2);
  684.     } else if (floor(p[0].y + 0.5) == floor(p[1].y + 0.5)) {
  685.       DB(printf("\nthickHstroke\n");)
  686.       short y1 = xoutRound(p[0].y - lineWidth/2);
  687.       short y2 = xoutRound(p[0].y + lineWidth/2);
  688.       short x1 = xoutRound(p[0].x);
  689.       short x2 = xoutRound(p[1].x);
  690.       if (x1 > x2) {
  691.           short t = x1;
  692.           x1 = x2;
  693.           x2 = t;
  694.       }
  695.       gfx.rectfill(x1,y1,x2,y2);
  696.     } else {
  697.       DB(printf("\nthickstroke\n");)
  698.       double w = lineWidth/2;
  699.       double dx = p[1].x - p[0].x;
  700.       double dy = p[1].y - p[0].y;
  701.       double l = sqrt(dx*dx+dy*dy);
  702.       double c = dx/l;
  703.       double s = dy/l;
  704.       Polygon<short> pts;
  705.       pts.reserve(4);
  706.       pts.push_back(Vertex<short>(xoutRound(p[0].x - w*s),
  707.                       xoutRound(p[0].y - w*c)));
  708.       pts.push_back(Vertex<short>(xoutRound(p[1].x - w*s),
  709.                       xoutRound(p[1].y - w*c)));
  710.       pts.push_back(Vertex<short>(xoutRound(p[1].x + w*s),
  711.                       xoutRound(p[1].y + w*c)));
  712.       pts.push_back(Vertex<short>(xoutRound(p[0].x + w*s),
  713.                       xoutRound(p[0].y + w*c)));
  714.       AGfx::AreaDrawer(gfx).add(pts);
  715.     }
  716.       }
  717.     }
  718.   }
  719. }
  720.  
  721. void AOutputDev::fill(GfxState *state) {
  722.   DB(printf("\nfill\n");)
  723.   doFill(state, PArea<double>::winding);
  724. }
  725.  
  726. void AOutputDev::eoFill(GfxState *state) {
  727.   DB(printf("\neofill\n");)
  728.   doFill(state, PArea<double>::even_odd);
  729. }
  730.  
  731. void AOutputDev::doFill(GfxState *state, int rule) {
  732.  
  733.   if (curColor != fillColor) {
  734.     curColor = fillColor;
  735.     gfx.setapen(curColor);
  736.   }
  737.  
  738.   // transform points
  739.   PArea<short> area;
  740.   {
  741.     PArea<double> t(convertPath(state));
  742.     t.rule(PArea<double>::Rule(rule));
  743.     t.reduce();
  744.     if(rule == PArea<double>::winding)
  745.       t = t.make_convex_union();
  746.     area = xoutRound(t);
  747.   }
  748.  
  749.   /*for (PArea<short>::const_iterator p(area.begin()); p != area.end(); ++p)
  750.       if(!p->empty()) {
  751.     Polygon<short> q(*p);
  752.     DB(printf("\nfill(%d)\n",q.size());)
  753.     q.push_back(*q.begin());
  754.     gfx.polydraw(q);
  755.       }*/
  756.  
  757.   // fill them
  758.   if(area.is_disjoint_rectangle_union()) {
  759.     for(PArea<short>::const_iterator p(area.begin()); p != area.end(); ++p) {
  760.       if(!p->empty()) {
  761.     Polygon<short>::const_iterator points(p->begin());
  762.     short x1,x2,y1,y2;
  763.     if(points[0].x>points[2].x) {
  764.         x1=points[2].x;
  765.         x2=points[0].x;
  766.     } else {
  767.         x1=points[0].x;
  768.         x2=points[2].x;
  769.     }
  770.     if(points[0].y>points[2].y) {
  771.         y1=points[2].y;
  772.         y2=points[0].y;
  773.     } else {
  774.         y1=points[0].y;
  775.         y2=points[2].y;
  776.     }
  777.     DB(printf("rectfill: (%d,%d)-(%d,%d)\n",x1,y1,x2,y2);)
  778.     gfx.rectfill(x1,y1,x2,y2);
  779.       }
  780.     }
  781.   } else {
  782.     DB(printf("polyfill:");)
  783.     AGfx::AreaDrawer ad(gfx);
  784.     for(PArea<short>::const_iterator p(area.begin()); p != area.end(); ++p)
  785.       ad.add(*p);
  786.   }
  787.  
  788. }
  789.  
  790. void AOutputDev::clip(GfxState *state) {
  791.   DB(printf("\nclip\n");)
  792.   doClip(state, PArea<double>::winding);
  793. }
  794.  
  795. void AOutputDev::eoClip(GfxState *state) {
  796.   DB(printf("\neoclip\n");)
  797.   doClip(state, PArea<double>::even_odd);
  798. }
  799.  
  800. void AOutputDev::doClip(GfxState *state, int rule) {
  801.  
  802.   // transform points
  803.   PArea<double> area(convertPath(state));
  804.   area.rule(PArea<double>::Rule(rule));
  805.  
  806.   // open closed paths
  807.   area.reduce();
  808.  
  809.   area = area.make_convex_union();
  810.  
  811.   // intersect with clipping region
  812.   clipRegion = clipRegion & area;
  813.   clipRegion.reduce();
  814.  
  815.   installClip();
  816. }
  817.  
  818. void AOutputDev::installClip() {
  819.   PArea<short> c(xoutRound(clipRegion));
  820.   gfx.clearclip();
  821.   for(PArea<short>::const_iterator p(c.begin()); p != c.end(); ++p) {
  822.     if(!p->empty()) {
  823.       if(p->is_rectangle()) {
  824.     Polygon<short>::const_iterator points(p->begin());
  825.     short x1,x2,y1,y2;
  826.     if(points[0].x>points[2].x) {
  827.         x1=points[2].x;
  828.         x2=points[0].x;
  829.     } else {
  830.         x1=points[0].x;
  831.         x2=points[2].x;
  832.     }
  833.     if(points[0].y>points[2].y) {
  834.         y1=points[2].y;
  835.         y2=points[0].y;
  836.     } else {
  837.         y1=points[0].y;
  838.         y2=points[2].y;
  839.     }
  840.     DB(printf("cliprect: (%d,%d)-(%d,%d)\n",x1,y1,x2,y2);)
  841.     gfx.rectclip(x1,y1,x2,y2);
  842.       } else {
  843.     DB(printf("clippoly(%d):\n",p->size());)
  844.     gfx.polyclip(*p);
  845.       }
  846.     }
  847.   }
  848.   gfx.installclip();
  849. }
  850.  
  851. //
  852. // Transform points in the path and convert curves to line segments.
  853. //
  854. PArea<double> AOutputDev::convertPath(GfxState *state) {
  855.   DB(printf("path[");)
  856.   PArea<double> res;
  857.  
  858.   // get path and number of subpaths
  859.   GfxPath *path = state->getPath();
  860.   int n = path->getNumSubpaths();
  861.  
  862.   // do each subpath
  863.   for (int i = 0; i < n; ++i)
  864.     res.push_back(convertSubpath(state, path->getSubpath(i)));
  865.  
  866.   DB(printf("]\n");)
  867.   return res;
  868. }
  869.  
  870. //
  871. // Transform points in a single subpath and convert curves to line
  872. // segments.
  873. //
  874. Polygon<double> AOutputDev::convertSubpath(GfxState *state, GfxSubpath *subpath) {
  875.   DB(printf("[");)
  876.   DB(int k = 0;)
  877.   double x0, y0, x1, y1, x2, y2, x3, y3;
  878.   int m, i;
  879.   Polygon<double> poly;
  880.  
  881.   m = subpath->getNumPoints();
  882.   i = 0;
  883.   while (i < m) {
  884.     if (i >= 1 && subpath->getCurve(i)) {
  885.       state->transform(subpath->getX(i-1), subpath->getY(i-1), &x0, &y0);
  886.       state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
  887.       state->transform(subpath->getX(i+1), subpath->getY(i+1), &x2, &y2);
  888.       state->transform(subpath->getX(i+2), subpath->getY(i+2), &x3, &y3);
  889.       doCurve(poly, x0, y0, x1, y1, x2, y2, x3, y3);
  890.       i += 3;
  891.     } else {
  892.       state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
  893.       DB(if(!(k++&3))printf("\n");printf(" (%g,%g)",x1,y1);)
  894.       poly.push_back(Vertex<double>(x1, y1));
  895.       ++i;
  896.     }
  897.   }
  898.   DB(printf(" ]\n");)
  899.   return poly;
  900. }
  901.  
  902. //
  903. // Subdivide a Bezier curve.  This uses floating point to avoid
  904. // propagating rounding errors.  (The curves look noticeably more
  905. // jagged with integer arithmetic.)
  906. //
  907. void AOutputDev::doCurve(Polygon<double>& poly,
  908.              double x0, double y0, double x1, double y1,
  909.              double x2, double y2, double x3, double y3) {
  910.   double x[(1<<maxCurveSplits)+1][3];
  911.   double y[(1<<maxCurveSplits)+1][3];
  912.   int next[1<<maxCurveSplits];
  913.   int p1, p2, p3;
  914.   double xx1, yy1, xx2, yy2;
  915.   double dx, dy, mx, my, d1, d2;
  916.   double xl0, yl0, xl1, yl1, xl2, yl2;
  917.   double xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3;
  918.   double xh, yh;
  919.   double flat;
  920.  
  921.   flat = (double)(flatness * flatness);
  922.   if (flat < 1)
  923.     flat = 1;
  924.  
  925.   // initial segment
  926.   p1 = 0;
  927.   p2 = 1<<maxCurveSplits;
  928.   x[p1][0] = x0;  y[p1][0] = y0;
  929.   x[p1][1] = x1;  y[p1][1] = y1;
  930.   x[p1][2] = x2;  y[p1][2] = y2;
  931.   x[p2][0] = x3;  y[p2][0] = y3;
  932.   next[p1] = p2;
  933.  
  934.   while (p1 < (1<<maxCurveSplits)) {
  935.  
  936.     // get next segment
  937.     xl0 = x[p1][0];  yl0 = y[p1][0];
  938.     xx1 = x[p1][1];  yy1 = y[p1][1];
  939.     xx2 = x[p1][2];  yy2 = y[p1][2];
  940.     p2 = next[p1];
  941.     xr3 = x[p2][0];  yr3 = y[p2][0];
  942.  
  943.     // compute distances from control points to midpoint of the
  944.     // straight line (this is a bit of a hack, but it's much faster
  945.     // than computing the actual distances to the line)
  946.     mx = (xl0 + xr3) * 0.5;
  947.     my = (yl0 + yr3) * 0.5;
  948.     dx = xx1 - mx;
  949.     dy = yy1 - my;
  950.     d1 = dx*dx + dy*dy;
  951.     dx = xx2 - mx;
  952.     dy = yy2 - my;
  953.     d2 = dx*dx + dy*dy;
  954.  
  955.     // if curve is flat enough, or no more divisions allowed then
  956.     // add the straight line segment
  957.     if (p2 - p1 <= 1 || (d1 <= flat && d2 <= flat)) {
  958.       DB(printf(" (%g,%g)",xr3,yr3);)
  959.       poly.push_back(Vertex<double>(xr3, yr3));
  960.       p1 = p2;
  961.  
  962.     // otherwise, subdivide the curve
  963.     } else {
  964.       xl1 = (xl0 + xx1) * 0.5;
  965.       yl1 = (yl0 + yy1) * 0.5;
  966.       xh = (xx1 + xx2) * 0.5;
  967.       yh = (yy1 + yy2) * 0.5;
  968.       xl2 = (xl1 + xh) * 0.5;
  969.       yl2 = (yl1 + yh) * 0.5;
  970.       xr2 = (xx2 + xr3) * 0.5;
  971.       yr2 = (yy2 + yr3) * 0.5;
  972.       xr1 = (xh + xr2) * 0.5;
  973.       yr1 = (yh + yr2) * 0.5;
  974.       xr0 = (xl2 + xr1) * 0.5;
  975.       yr0 = (yl2 + yr1) * 0.5;
  976.  
  977.       // add the new subdivision points
  978.       p3 = (p1 + p2) / 2;
  979.       x[p1][1] = xl1;  y[p1][1] = yl1;
  980.       x[p1][2] = xl2;  y[p1][2] = yl2;
  981.       next[p1] = p3;
  982.       x[p3][0] = xr0;  y[p3][0] = yr0;
  983.       x[p3][1] = xr1;  y[p3][1] = yr1;
  984.       x[p3][2] = xr2;  y[p3][2] = yr2;
  985.       next[p3] = p2;
  986.     }
  987.   }
  988. }
  989.  
  990. void AOutputDev::beginString(GfxState *state, GString *s) {
  991.   text->beginString(state, s, font ? font->isHex() : gFalse);
  992. }
  993.  
  994. void AOutputDev::endString(GfxState *state) {
  995.   text->endString();
  996. }
  997.  
  998. void AOutputDev::drawChar(GfxState *state, double x, double y,
  999.               double dx, double dy, Guchar c) {
  1000.   Gushort c1;
  1001.   char *p;
  1002.   int n, i;
  1003.   double x1, y1;
  1004.   double tx;
  1005.  
  1006.   text->addChar(state, x, y, dx, dy, c);
  1007.  
  1008.   if (!font || c==13)
  1009.     return;
  1010.  
  1011.   // check for invisible text -- this is used by Acrobat Capture
  1012.   if ((state->getRender() & 3) == 3)
  1013.     return;
  1014.  
  1015.   DB(if(c>=32)printf("%c",c);else printf(" char(%x) ",c);)
  1016.   if (state->getRender() & 1) {
  1017.       if (curColor != strokeColor) {
  1018.       curColor = strokeColor;
  1019.       gfx.setapen(curColor);
  1020.       }
  1021.   } else {
  1022.       if (curColor != fillColor) {
  1023.       curColor = fillColor;
  1024.       gfx.setapen(curColor);
  1025.       }
  1026.   }
  1027.  
  1028.   state->transform(x, y, &x1, &y1);
  1029.   c1 = font->mapChar(c);
  1030.   if (c1 <= lastRegularChar)
  1031.     gfx.addchar(xoutRound(x1), xoutRound(y1), c1);
  1032.   else if (c1 <= lastSubstChar) {
  1033.     char c = (char)substChars[c1 - firstSubstChar];
  1034.     gfx.addchar(xoutRound(x1), xoutRound(y1), c);
  1035.   } else if (c1 <= lastConstrChar) {
  1036.     //~ need to deal with rotated text here
  1037.     switch (c1 - firstConstrChar) {
  1038.     case 0: // bullet
  1039.       tx = 0.25 * state->getTransformedFontSize() * gfxFont->getWidth(c);
  1040.       y1 -= 0.3 * state->getTransformedFontSize() * gfxFont->getWidth(c);
  1041.       //***y1 -= 0.4 * font->getTextFont()->tf_Baseline;
  1042.       gfx.rectfill(xoutRound(x1 + tx), xoutRound(y1 - tx),
  1043.            xoutRound(x1 + 3 * tx), xoutRound(y1 + tx));
  1044.       break;
  1045.     case 1: // trademark
  1046. //~ this should use a smaller font
  1047. //      tx = state->getTransformedFontSize() *
  1048. //           (gfxFont->getWidth(c) -
  1049. //            gfxFont->getWidth(font->revCharMap('M')));
  1050.       tx = 0.9 * state->getTransformedFontSize() *
  1051.        gfxFont->getWidth(font->revMapChar('T'));
  1052.       y1 -= 0.33 * state->getTransformedFontSize() *
  1053.         gfxFont->getWidth(font->revMapChar('T'));
  1054.       //***y1 -= 0.33 * (double)font->getTextFont()->tf_Baseline;
  1055.       gfx.addchar(xoutRound(x1), xoutRound(y1), 'T');
  1056.       x1 += tx;
  1057.       gfx.addchar(xoutRound(x1), xoutRound(y1), 'M');
  1058.       break;
  1059.     }
  1060.   } else if (c1 <= lastMultiChar) {
  1061.     p = multiChars[c1 - firstMultiChar];
  1062.     n = strlen(p);
  1063.     tx = gfxFont->getWidth(c);
  1064.     tx -= gfxFont->getWidth(font->revMapChar(p[n-1]));
  1065.     tx = tx * state->getTransformedFontSize() / (double)(n - 1);
  1066.     for (i = 0; i < n; ++i) {
  1067.       gfx.addchar(xoutRound(x1), xoutRound(y1), p[i]);
  1068.       x1 += tx;
  1069.     }
  1070.   }
  1071. }
  1072.  
  1073. void AOutputDev::drawChar16(GfxState *state, double x, double y,
  1074.                 double dx, double dy, int c) {
  1075.   DB(printf("\ndrawchar16\n");)
  1076. }
  1077.  
  1078. // These four functions are defined to work around a bug
  1079. // in egcs for 68k: it gets confused when trying to inline
  1080. // calls to Read/WritePixelArrays(8).
  1081. void getimage(AGfx& gfx,AGfx::Image& im,short x,short y) {
  1082.     gfx.get_image(im, x, y);
  1083. }
  1084.  
  1085. void getimage(AGfx& gfx,AGfx::Image24& im,short x,short y) {
  1086.     gfx.get_image(im, x, y);
  1087. }
  1088.  
  1089. void putimage(AGfx& gfx,AGfx::Image& im,short x,short y) {
  1090.     gfx.put_image(im, x, y);
  1091. }
  1092.  
  1093. void putimage(AGfx& gfx,AGfx::Image24& im,short x,short y) {
  1094.     gfx.put_image(im, x, y);
  1095. }
  1096.  
  1097. void AOutputDev::drawImageMask(GfxState *state, Stream *str,
  1098.                    int width, int height, GBool invert,
  1099.                    GBool inlineImg) {
  1100.   int x0, y0;                   // top left corner of image
  1101.   int w0, h0, w1, h1;           // size of image
  1102.   //int x2, y2;
  1103.   //int w2, h2;
  1104.   double xt, yt, wt, ht;
  1105.   GBool rotate, xFlip, yFlip;
  1106.   int x, y;
  1107.   int ix, iy;
  1108.   int px1, px2, qx, dx;
  1109.   int py1, py2, qy, dy;
  1110.   Guchar pixBuf;
  1111.   int i, j;
  1112.  
  1113.   // get image position and size
  1114.   state->transform(0, 0, &xt, &yt);
  1115.   state->transformDelta(1, 1, &wt, &ht);
  1116.   if (wt > 0) {
  1117.     x0 = xoutRound(xt);
  1118.     w0 = xoutRound(wt);
  1119.   } else {
  1120.     x0 = xoutRound(xt + wt);
  1121.     w0 = xoutRound(-wt);
  1122.   }
  1123.   if (ht > 0) {
  1124.     y0 = xoutRound(yt);
  1125.     h0 = xoutRound(ht);
  1126.   } else {
  1127.     y0 = xoutRound(yt + ht);
  1128.     h0 = xoutRound(-ht);
  1129.   }
  1130.   state->transformDelta(1, 0, &xt, &yt);
  1131.   rotate = fabs(xt) < fabs(yt);
  1132.   if (rotate) {
  1133.     w1 = h0;
  1134.     h1 = w0;
  1135.     xFlip = ht < 0;
  1136.     yFlip = wt > 0;
  1137.   } else {
  1138.     w1 = w0;
  1139.     h1 = h0;
  1140.     xFlip = wt < 0;
  1141.     yFlip = ht > 0;
  1142.   }
  1143.  
  1144.   // check for tiny (zero width or height) images
  1145.   if (w0 == 0 || h0 == 0) {
  1146.     j = height * ((width + 7) / 8);
  1147.     str->reset();
  1148.     for (i = 0; i < j; ++i)
  1149.       str->getChar();
  1150.     return;
  1151.   }
  1152.  
  1153.   // Bresenham parameters
  1154.   px1 = w1 / width;
  1155.   px2 = w1 - px1 * width;
  1156.   py1 = h1 / height;
  1157.   py2 = h1 - py1 * height;
  1158.  
  1159.   // initialize the image stream
  1160.   str->resetImage(width, 1, 1);
  1161.  
  1162.   // first line (column)
  1163.   y = yFlip ? h1 - 1 : 0;
  1164.   qy = 0;
  1165.  
  1166.   if(trueColor) {
  1167.     Gulong rgb = colorTable.find_rgb(fillColor);
  1168.     Color color;
  1169.     color.r = UBYTE(rgb >> 16);
  1170.     color.g = UBYTE(rgb >> 8);
  1171.     color.b = UBYTE(rgb);
  1172.  
  1173.     // allocate XImage
  1174.     AGfx::Image24Ptr image(gfx.allocate_image24(w0,h0));
  1175.     /*if (x0 + w0 > pixmapW)
  1176.       w2 = pixmapW - x0;
  1177.     else
  1178.       w2 = w0;
  1179.     if (x0 < 0) {
  1180.       x2 = -x0;
  1181.       w2 += x0;
  1182.       x0 = 0;
  1183.     } else {
  1184.       x2 = 0;
  1185.     }
  1186.     if (y0 + h0 > pixmapH)
  1187.       h2 = pixmapH - y0;
  1188.     else
  1189.       h2 = h0;
  1190.     if (y0 < 0) {
  1191.       y2 = -y0;
  1192.       h2 += y0;
  1193.       y0 = 0;
  1194.     } else {
  1195.       y2 = 0;
  1196.     }
  1197.     XGetSubImage(display, pixmap, x0, y0, w2, h2, (1 << depth) - 1, ZPixmap,
  1198.          image, x2, y2);*/
  1199.     getimage(gfx, *image, x0, y0);
  1200.  
  1201.     // read image
  1202.     for (i = 0; i < height; ++i) {
  1203.  
  1204.       // vertical (horizontal) Bresenham
  1205.       dy = py1;
  1206.       if ((qy += py2) >= height) {
  1207.     ++dy;
  1208.     qy -= height;
  1209.       }
  1210.  
  1211.       // drop a line (column)
  1212.       if (dy == 0) {
  1213.     str->skipImageLine();
  1214.  
  1215.       } else {
  1216.  
  1217.     // first column (line)
  1218.     x = xFlip ? w1 - 1 : 0;
  1219.     qx = 0;
  1220.  
  1221.     // for each column (line)...
  1222.     for (j = 0; j < width; ++j) {
  1223.  
  1224.       // horizontal (vertical) Bresenham
  1225.       dx = px1;
  1226.       if ((qx += px2) >= width) {
  1227.         ++dx;
  1228.         qx -= width;
  1229.       }
  1230.  
  1231.       // get image pixel
  1232.       str->getImagePixel(&pixBuf);
  1233.       if (invert)
  1234.         pixBuf ^= 1;
  1235.  
  1236.       // draw image pixel
  1237.       if (dx > 0 && pixBuf == 0) {
  1238.         if (dx == 1 && dy == 1) {
  1239.           if (rotate)
  1240.         image->put(y, x, color);
  1241.           else
  1242.         image->put(x, y, color);
  1243.         } else {
  1244.           for (ix = 0; ix < dx; ++ix) {
  1245.         for (iy = 0; iy < dy; ++iy) {
  1246.           if (rotate)
  1247.             image->put(yFlip ? y - iy : y + iy,
  1248.                    xFlip ? x - ix : x + ix, color);
  1249.           else
  1250.             image->put(xFlip ? x - ix : x + ix,
  1251.                    yFlip ? y - iy : y + iy, color);
  1252.         }
  1253.           }
  1254.         }
  1255.       }
  1256.  
  1257.       // next column (line)
  1258.       if (xFlip)
  1259.         x -= dx;
  1260.       else
  1261.         x += dx;
  1262.     }
  1263.       }
  1264.  
  1265.       // next line (column)
  1266.       if (yFlip)
  1267.     y -= dy;
  1268.       else
  1269.     y += dy;
  1270.     }
  1271.  
  1272.     // blit the image into the pixmap
  1273.     DB(printf("\nimagemask24(%d,%d)->(%d,%d,%d,%d)\n",width,height,x0,y0,w0,h0);)
  1274.     putimage(gfx, *image, x0, y0);
  1275.   } else {
  1276.     // Inefficient hack. I should add a get_color() memberin AGfx...
  1277.     Gulong color;
  1278.     {
  1279.     AGfx::ColorTable table(1);
  1280.     ColorEntry* p=table.data();
  1281.     Gulong rgb = colorTable.find_rgb(fillColor);
  1282.     p->color.r = UBYTE(rgb >> 16) * 0x01010101;
  1283.     p->color.g = UBYTE(rgb >> 8) * 0x01010101;
  1284.     p->color.b = UBYTE(rgb) * 0x01010101;
  1285.     gfx.get_colors(table,1);
  1286.     color = table.data()->index;
  1287.     }
  1288.  
  1289.     // allocate XImage
  1290.     AGfx::ImagePtr image(gfx.allocate_image(w0,h0));
  1291.     /*if (x0 + w0 > pixmapW)
  1292.       w2 = pixmapW - x0;
  1293.     else
  1294.       w2 = w0;
  1295.     if (x0 < 0) {
  1296.       x2 = -x0;
  1297.       w2 += x0;
  1298.       x0 = 0;
  1299.     } else {
  1300.       x2 = 0;
  1301.     }
  1302.     if (y0 + h0 > pixmapH)
  1303.       h2 = pixmapH - y0;
  1304.     else
  1305.       h2 = h0;
  1306.     if (y0 < 0) {
  1307.       y2 = -y0;
  1308.       h2 += y0;
  1309.       y0 = 0;
  1310.     } else {
  1311.       y2 = 0;
  1312.     }
  1313.     XGetSubImage(display, pixmap, x0, y0, w2, h2, (1 << depth) - 1, ZPixmap,
  1314.          image, x2, y2);*/
  1315.     getimage(gfx, *image, x0, y0);
  1316.  
  1317.     // read image
  1318.     for (i = 0; i < height; ++i) {
  1319.  
  1320.       // vertical (horizontal) Bresenham
  1321.       dy = py1;
  1322.       if ((qy += py2) >= height) {
  1323.     ++dy;
  1324.     qy -= height;
  1325.       }
  1326.  
  1327.       // drop a line (column)
  1328.       if (dy == 0) {
  1329.     str->skipImageLine();
  1330.  
  1331.       } else {
  1332.  
  1333.     // first column (line)
  1334.     x = xFlip ? w1 - 1 : 0;
  1335.     qx = 0;
  1336.  
  1337.     // for each column (line)...
  1338.     for (j = 0; j < width; ++j) {
  1339.  
  1340.       // horizontal (vertical) Bresenham
  1341.       dx = px1;
  1342.       if ((qx += px2) >= width) {
  1343.         ++dx;
  1344.         qx -= width;
  1345.       }
  1346.  
  1347.       // get image pixel
  1348.       str->getImagePixel(&pixBuf);
  1349.       if (invert)
  1350.         pixBuf ^= 1;
  1351.  
  1352.       // draw image pixel
  1353.       if (dx > 0 && pixBuf == 0) {
  1354.         if (dx == 1 && dy == 1) {
  1355.           if (rotate)
  1356.         image->put(y, x, color);
  1357.           else
  1358.         image->put(x, y, color);
  1359.         } else {
  1360.           for (ix = 0; ix < dx; ++ix) {
  1361.         for (iy = 0; iy < dy; ++iy) {
  1362.           if (rotate)
  1363.             image->put(yFlip ? y - iy : y + iy,
  1364.                    xFlip ? x - ix : x + ix, color);
  1365.           else
  1366.             image->put(xFlip ? x - ix : x + ix,
  1367.                    yFlip ? y - iy : y + iy, color);
  1368.         }
  1369.           }
  1370.         }
  1371.       }
  1372.  
  1373.       // next column (line)
  1374.       if (xFlip)
  1375.         x -= dx;
  1376.       else
  1377.         x += dx;
  1378.     }
  1379.       }
  1380.  
  1381.       // next line (column)
  1382.       if (yFlip)
  1383.     y -= dy;
  1384.       else
  1385.     y += dy;
  1386.     }
  1387.  
  1388.     // blit the image into the pixmap
  1389.     DB(printf("\nimagemask(%d,%d)->(%d,%d,%d,%d)\n",width,height,x0,y0,w0,h0);)
  1390.     putimage(gfx,*image, x0, y0);
  1391.   }
  1392. }
  1393.  
  1394. #if 1
  1395.  
  1396. // Color quantization code, to display true color embedded pictures
  1397. // on colormap screens.
  1398. // Not sure where I got that algorithm from. Maybe the newsgroup
  1399. // comp.graphics.algorithm, maybe Xv, maybe somewhere else...
  1400.  
  1401. struct ColorDiff32 {
  1402.     LONG r, g, b;
  1403. };
  1404.  
  1405. struct col_hist {
  1406.   Color color;
  1407.   int value;
  1408. };
  1409.  
  1410. static col_hist* get_color_hist(const Color* p,int size,int maxcols,int& hist_size,UBYTE mask) {
  1411.  
  1412.   class hash_table {
  1413.     enum { hash_table_size = 6553 };
  1414.     struct node {
  1415.       node* next;
  1416.       col_hist ch;
  1417.     };
  1418.     static bool equal(const Color& c1,const Color& c2,UBYTE mask) {
  1419.       return (((c1.r^c2.r)|(c1.g^c2.g)|(c1.b^c2.b))&mask)==0;
  1420.     }
  1421.     static int hash(const Color& c, UBYTE m) {
  1422.       return ((c.r & m) * 33023 +
  1423.           (c.g & m) * 30013 +
  1424.           (c.b & m) * 27011) % hash_table_size;
  1425.     }
  1426.   public:
  1427.     class iterator {
  1428.       friend class hash_table;
  1429.     public:
  1430.       bool operator == (const iterator& i) const { return q == i.q; }
  1431.       bool operator != (const iterator& i) const { return q != i.q; }
  1432.       col_hist& operator * () const { return q->ch; }
  1433.       iterator& operator ++ () {
  1434.     q=q->next;
  1435.     if(!q) {
  1436.       while (++p != end && !*p);
  1437.       if (p != end)
  1438.         q=*p;
  1439.     }
  1440.     return *this;
  1441.       }
  1442.     private:
  1443.       node** p;
  1444.       node* q;
  1445.       node** end;
  1446.     };
  1447.  
  1448.     hash_table() : nodes(new node* [hash_table_size]),sz(0) {
  1449.       memset(nodes,0,sizeof(*nodes)*hash_table_size);
  1450.     }
  1451.     ~hash_table() {
  1452.       for(int k = 0; k < hash_table_size; ++k) {
  1453.     node* p = nodes[k];
  1454.     while(p) {
  1455.       node* q = p->next;
  1456.       delete p;
  1457.       p = q;
  1458.     }
  1459.       }
  1460.       delete [] nodes;
  1461.     }
  1462.  
  1463.     int size() const { return sz; }
  1464.  
  1465.     iterator begin() {
  1466.       iterator i;
  1467.       i.p = nodes;
  1468.       i.end = nodes + hash_table_size;
  1469.       while (!*i.p && ++i.p != i.end);
  1470.       if (i.p != i.end)
  1471.     i.q = *i.p;
  1472.       else
  1473.     i.q = NULL;
  1474.       return i;
  1475.     }
  1476.  
  1477.     iterator end() {
  1478.     iterator i;
  1479.     i.q = NULL;
  1480.     return i;
  1481.     }
  1482.  
  1483.     col_hist& get(const Color& c,UBYTE mask) {
  1484.       int h = hash(c, mask);
  1485.       for(node* hn = nodes[h]; hn; hn = hn->next)
  1486.     if(equal(c, hn->ch.color, mask))
  1487.        return hn->ch;
  1488.       ++sz;
  1489.       node* hn = new node;
  1490.       hn->ch.color = c;
  1491.       hn->ch.value = 0;
  1492.       hn->next = nodes[h];
  1493.       nodes[h] = hn;
  1494.       return hn->ch;
  1495.     }
  1496.   private:
  1497.     node** nodes;
  1498.     int sz;
  1499.   };
  1500.  
  1501.  
  1502.   hash_table ht;
  1503.  
  1504.   while (--size >= 0) {
  1505.     col_hist& hn = ht.get(*p++, mask);
  1506.     ++hn.value;
  1507.     if (ht.size() > maxcols)
  1508.       return NULL;
  1509.   }
  1510.  
  1511.   hist_size = ht.size();
  1512.   col_hist* ch = new col_hist [hist_size];
  1513.   col_hist* q = ch;
  1514.   hash_table::iterator e(ht.end());
  1515.   for(hash_table::iterator i(ht.begin()); i != e; ++i)
  1516.       *q++ = *i;
  1517.  
  1518.   return ch;
  1519. }
  1520.  
  1521. static int redcmp(const void *p1, const void *p2) {
  1522.     const col_hist *ch1 = (const col_hist *)p1;
  1523.     const col_hist *ch2 = (const col_hist *)p2;
  1524.     return ch1->color.r - ch2->color.r;
  1525. }
  1526. static int greencmp(const void *p1, const void *p2) {
  1527.     const col_hist *ch1 = (const col_hist *)p1;
  1528.     const col_hist *ch2 = (const col_hist *)p2;
  1529.     return ch1->color.g - ch2->color.g;
  1530. }
  1531. static int bluecmp(const void *p1, const void *p2) {
  1532.     const col_hist *ch1 = (const col_hist *)p1;
  1533.     const col_hist *ch2 = (const col_hist *)p2;
  1534.     return ch1->color.b - ch2->color.b;
  1535. }
  1536.  
  1537.  
  1538. static bool median_cut(ColorEntry* cm, col_hist* ch, int colors, long sum, int newcolors) {
  1539.   struct box {
  1540.     int index;
  1541.     int colors;
  1542.     long sum;
  1543.   };
  1544.  
  1545.    box* boxes = new box [newcolors];
  1546. /*
  1547.  * Start with 1 big box
  1548.  */
  1549.    int nboxes = 1;
  1550.    boxes[0].index = 0;
  1551.    boxes[0].colors = colors;
  1552.    boxes[0].sum = sum;
  1553.  
  1554. /*
  1555.  * Split boxes
  1556.  */
  1557.  
  1558.   while (nboxes < newcolors) {
  1559.     int bi;
  1560.     UBYTE minr, maxr, ming, maxg, minb, maxb;
  1561.  
  1562.     /*
  1563.      * Find the first splitable box. Boxes are sorted by sums.
  1564.      */
  1565.     for(bi = 0; bi < nboxes && boxes[bi].colors < 2; bi++);
  1566.     if (bi == nboxes)
  1567.       break;
  1568.  
  1569.     int indx = boxes[bi].index;
  1570.     int clrs = boxes[bi].colors;
  1571.     long sm = boxes[bi].sum;
  1572.  
  1573.     /*
  1574.      * Find the boundaries of the box
  1575.      */
  1576.  
  1577.     minr = maxr = ch[indx].color.r;
  1578.     ming = maxg = ch[indx].color.g;
  1579.     minb = maxb = ch[indx].color.b;
  1580.  
  1581.     for(int i = 1; i < clrs; ++i) {
  1582.       UBYTE v = ch[i].color.r;
  1583.       if (v < minr) minr = v; else if (v > maxr) maxr = v;
  1584.       v = ch[i].color.g;
  1585.       if (v < ming) ming = v; else if (v > maxg) maxg = v;
  1586.       v = ch[i].color.b;
  1587.       if (v < minb) minb = v; else if (v > maxb) maxb = v;
  1588.     }
  1589.  
  1590.     /*
  1591.      * Find the largest dimension, and sort the colors in the box by
  1592.      * this component.
  1593.      */
  1594.     int rl = 77 * (maxr - minr);
  1595.     int gl = 150 * (maxg - ming);
  1596.     int bl = 29 * (maxb - minb);
  1597.  
  1598.     if (rl >= gl && rl >= bl)
  1599.       qsort(&ch[indx], clrs, sizeof(col_hist), redcmp);
  1600.     else if (gl >= bl)
  1601.       qsort(&ch[indx], clrs, sizeof(col_hist), greencmp);
  1602.     else
  1603.       qsort(&ch[indx], clrs, sizeof(col_hist), bluecmp);
  1604.  
  1605.     /*
  1606.      * Split the box.
  1607.      */
  1608.  
  1609.     long lsum = ch[indx].value;
  1610.     long hsum = sm / 2;
  1611.     int i;
  1612.     for (i = 1; i < clrs-1; i++) {
  1613.       if (lsum >= hsum)
  1614.     break;
  1615.       lsum += ch[indx+i].value;
  1616.     }
  1617.     sm -= lsum;
  1618.  
  1619.     /*
  1620.      * Add the two boxes in the right order
  1621.      */
  1622.     boxes[nboxes].sum=0;
  1623.     int a;
  1624.     for(a = bi+1; boxes[a].sum > lsum; ++a);
  1625.     --a;
  1626.     if (a != bi)
  1627.       memmove(&boxes[bi], &boxes[bi+1], (a-bi) * sizeof(box));
  1628.     boxes[a].index = indx;
  1629.     boxes[a].colors = i;
  1630.     boxes[a].sum = lsum;
  1631.     for (++a; boxes[a].sum > sm; ++a);
  1632.     if (a != nboxes)
  1633.       memmove(&boxes[a+1], &boxes[a], (nboxes-a) * sizeof(box));
  1634.     boxes[a].index = indx + i;
  1635.     boxes[a].colors = clrs - i;
  1636.     boxes[a].sum = sm;
  1637.     ++nboxes;
  1638.   }
  1639.  
  1640. /*
  1641.  * Find a representative color for each box.
  1642.  */
  1643.  
  1644.   for (int i = 0; i < nboxes; ++i) {
  1645.     long s=0, r=0, g=0, b=0;
  1646.     col_hist* p = &ch[boxes[i].index];
  1647.  
  1648.     for (int j = 0; j < boxes[i].colors; ++j, ++p) {
  1649.       r += p->color.r * p->value;
  1650.       g += p->color.g * p->value;
  1651.       b += p->color.b * p->value;
  1652.       s += p->value;
  1653.     }
  1654.     r /= s;
  1655.     g /= s;
  1656.     b /= s;
  1657.     cm[i].color.r = r | (r << 8) | (r << 16) | (r << 24);
  1658.     cm[i].color.g = g | (g << 8) | (g << 16) | (g << 24);
  1659.     cm[i].color.b = b | (b << 8) | (b << 16) | (b << 24);
  1660.   }
  1661.  
  1662.   delete [] boxes;
  1663.   return true;
  1664. }
  1665.  
  1666.  
  1667.  
  1668.  
  1669. class hash_table {
  1670.   enum { hash_table_size = 6553 };
  1671.   struct node {
  1672.     node* next;
  1673.     ColorDiff32 color;
  1674.     ColorDiff32 err;
  1675.     int index;
  1676.   };
  1677.   static int hash(const ColorDiff32& c) {
  1678.       return ((c.r >> 8) * 33023 +
  1679.           (c.g >> 8) * 30013 +
  1680.           (c.b >> 8) * 27011) % hash_table_size;
  1681.   }
  1682.   static ULONG sq(LONG x) { return ULONG(x * x) >> 4; }
  1683. public:
  1684.   hash_table(ColorEntry* t, int n)
  1685.     : nodes(new node* [hash_table_size]), table(t), colors(n) {
  1686.     memset(nodes,0,sizeof(*nodes)*hash_table_size);
  1687.   }
  1688.   ~hash_table() {
  1689.     for(int k = 0; k < hash_table_size; ++k) {
  1690.       node* p = nodes[k];
  1691.       while(p) {
  1692.     node* q = p->next;
  1693.     delete p;
  1694.     p = q;
  1695.       }
  1696.     }
  1697.     delete [] nodes;
  1698.   }
  1699.  
  1700.   int get(const ColorDiff32& c, ColorDiff32& err) {
  1701.     int h = hash(c);
  1702.     for(node* hn = nodes[h]; hn; hn = hn->next)
  1703.       if((((hn->color.r ^ c.r) |
  1704.        (hn->color.g ^ c.g) |
  1705.        (hn->color.b ^ c.b)) & 0xff00) == 0) {
  1706.     err = hn->err;
  1707.     return hn->index;
  1708.       }
  1709.  
  1710.     ULONG d = 0xffffffffL;
  1711.     ColorEntry* q = table;
  1712.     ColorEntry* e = q;
  1713.     for (int k = 0; k < colors; ++k, ++q) {
  1714.       ULONG d2 = sq(c.r - (q->color.r >> 16)) +
  1715.          sq(c.g - (q->color.g >> 16)) +
  1716.          sq(c.b - (q->color.b >> 16));
  1717.       if (d2 < d) {
  1718.     d = d2;
  1719.     e = q;
  1720.       }
  1721.     }
  1722.     err.r = c.r - (e->color.r >> 16);
  1723.     err.g = c.g - (e->color.g >> 16);
  1724.     err.b = c.b - (e->color.b >> 16);
  1725.     node* hn = new node;
  1726.     hn->color = c;
  1727.     hn->err = err;
  1728.     hn->index = e->index;
  1729.     hn->next = nodes[h];
  1730.     nodes[h] = hn;
  1731.     return e->index;
  1732.   }
  1733. private:
  1734.   node** nodes;
  1735.   int colors;
  1736.   ColorEntry* table;
  1737. };
  1738.  
  1739.  
  1740.  
  1741. void AOutputDev::drawImage(GfxState *state, Stream *str, int width,
  1742.                int height, GfxImageColorMap *colorMap,
  1743.                GBool inlineImg) {
  1744.   int x0, y0;                   // top left corner of image
  1745.   int w0, h0, w1, h1;           // size of image
  1746.   double xt, yt, wt, ht;
  1747.   GBool rotate, xFlip, yFlip;
  1748.   GBool dither;
  1749.   int x, y;
  1750.   int ix, iy;
  1751.   int px1, px2, qx, dx;
  1752.   int py1, py2, qy, dy;
  1753.   Guchar pixBuf[4];
  1754.   int nComps, nVals, nBits;
  1755.   int i, j;
  1756.  
  1757.   // get image position and size
  1758.   state->transform(0, 0, &xt, &yt);
  1759.   state->transformDelta(1, 1, &wt, &ht);
  1760.   if (wt > 0) {
  1761.     x0 = xoutRound(xt);
  1762.     w0 = xoutRound(wt);
  1763.   } else {
  1764.     x0 = xoutRound(xt + wt);
  1765.     w0 = xoutRound(-wt);
  1766.   }
  1767.   if (ht > 0) {
  1768.     y0 = xoutRound(yt);
  1769.     h0 = xoutRound(ht);
  1770.   } else {
  1771.     y0 = xoutRound(yt + ht);
  1772.     h0 = xoutRound(-ht);
  1773.   }
  1774.   state->transformDelta(1, 0, &xt, &yt);
  1775.   rotate = fabs(xt) < fabs(yt);
  1776.   if (rotate) {
  1777.     w1 = h0;
  1778.     h1 = w0;
  1779.     xFlip = ht < 0;
  1780.     yFlip = wt > 0;
  1781.   } else {
  1782.     w1 = w0;
  1783.     h1 = h0;
  1784.     xFlip = wt < 0;
  1785.     yFlip = ht > 0;
  1786.   }
  1787.  
  1788.   DB(printf("image(%dx%d)->(%d,%d)\n",width,height,w0,h0);)
  1789.   // set up
  1790.   nComps = colorMap->getNumPixelComps();
  1791.   nVals = width * nComps;
  1792.   nBits = colorMap->getBits();
  1793.   dither = nComps > 1 || nBits > 1;
  1794.  
  1795.   // check for tiny (zero width or height) images
  1796.   if (w0 == 0 || h0 == 0) {
  1797.     j = height * ((nVals * nBits + 7) / 8);
  1798.     str->reset();
  1799.     for (i = 0; i < j; ++i)
  1800.       str->getChar();
  1801.     return;
  1802.   }
  1803.  
  1804.   // Bresenham parameters
  1805.   px1 = w1 / width;
  1806.   px2 = w1 - px1 * width;
  1807.   py1 = h1 / height;
  1808.   py2 = h1 - py1 * height;
  1809.  
  1810.   // allocate the true color image
  1811.   AGfx::Image24Ptr image24(gfx.allocate_image24(w0, h0));
  1812.  
  1813.   // initialize the image stream
  1814.   str->resetImage(width, nComps, nBits);
  1815.  
  1816.   // first line (column)
  1817.   y = yFlip ? h1 - 1 : 0;
  1818.   qy = 0;
  1819.  
  1820.   // read image
  1821.   for (i = 0; i < height; ++i) {
  1822.  
  1823.     // vertical (horizontal) Bresenham
  1824.     dy = py1;
  1825.     if ((qy += py2) >= height) {
  1826.       ++dy;
  1827.       qy -= height;
  1828.     }
  1829.  
  1830.     // drop a line (column)
  1831.     if (dy == 0) {
  1832.       str->skipImageLine();
  1833.  
  1834.     } else {
  1835.  
  1836.       // first column (line)
  1837.       x = xFlip ? w1 - 1 : 0;
  1838.       qx = 0;
  1839.  
  1840.       // for each column (line)...
  1841.       for (j = 0; j < width; ++j) {
  1842.  
  1843.     // horizontal (vertical) Bresenham
  1844.     dx = px1;
  1845.     if ((qx += px2) >= width) {
  1846.       ++dx;
  1847.       qx -= width;
  1848.     }
  1849.  
  1850.     // get image pixel
  1851.     str->getImagePixel(pixBuf);
  1852.     GfxColor color;
  1853.     colorMap->getColor(pixBuf, &color);
  1854.     Color c;
  1855.     c.r = (UBYTE)(255 * color.getR());
  1856.     c.g = (UBYTE)(255 * color.getG());
  1857.     c.b = (UBYTE)(255 * color.getB());
  1858.  
  1859.     // draw image pixel
  1860.     if (dx > 0) {
  1861.       for (iy = 0; iy < dy; ++iy) {
  1862.         for (ix = 0; ix < dx; ++ix) {
  1863.           if (rotate)
  1864.         image24->put(yFlip ? y - iy : y + iy,
  1865.                  xFlip ? x - ix : x + ix, c);
  1866.           else
  1867.         image24->put(xFlip ? x - ix : x + ix,
  1868.                  yFlip ? y - iy : y + iy, c);
  1869.         }
  1870.       }
  1871.     }
  1872.  
  1873.     // next column (line)
  1874.     if (xFlip)
  1875.       x -= dx;
  1876.     else
  1877.       x += dx;
  1878.       }
  1879.     }
  1880.  
  1881.     // next line (column)
  1882.     if (yFlip)
  1883.       y -= dy;
  1884.     else
  1885.       y += dy;
  1886.   }
  1887.  
  1888.   if (trueColor) {
  1889.     putimage(gfx,*image24, x0, y0);
  1890.     DB(printf("\nimage24(%d,%d)->(%d,%d,%d,%d)\n",width,height,x0,y0,w0,h0);)
  1891.     return;
  1892.   }
  1893.  
  1894.   // compute color histogram
  1895.   const int max_colors = 32767;
  1896.  
  1897.   int colors;
  1898.   UBYTE mask = 255;//...
  1899.   int newColors = maxColors<2?2:maxColors;
  1900.   col_hist* ch;
  1901.   do {
  1902.     ch = get_color_hist(image24->data(), w0*h0, max_colors, colors, mask);
  1903.     mask = ~((((~mask)+1)<<1)-1);
  1904.   } while (!ch);
  1905.  
  1906.   // find the prefered colors
  1907.   if (colors < newColors)
  1908.     newColors = colors;
  1909.   AGfx::ColorTablePtr colorTable2(gfx.allocate_color_table(newColors));
  1910.   median_cut(colorTable2->data(), ch, colors, w0*h0, newColors);
  1911.  
  1912.   // allocate those colors
  1913.   gfx.get_colors(*colorTable2, newColors);
  1914.   {
  1915.     ColorEntry* p = colorTable2->data();
  1916.     for(int k = 0; k < newColors; ++k, ++p)
  1917.       colorTable.add(((p->color.r >> 8) & 0xff0000)|
  1918.              ((p->color.g >> 16) & 0x00ff00) |
  1919.              ((p->color.b >> 24) & 0x0000ff));
  1920.   }
  1921.  
  1922.   // allocate image
  1923.   AGfx::ImagePtr image(gfx.allocate_image(w0, h0));
  1924.  
  1925.   // allocate error diffusion accumulators
  1926.   ColorDiff32 errRight, *errDown;
  1927.   if (dither) {
  1928.     errDown = new ColorDiff32 [w0];
  1929.     memset(errDown, 0, w0*sizeof(Color32));
  1930.   } else {
  1931.     errDown = NULL;
  1932.   }
  1933.  
  1934.   hash_table table(colorTable2->data(), newColors);
  1935.  
  1936.   // first line
  1937.   Color* p = image24->data();
  1938.  
  1939.   // read image
  1940.   for (y = 0; y < h0; ++y) {
  1941.  
  1942.     // clear error accumulator
  1943.     errRight.r = errRight.g = errRight.b = 0;
  1944.  
  1945.     // for each column (line)...
  1946.     for (x = 0; x < w0; ++x) {
  1947.  
  1948.       // draw image pixel
  1949.       ColorDiff32 color1;
  1950.       color1.r = LONG(p->r << 8);
  1951.       color1.g = LONG(p->g << 8);
  1952.       color1.b = LONG(p->b << 8);
  1953.       ++p;
  1954.  
  1955.       if (dither) {
  1956.     color1.r += errRight.r + errDown[x].r;
  1957.     if (color1.r > 0xffff)
  1958.       color1.r = 0xffff;
  1959.     else if (color1.r < 0)
  1960.       color1.r = 0;
  1961.     color1.g += errRight.g + errDown[x].g;
  1962.     if (color1.g > 0xffff)
  1963.       color1.g = 0xffff;
  1964.     else if (color1.g < 0)
  1965.       color1.g = 0;
  1966.     color1.b += errRight.b + errDown[x].b;
  1967.     if (color1.b > 0xffff)
  1968.       color1.b = 0xffff;
  1969.     else if (color1.b < 0)
  1970.       color1.b = 0;
  1971.       }
  1972.       ColorDiff32 err;
  1973.       image->put(x, y, table.get(color1, err));
  1974.       if (dither) {
  1975.     errRight.r = errDown[x].r = err.r / 2;
  1976.     errRight.g = errDown[x].g = err.g / 2;
  1977.     errRight.b = errDown[x].b = err.b / 2;
  1978.       }
  1979.     }
  1980.   }
  1981.  
  1982.   // blit the image into the pixmap
  1983.   putimage(gfx,*image, x0, y0/*, w0, h0*/);
  1984.   DB(printf("\nimage(%d,%d)->(%d,%d,%d,%d)\n",width,height,x0,y0,w0,h0);)
  1985.  
  1986.   // free memory
  1987.   delete [] errDown;
  1988. }
  1989. #else
  1990.  
  1991. inline Gulong AOutputDev::findColor(RGBColor *x, RGBColor *err) {
  1992.   double gray;
  1993.   int r, g, b;
  1994.   Gulong pixel;
  1995.  
  1996.   /*if (trueColor) {
  1997.     r = xoutRound(x->r * rMul);
  1998.     g = xoutRound(x->g * gMul);
  1999.     b = xoutRound(x->b * bMul);
  2000.     pixel = ((Gulong)r << rShift) +
  2001.         ((Gulong)g << gShift) +
  2002.         ((Gulong)b << bShift);
  2003.     err->r = x->r - (double)r / rMul;
  2004.     err->g = x->g - (double)g / gMul;
  2005.     err->b = x->b - (double)b / bMul;
  2006.   } else if (numColors == 1) {*/
  2007.     gray = 0.299 * x->r + 0.587 * x->g + 0.114 * x->b;
  2008.     if (gray < 0.5) {
  2009.       pixel = 0;//colors[0];
  2010.       err->r = x->r;
  2011.       err->g = x->g;
  2012.       err->b = x->b;
  2013.     } else {
  2014.       pixel = 1;//colors[1];
  2015.       err->r = x->r - 1;
  2016.       err->g = x->g - 1;
  2017.       err->b = x->b - 1;
  2018.     }
  2019.   /*} else {
  2020.     r = xoutRound(x->r * (numColors - 1));
  2021.     g = xoutRound(x->g * (numColors - 1));
  2022.     b = xoutRound(x->b * (numColors - 1));
  2023.     pixel = colors[(r * numColors + g) * numColors + b];
  2024.     err->r = x->r - (double)r / (numColors - 1);
  2025.     err->g = x->g - (double)g / (numColors - 1);
  2026.     err->b = x->b - (double)b / (numColors - 1);
  2027.   }*/
  2028.   return pixel;
  2029. }
  2030.  
  2031. void AOutputDev::drawImage(GfxState *state, Stream *str, int width,
  2032.                int height, GfxImageColorMap *colorMap,
  2033.                GBool inlineImg) {
  2034.   AGfx::ImagePtr image;
  2035.   int x0, y0;                   // top left corner of image
  2036.   int w0, h0, w1, h1;           // size of image
  2037.   double xt, yt, wt, ht;
  2038.   GBool rotate, xFlip, yFlip;
  2039.   GBool dither;
  2040.   int x, y;
  2041.   int ix, iy;
  2042.   int px1, px2, qx, dx;
  2043.   int py1, py2, qy, dy;
  2044.   Guchar pixBuf[4];
  2045.   Gulong pixel;
  2046.   int nComps, nVals, nBits;
  2047.   double r1, g1, b1;
  2048.   GfxColor color;
  2049.   RGBColor color2, err;
  2050.   RGBColor *errRight, *errDown;
  2051.   int i, j;
  2052.  
  2053.   // get image position and size
  2054.   state->transform(0, 0, &xt, &yt);
  2055.   state->transformDelta(1, 1, &wt, &ht);
  2056.   if (wt > 0) {
  2057.     x0 = xoutRound(xt);
  2058.     w0 = xoutRound(wt);
  2059.   } else {
  2060.     x0 = xoutRound(xt + wt);
  2061.     w0 = xoutRound(-wt);
  2062.   }
  2063.   if (ht > 0) {
  2064.     y0 = xoutRound(yt);
  2065.     h0 = xoutRound(ht);
  2066.   } else {
  2067.     y0 = xoutRound(yt + ht);
  2068.     h0 = xoutRound(-ht);
  2069.   }
  2070.   state->transformDelta(1, 0, &xt, &yt);
  2071.   rotate = fabs(xt) < fabs(yt);
  2072.   if (rotate) {
  2073.     w1 = h0;
  2074.     h1 = w0;
  2075.     xFlip = ht < 0;
  2076.     yFlip = wt > 0;
  2077.   } else {
  2078.     w1 = w0;
  2079.     h1 = h0;
  2080.     xFlip = wt < 0;
  2081.     yFlip = ht > 0;
  2082.   }
  2083.  
  2084.   // set up
  2085.   nComps = colorMap->getNumPixelComps();
  2086.   nVals = width * nComps;
  2087.   nBits = colorMap->getBits();
  2088.   dither = nComps > 1 || nBits > 1;
  2089.  
  2090.   // check for tiny (zero width or height) images
  2091.   if (w0 == 0 || h0 == 0) {
  2092.     j = height * ((nVals * nBits + 7) / 8);
  2093.     str->reset();
  2094.     for (i = 0; i < j; ++i)
  2095.       str->getChar();
  2096.     return;
  2097.   }
  2098.  
  2099.   // Bresenham parameters
  2100.   px1 = w1 / width;
  2101.   px2 = w1 - px1 * width;
  2102.   py1 = h1 / height;
  2103.   py2 = h1 - py1 * height;
  2104.  
  2105.   // allocate XImage
  2106.   /*
  2107.   image = XCreateImage(display, DefaultVisual(display, screenNum),
  2108.                depth, ZPixmap, 0, NULL, w0, h0, 8, 0);
  2109.   image->data = (char *)gmalloc(h0 * image->bytes_per_line);*/
  2110.   image = gfx.allocate_image(w0,h0);
  2111.  
  2112.   // allocate error diffusion accumulators
  2113.   if (dither) {
  2114.     errDown = (RGBColor *)gmalloc(w1 * sizeof(RGBColor));
  2115.     errRight = (RGBColor *)gmalloc((py1 + 1) * sizeof(RGBColor));
  2116.     for (j = 0; j < w1; ++j)
  2117.       errDown[j].r = errDown[j].g = errDown[j].b = 0;
  2118.   } else {
  2119.     errDown = NULL;
  2120.     errRight = NULL;
  2121.   }
  2122.  
  2123.   // initialize the image stream
  2124.   str->resetImage(width, nComps, nBits);
  2125.  
  2126.   // first line (column)
  2127.   y = yFlip ? h1 - 1 : 0;
  2128.   qy = 0;
  2129.  
  2130.   // read image
  2131.   for (i = 0; i < height; ++i) {
  2132.  
  2133.     // vertical (horizontal) Bresenham
  2134.     dy = py1;
  2135.     if ((qy += py2) >= height) {
  2136.       ++dy;
  2137.       qy -= height;
  2138.     }
  2139.  
  2140.     // drop a line (column)
  2141.     if (dy == 0) {
  2142.       str->skipImageLine();
  2143.  
  2144.     } else {
  2145.  
  2146.       // first column (line)
  2147.       x = xFlip ? w1 - 1 : 0;
  2148.       qx = 0;
  2149.  
  2150.       // clear error accumulator
  2151.       if (dither) {
  2152.     for (j = 0; j <= py1; ++j)
  2153.       errRight[j].r = errRight[j].g = errRight[j].b = 0;
  2154.       }
  2155.  
  2156.       // for each column (line)...
  2157.       for (j = 0; j < width; ++j) {
  2158.  
  2159.     // horizontal (vertical) Bresenham
  2160.     dx = px1;
  2161.     if ((qx += px2) >= width) {
  2162.       ++dx;
  2163.       qx -= width;
  2164.     }
  2165.  
  2166.     // get image pixel
  2167.     str->getImagePixel(pixBuf);
  2168.  
  2169.     // draw image pixel
  2170.     if (dx > 0) {
  2171.       colorMap->getColor(pixBuf, &color);
  2172.       r1 = color.getR();
  2173.       g1 = color.getG();
  2174.       b1 = color.getB();
  2175.       if (dither) {
  2176.         pixel = 0;
  2177.       } else {
  2178.         color2.r = r1;
  2179.         color2.g = g1;
  2180.         color2.b = b1;
  2181.         pixel = findColor(&color2, &err);
  2182.       }
  2183.       if (dx == 1 && dy == 1) {
  2184.         if (dither) {
  2185.           color2.r = r1 + errRight[0].r + errDown[x].r;
  2186.           if (color2.r > 1)
  2187.         color2.r = 1;
  2188.           else if (color2.r < 0)
  2189.         color2.r = 0;
  2190.           color2.g = g1 + errRight[0].g + errDown[x].g;
  2191.           if (color2.g > 1)
  2192.         color2.g = 1;
  2193.           else if (color2.g < 0)
  2194.         color2.g = 0;
  2195.           color2.b = b1 + errRight[0].b + errDown[x].b;
  2196.           if (color2.b > 1)
  2197.         color2.b = 1;
  2198.           else if (color2.b < 0)
  2199.         color2.b = 0;
  2200.           pixel = findColor(&color2, &err);
  2201.           errRight[0].r = errDown[x].r = err.r / 2;
  2202.           errRight[0].g = errDown[x].g = err.g / 2;
  2203.           errRight[0].b = errDown[x].b = err.b / 2;
  2204.         }
  2205.         if (rotate)
  2206.           image->put(y, x, pixel);
  2207.         else
  2208.           image->put(x, y, pixel);
  2209.       } else {
  2210.         for (iy = 0; iy < dy; ++iy) {
  2211.           for (ix = 0; ix < dx; ++ix) {
  2212.         if (dither) {
  2213.           color2.r = r1 + errRight[iy].r +
  2214.             errDown[xFlip ? x - ix : x + ix].r;
  2215.           if (color2.r > 1)
  2216.             color2.r = 1;
  2217.           else if (color2.r < 0)
  2218.             color2.r = 0;
  2219.           color2.g = g1 + errRight[iy].g +
  2220.             errDown[xFlip ? x - ix : x + ix].g;
  2221.           if (color2.g > 1)
  2222.             color2.g = 1;
  2223.           else if (color2.g < 0)
  2224.             color2.g = 0;
  2225.           color2.b = b1 + errRight[iy].b +
  2226.             errDown[xFlip ? x - ix : x + ix].b;
  2227.           if (color2.b > 1)
  2228.             color2.b = 1;
  2229.           else if (color2.b < 0)
  2230.             color2.b = 0;
  2231.           pixel = findColor(&color2, &err);
  2232.           errRight[iy].r = errDown[xFlip ? x - ix : x + ix].r =
  2233.             err.r / 2;
  2234.           errRight[iy].g = errDown[xFlip ? x - ix : x + ix].g =
  2235.             err.g / 2;
  2236.           errRight[iy].b = errDown[xFlip ? x - ix : x + ix].b =
  2237.             err.b / 2;
  2238.         }
  2239.         if (rotate)
  2240.           image->put(yFlip ? y - iy : y + iy,
  2241.                  xFlip ? x - ix : x + ix, pixel);
  2242.         else
  2243.           image->put(xFlip ? x - ix : x + ix,
  2244.                  yFlip ? y - iy : y + iy, pixel);
  2245.           }
  2246.         }
  2247.       }
  2248.     }
  2249.  
  2250.     // next column (line)
  2251.     if (xFlip)
  2252.       x -= dx;
  2253.     else
  2254.       x += dx;
  2255.       }
  2256.     }
  2257.  
  2258.     // next line (column)
  2259.     if (yFlip)
  2260.       y -= dy;
  2261.     else
  2262.       y += dy;
  2263.   }
  2264.  
  2265.   // blit the image into the pixmap
  2266.   gfx.put_image(*image, x0, y0/*, w0, h0*/);
  2267.   DB(printf("\nimage(%d,%d)->(%d,%d,%d,%d)\n",width,height,x0,y0,w0,h0);)
  2268.  
  2269.   // free memory
  2270.   gfree(errRight);
  2271.   gfree(errDown);
  2272. }
  2273. #endif
  2274.  
  2275. Gulong AOutputDev::findColor(GfxColor *color) {
  2276.   int r, g, b;
  2277.   Gulong pixel;
  2278.  
  2279. #if !defined(__HAVE_68881__) && !defined(__PPC__)
  2280.   // when compiling for 68k without fpu, I get r==256 if
  2281.   // getR()==1.0, which is wrong. Unfortunately have been
  2282.   // unable to reproduce the problem on a small snipset...
  2283.   r = int(color->getR() * 255);
  2284.   g = int(color->getG() * 255);
  2285.   b = int(color->getB() * 255);
  2286. #else
  2287.   r = xoutRound(color->getR() * 255);
  2288.   g = xoutRound(color->getG() * 255);
  2289.   b = xoutRound(color->getB() * 255);
  2290. #endif
  2291.  
  2292.   pixel = (((Gulong)r << 16) +
  2293.        ((Gulong)g << 8) +
  2294.        ((Gulong)b << 0)) & colorMask;
  2295.  
  2296.   Gulong c = colorTable.find(pixel);
  2297.   if (c != Gulong(-1))
  2298.       return c;
  2299.   else {
  2300.       gfx.color(Gulong(color->getR() * 0xffffffffUL + 0.5),
  2301.         Gulong(color->getG() * 0xffffffffUL + 0.5),
  2302.         Gulong(color->getB() * 0xffffffffUL + 0.5));
  2303.       return colorTable.add(pixel);
  2304.   }
  2305. #if 0
  2306.   double gray;
  2307.  
  2308.   if (trueColor) {
  2309.   } else if (numColors == 1) {
  2310.     gray = color->getGray();
  2311.     if (gray < 0.5)
  2312.       pixel = colors[0];
  2313.     else
  2314.       pixel = colors[1];
  2315.   } else {
  2316.     r = xoutRound(color->getR() * (numColors - 1));
  2317.     g = xoutRound(color->getG() * (numColors - 1));
  2318.     b = xoutRound(color->getB() * (numColors - 1));
  2319. #if 0 //~ this makes things worse as often as better
  2320.     // even a very light color shouldn't map to white
  2321.     if (r == numColors - 1 && g == numColors - 1 && b == numColors - 1) {
  2322.       if (color->getR() < 0.95)
  2323.     --r;
  2324.       if (color->getG() < 0.95)
  2325.     --g;
  2326.       if (color->getB() < 0.95)
  2327.     --b;
  2328.     }
  2329. #endif
  2330.     pixel = colors[(r * numColors + g) * numColors + b];
  2331.   }
  2332.   return pixel;
  2333. #endif
  2334. }
  2335.  
  2336. GBool AOutputDev::findText(char *s, GBool top, GBool bottom,
  2337.                int *xMin, int *yMin, int *xMax, int *yMax) {
  2338.   double xMin1, yMin1, xMax1, yMax1;
  2339.  
  2340.   xMin1 = (double)*xMin;
  2341.   yMin1 = (double)*yMin;
  2342.   xMax1 = (double)*xMax;
  2343.   yMax1 = (double)*yMax;
  2344.   if (text->findText(s, top, bottom, &xMin1, &yMin1, &xMax1, &yMax1)) {
  2345.     *xMin = xoutRound(xMin1);
  2346.     *xMax = xoutRound(xMax1);
  2347.     *yMin = xoutRound(yMin1);
  2348.     *yMax = xoutRound(yMax1);
  2349.     return gTrue;
  2350.   }
  2351.   return gFalse;
  2352. }
  2353.  
  2354. GString *AOutputDev::getText(int xMin, int yMin, int xMax, int yMax) {
  2355.   return text->getText((double)xMin, (double)yMin,
  2356.                (double)xMax, (double)yMax);
  2357. }
  2358.