home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 110 / EnigmaAmiga110CD.iso / indispensabili / utility / apdf / xpdf-0.80 / xpdf / xoutputdev.cc < prev    next >
C/C++ Source or Header  |  1998-11-27  |  59KB  |  2,184 lines

  1. //========================================================================
  2. //
  3. // XOutputDev.cc
  4. //
  5. // Copyright 1996 Derek B. Noonburg
  6. //
  7. //========================================================================
  8.  
  9. #ifdef __GNUC__
  10. #pragma implementation
  11. #endif
  12.  
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <stddef.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include <math.h>
  19. #include "gmem.h"
  20. #include "GString.h"
  21. #include "Object.h"
  22. #include "Stream.h"
  23. #include "GfxState.h"
  24. #include "GfxFont.h"
  25. #include "Error.h"
  26. #include "Params.h"
  27. #include "TextOutputDev.h"
  28. #include "XOutputDev.h"
  29.  
  30. #include "XOutputFontInfo.h"
  31.  
  32. #ifdef XlibSpecificationRelease
  33. #if XlibSpecificationRelease < 5
  34. typedef char *XPointer;
  35. #endif
  36. #else
  37. typedef char *XPointer;
  38. #endif
  39.  
  40. //------------------------------------------------------------------------
  41. // Constants and macros
  42. //------------------------------------------------------------------------
  43.  
  44. #define xoutRound(x) ((int)(x + 0.5))
  45.  
  46. #define maxCurveSplits 6    // max number of splits when recursively
  47.                 //   drawing Bezier curves
  48.  
  49. //------------------------------------------------------------------------
  50. // Parameters
  51. //------------------------------------------------------------------------
  52.  
  53. GBool installCmap;
  54.  
  55. int rgbCubeSize;
  56.  
  57. //------------------------------------------------------------------------
  58. // Font map
  59. //------------------------------------------------------------------------
  60.  
  61. struct FontMapEntry {
  62.   char *pdfFont;
  63.   char *xFont;
  64.   GfxFontEncoding *encoding;
  65. };
  66.  
  67. static FontMapEntry fontMap[] = {
  68.   {"Courier",
  69.    "-*-courier-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1",
  70.    &isoLatin1Encoding},
  71.   {"Courier-Bold",
  72.    "-*-courier-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1",
  73.    &isoLatin1Encoding},
  74.   {"Courier-BoldOblique",
  75.    "-*-courier-bold-o-normal-*-%s-*-*-*-*-*-iso8859-1",
  76.    &isoLatin1Encoding},
  77.   {"Courier-Oblique",
  78.    "-*-courier-medium-o-normal-*-%s-*-*-*-*-*-iso8859-1",
  79.    &isoLatin1Encoding},
  80.   {"Helvetica",
  81.    "-*-helvetica-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1",
  82.    &isoLatin1Encoding},
  83.   {"Helvetica-Bold",
  84.    "-*-helvetica-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1",
  85.    &isoLatin1Encoding},
  86.   {"Helvetica-BoldOblique",
  87.    "-*-helvetica-bold-o-normal-*-%s-*-*-*-*-*-iso8859-1",
  88.    &isoLatin1Encoding},
  89.   {"Helvetica-Oblique",
  90.    "-*-helvetica-medium-o-normal-*-%s-*-*-*-*-*-iso8859-1",
  91.    &isoLatin1Encoding},
  92.   {"Symbol",
  93.    "-*-symbol-medium-r-normal-*-%s-*-*-*-*-*-adobe-fontspecific",
  94.    &symbolEncoding},
  95.   {"Times-Bold",
  96.    "-*-times-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1",
  97.    &isoLatin1Encoding},
  98.   {"Times-BoldItalic",
  99.    "-*-times-bold-i-normal-*-%s-*-*-*-*-*-iso8859-1",
  100.    &isoLatin1Encoding},
  101.   {"Times-Italic",
  102.    "-*-times-medium-i-normal-*-%s-*-*-*-*-*-iso8859-1",
  103.    &isoLatin1Encoding},
  104.   {"Times-Roman",
  105.    "-*-times-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1",
  106.    &isoLatin1Encoding},
  107.   {"ZapfDingbats",
  108.    "-*-zapfdingbats-medium-r-normal-*-%s-*-*-*-*-*-*-*",
  109.    &zapfDingbatsEncoding},
  110.   {NULL}
  111. };
  112.  
  113. static FontMapEntry *userFontMap;
  114.  
  115. //------------------------------------------------------------------------
  116. // Font substitutions
  117. //------------------------------------------------------------------------
  118.  
  119. struct FontSubst {
  120.   char *xFont;
  121.   double mWidth;
  122. };
  123.  
  124. // index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic
  125. static FontSubst fontSubst[16] = {
  126.   {"-*-helvetica-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1",       0.833},
  127.   {"-*-helvetica-medium-o-normal-*-%s-*-*-*-*-*-iso8859-1",       0.833},
  128.   {"-*-helvetica-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1",         0.889},
  129.   {"-*-helvetica-bold-o-normal-*-%s-*-*-*-*-*-iso8859-1",         0.889},
  130.   {"-*-times-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1",           0.788},
  131.   {"-*-times-medium-i-normal-*-%s-*-*-*-*-*-iso8859-1",           0.722},
  132.   {"-*-times-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1",             0.833},
  133.   {"-*-times-bold-i-normal-*-%s-*-*-*-*-*-iso8859-1",             0.778},
  134.   {"-*-courier-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1",         0.600},
  135.   {"-*-courier-medium-o-normal-*-%s-*-*-*-*-*-iso8859-1",         0.600},
  136.   {"-*-courier-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1",           0.600},
  137.   {"-*-courier-bold-o-normal-*-%s-*-*-*-*-*-iso8859-1",           0.600},
  138.   {"-*-symbol-medium-r-normal-*-%s-*-*-*-*-*-adobe-fontspecific", 0.576},
  139.   {"-*-symbol-medium-r-normal-*-%s-*-*-*-*-*-adobe-fontspecific", 0.576},
  140.   {"-*-symbol-medium-r-normal-*-%s-*-*-*-*-*-adobe-fontspecific", 0.576},
  141.   {"-*-symbol-medium-r-normal-*-%s-*-*-*-*-*-adobe-fontspecific", 0.576}
  142. };
  143.  
  144. //------------------------------------------------------------------------
  145. // 16-bit fonts
  146. //------------------------------------------------------------------------
  147.  
  148. #if JAPANESE_SUPPORT
  149.  
  150. static char *japan12Font = "-*-fixed-medium-r-normal-*-%s-*-*-*-*-*-jisx0208.1983-0";
  151.  
  152. // CID 0 .. 96
  153. static Gushort japan12Map[96] = {
  154.   0x2120, 0x2120, 0x212a, 0x2149, 0x2174, 0x2170, 0x2173, 0x2175, // 00 .. 07
  155.   0x2147, 0x214a, 0x214b, 0x2176, 0x215c, 0x2124, 0x213e, 0x2123, // 08 .. 0f
  156.   0x213f, 0x2330, 0x2331, 0x2332, 0x2333, 0x2334, 0x2335, 0x2336, // 10 .. 17
  157.   0x2337, 0x2338, 0x2339, 0x2127, 0x2128, 0x2163, 0x2161, 0x2164, // 18 .. 1f
  158.   0x2129, 0x2177, 0x2341, 0x2342, 0x2343, 0x2344, 0x2345, 0x2346, // 20 .. 27
  159.   0x2347, 0x2348, 0x2349, 0x234a, 0x234b, 0x234c, 0x234d, 0x234e, // 28 .. 2f
  160.   0x234f, 0x2350, 0x2351, 0x2352, 0x2353, 0x2354, 0x2355, 0x2356, // 30 .. 37
  161.   0x2357, 0x2358, 0x2359, 0x235a, 0x214e, 0x216f, 0x214f, 0x2130, // 38 .. 3f
  162.   0x2132, 0x2146, 0x2361, 0x2362, 0x2363, 0x2364, 0x2365, 0x2366, // 40 .. 47
  163.   0x2367, 0x2368, 0x2369, 0x236a, 0x236b, 0x236c, 0x236d, 0x236e, // 48 .. 4f
  164.   0x236f, 0x2370, 0x2371, 0x2372, 0x2373, 0x2374, 0x2375, 0x2376, // 50 .. 57
  165.   0x2377, 0x2378, 0x2379, 0x237a, 0x2150, 0x2143, 0x2151, 0x2141  // 58 .. 5f
  166. };
  167.  
  168. // CID 325 .. 421
  169. static Gushort japan12KanaMap1[97] = {
  170.   0x2131, 0x2121, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572,
  171.   0x2521, 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567,
  172.   0x2543, 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b,
  173.   0x252d, 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b,
  174.   0x253d, 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b,
  175.   0x254c, 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b,
  176.   0x255e, 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568,
  177.   0x2569, 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b,
  178.   0x212c, 0x212e, 0x2570, 0x2571, 0x256e, 0x2575, 0x2576, 0x2574,
  179.   0x252c, 0x252e, 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a,
  180.   0x253c, 0x253e, 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x2550,
  181.   0x2551, 0x2553, 0x2554, 0x2556, 0x2557, 0x2559, 0x255a, 0x255c,
  182.   0x255d
  183. };
  184.  
  185. // CID 501 .. 598
  186. static Gushort japan12KanaMap2[98] = {
  187.   0x212d, 0x212f, 0x216d, 0x214c, 0x214d, 0x2152, 0x2153, 0x2154,
  188.   0x2155, 0x2158, 0x2159, 0x215a, 0x215b, 0x213d, 0x2121, 0x2472,
  189.   0x2421, 0x2423, 0x2425, 0x2427, 0x2429, 0x2463, 0x2465, 0x2467,
  190.   0x2443, 0x2422, 0x2424, 0x2426, 0x2428, 0x242a, 0x242b, 0x242d,
  191.   0x242f, 0x2431, 0x2433, 0x2435, 0x2437, 0x2439, 0x243b, 0x243d,
  192.   0x243f, 0x2441, 0x2444, 0x2446, 0x2448, 0x244a, 0x244b, 0x244c,
  193.   0x244d, 0x244e, 0x244f, 0x2452, 0x2455, 0x2458, 0x245b, 0x245e,
  194.   0x245f, 0x2460, 0x2461, 0x2462, 0x2464, 0x2466, 0x2468, 0x2469,
  195.   0x246a, 0x246b, 0x246c, 0x246d, 0x246f, 0x2473, 0x2470, 0x2471,
  196.   0x246e, 0x242c, 0x242e, 0x2430, 0x2432, 0x2434, 0x2436, 0x2438,
  197.   0x243a, 0x243c, 0x243e, 0x2440, 0x2442, 0x2445, 0x2447, 0x2449,
  198.   0x2450, 0x2451, 0x2453, 0x2454, 0x2456, 0x2457, 0x2459, 0x245a,
  199.   0x245c, 0x245d
  200. };
  201.  
  202. static char *japan12Roman[10] = {
  203.   "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"
  204. };
  205.  
  206. static char *japan12Abbrev1[6] = {
  207.   "mm", "cm", "km", "mg", "kg", "cc"
  208. };
  209.  
  210. #endif
  211.  
  212. //------------------------------------------------------------------------
  213. // Constructed characters
  214. //------------------------------------------------------------------------
  215.  
  216. #define lastRegularChar 0x0ff
  217. #define firstSubstChar  0x100
  218. #define lastSubstChar   0x104
  219. #define firstConstrChar 0x105
  220. #define lastConstrChar  0x106
  221. #define firstMultiChar  0x107
  222. #define lastMultiChar   0x10d
  223.  
  224. // substituted chars
  225. static Guchar substChars[] = {
  226.   0x27,                // 100: quotesingle --> quoteright
  227.   0x2d,                // 101: emdash --> hyphen
  228.   0xad,                // 102: hyphen --> endash
  229.   0x2f,                // 103: fraction --> slash
  230.   0xb0,                // 104: ring --> degree
  231. };
  232.  
  233. // constructed chars
  234. // 105: bullet
  235. // 106: trademark
  236.  
  237. // built-up chars
  238. static char *multiChars[] = {
  239.   "fi",                // 107: fi
  240.   "fl",                // 108: fl
  241.   "OE",                // 109: OE
  242.   "oe",                // 10a: oe
  243.   "...",            // 10b: ellipsis
  244.   "``",                // 10c: quotedblleft
  245.   "''"                // 10d: quotedblright
  246. };
  247.  
  248. // ignored chars
  249. // 10c: Lslash
  250. // 10d: Scaron
  251. // 10e: Zcaron
  252. // 10f: Ydieresis
  253. // 110: breve
  254. // 111: caron
  255. // 112: circumflex
  256. // 113: dagger
  257. // 114: daggerdbl
  258. // 115: dotaccent
  259. // 116: dotlessi
  260. // 117: florin
  261. // 118: grave
  262. // 119: guilsinglleft
  263. // 11a: guilsinglright
  264. // 11b: hungarumlaut
  265. // 11c: lslash
  266. // 11d: ogonek
  267. // 11e: perthousand
  268. // 11f: quotedblbase
  269. // 120: quotesinglbase
  270. // 121: scaron
  271. // 122: tilde
  272. // 123: zcaron
  273.  
  274. //------------------------------------------------------------------------
  275. // XOutputFont
  276. //------------------------------------------------------------------------
  277.  
  278. // Note: if real font is substantially narrower than substituted
  279. // font, the size is reduced accordingly.
  280. XOutputFont::XOutputFont(GfxFont *gfxFont, double m11, double m12,
  281.              double m21, double m22, Display *display1) {
  282.   GString *pdfFont;
  283.   FontMapEntry *p;
  284.   GfxFontEncoding *encoding;
  285.   char *fontNameFmt;
  286.   char fontName[200], fontSize[100];
  287.   GBool rotated;
  288.   double size;
  289.   int startSize, sz;
  290.   int index;
  291.   int code, code2;
  292.   double w1, w2, v;
  293.   double *fm;
  294.   char *charName;
  295.   int n;
  296.  
  297.   // init
  298.   id = gfxFont->getID();
  299.   mat11 = m11;
  300.   mat12 = m12;
  301.   mat21 = m21;
  302.   mat22 = m22;
  303.   display = display1;
  304.   xFont = NULL;
  305.   hex = gFalse;
  306.  
  307.   // construct X font name
  308.   if (gfxFont->is16Bit()) {
  309.     fontNameFmt = fontSubst[0].xFont;
  310.     switch (gfxFont->getCharSet16()) {
  311.     case font16AdobeJapan12:
  312. #if JAPANESE_SUPPORT
  313.       fontNameFmt = japan12Font;
  314. #endif
  315.       break;
  316.     }
  317.   } else {
  318.     pdfFont = gfxFont->getName();
  319.     if (pdfFont) {
  320.       for (p = userFontMap; p->pdfFont; ++p) {
  321.     if (!pdfFont->cmp(p->pdfFont))
  322.       break;
  323.       }
  324.       if (!p->pdfFont) {
  325.     for (p = fontMap; p->pdfFont; ++p) {
  326.       if (!pdfFont->cmp(p->pdfFont))
  327.         break;
  328.     }
  329.       }
  330.     } else {
  331.       p = NULL;
  332.     }
  333.     if (p && p->pdfFont) {
  334.       fontNameFmt = p->xFont;
  335.       encoding = p->encoding;
  336.     } else {
  337.       encoding = &isoLatin1Encoding;
  338. //~ Some non-symbolic fonts are tagged as symbolic.
  339. //      if (gfxFont->isSymbolic()) {
  340. //        index = 12;
  341. //        encoding = symbolEncoding;
  342. //      } else
  343.       if (gfxFont->isFixedWidth()) {
  344.     index = 8;
  345.       } else if (gfxFont->isSerif()) {
  346.     index = 4;
  347.       } else {
  348.     index = 0;
  349.       }
  350.       if (gfxFont->isBold())
  351.     index += 2;
  352.       if (gfxFont->isItalic())
  353.     index += 1;
  354.       if ((code = gfxFont->getCharCode("m")) >= 0)
  355.     w1 = gfxFont->getWidth(code);
  356.       else
  357.     w1 = 0;
  358.       w2 = fontSubst[index].mWidth;
  359.       if (gfxFont->getType() == fontType3) {
  360.     // This is a hack which makes it possible to substitute for some
  361.     // Type 3 fonts.  The problem is that it's impossible to know what
  362.     // the base coordinate system used in the font is without actually
  363.     // rendering the font.  This code tries to guess by looking at the
  364.     // width of the character 'm' (which breaks if the font is a
  365.     // subset that doesn't contain 'm').
  366.     if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) {
  367.       w1 /= w2;
  368.       mat11 *= w1;
  369.       mat12 *= w1;
  370.       mat21 *= w1;
  371.       mat22 *= w1;
  372.     }
  373.     fm = gfxFont->getFontMatrix();
  374.     v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]);
  375.     mat12 *= v;
  376.     mat22 *= v;
  377.       } else if (!gfxFont->isSymbolic()) {
  378.     if (w1 > 0.01 && w1 < 0.9 * w2) {
  379.       w1 /= w2;
  380.       if (w1 < 0.8)
  381.         w1 = 0.8;
  382.       mat11 *= w1;
  383.       mat12 *= w1;
  384.       mat21 *= w1;
  385.       mat22 *= w1;
  386.     }
  387.       }
  388.       fontNameFmt = fontSubst[index].xFont;
  389.     }
  390.  
  391.     // Construct forward and reverse map.
  392.     // This tries to deal with font subset character names of the
  393.     // form 'Bxx', 'Cxx', 'Gxx', with decimal or hex numbering.
  394.     for (code = 0; code < 256; ++code)
  395.       revMap[code] = 0;
  396.     if (encoding) {
  397.       for (code = 0; code < 256; ++code) {
  398.     if ((charName = gfxFont->getCharName(code))) {
  399.       if ((charName[0] == 'B' || charName[0] == 'C' ||
  400.            charName[0] == 'G') &&
  401.           strlen(charName) == 3 &&
  402.           ((charName[1] >= 'a' && charName[1] <= 'f') ||
  403.            (charName[1] >= 'A' && charName[1] <= 'F') ||
  404.            (charName[2] >= 'a' && charName[2] <= 'f') ||
  405.            (charName[2] >= 'A' && charName[2] <= 'F'))) {
  406.         hex = gTrue;
  407.         break;
  408.       }
  409.     }
  410.       }
  411.       for (code = 0; code < 256; ++code) {
  412.     if ((charName = gfxFont->getCharName(code))) {
  413.       if ((code2 = encoding->getCharCode(charName)) < 0) {
  414.         n = strlen(charName);
  415.         if (hex && n == 3 &&
  416.         (charName[0] == 'B' || charName[0] == 'C' ||
  417.          charName[0] == 'G') &&
  418.         isxdigit(charName[1]) && isxdigit(charName[2])) {
  419.           sscanf(charName+1, "%x", &code2);
  420.         } else if (!hex && n >= 2 && n <= 3 &&
  421.                isdigit(charName[0]) && isdigit(charName[1])) {
  422.           code2 = atoi(charName);
  423.           if (code2 >= 256)
  424.         code2 = -1;
  425.         } else if (!hex && n >= 3 && n <= 5 && isdigit(charName[1])) {
  426.           code2 = atoi(charName+1);
  427.           if (code2 >= 256)
  428.         code2 = -1;
  429.         }
  430.         //~ this is a kludge -- is there a standard internal encoding
  431.         //~ used by all/most Type 1 fonts?
  432.         if (code2 == 262)        // hyphen
  433.           code2 = 45;
  434.         else if (code2 == 266)    // emdash
  435.           code2 = 208;
  436.       }
  437.       if (code2 >= 0) {
  438.         map[code] = (Gushort)code2;
  439.         if (code2 < 256)
  440.           revMap[code2] = (Guchar)code;
  441.       } else {
  442.         map[code] = 0;
  443.       }
  444.     } else {
  445.       map[code] = 0;
  446.     }
  447.       }
  448.     } else {
  449.       code2 = 0; // to make gcc happy
  450.       //~ this is a hack to get around the fact that X won't draw
  451.       //~ chars 0..31; this works when the fonts have duplicate encodings
  452.       //~ for those chars
  453.       for (code = 0; code < 32; ++code) {
  454.     if ((charName = gfxFont->getCharName(code)) &&
  455.         (code2 = gfxFont->getCharCode(charName)) >= 0) {
  456.       map[code] = (Gushort)code2;
  457.       if (code2 < 256)
  458.         revMap[code2] = (Guchar)code;
  459.     }
  460.       }
  461.       for (code = 32; code < 256; ++code) {
  462.     map[code] = (Gushort)code;
  463.     revMap[code] = (Guchar)code;
  464.       }
  465.     }
  466.   }
  467.  
  468.   // compute size, normalize matrix
  469.   size = sqrt(mat21*mat21 + mat22*mat22);
  470.   mat11 = mat11 / size;
  471.   mat12 = -mat12 / size;
  472.   mat21 = mat21 / size;
  473.   mat22 = -mat22 / size;
  474.   startSize = (int)size;
  475.  
  476.   // try to get a rotated font?
  477.   rotated = !(mat11 > 0 && mat22 > 0 && fabs(mat11/mat22 - 1) < 0.2 &&
  478.           fabs(mat12) < 0.01 && fabs(mat21) < 0.01);
  479.  
  480.   // open X font -- if font is not found (which means the server can't
  481.   // scale fonts), try progressively smaller and then larger sizes
  482.   //~ This does a linear search -- it should get a list of fonts from
  483.   //~ the server and pick the closest.
  484.   if (rotated)
  485.     sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]",
  486.         mat11<0 ? "~" : "", fabs(mat11 * startSize),
  487.         mat12<0 ? "~" : "", fabs(mat12 * startSize),
  488.         mat21<0 ? "~" : "", fabs(mat21 * startSize),
  489.         mat22<0 ? "~" : "", fabs(mat22 * startSize));
  490.   else
  491.     sprintf(fontSize, "%d", startSize);
  492.   sprintf(fontName, fontNameFmt, fontSize);
  493.   xFont = XLoadQueryFont(display, fontName);
  494.   if (!xFont) {
  495.     for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) {
  496.       sprintf(fontSize, "%d", sz);
  497.       sprintf(fontName, fontNameFmt, fontSize);
  498.       if ((xFont = XLoadQueryFont(display, fontName)))
  499.     break;
  500.     }
  501.     if (!xFont) {
  502.       for (sz = startSize + 1; sz < startSize + 10; ++sz) {
  503.     sprintf(fontSize, "%d", sz);
  504.     sprintf(fontName, fontNameFmt, fontSize);
  505.     if ((xFont = XLoadQueryFont(display, fontName)))
  506.       break;
  507.       }
  508.       if (!xFont) {
  509.     sprintf(fontSize, "%d", startSize);
  510.     sprintf(fontName, fontNameFmt, fontSize);
  511.     error(-1, "Failed to open font: '%s'", fontName);
  512.     return;
  513.       }
  514.     }
  515.   }
  516. }
  517.  
  518. XOutputFont::~XOutputFont() {
  519.   if (xFont)
  520.     XFreeFont(display, xFont);
  521. }
  522.  
  523. //------------------------------------------------------------------------
  524. // XOutputFontCache
  525. //------------------------------------------------------------------------
  526.  
  527. XOutputFontCache::XOutputFontCache(Display *display1) {
  528.   int i;
  529.  
  530.   display = display1;
  531.   for (i = 0; i < fontCacheSize; ++i)
  532.     fonts[i] = NULL;
  533.   numFonts = 0;
  534. }
  535.  
  536. XOutputFontCache::~XOutputFontCache() {
  537.   int i;
  538.  
  539.   for (i = 0; i < numFonts; ++i)
  540.     delete fonts[i];
  541. }
  542.  
  543. XOutputFont *XOutputFontCache::getFont(GfxFont *gfxFont,
  544.                        double m11, double m12,
  545.                        double m21, double m22) {
  546.   XOutputFont *font;
  547.   int i, j;
  548.  
  549.   // is it the most recently used font?
  550.   if (numFonts > 0 && fonts[0]->matches(gfxFont->getID(),
  551.                     m11, m12, m21, m22))
  552.     return fonts[0];
  553.  
  554.   // is it in the cache?
  555.   for (i = 1; i < numFonts; ++i) {
  556.     if (fonts[i]->matches(gfxFont->getID(), m11, m12, m21, m22)) {
  557.       font = fonts[i];
  558.       for (j = i; j > 0; --j)
  559.     fonts[j] = fonts[j-1];
  560.       fonts[0] = font;
  561.       return font;
  562.     }
  563.   }
  564.  
  565.   // make a new font
  566.   font = new XOutputFont(gfxFont, m11, m12, m21, m22, display);
  567.   if (!font->getXFont()) {
  568.     delete font;
  569.     return NULL;
  570.   }
  571.  
  572.   // insert font in cache
  573.   if (numFonts == fontCacheSize) {
  574.     --numFonts;
  575.     delete fonts[numFonts];
  576.   }
  577.   for (j = numFonts; j > 0; --j)
  578.     fonts[j] = fonts[j-1];
  579.   fonts[0] = font;
  580.   ++numFonts;
  581.  
  582.   // return it
  583.   return font;
  584. }
  585.  
  586. //------------------------------------------------------------------------
  587. // XOutputDev
  588. //------------------------------------------------------------------------
  589.  
  590. XOutputDev::XOutputDev(Display *display1, Pixmap pixmap1, Guint depth1,
  591.                Colormap colormap, unsigned long paperColor) {
  592.   XVisualInfo visualTempl;
  593.   XVisualInfo *visualList;
  594.   int nVisuals;
  595.   Gulong mask;
  596.   XGCValues gcValues;
  597.   XColor xcolor;
  598.   XColor *xcolors;
  599.   int r, g, b, n, m, i;
  600.   GBool ok;
  601.  
  602.   // get display/pixmap info
  603.   display = display1;
  604.   screenNum = DefaultScreen(display);
  605.   pixmap = pixmap1;
  606.   depth = depth1;
  607.  
  608.   // check for TrueColor visual
  609.   trueColor = gFalse;
  610.   if (depth == 0) {
  611.     depth = DefaultDepth(display, screenNum);
  612.     visualList = XGetVisualInfo(display, 0, &visualTempl, &nVisuals);
  613.     for (i = 0; i < nVisuals; ++i) {
  614.       if (visualList[i].visual == DefaultVisual(display, screenNum)) {
  615.     if (visualList[i].c_class == TrueColor) {
  616.       trueColor = gTrue;
  617.       mask = visualList[i].red_mask;
  618.       rShift = 0;
  619.       while (mask && !(mask & 1)) {
  620.         ++rShift;
  621.         mask >>= 1;
  622.       }
  623.       rMul = (int)mask;
  624.       mask = visualList[i].green_mask;
  625.       gShift = 0;
  626.       while (mask && !(mask & 1)) {
  627.         ++gShift;
  628.         mask >>= 1;
  629.       }
  630.       gMul = (int)mask;
  631.       mask = visualList[i].blue_mask;
  632.       bShift = 0;
  633.       while (mask && !(mask & 1)) {
  634.         ++bShift;
  635.         mask >>= 1;
  636.       }
  637.       bMul = (int)mask;
  638.     }
  639.     break;
  640.       }
  641.     }
  642.     XFree((XPointer)visualList);
  643.   }
  644.  
  645.   // allocate a color cube
  646.   if (!trueColor) {
  647.  
  648.     // set colors in private colormap
  649.     if (installCmap) {
  650.       for (numColors = 6; numColors >= 2; --numColors) {
  651.     m = numColors * numColors * numColors;
  652.     if (XAllocColorCells(display, colormap, False, NULL, 0, colors, m))
  653.       break;
  654.       }
  655.       if (numColors >= 2) {
  656.     m = numColors * numColors * numColors;
  657.     xcolors = (XColor *)gmalloc(m * sizeof(XColor));
  658.     n = 0;
  659.     for (r = 0; r < numColors; ++r) {
  660.       for (g = 0; g < numColors; ++g) {
  661.         for (b = 0; b < numColors; ++b) {
  662.           xcolors[n].pixel = colors[n];
  663.           xcolors[n].red = (r * 65535) / (numColors - 1);
  664.           xcolors[n].green = (g * 65535) / (numColors - 1);
  665.           xcolors[n].blue = (b * 65535) / (numColors - 1);
  666.           xcolors[n].flags = DoRed | DoGreen | DoBlue;
  667.           ++n;
  668.         }
  669.       }
  670.     }
  671.     XStoreColors(display, colormap, xcolors, m);
  672.     gfree(xcolors);
  673.       } else {
  674.     numColors = 1;
  675.     colors[0] = BlackPixel(display, screenNum);
  676.     colors[1] = WhitePixel(display, screenNum);
  677.       }
  678.  
  679.     // allocate colors in shared colormap
  680.     } else {
  681.       if (rgbCubeSize > maxRGBCube)
  682.     rgbCubeSize = maxRGBCube;
  683.       ok = gFalse;
  684.       for (numColors = rgbCubeSize; numColors >= 2; --numColors) {
  685.     ok = gTrue;
  686.     n = 0;
  687.     for (r = 0; r < numColors && ok; ++r) {
  688.       for (g = 0; g < numColors && ok; ++g) {
  689.         for (b = 0; b < numColors && ok; ++b) {
  690.           if (n == 0) {
  691.         colors[n++] = BlackPixel(display, screenNum);
  692.           } else {
  693.         xcolor.red = (r * 65535) / (numColors - 1);
  694.         xcolor.green = (g * 65535) / (numColors - 1);
  695.         xcolor.blue = (b * 65535) / (numColors - 1);
  696.         if (XAllocColor(display, colormap, &xcolor))
  697.           colors[n++] = xcolor.pixel;
  698.         else
  699.           ok = gFalse;
  700.           }
  701.         }
  702.       }
  703.     }
  704.     if (ok)
  705.       break;
  706.     XFreeColors(display, colormap, &colors[1], n-1, 0);
  707.       }
  708.       if (!ok) {
  709.     numColors = 1;
  710.     colors[0] = BlackPixel(display, screenNum);
  711.     colors[1] = WhitePixel(display, screenNum);
  712.       }
  713.     }
  714.   }
  715.  
  716.   // allocate GCs
  717.   gcValues.foreground = BlackPixel(display, screenNum);
  718.   gcValues.background = WhitePixel(display, screenNum);
  719.   gcValues.line_width = 0;
  720.   gcValues.line_style = LineSolid;
  721.   strokeGC = XCreateGC(display, pixmap,
  722.                GCForeground | GCBackground | GCLineWidth | GCLineStyle,
  723.                        &gcValues);
  724.   fillGC = XCreateGC(display, pixmap,
  725.              GCForeground | GCBackground | GCLineWidth | GCLineStyle,
  726.              &gcValues);
  727.   gcValues.foreground = paperColor;
  728.   paperGC = XCreateGC(display, pixmap,
  729.               GCForeground | GCBackground | GCLineWidth | GCLineStyle,
  730.               &gcValues);
  731.  
  732.   // no clip region yet
  733.   clipRegion = NULL;
  734.  
  735.   // get user font map
  736.   for (n = 0; devFontMap[n].pdfFont; ++n) ;
  737.   userFontMap = (FontMapEntry *)gmalloc((n+1) * sizeof(FontMapEntry));
  738.   for (i = 0; i < n; ++i) {
  739.     userFontMap[i].pdfFont = devFontMap[i].pdfFont;
  740.     userFontMap[i].xFont = devFontMap[i].devFont;
  741.     m = strlen(userFontMap[i].xFont);
  742.     if (m >= 10 && !strcmp(userFontMap[i].xFont + m - 10, "-iso8859-2"))
  743.       userFontMap[i].encoding = &isoLatin2Encoding;
  744.     else if (m >= 13 && !strcmp(userFontMap[i].xFont + m - 13,
  745.                 "-fontspecific"))
  746.       userFontMap[i].encoding = NULL;
  747.     else
  748.       userFontMap[i].encoding = &isoLatin1Encoding;
  749.   }
  750.   userFontMap[n].pdfFont = NULL;
  751.  
  752.   // set up the font cache and fonts
  753.   gfxFont = NULL;
  754.   font = NULL;
  755.   fontCache = new XOutputFontCache(display);
  756.  
  757.   // empty state stack
  758.   save = NULL;
  759.  
  760.   // create text object
  761.   text = new TextPage(gFalse);
  762. }
  763.  
  764. XOutputDev::~XOutputDev() {
  765.   gfree(userFontMap);
  766.   delete fontCache;
  767.   XFreeGC(display, strokeGC);
  768.   XFreeGC(display, fillGC);
  769.   XFreeGC(display, paperGC);
  770.   if (clipRegion)
  771.     XDestroyRegion(clipRegion);
  772.   delete text;
  773. }
  774.  
  775. void XOutputDev::startPage(int pageNum, GfxState *state) {
  776.   XOutputState *s;
  777.   XGCValues gcValues;
  778.   XRectangle rect;
  779.  
  780.   // clear state stack
  781.   while (save) {
  782.     s = save;
  783.     save = save->next;
  784.     XFreeGC(display, s->strokeGC);
  785.     XFreeGC(display, s->fillGC);
  786.     XDestroyRegion(s->clipRegion);
  787.     delete s;
  788.   }
  789.   save = NULL;
  790.  
  791.   // default line flatness
  792.   flatness = 0;
  793.  
  794.   // reset GCs
  795.   gcValues.foreground = BlackPixel(display, screenNum);
  796.   gcValues.background = WhitePixel(display, screenNum);
  797.   gcValues.line_width = 0;
  798.   gcValues.line_style = LineSolid;
  799.   XChangeGC(display, strokeGC,
  800.         GCForeground | GCBackground | GCLineWidth | GCLineStyle,
  801.         &gcValues);
  802.   XChangeGC(display, fillGC,
  803.         GCForeground | GCBackground | GCLineWidth | GCLineStyle,
  804.         &gcValues);
  805.  
  806.   // clear clipping region
  807.   if (clipRegion)
  808.     XDestroyRegion(clipRegion);
  809.   clipRegion = XCreateRegion();
  810.   rect.x = rect.y = 0;
  811.   rect.width = pixmapW;
  812.   rect.height = pixmapH;
  813.   XUnionRectWithRegion(&rect, clipRegion, clipRegion);
  814.   XSetRegion(display, strokeGC, clipRegion);
  815.   XSetRegion(display, fillGC, clipRegion);
  816.  
  817.   // clear font
  818.   gfxFont = NULL;
  819.   font = NULL;
  820.  
  821.   // clear window
  822.   XFillRectangle(display, pixmap, paperGC, 0, 0, pixmapW, pixmapH);
  823.  
  824.   // clear text object
  825.   text->clear();
  826. }
  827.  
  828. void XOutputDev::endPage() {
  829.   text->coalesce();
  830. }
  831.  
  832. void XOutputDev::drawLinkBorder(double x1, double y1, double x2, double y2,
  833.                 double w) {
  834.   GfxColor color;
  835.   XPoint points[5];
  836.   int x, y;
  837.  
  838.   color.setRGB(0, 0, 1);
  839.   XSetForeground(display, strokeGC, findColor(&color));
  840.   XSetLineAttributes(display, strokeGC, xoutRound(w),
  841.              LineSolid, CapRound, JoinRound);
  842.   cvtUserToDev(x1, y1, &x, &y);
  843.   points[0].x = points[4].x = x;
  844.   points[0].y = points[4].y = y;
  845.   cvtUserToDev(x2, y1, &x, &y);
  846.   points[1].x = x;
  847.   points[1].y = y;
  848.   cvtUserToDev(x2, y2, &x, &y);
  849.   points[2].x = x;
  850.   points[2].y = y;
  851.   cvtUserToDev(x1, y2, &x, &y);
  852.   points[3].x = x;
  853.   points[3].y = y;
  854.   XDrawLines(display, pixmap, strokeGC, points, 5, CoordModeOrigin);
  855. }
  856.  
  857. void XOutputDev::saveState(GfxState *state) {
  858.   XOutputState *s;
  859.   XGCValues values;
  860.  
  861.   // save current state
  862.   s = new XOutputState;
  863.   s->strokeGC = strokeGC;
  864.   s->fillGC = fillGC;
  865.   s->clipRegion = clipRegion;
  866.  
  867.   // push onto state stack
  868.   s->next = save;
  869.   save = s;
  870.  
  871.   // create a new current state by copying
  872.   strokeGC = XCreateGC(display, pixmap, 0, &values);
  873.   XCopyGC(display, s->strokeGC, 0xffffffff, strokeGC);
  874.   fillGC = XCreateGC(display, pixmap, 0, &values);
  875.   XCopyGC(display, s->fillGC, 0xffffffff, fillGC);
  876.   clipRegion = XCreateRegion();
  877.   XUnionRegion(s->clipRegion, clipRegion, clipRegion);
  878.   XSetRegion(display, strokeGC, clipRegion);
  879.   XSetRegion(display, fillGC, clipRegion);
  880. }
  881.  
  882. void XOutputDev::restoreState(GfxState *state) {
  883.   XOutputState *s;
  884.  
  885.   if (save) {
  886.     // kill current state
  887.     XFreeGC(display, strokeGC);
  888.     XFreeGC(display, fillGC);
  889.     XDestroyRegion(clipRegion);
  890.  
  891.     // restore state
  892.     flatness = state->getFlatness();
  893.     strokeGC = save->strokeGC;
  894.     fillGC = save->fillGC;
  895.     clipRegion = save->clipRegion;
  896.     XSetRegion(display, strokeGC, clipRegion);
  897.     XSetRegion(display, fillGC, clipRegion);
  898.  
  899.     // pop state stack
  900.     s = save;
  901.     save = save->next;
  902.     delete s;
  903.   }
  904. }
  905.  
  906. void XOutputDev::updateAll(GfxState *state) {
  907.   updateLineAttrs(state, gTrue);
  908.   updateFlatness(state);
  909.   updateMiterLimit(state);
  910.   updateFillColor(state);
  911.   updateStrokeColor(state);
  912.   updateFont(state);
  913. }
  914.  
  915. void XOutputDev::updateCTM(GfxState *state, double m11, double m12,
  916.                double m21, double m22, double m31, double m32) {
  917.   updateLineAttrs(state, gTrue);
  918. }
  919.  
  920. void XOutputDev::updateLineDash(GfxState *state) {
  921.   updateLineAttrs(state, gTrue);
  922. }
  923.  
  924. void XOutputDev::updateFlatness(GfxState *state) {
  925.   flatness = state->getFlatness();
  926. }
  927.  
  928. void XOutputDev::updateLineJoin(GfxState *state) {
  929.   updateLineAttrs(state, gFalse);
  930. }
  931.  
  932. void XOutputDev::updateLineCap(GfxState *state) {
  933.   updateLineAttrs(state, gFalse);
  934. }
  935.  
  936. // unimplemented
  937. void XOutputDev::updateMiterLimit(GfxState *state) {
  938. }
  939.  
  940. void XOutputDev::updateLineWidth(GfxState *state) {
  941.   updateLineAttrs(state, gFalse);
  942. }
  943.  
  944. void XOutputDev::updateLineAttrs(GfxState *state, GBool updateDash) {
  945.   double width;
  946.   int cap, join;
  947.   double *dashPattern;
  948.   int dashLength;
  949.   double dashStart;
  950.   char dashList[20];
  951.   int i;
  952.  
  953.   width = state->getTransformedLineWidth();
  954.   switch (state->getLineCap()) {
  955.   case 0: cap = CapButt; break;
  956.   case 1: cap = CapRound; break;
  957.   case 2: cap = CapProjecting; break;
  958.   default:
  959.     error(-1, "Bad line cap style (%d)", state->getLineCap());
  960.     cap = CapButt;
  961.     break;
  962.   }
  963.   switch (state->getLineJoin()) {
  964.   case 0: join = JoinMiter; break;
  965.   case 1: join = JoinRound; break;
  966.   case 2: join = JoinBevel; break;
  967.   default:
  968.     error(-1, "Bad line join style (%d)", state->getLineJoin());
  969.     join = JoinMiter;
  970.     break;
  971.   }
  972.   state->getLineDash(&dashPattern, &dashLength, &dashStart);
  973.   XSetLineAttributes(display, strokeGC, xoutRound(width),
  974.              dashLength > 0 ? LineOnOffDash : LineSolid,
  975.              cap, join);
  976.   if (updateDash && dashLength > 0) {
  977.     if (dashLength > 20)
  978.       dashLength = 20;
  979.     for (i = 0; i < dashLength; ++i) {
  980.       dashList[i] = xoutRound(state->transformWidth(dashPattern[i]));
  981.       if (dashList[i] == 0)
  982.     dashList[i] = 1;
  983.     }
  984.     XSetDashes(display, strokeGC, xoutRound(dashStart), dashList, dashLength);
  985.   }
  986. }
  987.  
  988. void XOutputDev::updateFillColor(GfxState *state) {
  989.   XSetForeground(display, fillGC, findColor(state->getFillColor()));
  990. }
  991.  
  992. void XOutputDev::updateStrokeColor(GfxState *state) {
  993.   XSetForeground(display, strokeGC, findColor(state->getStrokeColor()));
  994. }
  995.  
  996. void XOutputDev::updateFont(GfxState *state) {
  997.   double m11, m12, m21, m22;
  998.  
  999.   if (!(gfxFont = state->getFont())) {
  1000.     font = NULL;
  1001.     return;
  1002.   }
  1003.   state->getFontTransMat(&m11, &m12, &m21, &m22);
  1004.   m11 *= state->getHorizScaling();
  1005.   m21 *= state->getHorizScaling();
  1006.   font = fontCache->getFont(gfxFont, m11, m12, m21, m22);
  1007.   if (font) {
  1008.     XSetFont(display, fillGC, font->getXFont()->fid);
  1009.     XSetFont(display, strokeGC, font->getXFont()->fid);
  1010.   }
  1011. }
  1012.  
  1013. void XOutputDev::stroke(GfxState *state) {
  1014.   XPoint *points;
  1015.   int *lengths;
  1016.   int n, size, numPoints, i, j;
  1017.  
  1018.   // transform points
  1019.   n = convertPath(state, &points, &size, &numPoints, &lengths, gFalse);
  1020.  
  1021.   // draw each subpath
  1022.   j = 0;
  1023.   for (i = 0; i < n; ++i) {
  1024.     XDrawLines(display, pixmap, strokeGC, points + j, lengths[i],
  1025.            CoordModeOrigin);
  1026.     j += lengths[i];
  1027.   }
  1028.  
  1029.   // free points and lengths arrays
  1030.   if (points != tmpPoints)
  1031.     gfree(points);
  1032.   if (lengths != tmpLengths)
  1033.     gfree(lengths);
  1034. }
  1035.  
  1036. void XOutputDev::fill(GfxState *state) {
  1037.   doFill(state, WindingRule);
  1038. }
  1039.  
  1040. void XOutputDev::eoFill(GfxState *state) {
  1041.   doFill(state, EvenOddRule);
  1042. }
  1043.  
  1044. //
  1045. //  X doesn't color the pixels on the right-most and bottom-most
  1046. //  borders of a polygon.  This means that one-pixel-thick polygons
  1047. //  are not colored at all.  I think this is supposed to be a
  1048. //  feature, but I can't figure out why.  So after it fills a
  1049. //  polygon, it also draws lines around the border.  This is done
  1050. //  only for single-component polygons, since it's not very
  1051. //  compatible with the compound polygon kludge (see convertPath()).
  1052. //
  1053. void XOutputDev::doFill(GfxState *state, int rule) {
  1054.   XPoint *points;
  1055.   int *lengths;
  1056.   int n, size, numPoints, i, j;
  1057.  
  1058.   // set fill rule
  1059.   XSetFillRule(display, fillGC, rule);
  1060.  
  1061.   // transform points, build separate polygons
  1062.   n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
  1063.  
  1064.   // fill them
  1065.   j = 0;
  1066.   for (i = 0; i < n; ++i) {
  1067.     XFillPolygon(display, pixmap, fillGC, points + j, lengths[i],
  1068.          Complex, CoordModeOrigin);
  1069.     if (state->getPath()->getNumSubpaths() == 1) {
  1070.       XDrawLines(display, pixmap, fillGC, points + j, lengths[i],
  1071.          CoordModeOrigin);
  1072.     }
  1073.     j += lengths[i] + 1;
  1074.   }
  1075.  
  1076.   // free points and lengths arrays
  1077.   if (points != tmpPoints)
  1078.     gfree(points);
  1079.   if (lengths != tmpLengths)
  1080.     gfree(lengths);
  1081. }
  1082.  
  1083. void XOutputDev::clip(GfxState *state) {
  1084.   doClip(state, WindingRule);
  1085. }
  1086.  
  1087. void XOutputDev::eoClip(GfxState *state) {
  1088.   doClip(state, EvenOddRule);
  1089. }
  1090.  
  1091. void XOutputDev::doClip(GfxState *state, int rule) {
  1092.   Region region, region2;
  1093.   XPoint *points;
  1094.   int *lengths;
  1095.   int n, size, numPoints, i, j;
  1096.  
  1097.   // transform points, build separate polygons
  1098.   n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
  1099.  
  1100.   // construct union of subpath regions
  1101.   region = XPolygonRegion(points, lengths[0], rule);
  1102.   j = lengths[0] + 1;
  1103.   for (i = 1; i < n; ++i) {
  1104.     region2 = XPolygonRegion(points + j, lengths[i], rule);
  1105.     XUnionRegion(region2, region, region);
  1106.     XDestroyRegion(region2);
  1107.     j += lengths[i] + 1;
  1108.   }
  1109.  
  1110.   // intersect region with clipping region
  1111.   XIntersectRegion(region, clipRegion, clipRegion);
  1112.   XDestroyRegion(region);
  1113.   XSetRegion(display, strokeGC, clipRegion);
  1114.   XSetRegion(display, fillGC, clipRegion);
  1115.  
  1116.   // free points and lengths arrays
  1117.   if (points != tmpPoints)
  1118.     gfree(points);
  1119.   if (lengths != tmpLengths)
  1120.     gfree(lengths);
  1121. }
  1122.  
  1123. //
  1124. // Transform points in the path and convert curves to line segments.
  1125. // Builds a set of subpaths and returns the number of subpaths.
  1126. // If <fillHack> is set, close any unclosed subpaths and activate a
  1127. // kludge for polygon fills:  First, it divides up the subpaths into
  1128. // non-overlapping polygons by simply comparing bounding rectangles.
  1129. // Then it connects subaths within a single compound polygon to a single
  1130. // point so that X can fill the polygon (sort of).
  1131. //
  1132. int XOutputDev::convertPath(GfxState *state, XPoint **points, int *size,
  1133.                 int *numPoints, int **lengths, GBool fillHack) {
  1134.   GfxPath *path;
  1135.   BoundingRect *rects;
  1136.   BoundingRect rect;
  1137.   int n, i, ii, j, k, k0;
  1138.  
  1139.   // get path and number of subpaths
  1140.   path = state->getPath();
  1141.   n = path->getNumSubpaths();
  1142.  
  1143.   // allocate lengths array
  1144.   if (n < numTmpSubpaths)
  1145.     *lengths = tmpLengths;
  1146.   else
  1147.     *lengths = (int *)gmalloc(n * sizeof(int));
  1148.  
  1149.   // allocate bounding rectangles array
  1150.   if (fillHack) {
  1151.     if (n < numTmpSubpaths)
  1152.       rects = tmpRects;
  1153.     else
  1154.       rects = (BoundingRect *)gmalloc(n * sizeof(BoundingRect));
  1155.   } else {
  1156.     rects = NULL;
  1157.   }
  1158.  
  1159.   // do each subpath
  1160.   *points = tmpPoints;
  1161.   *size = numTmpPoints;
  1162.   *numPoints = 0;
  1163.   for (i = 0; i < n; ++i) {
  1164.  
  1165.     // transform the points
  1166.     j = *numPoints;
  1167.     convertSubpath(state, path->getSubpath(i), points, size, numPoints);
  1168.  
  1169.     // construct bounding rectangle
  1170.     if (fillHack) {
  1171.       rects[i].xMin = rects[i].xMax = (*points)[j].x;
  1172.       rects[i].yMin = rects[i].yMax = (*points)[j].y;
  1173.       for (k = j + 1; k < *numPoints; ++k) {
  1174.     if ((*points)[k].x < rects[i].xMin)
  1175.       rects[i].xMin = (*points)[k].x;
  1176.     else if ((*points)[k].x > rects[i].xMax)
  1177.       rects[i].xMax = (*points)[k].x;
  1178.     if ((*points)[k].y < rects[i].yMin)
  1179.       rects[i].yMin = (*points)[k].y;
  1180.     else if ((*points)[k].y > rects[i].yMax)
  1181.       rects[i].yMax = (*points)[k].y;
  1182.       }
  1183.     }
  1184.  
  1185.     // close subpath if necessary
  1186.     if (fillHack && ((*points)[*numPoints-1].x != (*points)[j].x ||
  1187.            (*points)[*numPoints-1].y != (*points)[j].y)) {
  1188.       addPoint(points, size, numPoints, (*points)[j].x, (*points)[j].y);
  1189.     }
  1190.  
  1191.     // length of this subpath
  1192.     (*lengths)[i] = *numPoints - j;
  1193.  
  1194.     // leave an extra point for compound fill hack
  1195.     if (fillHack)
  1196.       addPoint(points, size, numPoints, 0, 0);
  1197.   }
  1198.  
  1199.   // combine compound polygons
  1200.   if (fillHack) {
  1201.     i = j = k = 0;
  1202.     while (i < n) {
  1203.  
  1204.       // start with subpath i
  1205.       rect = rects[i];
  1206.       (*lengths)[j] = (*lengths)[i];
  1207.       k0 = k;
  1208.       (*points)[k + (*lengths)[i]] = (*points)[k0];
  1209.       k += (*lengths)[i] + 1;
  1210.       ++i;
  1211.  
  1212.       // combine overlapping polygons
  1213.       do {
  1214.  
  1215.     // look for the first subsequent subpath, if any, which overlaps
  1216.     for (ii = i; ii < n; ++ii) {
  1217.       if (((rects[ii].xMin > rect.xMin && rects[ii].xMin < rect.xMax) ||
  1218.            (rects[ii].xMax > rect.xMin && rects[ii].xMax < rect.xMax) ||
  1219.            (rects[ii].xMin < rect.xMin && rects[ii].xMax > rect.xMax)) &&
  1220.           ((rects[ii].yMin > rect.yMin && rects[ii].yMin < rect.yMax) ||
  1221.            (rects[ii].yMax > rect.yMin && rects[ii].yMax < rect.yMax) ||
  1222.            (rects[ii].yMin < rect.yMin && rects[ii].yMax > rect.yMax)))
  1223.         break;
  1224.     }
  1225.  
  1226.     // if there is an overlap, combine the polygons
  1227.     if (ii < n) {
  1228.       for (; i <= ii; ++i) {
  1229.         if (rects[i].xMin < rect.xMin)
  1230.           rect.xMin = rects[j].xMin;
  1231.         if (rects[i].xMax > rect.xMax)
  1232.           rect.xMax = rects[j].xMax;
  1233.         if (rects[i].yMin < rect.yMin)
  1234.           rect.yMin = rects[j].yMin;
  1235.         if (rects[i].yMax > rect.yMax)
  1236.           rect.yMax = rects[j].yMax;
  1237.         (*lengths)[j] += (*lengths)[i] + 1;
  1238.         (*points)[k + (*lengths)[i]] = (*points)[k0];
  1239.         k += (*lengths)[i] + 1;
  1240.       }
  1241.     }
  1242.       } while (ii < n && i < n);
  1243.  
  1244.       ++j;
  1245.     }
  1246.  
  1247.     // free bounding rectangles
  1248.     if (rects != tmpRects)
  1249.       gfree(rects);
  1250.  
  1251.     n = j;
  1252.   }
  1253.  
  1254.   return n;
  1255. }
  1256.  
  1257. //
  1258. // Transform points in a single subpath and convert curves to line
  1259. // segments.
  1260. //
  1261. void XOutputDev::convertSubpath(GfxState *state, GfxSubpath *subpath,
  1262.                 XPoint **points, int *size, int *n) {
  1263.   double x0, y0, x1, y1, x2, y2, x3, y3;
  1264.   int m, i;
  1265.  
  1266.   m = subpath->getNumPoints();
  1267.   i = 0;
  1268.   while (i < m) {
  1269.     if (i >= 1 && subpath->getCurve(i)) {
  1270.       state->transform(subpath->getX(i-1), subpath->getY(i-1), &x0, &y0);
  1271.       state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
  1272.       state->transform(subpath->getX(i+1), subpath->getY(i+1), &x2, &y2);
  1273.       state->transform(subpath->getX(i+2), subpath->getY(i+2), &x3, &y3);
  1274.       doCurve(points, size, n, x0, y0, x1, y1, x2, y2, x3, y3);
  1275.       i += 3;
  1276.     } else {
  1277.       state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
  1278.       addPoint(points, size, n, xoutRound(x1), xoutRound(y1));
  1279.       ++i;
  1280.     }
  1281.   }
  1282. }
  1283.  
  1284. //
  1285. // Subdivide a Bezier curve.  This uses floating point to avoid
  1286. // propagating rounding errors.  (The curves look noticeably more
  1287. // jagged with integer arithmetic.)
  1288. //
  1289. void XOutputDev::doCurve(XPoint **points, int *size, int *n,
  1290.              double x0, double y0, double x1, double y1,
  1291.              double x2, double y2, double x3, double y3) {
  1292.   double x[(1<<maxCurveSplits)+1][3];
  1293.   double y[(1<<maxCurveSplits)+1][3];
  1294.   int next[1<<maxCurveSplits];
  1295.   int p1, p2, p3;
  1296.   double xx1, yy1, xx2, yy2;
  1297.   double dx, dy, mx, my, d1, d2;
  1298.   double xl0, yl0, xl1, yl1, xl2, yl2;
  1299.   double xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3;
  1300.   double xh, yh;
  1301.   double flat;
  1302.  
  1303.   flat = (double)(flatness * flatness);
  1304.   if (flat < 1)
  1305.     flat = 1;
  1306.  
  1307.   // initial segment
  1308.   p1 = 0;
  1309.   p2 = 1<<maxCurveSplits;
  1310.   x[p1][0] = x0;  y[p1][0] = y0;
  1311.   x[p1][1] = x1;  y[p1][1] = y1;
  1312.   x[p1][2] = x2;  y[p1][2] = y2;
  1313.   x[p2][0] = x3;  y[p2][0] = y3;
  1314.   next[p1] = p2;
  1315.  
  1316.   while (p1 < (1<<maxCurveSplits)) {
  1317.  
  1318.     // get next segment
  1319.     xl0 = x[p1][0];  yl0 = y[p1][0];
  1320.     xx1 = x[p1][1];  yy1 = y[p1][1];
  1321.     xx2 = x[p1][2];  yy2 = y[p1][2];
  1322.     p2 = next[p1];
  1323.     xr3 = x[p2][0];  yr3 = y[p2][0];
  1324.  
  1325.     // compute distances from control points to midpoint of the
  1326.     // straight line (this is a bit of a hack, but it's much faster
  1327.     // than computing the actual distances to the line)
  1328.     mx = (xl0 + xr3) * 0.5;
  1329.     my = (yl0 + yr3) * 0.5;
  1330.     dx = xx1 - mx;
  1331.     dy = yy1 - my;
  1332.     d1 = dx*dx + dy*dy;
  1333.     dx = xx2 - mx;
  1334.     dy = yy2 - my;
  1335.     d2 = dx*dx + dy*dy;
  1336.  
  1337.     // if curve is flat enough, or no more divisions allowed then
  1338.     // add the straight line segment
  1339.     if (p2 - p1 <= 1 || (d1 <= flat && d2 <= flat)) {
  1340.       addPoint(points, size, n, xoutRound(xr3), xoutRound(yr3));
  1341.       p1 = p2;
  1342.  
  1343.     // otherwise, subdivide the curve
  1344.     } else {
  1345.       xl1 = (xl0 + xx1) * 0.5;
  1346.       yl1 = (yl0 + yy1) * 0.5;
  1347.       xh = (xx1 + xx2) * 0.5;
  1348.       yh = (yy1 + yy2) * 0.5;
  1349.       xl2 = (xl1 + xh) * 0.5;
  1350.       yl2 = (yl1 + yh) * 0.5;
  1351.       xr2 = (xx2 + xr3) * 0.5;
  1352.       yr2 = (yy2 + yr3) * 0.5;
  1353.       xr1 = (xh + xr2) * 0.5;
  1354.       yr1 = (yh + yr2) * 0.5;
  1355.       xr0 = (xl2 + xr1) * 0.5;
  1356.       yr0 = (yl2 + yr1) * 0.5;
  1357.  
  1358.       // add the new subdivision points
  1359.       p3 = (p1 + p2) / 2;
  1360.       x[p1][1] = xl1;  y[p1][1] = yl1;
  1361.       x[p1][2] = xl2;  y[p1][2] = yl2;
  1362.       next[p1] = p3;
  1363.       x[p3][0] = xr0;  y[p3][0] = yr0;
  1364.       x[p3][1] = xr1;  y[p3][1] = yr1;
  1365.       x[p3][2] = xr2;  y[p3][2] = yr2;
  1366.       next[p3] = p2;
  1367.     }
  1368.   }
  1369. }
  1370.  
  1371. //
  1372. // Add a point to the points array.  (This would use a generic resizable
  1373. // array type if C++ supported parameterized types in some reasonable
  1374. // way -- templates are a disgusting kludge.)
  1375. //
  1376. void XOutputDev::addPoint(XPoint **points, int *size, int *k, int x, int y) {
  1377.   if (*k >= *size) {
  1378.     *size += 32;
  1379.     if (*points == tmpPoints) {
  1380.       *points = (XPoint *)gmalloc(*size * sizeof(XPoint));
  1381.       memcpy(*points, tmpPoints, *k * sizeof(XPoint));
  1382.     } else {
  1383.       *points = (XPoint *)grealloc(*points, *size * sizeof(XPoint));
  1384.     }
  1385.   }
  1386.   (*points)[*k].x = x;
  1387.   (*points)[*k].y = y;
  1388.   ++(*k);
  1389. }
  1390.  
  1391. void XOutputDev::beginString(GfxState *state, GString *s) {
  1392.   text->beginString(state, s, font ? font->isHex() : gFalse);
  1393. }
  1394.  
  1395. void XOutputDev::endString(GfxState *state) {
  1396.   text->endString();
  1397. }
  1398.  
  1399. void XOutputDev::drawChar(GfxState *state, double x, double y,
  1400.               double dx, double dy, Guchar c) {
  1401.   Gushort c1;
  1402.   char buf;
  1403.   char *p;
  1404.   int n, i;
  1405.   double x1, y1;
  1406.   double tx;
  1407.  
  1408.   text->addChar(state, x, y, dx, dy, c);
  1409.  
  1410.   if (!font)
  1411.     return;
  1412.  
  1413.   // check for invisible text -- this is used by Acrobat Capture
  1414.   if ((state->getRender() & 3) == 3)
  1415.     return;
  1416.  
  1417.   state->transform(x, y, &x1, &y1);
  1418.   c1 = font->mapChar(c);
  1419.   if (c1 <= lastRegularChar) {
  1420.     buf = (char)c1;
  1421.     XDrawString(display, pixmap,
  1422.         (state->getRender() & 1) ? strokeGC : fillGC,
  1423.         xoutRound(x1), xoutRound(y1), &buf, 1);
  1424.   } else if (c1 <= lastSubstChar) {
  1425.     buf = (char)substChars[c1 - firstSubstChar];
  1426.     XDrawString(display, pixmap,
  1427.         (state->getRender() & 1) ? strokeGC : fillGC,
  1428.         xoutRound(x1), xoutRound(y1), &buf, 1);
  1429.   } else if (c1 <= lastConstrChar) {
  1430.     //~ need to deal with rotated text here
  1431.     switch (c1 - firstConstrChar) {
  1432.     case 0: // bullet
  1433.       tx = 0.25 * state->getTransformedFontSize() * 
  1434.            gfxFont->getWidth(c);
  1435.       XFillRectangle(display, pixmap,
  1436.              (state->getRender() & 1) ? strokeGC : fillGC,
  1437.              xoutRound(x1 + tx),
  1438.              xoutRound(y1 - 0.4 * font->getXFont()->ascent - tx),
  1439.              xoutRound(2 * tx), xoutRound(2 * tx));
  1440.       break;
  1441.     case 1: // trademark
  1442. //~ this should use a smaller font
  1443. //      tx = state->getTransformedFontSize() *
  1444. //           (gfxFont->getWidth(c) -
  1445. //            gfxFont->getWidth(font->revCharMap('M')));
  1446.       tx = 0.9 * state->getTransformedFontSize() *
  1447.            gfxFont->getWidth(font->revMapChar('T'));
  1448.       y1 -= 0.33 * (double)font->getXFont()->ascent;
  1449.       buf = 'T';
  1450.       XDrawString(display, pixmap,
  1451.           (state->getRender() & 1) ? strokeGC : fillGC,
  1452.           xoutRound(x1), xoutRound(y1), &buf, 1);
  1453.       x1 += tx;
  1454.       buf = 'M';
  1455.       XDrawString(display, pixmap,
  1456.           (state->getRender() & 1) ? strokeGC : fillGC,
  1457.           xoutRound(x1), xoutRound(y1), &buf, 1);
  1458.       break;
  1459.     }
  1460.   } else if (c1 <= lastMultiChar) {
  1461.     p = multiChars[c1 - firstMultiChar];
  1462.     n = strlen(p);
  1463.     tx = gfxFont->getWidth(c);
  1464.     tx -= gfxFont->getWidth(font->revMapChar(p[n-1]));
  1465.     tx = tx * state->getTransformedFontSize() / (double)(n - 1);
  1466.     for (i = 0; i < n; ++i) {
  1467.       XDrawString(display, pixmap,
  1468.           (state->getRender() & 1) ? strokeGC : fillGC,
  1469.           xoutRound(x1), xoutRound(y1), p + i, 1);
  1470.       x1 += tx;
  1471.     }
  1472.   }
  1473. }
  1474.  
  1475. void XOutputDev::drawChar16(GfxState *state, double x, double y,
  1476.                 double dx, double dy, int c) {
  1477.   int c1;
  1478.   XChar2b c2[4];
  1479.   double x1, y1;
  1480. #if JAPANESE_SUPPORT
  1481.   int t1, t2;
  1482.   double x2;
  1483.   char *p;
  1484.   int n, i;
  1485. #endif
  1486.  
  1487.   if (!font)
  1488.     return;
  1489.  
  1490.   // check for invisible text -- this is used by Acrobat Capture
  1491.   if ((state->getRender() & 3) == 3)
  1492.     return;
  1493.  
  1494.   state->transform(x, y, &x1, &y1);
  1495.  
  1496.   c1 = 0;
  1497.   switch (gfxFont->getCharSet16()) {
  1498.  
  1499.   // convert Adobe-Japan1-2 to JIS X 0208-1983
  1500.   case font16AdobeJapan12:
  1501. #if JAPANESE_SUPPORT
  1502.     if (c <= 96) {
  1503.       c1 = japan12Map[c];
  1504.     } else if (c <= 632) {
  1505.       if (c <= 230)
  1506.     c1 = 0;
  1507.       else if (c <= 324)
  1508.     c1 = japan12Map[c - 230];
  1509.       else if (c <= 421)
  1510.     c1 = japan12KanaMap1[c - 325];
  1511.       else if (c <= 500)
  1512.     c1 = 0;
  1513.       else if (c <= 598)
  1514.     c1 = japan12KanaMap2[c - 501];
  1515.       else
  1516.     c1 = 0;
  1517.     } else if (c <= 1124) {
  1518.       if (c <= 779) {
  1519.     if (c <= 726)
  1520.       c1 = 0x2121 + (c - 633);
  1521.     else if (c <= 740)
  1522.       c1 = 0x2221 + (c - 727);
  1523.     else if (c <= 748)
  1524.       c1 = 0x223a + (c - 741);
  1525.     else if (c <= 755)
  1526.       c1 = 0x224a + (c - 749);
  1527.     else if (c <= 770)
  1528.       c1 = 0x225c + (c - 756);
  1529.     else if (c <= 778)
  1530.       c1 = 0x2272 + (c - 771);
  1531.     else
  1532.       c1 = 0x227e;
  1533.       } else if (c <= 841) {
  1534.     if (c <= 789)
  1535.       c1 = 0x2330 + (c - 780);
  1536.     else if (c <= 815)
  1537.       c1 = 0x2341 + (c - 790);
  1538.     else
  1539.       c1 = 0x2361 + (c - 816);
  1540.       } else if (c <= 1010) {
  1541.     if (c <= 924)
  1542.       c1 = 0x2421 + (c - 842);
  1543.     else
  1544.       c1 = 0x2521 + (c - 925);
  1545.       } else {
  1546.     if (c <= 1034)
  1547.       c1 = 0x2621 + (c - 1011);
  1548.     else if (c <= 1058)
  1549.       c1 = 0x2641 + (c - 1035);
  1550.     else if (c <= 1091)
  1551.       c1 = 0x2721 + (c - 1059);
  1552.     else
  1553.       c1 = 0x2751 + (c - 1092);
  1554.       }
  1555.     } else if (c <= 4089) {
  1556.       t1 = (c - 1125) / 94;
  1557.       t2 = (c - 1125) % 94;
  1558.       c1 = 0x3021 + (t1 << 8) + t2;
  1559.     } else if (c <= 7477) {
  1560.       t1 = (c - 4090) / 94;
  1561.       t2 = (c - 4090) % 94;
  1562.       c1 = 0x5021 + (t1 << 8) + t2;
  1563.     } else if (c <= 7554) {
  1564.       c1 = 0;
  1565.     } else if (c <= 7563) {    // circled Arabic numbers 1..9
  1566.       c1 = 0x2331 + (c - 7555);
  1567.       c2[0].byte1 = c1 >> 8;
  1568.       c2[0].byte2 = c1 & 0xff;
  1569.       XDrawString16(display, pixmap,
  1570.             (state->getRender() & 1) ? strokeGC : fillGC,
  1571.             xoutRound(x1), xoutRound(y1), c2, 1);
  1572.       c1 = 0x227e;
  1573.       c2[0].byte1 = c1 >> 8;
  1574.       c2[0].byte2 = c1 & 0xff;
  1575.       XDrawString16(display, pixmap,
  1576.             (state->getRender() & 1) ? strokeGC : fillGC,
  1577.             xoutRound(x1), xoutRound(y1), c2, 1);
  1578.       c1 = -1;
  1579.     } else if (c <= 7574) {    // circled Arabic numbers 10..20
  1580.       n = c - 7564 + 10;
  1581.       x2 = x1;
  1582.       for (i = 0; i < 2; ++i) {
  1583.     c1 = 0x2330 + (i == 0 ? (n / 10) : (n % 10));
  1584.     c2[0].byte1 = c1 >> 8;
  1585.     c2[0].byte2 = c1 & 0xff;
  1586.     XDrawString16(display, pixmap,
  1587.               (state->getRender() & 1) ? strokeGC : fillGC,
  1588.               xoutRound(x2), xoutRound(y1), c2, 1);
  1589.     x2 += 0.5 * state->getTransformedFontSize();
  1590.       }
  1591.       c1 = 0x227e;
  1592.       c2[0].byte1 = c1 >> 8;
  1593.       c2[0].byte2 = c1 & 0xff;
  1594.       XDrawString16(display, pixmap,
  1595.             (state->getRender() & 1) ? strokeGC : fillGC,
  1596.             xoutRound(x1), xoutRound(y1), c2, 1);
  1597.       c1 = -1;
  1598.     } else if (c <= 7584) {    // Roman numbers I..X
  1599.       p = japan12Roman[c - 7575];
  1600.       n = strlen(p);
  1601.       for (; *p; ++p) {
  1602.     if (*p == 'I')
  1603.       c1 = 0x2349;
  1604.     else if (*p == 'V')
  1605.       c1 = 0x2356;
  1606.     else // 'X'
  1607.       c1 = 0x2358;
  1608.     c2[0].byte1 = c1 >> 8;
  1609.     c2[0].byte2 = c1 & 0xff;
  1610.     XDrawString16(display, pixmap,
  1611.               (state->getRender() & 1) ? strokeGC : fillGC,
  1612.               xoutRound(x1), xoutRound(y1), c2, 1);
  1613.     if (*p == 'I')
  1614.       x1 += 0.2 * state->getTransformedFontSize();
  1615.     else
  1616.       x1 += 0.5 * state->getTransformedFontSize();
  1617.       }
  1618.       c1 = -1;
  1619.     } else if (c <= 7632) {
  1620.       if (c <= 7600) {
  1621.     c1 = 0;
  1622.       } else if (c <= 7606) {
  1623.     p = japan12Abbrev1[c - 7601];
  1624.     n = strlen(p);
  1625.     for (; *p; ++p) {
  1626.       c1 = 0x2300 + *p;
  1627.       c2[0].byte1 = c1 >> 8;
  1628.       c2[0].byte2 = c1 & 0xff;
  1629.       XDrawString16(display, pixmap,
  1630.             (state->getRender() & 1) ? strokeGC : fillGC,
  1631.             xoutRound(x1), xoutRound(y1), c2, 1);
  1632.       x1 += 0.5 * state->getTransformedFontSize();
  1633.     }
  1634.     c1 = -1;
  1635.       } else {
  1636.     c1 = 0;
  1637.       }
  1638.     } else {
  1639.       c1 = 0;
  1640.     }
  1641. #if 0 //~
  1642.     if (c1 == 0)
  1643.       error(-1, "Unsupported Adobe-Japan1-2 character: %d", c);
  1644. #endif
  1645. #endif // JAPANESE_SUPPORT
  1646.     break;
  1647.   }
  1648.  
  1649.   if (c1 > 0) {
  1650.     c2[0].byte1 = c1 >> 8;
  1651.     c2[0].byte2 = c1 & 0xff;
  1652.     XDrawString16(display, pixmap,
  1653.           (state->getRender() & 1) ? strokeGC : fillGC,
  1654.           xoutRound(x1), xoutRound(y1), c2, 1);
  1655.   }
  1656. }
  1657.  
  1658. void XOutputDev::drawImageMask(GfxState *state, Stream *str,
  1659.                    int width, int height, GBool invert,
  1660.                    GBool inlineImg) {
  1661.   XImage *image;
  1662.   int x0, y0;            // top left corner of image
  1663.   int w0, h0, w1, h1;        // size of image
  1664.   int x2, y2;
  1665.   int w2, h2;
  1666.   double xt, yt, wt, ht;
  1667.   GBool rotate, xFlip, yFlip;
  1668.   int x, y;
  1669.   int ix, iy;
  1670.   int px1, px2, qx, dx;
  1671.   int py1, py2, qy, dy;
  1672.   Guchar pixBuf;
  1673.   Gulong color;
  1674.   int i, j;
  1675.  
  1676.   // get image position and size
  1677.   state->transform(0, 0, &xt, &yt);
  1678.   state->transformDelta(1, 1, &wt, &ht);
  1679.   if (wt > 0) {
  1680.     x0 = xoutRound(xt);
  1681.     w0 = xoutRound(wt);
  1682.   } else {
  1683.     x0 = xoutRound(xt + wt);
  1684.     w0 = xoutRound(-wt);
  1685.   }
  1686.   if (ht > 0) {
  1687.     y0 = xoutRound(yt);
  1688.     h0 = xoutRound(ht);
  1689.   } else {
  1690.     y0 = xoutRound(yt + ht);
  1691.     h0 = xoutRound(-ht);
  1692.   }
  1693.   state->transformDelta(1, 0, &xt, &yt);
  1694.   rotate = fabs(xt) < fabs(yt);
  1695.   if (rotate) {
  1696.     w1 = h0;
  1697.     h1 = w0;
  1698.     xFlip = ht < 0;
  1699.     yFlip = wt > 0;
  1700.   } else {
  1701.     w1 = w0;
  1702.     h1 = h0;
  1703.     xFlip = wt < 0;
  1704.     yFlip = ht > 0;
  1705.   }
  1706.  
  1707.   // set up
  1708.   color = findColor(state->getFillColor());
  1709.  
  1710.   // check for tiny (zero width or height) images
  1711.   if (w0 == 0 || h0 == 0) {
  1712.     j = height * ((width + 7) / 8);
  1713.     str->reset();
  1714.     for (i = 0; i < j; ++i)
  1715.       str->getChar();
  1716.     return;
  1717.   }
  1718.  
  1719.   // Bresenham parameters
  1720.   px1 = w1 / width;
  1721.   px2 = w1 - px1 * width;
  1722.   py1 = h1 / height;
  1723.   py2 = h1 - py1 * height;
  1724.  
  1725.   // allocate XImage
  1726.   image = XCreateImage(display, DefaultVisual(display, screenNum),
  1727.                depth, ZPixmap, 0, NULL, w0, h0, 8, 0);
  1728.   image->data = (char *)gmalloc(h0 * image->bytes_per_line);
  1729.   if (x0 + w0 > pixmapW)
  1730.     w2 = pixmapW - x0;
  1731.   else
  1732.     w2 = w0;
  1733.   if (x0 < 0) {
  1734.     x2 = -x0;
  1735.     w2 += x0;
  1736.     x0 = 0;
  1737.   } else {
  1738.     x2 = 0;
  1739.   }
  1740.   if (y0 + h0 > pixmapH)
  1741.     h2 = pixmapH - y0;
  1742.   else
  1743.     h2 = h0;
  1744.   if (y0 < 0) {
  1745.     y2 = -y0;
  1746.     h2 += y0;
  1747.     y0 = 0;
  1748.   } else {
  1749.     y2 = 0;
  1750.   }
  1751.   XGetSubImage(display, pixmap, x0, y0, w2, h2, (1 << depth) - 1, ZPixmap,
  1752.            image, x2, y2);
  1753.  
  1754.   // initialize the image stream
  1755.   str->resetImage(width, 1, 1);
  1756.  
  1757.   // first line (column)
  1758.   y = yFlip ? h1 - 1 : 0;
  1759.   qy = 0;
  1760.  
  1761.   // read image
  1762.   for (i = 0; i < height; ++i) {
  1763.  
  1764.     // vertical (horizontal) Bresenham
  1765.     dy = py1;
  1766.     if ((qy += py2) >= height) {
  1767.       ++dy;
  1768.       qy -= height;
  1769.     }
  1770.  
  1771.     // drop a line (column)
  1772.     if (dy == 0) {
  1773.       str->skipImageLine();
  1774.  
  1775.     } else {
  1776.  
  1777.       // first column (line)
  1778.       x = xFlip ? w1 - 1 : 0;
  1779.       qx = 0;
  1780.  
  1781.       // for each column (line)...
  1782.       for (j = 0; j < width; ++j) {
  1783.  
  1784.     // horizontal (vertical) Bresenham
  1785.     dx = px1;
  1786.     if ((qx += px2) >= width) {
  1787.       ++dx;
  1788.       qx -= width;
  1789.     }
  1790.  
  1791.     // get image pixel
  1792.     str->getImagePixel(&pixBuf);
  1793.     if (invert)
  1794.       pixBuf ^= 1;
  1795.  
  1796.     // draw image pixel
  1797.     if (dx > 0 && pixBuf == 0) {
  1798.       if (dx == 1 && dy == 1) {
  1799.         if (rotate)
  1800.           XPutPixel(image, y, x, color);
  1801.         else
  1802.           XPutPixel(image, x, y, color);
  1803.       } else {
  1804.         for (ix = 0; ix < dx; ++ix) {
  1805.           for (iy = 0; iy < dy; ++iy) {
  1806.         if (rotate)
  1807.           XPutPixel(image, yFlip ? y - iy : y + iy,
  1808.                 xFlip ? x - ix : x + ix, color);
  1809.         else
  1810.           XPutPixel(image, xFlip ? x - ix : x + ix,
  1811.                 yFlip ? y - iy : y + iy, color);
  1812.           }
  1813.         }
  1814.       }
  1815.     }
  1816.  
  1817.     // next column (line)
  1818.     if (xFlip)
  1819.       x -= dx;
  1820.     else
  1821.       x += dx;
  1822.       }
  1823.     }
  1824.  
  1825.     // next line (column)
  1826.     if (yFlip)
  1827.       y -= dy;
  1828.     else
  1829.       y += dy;
  1830.   }
  1831.  
  1832.   // blit the image into the pixmap
  1833.   XPutImage(display, pixmap, fillGC, image, x2, y2, x0, y0, w2, h2);
  1834.  
  1835.   // free memory
  1836.   gfree(image->data);
  1837.   image->data = NULL;
  1838.   XDestroyImage(image);
  1839. }
  1840.  
  1841. inline Gulong XOutputDev::findColor(RGBColor *x, RGBColor *err) {
  1842.   double gray;
  1843.   int r, g, b;
  1844.   Gulong pixel;
  1845.  
  1846.   if (trueColor) {
  1847.     r = xoutRound(x->r * rMul);
  1848.     g = xoutRound(x->g * gMul);
  1849.     b = xoutRound(x->b * bMul);
  1850.     pixel = ((Gulong)r << rShift) +
  1851.             ((Gulong)g << gShift) +
  1852.             ((Gulong)b << bShift);
  1853.     err->r = x->r - (double)r / rMul;
  1854.     err->g = x->g - (double)g / gMul;
  1855.     err->b = x->b - (double)b / bMul;
  1856.   } else if (numColors == 1) {
  1857.     gray = 0.299 * x->r + 0.587 * x->g + 0.114 * x->b;
  1858.     if (gray < 0.5) {
  1859.       pixel = colors[0];
  1860.       err->r = x->r;
  1861.       err->g = x->g;
  1862.       err->b = x->b;
  1863.     } else {
  1864.       pixel = colors[1];
  1865.       err->r = x->r - 1;
  1866.       err->g = x->g - 1;
  1867.       err->b = x->b - 1;
  1868.     }
  1869.   } else {
  1870.     r = xoutRound(x->r * (numColors - 1));
  1871.     g = xoutRound(x->g * (numColors - 1));
  1872.     b = xoutRound(x->b * (numColors - 1));
  1873.     pixel = colors[(r * numColors + g) * numColors + b];
  1874.     err->r = x->r - (double)r / (numColors - 1);
  1875.     err->g = x->g - (double)g / (numColors - 1); 
  1876.     err->b = x->b - (double)b / (numColors - 1);
  1877.   }
  1878.   return pixel;
  1879. }
  1880.  
  1881. void XOutputDev::drawImage(GfxState *state, Stream *str, int width,
  1882.                int height, GfxImageColorMap *colorMap,
  1883.                GBool inlineImg) {
  1884.   XImage *image;
  1885.   int x0, y0;            // top left corner of image
  1886.   int w0, h0, w1, h1;        // size of image
  1887.   double xt, yt, wt, ht;
  1888.   GBool rotate, xFlip, yFlip;
  1889.   GBool dither;
  1890.   int x, y;
  1891.   int ix, iy;
  1892.   int px1, px2, qx, dx;
  1893.   int py1, py2, qy, dy;
  1894.   Guchar pixBuf[4];
  1895.   Gulong pixel;
  1896.   int nComps, nVals, nBits;
  1897.   double r1, g1, b1;
  1898.   GfxColor color;
  1899.   RGBColor color2, err;
  1900.   RGBColor *errRight, *errDown;
  1901.   int i, j;
  1902.  
  1903.   // get image position and size
  1904.   state->transform(0, 0, &xt, &yt);
  1905.   state->transformDelta(1, 1, &wt, &ht);
  1906.   if (wt > 0) {
  1907.     x0 = xoutRound(xt);
  1908.     w0 = xoutRound(wt);
  1909.   } else {
  1910.     x0 = xoutRound(xt + wt);
  1911.     w0 = xoutRound(-wt);
  1912.   }
  1913.   if (ht > 0) {
  1914.     y0 = xoutRound(yt);
  1915.     h0 = xoutRound(ht);
  1916.   } else {
  1917.     y0 = xoutRound(yt + ht);
  1918.     h0 = xoutRound(-ht);
  1919.   }
  1920.   state->transformDelta(1, 0, &xt, &yt);
  1921.   rotate = fabs(xt) < fabs(yt);
  1922.   if (rotate) {
  1923.     w1 = h0;
  1924.     h1 = w0;
  1925.     xFlip = ht < 0;
  1926.     yFlip = wt > 0;
  1927.   } else {
  1928.     w1 = w0;
  1929.     h1 = h0;
  1930.     xFlip = wt < 0;
  1931.     yFlip = ht > 0;
  1932.   }
  1933.  
  1934.   // set up
  1935.   nComps = colorMap->getNumPixelComps();
  1936.   nVals = width * nComps;
  1937.   nBits = colorMap->getBits();
  1938.   dither = nComps > 1 || nBits > 1;
  1939.  
  1940.   // check for tiny (zero width or height) images
  1941.   if (w0 == 0 || h0 == 0) {
  1942.     j = height * ((nVals * nBits + 7) / 8);
  1943.     str->reset();
  1944.     for (i = 0; i < j; ++i)
  1945.       str->getChar();
  1946.     return;
  1947.   }
  1948.  
  1949.   // Bresenham parameters
  1950.   px1 = w1 / width;
  1951.   px2 = w1 - px1 * width;
  1952.   py1 = h1 / height;
  1953.   py2 = h1 - py1 * height;
  1954.  
  1955.   // allocate XImage
  1956.   image = XCreateImage(display, DefaultVisual(display, screenNum),
  1957.                depth, ZPixmap, 0, NULL, w0, h0, 8, 0);
  1958.   image->data = (char *)gmalloc(h0 * image->bytes_per_line);
  1959.  
  1960.   // allocate error diffusion accumulators
  1961.   if (dither) {
  1962.     errDown = (RGBColor *)gmalloc(w1 * sizeof(RGBColor));
  1963.     errRight = (RGBColor *)gmalloc((py1 + 1) * sizeof(RGBColor));
  1964.     for (j = 0; j < w1; ++j)
  1965.       errDown[j].r = errDown[j].g = errDown[j].b = 0;
  1966.   } else {
  1967.     errDown = NULL;
  1968.     errRight = NULL;
  1969.   }
  1970.  
  1971.   // initialize the image stream
  1972.   str->resetImage(width, nComps, nBits);
  1973.  
  1974.   // first line (column)
  1975.   y = yFlip ? h1 - 1 : 0;
  1976.   qy = 0;
  1977.  
  1978.   // read image
  1979.   for (i = 0; i < height; ++i) {
  1980.  
  1981.     // vertical (horizontal) Bresenham
  1982.     dy = py1;
  1983.     if ((qy += py2) >= height) {
  1984.       ++dy;
  1985.       qy -= height;
  1986.     }
  1987.  
  1988.     // drop a line (column)
  1989.     if (dy == 0) {
  1990.       str->skipImageLine();
  1991.  
  1992.     } else {
  1993.  
  1994.       // first column (line)
  1995.       x = xFlip ? w1 - 1 : 0;
  1996.       qx = 0;
  1997.  
  1998.       // clear error accumulator
  1999.       if (dither) {
  2000.     for (j = 0; j <= py1; ++j)
  2001.       errRight[j].r = errRight[j].g = errRight[j].b = 0;
  2002.       }
  2003.  
  2004.       // for each column (line)...
  2005.       for (j = 0; j < width; ++j) {
  2006.  
  2007.     // horizontal (vertical) Bresenham
  2008.     dx = px1;
  2009.     if ((qx += px2) >= width) {
  2010.       ++dx;
  2011.       qx -= width;
  2012.     }
  2013.  
  2014.     // get image pixel
  2015.     str->getImagePixel(pixBuf);
  2016.  
  2017.     // draw image pixel
  2018.     if (dx > 0) {
  2019.       colorMap->getColor(pixBuf, &color);
  2020.       r1 = color.getR();
  2021.       g1 = color.getG();
  2022.       b1 = color.getB();
  2023.       if (dither) {
  2024.         pixel = 0;
  2025.       } else {
  2026.         color2.r = r1;
  2027.         color2.g = g1;
  2028.         color2.b = b1;
  2029.         pixel = findColor(&color2, &err);
  2030.       }
  2031.       if (dx == 1 && dy == 1) {
  2032.         if (dither) {
  2033.           color2.r = r1 + errRight[0].r + errDown[x].r;
  2034.           if (color2.r > 1)
  2035.         color2.r = 1;
  2036.           else if (color2.r < 0)
  2037.         color2.r = 0;
  2038.           color2.g = g1 + errRight[0].g + errDown[x].g;
  2039.           if (color2.g > 1)
  2040.         color2.g = 1;
  2041.           else if (color2.g < 0)
  2042.         color2.g = 0;
  2043.           color2.b = b1 + errRight[0].b + errDown[x].b;
  2044.           if (color2.b > 1)
  2045.         color2.b = 1;
  2046.           else if (color2.b < 0)
  2047.         color2.b = 0;
  2048.           pixel = findColor(&color2, &err);
  2049.           errRight[0].r = errDown[x].r = err.r / 2;
  2050.           errRight[0].g = errDown[x].g = err.g / 2;
  2051.           errRight[0].b = errDown[x].b = err.b / 2;
  2052.         }
  2053.         if (rotate)
  2054.           XPutPixel(image, y, x, pixel);
  2055.         else
  2056.           XPutPixel(image, x, y, pixel);
  2057.       } else {
  2058.         for (iy = 0; iy < dy; ++iy) {
  2059.           for (ix = 0; ix < dx; ++ix) {
  2060.         if (dither) {
  2061.           color2.r = r1 + errRight[iy].r +
  2062.             errDown[xFlip ? x - ix : x + ix].r;
  2063.           if (color2.r > 1)
  2064.             color2.r = 1;
  2065.           else if (color2.r < 0)
  2066.             color2.r = 0;
  2067.           color2.g = g1 + errRight[iy].g +
  2068.             errDown[xFlip ? x - ix : x + ix].g;
  2069.           if (color2.g > 1)
  2070.             color2.g = 1;
  2071.           else if (color2.g < 0)
  2072.             color2.g = 0;
  2073.           color2.b = b1 + errRight[iy].b +
  2074.             errDown[xFlip ? x - ix : x + ix].b;
  2075.           if (color2.b > 1)
  2076.             color2.b = 1;
  2077.           else if (color2.b < 0)
  2078.             color2.b = 0;
  2079.           pixel = findColor(&color2, &err);
  2080.           errRight[iy].r = errDown[xFlip ? x - ix : x + ix].r =
  2081.             err.r / 2;
  2082.           errRight[iy].g = errDown[xFlip ? x - ix : x + ix].g =
  2083.             err.g / 2;
  2084.           errRight[iy].b = errDown[xFlip ? x - ix : x + ix].b =
  2085.             err.b / 2;
  2086.         }
  2087.         if (rotate)
  2088.           XPutPixel(image, yFlip ? y - iy : y + iy,
  2089.                 xFlip ? x - ix : x + ix, pixel);
  2090.         else
  2091.           XPutPixel(image, xFlip ? x - ix : x + ix,
  2092.                 yFlip ? y - iy : y + iy, pixel);
  2093.           }
  2094.         }
  2095.       }
  2096.     }
  2097.  
  2098.     // next column (line)
  2099.     if (xFlip)
  2100.       x -= dx;
  2101.     else
  2102.       x += dx;
  2103.       }
  2104.     }
  2105.  
  2106.     // next line (column)
  2107.     if (yFlip)
  2108.       y -= dy;
  2109.     else
  2110.       y += dy;
  2111.   }
  2112.  
  2113.   // blit the image into the pixmap
  2114.   XPutImage(display, pixmap, fillGC, image, 0, 0, x0, y0, w0, h0);
  2115.  
  2116.   // free memory
  2117.   gfree(image->data);
  2118.   image->data = NULL;
  2119.   XDestroyImage(image);
  2120.   gfree(errRight);
  2121.   gfree(errDown);
  2122. }
  2123.  
  2124. Gulong XOutputDev::findColor(GfxColor *color) {
  2125.   int r, g, b;
  2126.   double gray;
  2127.   Gulong pixel;
  2128.  
  2129.   if (trueColor) {
  2130.     r = xoutRound(color->getR() * rMul);
  2131.     g = xoutRound(color->getG() * gMul);
  2132.     b = xoutRound(color->getB() * bMul);
  2133.     pixel = ((Gulong)r << rShift) +
  2134.             ((Gulong)g << gShift) +
  2135.             ((Gulong)b << bShift);
  2136.   } else if (numColors == 1) {
  2137.     gray = color->getGray();
  2138.     if (gray < 0.5)
  2139.       pixel = colors[0];
  2140.     else
  2141.       pixel = colors[1];
  2142.   } else {
  2143.     r = xoutRound(color->getR() * (numColors - 1));
  2144.     g = xoutRound(color->getG() * (numColors - 1));
  2145.     b = xoutRound(color->getB() * (numColors - 1));
  2146. #if 0 //~ this makes things worse as often as better
  2147.     // even a very light color shouldn't map to white
  2148.     if (r == numColors - 1 && g == numColors - 1 && b == numColors - 1) {
  2149.       if (color->getR() < 0.95)
  2150.     --r;
  2151.       if (color->getG() < 0.95)
  2152.     --g;
  2153.       if (color->getB() < 0.95)
  2154.     --b;
  2155.     }
  2156. #endif
  2157.     pixel = colors[(r * numColors + g) * numColors + b];
  2158.   }
  2159.   return pixel;
  2160. }
  2161.  
  2162. GBool XOutputDev::findText(char *s, GBool top, GBool bottom,
  2163.                int *xMin, int *yMin, int *xMax, int *yMax) {
  2164.   double xMin1, yMin1, xMax1, yMax1;
  2165.   
  2166.   xMin1 = (double)*xMin;
  2167.   yMin1 = (double)*yMin;
  2168.   xMax1 = (double)*xMax;
  2169.   yMax1 = (double)*yMax;
  2170.   if (text->findText(s, top, bottom, &xMin1, &yMin1, &xMax1, &yMax1)) {
  2171.     *xMin = xoutRound(xMin1);
  2172.     *xMax = xoutRound(xMax1);
  2173.     *yMin = xoutRound(yMin1);
  2174.     *yMax = xoutRound(yMax1);
  2175.     return gTrue;
  2176.   }
  2177.   return gFalse;
  2178. }
  2179.  
  2180. GString *XOutputDev::getText(int xMin, int yMin, int xMax, int yMax) {
  2181.   return text->getText((double)xMin, (double)yMin,
  2182.                (double)xMax, (double)yMax);
  2183. }
  2184.