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

  1. //========================================================================
  2. //
  3. // TextOutputDev.cc
  4. //
  5. // Copyright 1997 Derek B. Noonburg
  6. //
  7. //========================================================================
  8. //
  9. // Ported to EPOC by Sander van der Wal
  10. //
  11. // $Log: TextOutputDev.cpp $
  12. // Revision 1.2  2000-09-17 13:38:20+02  svdwal
  13. // Ported
  14. //
  15.  
  16. #ifdef __GNUC__
  17. #pragma implementation
  18. #endif
  19.  
  20. #ifndef __E32DEF_H__
  21. #include <e32def.h> // remove warning about NULL redefinition
  22. #endif
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <ctype.h>
  27. #include <errno.h>
  28.  
  29. #include "config.h"
  30. #include "Error.h"
  31. #include "GfxState.h"
  32. #include "FontEncoding.h"
  33. #include "TextOutputDev.h"
  34.  
  35. #include "TextOutputFontInfo.h"
  36.  
  37. #include "Pdf.rsg"
  38.  
  39.  
  40. //------------------------------------------------------------------------
  41. // Character substitutions
  42. //------------------------------------------------------------------------
  43.  
  44. static char *const isoLatin1Subst[] = {
  45.   "L",                // Lslash
  46.   "OE",                // OE
  47.   "S",                // Scaron
  48.   "Y",                // Ydieresis
  49.   "Z",                // Zcaron
  50.   "fi", "fl",            // ligatures
  51.   "ff", "ffi", "ffl",        // ligatures
  52.   "i",                // dotlessi
  53.   "l",                // lslash
  54.   "oe",                // oe
  55.   "s",                // scaron
  56.   "z",                // zcaron
  57.   "*",                // bullet
  58.   "...",            // ellipsis
  59.   "-", "-",            // emdash, hyphen
  60.   "\"", "\"",            // quotedblleft, quotedblright
  61.   "'",                // quotesingle
  62.   "TM"                // trademark
  63. };
  64.  
  65. static char * const ascii7Subst[] = {
  66.   "A", "A", "A", "A",        // A{acute,circumflex,dieresis,grave}
  67.   "A", "A",            // A{ring,tilde}
  68.   "AE",                // AE
  69.   "C",                // Ccedilla
  70.   "E", "E", "E", "E",        // E{acute,circumflex,dieresis,grave}
  71.   "I", "I", "I", "I",        // I{acute,circumflex,dieresis,grave}
  72.   "L",                // Lslash
  73.   "N",                // Ntilde
  74.   "O", "O", "O", "O",        // O{acute,circumflex,dieresis,grave}
  75.   "O", "O",            // O{slash,tilde}
  76.   "OE",                // OE
  77.   "S",                // Scaron
  78.   "U", "U", "U", "U",        // U{acute,circumflex,dieresis,grave}
  79.   "Y", "Y",            // T{acute,dieresis}
  80.   "Z",                // Zcaron
  81.   "a", "a", "a", "a",        // a{acute,circumflex,dieresis,grave}
  82.   "a", "a",            // a{ring,tilde}
  83.   "ae",                // ae
  84.   "c",                // ccedilla
  85.   "e", "e", "e", "e",        // e{acute,circumflex,dieresis,grave}
  86.   "fi", "fl",            // ligatures
  87.   "ff", "ffi", "ffl",        // ligatures
  88.   "i",                // dotlessi
  89.   "i", "i", "i", "i",        // i{acute,circumflex,dieresis,grave}
  90.   "l",                // lslash
  91.   "n",                // ntilde
  92.   "o", "o", "o", "o",        // o{acute,circumflex,dieresis,grave}
  93.   "o", "o",            // o{slash,tilde}
  94.   "oe",                // oe
  95.   "s",                // scaron
  96.   "u", "u", "u", "u",        // u{acute,circumflex,dieresis,grave}
  97.   "y", "y",            // t{acute,dieresis}
  98.   "z",                // zcaron
  99.   "|",                // brokenbar
  100.   "*",                // bullet
  101.   "...",            // ellipsis
  102.   "-", "-", "-",        // emdash, endash, hyphen
  103.   "\"", "\"",            // quotedblleft, quotedblright
  104.   "'",                // quotesingle
  105.   "(R)",            // registered
  106.   "TM"                // trademark
  107. };
  108.  
  109.  
  110. //------------------------------------------------------------------------
  111. // 16-bit fonts
  112. //------------------------------------------------------------------------
  113.  
  114. #if JAPANESE_SUPPORT
  115.  
  116. // CID 0 .. 96
  117. static const Gushort japan12Map[96] = {
  118.   0x2120, 0x2120, 0x212a, 0x2149, 0x2174, 0x2170, 0x2173, 0x2175, // 00 .. 07
  119.   0x2147, 0x214a, 0x214b, 0x2176, 0x215c, 0x2124, 0x213e, 0x2123, // 08 .. 0f
  120.   0x213f, 0x2330, 0x2331, 0x2332, 0x2333, 0x2334, 0x2335, 0x2336, // 10 .. 17
  121.   0x2337, 0x2338, 0x2339, 0x2127, 0x2128, 0x2163, 0x2161, 0x2164, // 18 .. 1f
  122.   0x2129, 0x2177, 0x2341, 0x2342, 0x2343, 0x2344, 0x2345, 0x2346, // 20 .. 27
  123.   0x2347, 0x2348, 0x2349, 0x234a, 0x234b, 0x234c, 0x234d, 0x234e, // 28 .. 2f
  124.   0x234f, 0x2350, 0x2351, 0x2352, 0x2353, 0x2354, 0x2355, 0x2356, // 30 .. 37
  125.   0x2357, 0x2358, 0x2359, 0x235a, 0x214e, 0x216f, 0x214f, 0x2130, // 38 .. 3f
  126.   0x2132, 0x2146, 0x2361, 0x2362, 0x2363, 0x2364, 0x2365, 0x2366, // 40 .. 47
  127.   0x2367, 0x2368, 0x2369, 0x236a, 0x236b, 0x236c, 0x236d, 0x236e, // 48 .. 4f
  128.   0x236f, 0x2370, 0x2371, 0x2372, 0x2373, 0x2374, 0x2375, 0x2376, // 50 .. 57
  129.   0x2377, 0x2378, 0x2379, 0x237a, 0x2150, 0x2143, 0x2151, 0x2141  // 58 .. 5f
  130. };
  131.  
  132. // CID 325 .. 421
  133. static const Gushort japan12KanaMap1[97] = {
  134.   0x2131, 0x2121, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572,
  135.   0x2521, 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567,
  136.   0x2543, 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b,
  137.   0x252d, 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b,
  138.   0x253d, 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b,
  139.   0x254c, 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b,
  140.   0x255e, 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568,
  141.   0x2569, 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b,
  142.   0x212c, 0x212e, 0x2570, 0x2571, 0x256e, 0x2575, 0x2576, 0x2574,
  143.   0x252c, 0x252e, 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a,
  144.   0x253c, 0x253e, 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x2550,
  145.   0x2551, 0x2553, 0x2554, 0x2556, 0x2557, 0x2559, 0x255a, 0x255c,
  146.   0x255d
  147. };
  148.  
  149. // CID 501 .. 598
  150. static const Gushort japan12KanaMap2[98] = {
  151.   0x212d, 0x212f, 0x216d, 0x214c, 0x214d, 0x2152, 0x2153, 0x2154,
  152.   0x2155, 0x2158, 0x2159, 0x215a, 0x215b, 0x213d, 0x2121, 0x2472,
  153.   0x2421, 0x2423, 0x2425, 0x2427, 0x2429, 0x2463, 0x2465, 0x2467,
  154.   0x2443, 0x2422, 0x2424, 0x2426, 0x2428, 0x242a, 0x242b, 0x242d,
  155.   0x242f, 0x2431, 0x2433, 0x2435, 0x2437, 0x2439, 0x243b, 0x243d,
  156.   0x243f, 0x2441, 0x2444, 0x2446, 0x2448, 0x244a, 0x244b, 0x244c,
  157.   0x244d, 0x244e, 0x244f, 0x2452, 0x2455, 0x2458, 0x245b, 0x245e,
  158.   0x245f, 0x2460, 0x2461, 0x2462, 0x2464, 0x2466, 0x2468, 0x2469,
  159.   0x246a, 0x246b, 0x246c, 0x246d, 0x246f, 0x2473, 0x2470, 0x2471,
  160.   0x246e, 0x242c, 0x242e, 0x2430, 0x2432, 0x2434, 0x2436, 0x2438,
  161.   0x243a, 0x243c, 0x243e, 0x2440, 0x2442, 0x2445, 0x2447, 0x2449,
  162.   0x2450, 0x2451, 0x2453, 0x2454, 0x2456, 0x2457, 0x2459, 0x245a,
  163.   0x245c, 0x245d
  164. };
  165.  
  166. static const char* const japan12Roman[10] = {
  167.   "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"
  168. };
  169.  
  170. static const char* const japan12Abbrev1[6] = {
  171.   "mm", "cm", "km", "mg", "kg", "cc"
  172. };
  173.  
  174. #endif
  175.  
  176. //------------------------------------------------------------------------
  177. // TextString
  178. //------------------------------------------------------------------------
  179.  
  180.  
  181.  
  182. void TextString::ConstructL(GfxState *state, GBool hexCodes1) 
  183. {
  184.   double x, y, h;
  185.  
  186.   state->transform(state->getCurX(), state->getCurY(), &x, &y);
  187.   h = state->getTransformedFontSize();
  188.  
  189.   //y = (state->getY2() - state->getY1()) - state->getCurY();
  190.   //state->textTransformDelta(0, state->getFontSize(), &x, &h);
  191.  
  192.   //~ yMin/yMax computation should use font ascent/descent values
  193.   yMin = y - 0.95 * h;
  194.   yMax = yMin + 1.3 * h;
  195.   col = 0;
  196.   text = GString::NewL();
  197.   xRight = NULL;
  198.   yxNext = NULL;
  199.   xyNext = NULL;
  200.   hexCodes = hexCodes1;
  201. }
  202.  
  203. TextString::~TextString() {
  204.   delete text;
  205.   User::Free(xRight);
  206. }
  207.  
  208. void TextString::addChar(GfxState *state, double x, double /* y */,
  209.              double dx, double /* dy */,
  210.              Guchar c, GBool useASCII7) {
  211.   const char *charName;
  212.   const char *sub;
  213.   int c1;
  214.   int i, j, n, m;
  215.  
  216.   // get current index
  217.   i = text->getLength();
  218.  
  219.   // append translated character(s) to string
  220.   sub = NULL;
  221.   n = 1;
  222.   charName = state->getFont()->getCharName(c);
  223.   if (charName) {
  224.     if (useASCII7)
  225.       c1 = ascii7Encoding.getCharCode(charName);
  226.     else
  227.       c1 = isoLatin1Encoding.getCharCode(charName);
  228.     if (c1 < 0) {
  229.       m = User::StringLength((const TUint8*)charName);
  230.       if (hexCodes && m == 3 &&
  231.       (charName[0] == 'B' || charName[0] == 'C' ||
  232.        charName[0] == 'G') &&
  233.       isxdigit(charName[1]) && isxdigit(charName[2])) {
  234.     sscanf(charName+1, "%x", &c1);
  235.       } else if (!hexCodes && m >= 2 && m <= 3 &&
  236.          isdigit(charName[0]) && isdigit(charName[1])) {
  237.     c1 = atoi(charName);
  238.     if (c1 >= 256)
  239.       c1 = -1;
  240.       } else if (!hexCodes && m >= 3 && m <= 5 && isdigit(charName[1])) {
  241.     c1 = atoi(charName+1);
  242.     if (c1 >= 256)
  243.       c1 = -1;
  244.       }
  245.       //~ this is a kludge -- is there a standard internal encoding
  246.       //~ used by all/most Type 1 fonts?
  247.       if (c1 == 262)        // hyphen
  248.     c1 = 45;
  249.       else if (c1 == 266)    // emdash
  250.     c1 = 208;
  251.       if (useASCII7)
  252.     c1 = ascii7Encoding.getCharCode(isoLatin1Encoding.getCharName(c1));
  253.     }
  254.     if (useASCII7) {
  255.       if (c1 >= 128) {
  256.           sub = ascii7Subst[c1 - 128];
  257.           n = User::StringLength((const TUint8*)sub);
  258.       }
  259.     } else {
  260.       if (c1 >= 256) {
  261.         sub = isoLatin1Subst[c1 - 256];
  262.         n = User::StringLength((const TUint8*)sub);
  263.       }
  264.     }
  265.   } else {
  266.     c1 = -1;
  267.   }
  268.   if (sub)
  269.     text->appendL(sub);
  270.   else if (c1 >= 0)
  271.     text->appendL((char)c1);
  272.   else
  273.     text->appendL(' ');
  274.  
  275.   // update position information
  276.   if (i+n > ((i+15) & ~15))
  277.     xRight = (double *)User::ReAllocL(xRight, ((i+n+15) & ~15) * sizeof(double));
  278.   if (i == 0)
  279.     xMin = x;
  280.   for (j = 0; j < n; ++j)
  281.     xRight[i+j] = x + ((j+1) * dx) / n;
  282.   xMax = x + dx;
  283. }
  284.  
  285. void TextString::addChar16(GfxState* /* state */, double x, double /* y */,
  286.                double dx, double /* dy */,
  287.                int /* c */, GfxFontCharSet16 charSet) {
  288.   int c1;
  289.   int sub[8];
  290.   int *q;
  291.   int i, j, n;
  292.  
  293.   // get current index
  294.   i = text->getLength();
  295.  
  296.   // convert the 16-bit character
  297.   c1 = 0;
  298.   sub[0] = 0;
  299.   switch (charSet) {
  300.  
  301.   // convert Adobe-Japan1-2 to JIS X 0208-1983
  302.   case font16AdobeJapan12:
  303. #if JAPANESE_SUPPORT
  304.     int t1, t2;
  305.     char *p;
  306.     if (c <= 96) {
  307.       c1 = 0x8080 + japan12Map[c];
  308.     } else if (c <= 632) {
  309.       if (c <= 230)
  310.     c1 = 0;
  311.       else if (c <= 324)
  312.     c1 = 0x8080 + japan12Map[c - 230];
  313.       else if (c <= 421)
  314.     c1 = 0x8080 + japan12KanaMap1[c - 325];
  315.       else if (c <= 500)
  316.     c1 = 0;
  317.       else if (c <= 598)
  318.     c1 = 0x8080 + japan12KanaMap2[c - 501];
  319.       else
  320.     c1 = 0;
  321.     } else if (c <= 1124) {
  322.       if (c <= 779) {
  323.     if (c <= 726)
  324.       c1 = 0xa1a1 + (c - 633);
  325.     else if (c <= 740)
  326.       c1 = 0xa2a1 + (c - 727);
  327.     else if (c <= 748)
  328.       c1 = 0xa2ba + (c - 741);
  329.     else if (c <= 755)
  330.       c1 = 0xa2ca + (c - 749);
  331.     else if (c <= 770)
  332.       c1 = 0xa2dc + (c - 756);
  333.     else if (c <= 778)
  334.       c1 = 0xa2f2 + (c - 771);
  335.     else
  336.       c1 = 0xa2fe;
  337.       } else if (c <= 841) {
  338.     if (c <= 789)
  339.       c1 = 0xa3b0 + (c - 780);
  340.     else if (c <= 815)
  341.       c1 = 0xa3c1 + (c - 790);
  342.     else
  343.       c1 = 0xa3e1 + (c - 816);
  344.       } else if (c <= 1010) {
  345.     if (c <= 924)
  346.       c1 = 0xa4a1 + (c - 842);
  347.     else
  348.       c1 = 0xa5a1 + (c - 925);
  349.       } else {
  350.     if (c <= 1034)
  351.       c1 = 0xa6a1 + (c - 1011);
  352.     else if (c <= 1058)
  353.       c1 = 0xa6c1 + (c - 1035);
  354.     else if (c <= 1091)
  355.       c1 = 0xa7a1 + (c - 1059);
  356.     else
  357.       c1 = 0xa7d1 + (c - 1092);
  358.       }
  359.     } else if (c <= 4089) {
  360.       t1 = (c - 1125) / 94;
  361.       t2 = (c - 1125) % 94;
  362.       c1 = 0xb0a1 + (t1 << 8) + t2;
  363.     } else if (c <= 7477) {
  364.       t1 = (c - 4090) / 94;
  365.       t2 = (c - 4090) % 94;
  366.       c1 = 0xd0a1 + (t1 << 8) + t2;
  367.     } else if (c <= 7554) {
  368.       c1 = 0;
  369.     } else if (c <= 7563) {    // circled Arabic numbers 1..9
  370.       c1 = 0xa3b1 + (c - 7555);
  371.     } else if (c <= 7574) {    // circled Arabic numbers 10..20
  372.       t1 = c - 7564 + 10;
  373.       sub[0] = 0xa3b0 + (t1 / 10);
  374.       sub[1] = 0xa3b0 + (t1 % 10);
  375.       sub[2] = 0;
  376.       c1 = -1;
  377.     } else if (c <= 7584) {    // Roman numbers I..X
  378.       for (p = japan12Roman[c - 7575], q = sub; *p; ++p, ++q) {
  379.     *q = 0xa380 + *p;
  380.       }
  381.       *q = 0;
  382.       c1 = -1;
  383.     } else if (c <= 7632) {
  384.       if (c <= 7600) {
  385.     c1 = 0;
  386.       } else if (c <= 7606) {
  387.     for (p = japan12Abbrev1[c - 7601], q = sub; *p; ++p, ++q) {
  388.       *q = 0xa380 + *p;
  389.     }
  390.     *q = 0;
  391.     c1 = -1;
  392.       } else {
  393.     c1 = 0;
  394.       }
  395.     } else {
  396.       c1 = 0;
  397.     }
  398. #endif // JAPANESE_SUPPORT
  399.     break;
  400.   }
  401.  
  402.   // append converted character to string
  403.   if (c1 == 0) {
  404. #if 0 //~
  405.     error(-1, R_UNSUPPORTED_ADOBE_JAPAN1_2_CHARACTER___D, c);
  406. #endif
  407.     text->appendL(' ');
  408.     n = 1;
  409.   } else if (c1 > 0) {
  410.     text->appendL(c1 >> 8);
  411.     text->appendL(c1 & 0xff);
  412.     n = 2;
  413.   } else {
  414.     n = 0;
  415.     for (q = sub; *q; ++q) {
  416.       text->appendL(*q >> 8);
  417.       text->appendL(*q & 0xff);
  418.       n += 2;
  419.     }
  420.   }
  421.  
  422.   // update position information
  423.   if (i+n > ((i+15) & ~15)) {
  424.     xRight = (double *)User::ReAllocL(xRight, ((i+n+15) & ~15) * sizeof(double));
  425.   }
  426.   if (i == 0) {
  427.     xMin = x;
  428.   }
  429.   for (j = 0; j < n; ++j) {
  430.     xRight[i+j] = x + dx;
  431.   }
  432.   xMax = x + dx;
  433. }
  434.  
  435. //------------------------------------------------------------------------
  436. // TextPage
  437. //------------------------------------------------------------------------
  438.  
  439.  
  440. void TextPage::ConstructL(GBool useASCII7, GBool rawOrder)
  441. {
  442.   this->useASCII7 = useASCII7;
  443.   this->rawOrder = rawOrder;
  444.   curStr = NULL;
  445.   yxStrings = NULL;
  446.   xyStrings = NULL;
  447.   yxCur1 = yxCur2 = NULL;
  448. }
  449.  
  450. TextPage::~TextPage() {
  451.   clear();
  452. }
  453.  
  454. void TextPage::beginString(GfxState *state, GString * /* s */, GBool hexCodes) {
  455.   curStr = new(ELeave) TextString(ascii7Encoding, isoLatin1Encoding);
  456.   curStr->ConstructL(state, hexCodes);
  457. }
  458.  
  459. void TextPage::addChar(GfxState *state, double x, double y,
  460.                double dx, double dy, Guchar c) {
  461.   double x1, y1, w1, h1, dx2, dy2;
  462.   int n;
  463.   GBool hexCodes;
  464.  
  465.   state->transform(x, y, &x1, &y1);
  466.   // faster with y1 == 0
  467.   state->textTransformDelta(state->getCharSpace(), /* 0 ,*/ &dx2, &dy2);
  468.   dx -= dx2;
  469.   dy -= dy2;
  470.   state->transformDelta(dx, dy, &w1, &h1);
  471.   //x1 = x;
  472.   //y1 = (state->getY2() - state->getY1()) - y;
  473.   //state->textTransformDelta(state->getCharSpace(), /* 0 ,*/ &dx2, &dy2);
  474.   //dx -= dx2;
  475.   //dy -= dy2;
  476.   //w1 = dx;
  477.   //h1 = dy;
  478.  
  479.   n = curStr->text->getLength();
  480.   if (n > 0 &&
  481.       x1 - curStr->xRight[n-1] > 0.1 * (curStr->yMax - curStr->yMin)) {
  482.     hexCodes = curStr->hexCodes;
  483.     endString();
  484.     beginString(state, NULL, hexCodes);
  485.   }
  486.   curStr->addChar(state, x1, y1, w1, h1, c, useASCII7);
  487. }
  488.  
  489. void TextPage::addChar16(GfxState *state, double x, double y,
  490.              double dx, double dy, int c,
  491.              GfxFontCharSet16 charSet) {
  492.   double x1, y1, w1, h1, dx2, dy2;
  493.   int n;
  494.   GBool hexCodes;
  495.  
  496.   state->transform(x, y, &x1, &y1);
  497.   // faster with y1 == 0
  498.   state->textTransformDelta(state->getCharSpace(), /* 0, */ &dx2, &dy2);
  499.   dx -= dx2;
  500.   dy -= dy2;
  501.   state->transformDelta(dx, dy, &w1, &h1);
  502.  
  503.   //x1 = x;
  504.   //y1 = (state->getY2() - state->getY1()) - y;
  505.   //state->textTransformDelta(state->getCharSpace(), /* 0 ,*/ &dx2, &dy2);
  506.   //dx -= dx2;
  507.   //dy -= dy2;
  508.   //w1 = dx;
  509.   //h1 = dy;
  510.  
  511.   n = curStr->text->getLength();
  512.   if (n > 0 &&
  513.       x1 - curStr->xRight[n-1] > 0.1 * (curStr->yMax - curStr->yMin)) {
  514.     hexCodes = curStr->hexCodes;
  515.     endString();
  516.     beginString(state, NULL, hexCodes);
  517.   }
  518.   curStr->addChar16(state, x1, y1, w1, h1, c, charSet);
  519. }
  520.  
  521. void TextPage::endString() {
  522.   TextString *p1, *p2;
  523.   double h, y1, y2;
  524.  
  525.   // throw away zero-length strings -- they don't have valid xMin/xMax
  526.   // values, and they're useless anyway
  527.   if (curStr->text->getLength() == 0) {
  528.     delete curStr;
  529.     curStr = NULL;
  530.     return;
  531.   }
  532.  
  533. #if 0 //~tmp
  534.   if (curStr->yMax - curStr->yMin > 20) {
  535.     delete curStr;
  536.     curStr = NULL;
  537.     return;
  538.   }
  539. #endif
  540.  
  541.   // insert string in y-major list
  542.   h = curStr->yMax - curStr->yMin;
  543.   y1 = curStr->yMin + 0.5 * h;
  544.   y2 = curStr->yMin + 0.8 * h;
  545.   if (rawOrder) {
  546.     p1 = yxCur1;
  547.     p2 = NULL;
  548.   } else if ((!yxCur1 ||
  549.           (y1 >= yxCur1->yMin &&
  550.            (y2 >= yxCur1->yMax || curStr->xMax >= yxCur1->xMin))) &&
  551.          (!yxCur2 ||
  552.           (y1 < yxCur2->yMin ||
  553.            (y2 < yxCur2->yMax && curStr->xMax < yxCur2->xMin)))) {
  554.     p1 = yxCur1;
  555.     p2 = yxCur2;
  556.   } else {
  557.     for (p1 = NULL, p2 = yxStrings; p2; p1 = p2, p2 = p2->yxNext) {
  558.       if (y1 < p2->yMin || (y2 < p2->yMax && curStr->xMax < p2->xMin))
  559.     break;
  560.     }
  561.     yxCur2 = p2;
  562.   }
  563.   yxCur1 = curStr;
  564.   if (p1)
  565.     p1->yxNext = curStr;
  566.   else
  567.     yxStrings = curStr;
  568.   curStr->yxNext = p2;
  569.   curStr = NULL;
  570. }
  571.  
  572. void TextPage::coalesce() {
  573.   TextString *str1, *str2;
  574.   double space, d;
  575.   int n, i;
  576.  
  577. #if 0 //~ for debugging
  578.   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
  579.     printf("x=%3d..%3d  y=%3d..%3d  size=%2d '%s'\n",
  580.        (int)str1->xMin, (int)str1->xMax, (int)str1->yMin, (int)str1->yMax,
  581.        (int)(str1->yMax - str1->yMin), str1->text->getCString());
  582.   }
  583.   printf("\n------------------------------------------------------------\n\n");
  584. #endif
  585.   str1 = yxStrings;
  586.   while (str1 && (str2 = str1->yxNext)) {
  587.     space = str1->yMax - str1->yMin;
  588.     d = str2->xMin - str1->xMax;
  589. #if 0 //~tmp
  590.     if (((rawOrder &&
  591.       ((str2->yMin >= str1->yMin && str2->yMin <= str1->yMax) ||
  592.        (str2->yMax >= str1->yMin && str2->yMax <= str1->yMax))) ||
  593.      (!rawOrder && str2->yMin < str1->yMax)) &&
  594.     d > -0.1 * space && d < 0.2 * space) {
  595. #else
  596.     if (((rawOrder &&
  597.       ((str2->yMin >= str1->yMin && str2->yMin <= str1->yMax) ||
  598.        (str2->yMax >= str1->yMin && str2->yMax <= str1->yMax))) ||
  599.      (!rawOrder && str2->yMin < str1->yMax)) &&
  600.     d > -0.5 * space && d < space) {
  601. #endif
  602.       n = str1->text->getLength();
  603.       if (d > 0.1 * space)
  604.     str1->text->appendL(' ');
  605.       str1->text->appendL(str2->text);
  606.       str1->xRight = (double *)
  607.         User::ReAllocL(str1->xRight, str1->text->getLength() * sizeof(double));
  608.       if (d > 0.1 * space)
  609.     str1->xRight[n++] = str2->xMin;
  610.       for (i = 0; i < str2->text->getLength(); ++i)
  611.     str1->xRight[n++] = str2->xRight[i];
  612.       if (str2->xMax > str1->xMax)
  613.     str1->xMax = str2->xMax;
  614.       if (str2->yMax > str1->yMax)
  615.     str1->yMax = str2->yMax;
  616.       str1->yxNext = str2->yxNext;
  617.       delete str2;
  618.     } else {
  619.       str1 = str2;
  620.     }
  621.   }
  622. }
  623.  
  624. GBool TextPage::findText(char *s, GBool top, GBool bottom,
  625.                          double *xMin, double *yMin,
  626.                          double *xMax, double *yMax,
  627.                          GBool aCaseSensitive)
  628. {
  629.   TextString *str;
  630.   char *p;
  631.   int n, m, i;
  632.   double x;
  633.  
  634.   // scan all strings on page
  635.   n = User::StringLength((const TUint8*)s);
  636.   for (str = yxStrings; str; str = str->yxNext) {
  637.  
  638.     // check: above top limit?
  639.     if (!top && (str->yMax < *yMin ||
  640.          (str->yMin < *yMin && str->xMax <= *xMin)))
  641.       continue;
  642.  
  643.     // check: below bottom limit?
  644.     if (!bottom && (str->yMin > *yMax ||
  645.             (str->yMax > *yMax && str->xMin >= *xMax)))
  646.       return gFalse;
  647.  
  648.     // search each position in this string
  649.     m = str->text->getLength();
  650.     for (i = 0, p = str->text->getCString(); i <= m - n; ++i, ++p) {
  651.  
  652.       // check: above top limit?
  653.       if (!top && str->yMin < *yMin) {
  654.         x = (((i == 0) ? str->xMin : str->xRight[i-1]) + str->xRight[i]) / 2;
  655.         if (x < *xMin)
  656.           continue;
  657.       }
  658.  
  659.       // check: below bottom limit?
  660.       if (!bottom && str->yMax > *yMax) {
  661.         x = (((i == 0) ? str->xMin : str->xRight[i-1]) + str->xRight[i]) / 2;
  662.         if (x > *xMax)
  663.           return gFalse;
  664.       }
  665.  
  666.       register char *p1;
  667.       register char *q;
  668.       // compare the strings
  669.       if (aCaseSensitive) {
  670.         for (p1 = p, q = s; *q; ++p1, ++q) {
  671.           if (*p1 != *q)
  672.             break;
  673.         }
  674.       }
  675.       else {
  676.         for (p1 = p, q = s; *q; ++p1, ++q) {
  677.           if (tolower(*p1) != tolower(*q))
  678.             break;
  679.         }
  680.       }
  681.  
  682.       // found it
  683.       if (!*q) {
  684.         *xMin = (i == 0) ? str->xMin : str->xRight[i-1];
  685.         *xMax = str->xRight[i+n-1];
  686.         *yMin = str->yMin;
  687.         *yMax = str->yMax;
  688.         return gTrue;
  689.       }
  690.     }
  691.   }
  692.   return gFalse;
  693. }
  694.  
  695. GString *TextPage::getText(double xMin, double yMin,
  696.                double xMax, double yMax) {
  697.   GString *s;
  698.   TextString *str1;
  699.   double x0, x1, x2, y;
  700.   double xPrev, yPrev;
  701.   int i1, i2;
  702.   GBool multiLine;
  703.  
  704.   s = GString::NewL();
  705.   xPrev = yPrev = 0;
  706.   multiLine = gFalse;
  707.   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
  708.     y = 0.5 * (str1->yMin + str1->yMax);
  709.     if (y > yMax)
  710.       break;
  711.     if (y > yMin && str1->xMin < xMax && str1->xMax > xMin) {
  712.       x0 = x1 = x2 = str1->xMin;
  713.       for (i1 = 0; i1 < str1->text->getLength(); ++i1) {
  714.     x0 = (i1==0) ? str1->xMin : str1->xRight[i1-1];
  715.     x1 = str1->xRight[i1];
  716.     if (0.5 * (x0 + x1) >= xMin)
  717.       break;
  718.       }
  719.       for (i2 = str1->text->getLength() - 1; i2 > i1; --i2) {
  720.     x1 = (i2==0) ? str1->xMin : str1->xRight[i2-1];
  721.     x2 = str1->xRight[i2];
  722.     if (0.5 * (x1 + x2) <= xMax)
  723.       break;
  724.       }
  725.       if (s->getLength() > 0) {
  726.     if (x0 < xPrev || str1->yMin > yPrev) {
  727.       s->appendL('\n');
  728.       multiLine = gTrue;
  729.     } else {
  730.       s->appendL("    ");
  731.     }
  732.       }
  733.       s->appendL(str1->text->getCString() + i1, i2 - i1 + 1);
  734.       xPrev = x2;
  735.       yPrev = str1->yMax;
  736.     }
  737.   }
  738.   if (multiLine)
  739.     s->appendL('\n');
  740.   return s;
  741. }
  742.  
  743. void TextPage::dump(FILE *f) {
  744.   TextString *str1, *str2, *str3;
  745.   double yMin, yMax;
  746.   int col1, col2;
  747.   double d;
  748.  
  749.   // build x-major list
  750.   xyStrings = NULL;
  751.   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
  752.     for (str2 = NULL, str3 = xyStrings;
  753.      str3;
  754.      str2 = str3, str3 = str3->xyNext) {
  755.       if (str1->xMin < str3->xMin ||
  756.       (str1->xMin == str3->xMin && str1->yMin < str3->yMin))
  757.     break;
  758.     }
  759.     if (str2)
  760.       str2->xyNext = str1;
  761.     else
  762.       xyStrings = str1;
  763.     str1->xyNext = str3;
  764.   }
  765.  
  766.   // do column assignment
  767.   for (str1 = xyStrings; str1; str1 = str1->xyNext) {
  768.     col1 = 0;
  769.     for (str2 = xyStrings; str2 != str1; str2 = str2->xyNext) {
  770.       if (str1->xMin >= str2->xMax) {
  771.     col2 = str2->col + str2->text->getLength() + 4;
  772.     if (col2 > col1)
  773.       col1 = col2;
  774.       } else if (str1->xMin > str2->xMin) {
  775.     col2 = str2->col +
  776.            (int)(((str1->xMin - str2->xMin) / (str2->xMax - str2->xMin)) *
  777.              str2->text->getLength());
  778.     if (col2 > col1) {
  779.       col1 = col2;
  780.     }
  781.       }
  782.     }
  783.     str1->col = col1;
  784.   }
  785.  
  786. #if 0 //~ for debugging
  787.   fprintf(f, "~~~~~~~~~~\n");
  788.   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
  789.     fprintf(f, "(%4d,%4d) - (%4d,%4d) [%3d] %s\n",
  790.         (int)str1->xMin, (int)str1->yMin, (int)str1->xMax, (int)str1->yMax,
  791.         str1->col, str1->text->getCString());
  792.   }
  793.   fprintf(f, "~~~~~~~~~~\n");
  794. #endif
  795.  
  796.   // output
  797.   col1 = 0;
  798.   yMax = yxStrings ? yxStrings->yMax : 0;
  799.   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
  800.  
  801.     // line this string up with the correct column
  802.     if (rawOrder && col1 == 0) {
  803.       col1 = str1->col;
  804.     } else {
  805.       for (; col1 < str1->col; ++col1) {
  806.     fputc(' ', f);
  807.       }
  808.     }
  809.  
  810.     // print the string
  811.     fputs(str1->text->getCString(), f);
  812.  
  813.     // increment column
  814.     col1 += str1->text->getLength();
  815.  
  816.     // update yMax for this line
  817.     if (str1->yMax > yMax)
  818.       yMax = str1->yMax;
  819.  
  820.     // if we've hit the end of the line...
  821. #if 0 //~
  822.     if (!(str1->yxNext &&
  823.       !(rawOrder && str1->yxNext->yMax < str1->yMin) &&
  824.       str1->yxNext->yMin < str1->yMax &&
  825.       str1->yxNext->xMin >= str1->xMax)) {
  826. #else
  827.     if (!(str1->yxNext &&
  828.       !(rawOrder && str1->yxNext->yMax < str1->yMin) &&
  829.       str1->yxNext->yMin < 0.2*str1->yMin + 0.8*str1->yMax &&
  830.       str1->yxNext->xMin >= str1->xMax)) {
  831. #endif
  832.  
  833.       // print a return
  834.       fputc('\n', f);
  835.  
  836.       // print extra vertical space if necessary
  837.       if (str1->yxNext) {
  838.  
  839.     // find yMin for next line
  840.     yMin = str1->yxNext->yMin;
  841.     for (str2 = str1->yxNext; str2; str2 = str2->yxNext) {
  842.       if (str2->yMin < yMin)
  843.         yMin = str2->yMin;
  844.       if (!(str2->yxNext && str2->yxNext->yMin < str2->yMax &&
  845.         str2->yxNext->xMin >= str2->xMax))
  846.         break;
  847.     }
  848.       
  849.     // print the space
  850.     d = (int)((yMin - yMax) / (str1->yMax - str1->yMin) + 0.5);
  851.     if (rawOrder && d > 2) {
  852.       d = 2;
  853.     }
  854.     for (; d > 0; --d) {
  855.       fputc('\n', f);
  856.     }
  857.       }
  858.  
  859.       // set up for next line
  860.       col1 = 0;
  861.       yMax = str1->yxNext ? str1->yxNext->yMax : 0;
  862.     }
  863.   }
  864. }
  865.  
  866. void TextPage::clear() {
  867.   TextString *p1, *p2;
  868.  
  869.   if (curStr) {
  870.     delete curStr;
  871.     curStr = NULL;
  872.   }
  873.   for (p1 = yxStrings; p1; p1 = p2) {
  874.     p2 = p1->yxNext;
  875.     delete p1;
  876.   }
  877.   yxStrings = NULL;
  878.   xyStrings = NULL;
  879.   yxCur1 = yxCur2 = NULL;
  880. }
  881.  
  882. //------------------------------------------------------------------------
  883. // TextOutputDev
  884. //------------------------------------------------------------------------
  885.  
  886. void TextOutputDev::ConstructL(TFileName *fileName, GBool useASCII7, GBool rawOrder) {
  887.   text = 0;
  888.   this->rawOrder = rawOrder;
  889.   ok = gTrue;
  890.  
  891.   // open file
  892.   needClose = gFalse;
  893.   if (fileName) {
  894.     const TUint8* fn=fileName->PtrZ();
  895.     f = fopen((const char*)fn, "w");
  896.     if (f) {
  897.       needClose = gTrue;
  898.     } else {
  899.       if (errno == ENOMEM)
  900.         User::LeaveNoMemory();
  901.       error(-1, R_COULDN_T_OPEN_TEXT_FILE___S_, fileName);
  902.       ok = gFalse;
  903.       return;
  904.     }
  905.   } else {
  906.     f = NULL;
  907.   }
  908.  
  909.   // set up font encodings
  910.   ascii7Encoding = new(ELeave) FontEncoding();
  911.   ascii7Encoding->Construct(ascii7EncodingNames, ascii7EncodingSize);
  912.  
  913.   isoLatin1Encoding =new(ELeave) FontEncoding ();
  914.   isoLatin1Encoding->Construct(isoLatin1EncodingNames, isoLatin1EncodingSize);
  915.   
  916.   // set up text object
  917.   text = new(ELeave) TextPage(*ascii7Encoding, *isoLatin1Encoding);
  918.   text->ConstructL(useASCII7, rawOrder);
  919. }
  920.  
  921.  
  922. TextOutputDev::~TextOutputDev() {
  923.   delete isoLatin1Encoding;
  924.   delete ascii7Encoding;
  925.   if (needClose)
  926.     fclose(f);
  927.   delete text;
  928. }
  929.  
  930. void TextOutputDev::startPageL(int /*pageNum*/, GfxState * /*state*/) {
  931.   text->clear();
  932. }
  933.  
  934. void TextOutputDev::endPage() {
  935.   text->coalesce();
  936.   if (f) {
  937.     text->dump(f);
  938.     fputc('\n', f);
  939.     fputs("\f\n", f);
  940.     fputc('\n', f);
  941.   }
  942. }
  943.  
  944. void TextOutputDev::updateFont(GfxState *state) {
  945.   GfxFont *font;
  946.   register const char *charName;
  947.   register int c;
  948.  
  949.   // look for hex char codes in subsetted font
  950.   hexCodes = gFalse;
  951.   font = state->getFont();
  952.   if (font && !font->is16Bit()) {
  953.     for (c = 0; c < 256; ++c) {
  954.       charName = font->getCharName(c);
  955.       if (charName) {
  956.     if ((charName[0] == 'B' || charName[0] == 'C' || charName[0] == 'G') &&
  957.         User::StringLength((const TUint8*)charName) == 3 &&
  958.         ((charName[1] >= 'a' && charName[1] <= 'f') ||
  959.          (charName[1] >= 'A' && charName[1] <= 'F') ||
  960.          (charName[2] >= 'a' && charName[2] <= 'f') ||
  961.          (charName[2] >= 'A' && charName[2] <= 'F'))) {
  962.       hexCodes = gTrue;
  963.       break;
  964.     }
  965.       }
  966.     }
  967.   }
  968. }
  969.  
  970. void TextOutputDev::beginString(GfxState *state, GString *s) {
  971.   text->beginString(state, s, hexCodes);
  972. }
  973.  
  974. void TextOutputDev::endString(GfxState * /* state */) {
  975.   text->endString();
  976. }
  977.  
  978. void TextOutputDev::drawChar(GfxState *state, double x, double y,
  979.                  double dx, double dy, Guchar c) {
  980.   text->addChar(state, x, y, dx, dy, c);
  981. }
  982.  
  983. void TextOutputDev::drawChar16(GfxState *state, double x, double y,
  984.                    double dx, double dy, int c) {
  985.   text->addChar16(state, x, y, dx, dy, c, state->getFont()->getCharSet16());
  986. }
  987.  
  988. GBool TextOutputDev::findText(char *s, GBool top, GBool bottom,
  989.                   double *xMin, double *yMin,
  990.                   double *xMax, double *yMax,
  991.             GBool aCaseSensitive) {
  992.   return text->findText(s, top, bottom, xMin, yMin, xMax, yMax, aCaseSensitive);
  993. }
  994.