]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/TextOutputDev.cc
754049238ead3fbfed6512e52a67d4f9258d0264
[evince.git] / pdf / xpdf / TextOutputDev.cc
1 //========================================================================
2 //
3 // TextOutputDev.cc
4 //
5 // Copyright 1997 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 <ctype.h>
17 #include "GString.h"
18 #include "gmem.h"
19 #include "config.h"
20 #include "Error.h"
21 #include "GfxState.h"
22 #include "FontEncoding.h"
23 #include "TextOutputDev.h"
24
25 #ifdef MACOS
26 // needed for setting type/creator of MacOS files
27 #include "ICSupport.h"
28 #endif
29
30 #include "TextOutputFontInfo.h"
31
32 //------------------------------------------------------------------------
33 // Character substitutions
34 //------------------------------------------------------------------------
35
36 static char *generalSubstNames[] = {
37   "zerooldstyle",
38   "oneoldstyle",
39   "twooldstyle",
40   "threeoldstyle",
41   "fouroldstyle",
42   "fiveoldstyle",
43   "sixoldstyle",
44   "sevenoldstyle",
45   "eightoldstyle",
46   "nineoldstyle",
47   "oldstylezero",
48   "oldstyleone",
49   "oldstyletwo",
50   "oldstylethree",
51   "oldstylefour",
52   "oldstylefive",
53   "oldstylesix",
54   "oldstyleseven",
55   "oldstyleeight",
56   "oldstylenine"
57 };
58
59 static FontEncoding generalSubstEncoding(generalSubstNames,
60                                          sizeof(generalSubstNames) /
61                                            sizeof(char *));
62
63 static char *generalSubst[] = {
64   "zero",
65   "one",
66   "two",
67   "three",
68   "four",
69   "five",
70   "six",
71   "seven",
72   "eight",
73   "nine",
74   "zero",
75   "one",
76   "two",
77   "three",
78   "four",
79   "five",
80   "six",
81   "seven",
82   "eight",
83   "nine"
84 };
85
86 static char *ascii7Subst[] = {
87   "A", "A", "A", "A",           // A{acute,circumflex,dieresis,grave}
88   "A", "A",                     // A{ring,tilde}
89   "AE",                         // AE
90   "C",                          // Ccedilla
91   "E", "E", "E", "E",           // E{acute,circumflex,dieresis,grave}
92   "I", "I", "I", "I",           // I{acute,circumflex,dieresis,grave}
93   "L",                          // Lslash
94   "N",                          // Ntilde
95   "O", "O", "O", "O",           // O{acute,circumflex,dieresis,grave}
96   "O", "O",                     // O{slash,tilde}
97   "OE",                         // OE
98   "S",                          // Scaron
99   "U", "U", "U", "U",           // U{acute,circumflex,dieresis,grave}
100   "Y", "Y",                     // T{acute,dieresis}
101   "Z",                          // Zcaron
102   "a", "a", "a", "a",           // a{acute,circumflex,dieresis,grave}
103   "a", "a",                     // a{ring,tilde}
104   "ae",                         // ae
105   "c",                          // ccedilla
106   "e", "e", "e", "e",           // e{acute,circumflex,dieresis,grave}
107   "fi", "fl",                   // ligatures
108   "ff", "ffi", "ffl",           // ligatures
109   "i",                          // dotlessi
110   "i", "i", "i", "i",           // i{acute,circumflex,dieresis,grave}
111   "l",                          // lslash
112   "n",                          // ntilde
113   "o", "o", "o", "o",           // o{acute,circumflex,dieresis,grave}
114   "o", "o",                     // o{slash,tilde}
115   "oe",                         // oe
116   "s",                          // scaron
117   "u", "u", "u", "u",           // u{acute,circumflex,dieresis,grave}
118   "y", "y",                     // t{acute,dieresis}
119   "z",                          // zcaron
120   "|",                          // brokenbar
121   "*",                          // bullet
122   "...",                        // ellipsis
123   "-", "-", "-",                // emdash, endash, hyphen
124   "\"", "\"",                   // quotedblleft, quotedblright
125   "'",                          // quotesingle
126   "(R)",                        // registered
127   "TM"                          // trademark
128 };
129
130 static char *isoLatin1Subst[] = {
131   "L",                          // Lslash
132   "OE",                         // OE
133   "S",                          // Scaron
134   "Y",                          // Ydieresis
135   "Z",                          // Zcaron
136   "fi", "fl",                   // ligatures
137   "ff", "ffi", "ffl",           // ligatures
138   "i",                          // dotlessi
139   "l",                          // lslash
140   "oe",                         // oe
141   "s",                          // scaron
142   "z",                          // zcaron
143   "*",                          // bullet
144   "...",                        // ellipsis
145   "-", "-",                     // emdash, hyphen
146   "\"", "\"",                   // quotedblleft, quotedblright
147   "'",                          // quotesingle
148   "TM"                          // trademark
149 };
150
151 static char *isoLatin2Subst[] = {
152   "fi", "fl",                   // ligatures
153   "ff", "ffi", "ffl",           // ligatures
154   "*",                          // bullet
155   "...",                        // ellipsis
156   "-", "-",                     // emdash, hyphen
157   "\"", "\"",                   // quotedblleft, quotedblright
158   "'",                          // quotesingle
159   "TM"                          // trademark
160 };
161
162 static char **isoLatin5Subst = isoLatin1Subst;
163
164 //------------------------------------------------------------------------
165 // 16-bit fonts
166 //------------------------------------------------------------------------
167
168 #if JAPANESE_SUPPORT
169
170 // CID 0 .. 96
171 static Gushort japan12Map[96] = {
172   0x2121, 0x2121, 0x212a, 0x2149, 0x2174, 0x2170, 0x2173, 0x2175, // 00 .. 07
173   0x2147, 0x214a, 0x214b, 0x2176, 0x215c, 0x2124, 0x213e, 0x2123, // 08 .. 0f
174   0x213f, 0x2330, 0x2331, 0x2332, 0x2333, 0x2334, 0x2335, 0x2336, // 10 .. 17
175   0x2337, 0x2338, 0x2339, 0x2127, 0x2128, 0x2163, 0x2161, 0x2164, // 18 .. 1f
176   0x2129, 0x2177, 0x2341, 0x2342, 0x2343, 0x2344, 0x2345, 0x2346, // 20 .. 27
177   0x2347, 0x2348, 0x2349, 0x234a, 0x234b, 0x234c, 0x234d, 0x234e, // 28 .. 2f
178   0x234f, 0x2350, 0x2351, 0x2352, 0x2353, 0x2354, 0x2355, 0x2356, // 30 .. 37
179   0x2357, 0x2358, 0x2359, 0x235a, 0x214e, 0x216f, 0x214f, 0x2130, // 38 .. 3f
180   0x2132, 0x2146, 0x2361, 0x2362, 0x2363, 0x2364, 0x2365, 0x2366, // 40 .. 47
181   0x2367, 0x2368, 0x2369, 0x236a, 0x236b, 0x236c, 0x236d, 0x236e, // 48 .. 4f
182   0x236f, 0x2370, 0x2371, 0x2372, 0x2373, 0x2374, 0x2375, 0x2376, // 50 .. 57
183   0x2377, 0x2378, 0x2379, 0x237a, 0x2150, 0x2143, 0x2151, 0x2141  // 58 .. 5f
184 };
185
186 // CID 325 .. 421
187 static Gushort japan12KanaMap1[97] = {
188   0x2131, 0x2121, 0x2123, 0x2156, 0x2157, 0x2122, 0x2126, 0x2572,
189   0x2521, 0x2523, 0x2525, 0x2527, 0x2529, 0x2563, 0x2565, 0x2567,
190   0x2543, 0x213c, 0x2522, 0x2524, 0x2526, 0x2528, 0x252a, 0x252b,
191   0x252d, 0x252f, 0x2531, 0x2533, 0x2535, 0x2537, 0x2539, 0x253b,
192   0x253d, 0x253f, 0x2541, 0x2544, 0x2546, 0x2548, 0x254a, 0x254b,
193   0x254c, 0x254d, 0x254e, 0x254f, 0x2552, 0x2555, 0x2558, 0x255b,
194   0x255e, 0x255f, 0x2560, 0x2561, 0x2562, 0x2564, 0x2566, 0x2568,
195   0x2569, 0x256a, 0x256b, 0x256c, 0x256d, 0x256f, 0x2573, 0x212b,
196   0x212c, 0x212e, 0x2570, 0x2571, 0x256e, 0x2575, 0x2576, 0x2574,
197   0x252c, 0x252e, 0x2530, 0x2532, 0x2534, 0x2536, 0x2538, 0x253a,
198   0x253c, 0x253e, 0x2540, 0x2542, 0x2545, 0x2547, 0x2549, 0x2550,
199   0x2551, 0x2553, 0x2554, 0x2556, 0x2557, 0x2559, 0x255a, 0x255c,
200   0x255d
201 };
202
203 // CID 501 .. 598
204 static Gushort japan12KanaMap2[98] = {
205   0x212d, 0x212f, 0x216d, 0x214c, 0x214d, 0x2152, 0x2153, 0x2154,
206   0x2155, 0x2158, 0x2159, 0x215a, 0x215b, 0x213d, 0x2121, 0x2472,
207   0x2421, 0x2423, 0x2425, 0x2427, 0x2429, 0x2463, 0x2465, 0x2467,
208   0x2443, 0x2422, 0x2424, 0x2426, 0x2428, 0x242a, 0x242b, 0x242d,
209   0x242f, 0x2431, 0x2433, 0x2435, 0x2437, 0x2439, 0x243b, 0x243d,
210   0x243f, 0x2441, 0x2444, 0x2446, 0x2448, 0x244a, 0x244b, 0x244c,
211   0x244d, 0x244e, 0x244f, 0x2452, 0x2455, 0x2458, 0x245b, 0x245e,
212   0x245f, 0x2460, 0x2461, 0x2462, 0x2464, 0x2466, 0x2468, 0x2469,
213   0x246a, 0x246b, 0x246c, 0x246d, 0x246f, 0x2473, 0x2470, 0x2471,
214   0x246e, 0x242c, 0x242e, 0x2430, 0x2432, 0x2434, 0x2436, 0x2438,
215   0x243a, 0x243c, 0x243e, 0x2440, 0x2442, 0x2445, 0x2447, 0x2449,
216   0x2450, 0x2451, 0x2453, 0x2454, 0x2456, 0x2457, 0x2459, 0x245a,
217   0x245c, 0x245d
218 };
219
220 static char *japan12Roman[10] = {
221   "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"
222 };
223
224 static char *japan12Abbrev1[6] = {
225   "mm", "cm", "km", "mg", "kg", "cc"
226 };
227
228 #endif
229
230 #if CHINESE_CNS_SUPPORT
231
232 static Gushort cns13Map1[99] = {
233   // 0-98
234   0,      0xa140, 0xa149, 0xa1a8, 0xa1ad, 0xa243, 0xa248, 0xa1ae,
235   0xa1a6, 0xa15d, 0xa15e, 0xa1af, 0xa1cf, 0xa141, 0xa1df, 0xa144,
236   0xa241, 0xa2af, 0xa2b0, 0xa2b1, 0xa2b2, 0xa2b3, 0xa2b4, 0xa2b5,
237   0xa2b6, 0xa2b7, 0xa2b8, 0xa147, 0xa146, 0xa1d5, 0xa1d7, 0xa1d6,
238   0xa148, 0xa249, 0xa2cf, 0xa2d0, 0xa2d1, 0xa2d2, 0xa2d3, 0xa2d4,
239   0xa2d5, 0xa2d6, 0xa2d7, 0xa2d8, 0xa2d9, 0xa2da, 0xa2db, 0xa2dc,
240   0xa2dd, 0xa2de, 0xa2df, 0xa2e0, 0xa2e1, 0xa2e2, 0xa2e3, 0xa2e4,
241   0xa2e5, 0xa2e6, 0xa2e7, 0xa2e8, 0xa165, 0xa242, 0xa166, 0xa173,
242   0xa15a, 0xa1a5, 0xa2e9, 0xa2ea, 0xa2eb, 0xa2ec, 0xa2ed, 0xa2ee,
243   0xa2ef, 0xa2f0, 0xa2f1, 0xa2f2, 0xa2f3, 0xa2f4, 0xa2f5, 0xa2f6,
244   0xa2f7, 0xa2f8, 0xa2f9, 0xa2fa, 0xa2fb, 0xa2fc, 0xa2fd, 0xa2fe,
245   0xa340, 0xa341, 0xa342, 0xa343, 0xa161, 0xa159, 0xa162, 0xa1e3,
246   0,      0,      0xa14b
247 };
248
249 static Gushort cns13Map2[95] = {
250   // 13648-13742
251           0xa140, 0xa149, 0xa1a8, 0xa1ad, 0xa244, 0xa248, 0xa1ae,
252   0xa1a6, 0xa15d, 0xa15e, 0xa1af, 0xa1cf, 0xa141, 0xa1df, 0xa144,
253   0xa241, 0xa2af, 0xa2b0, 0xa2b1, 0xa2b2, 0xa2b3, 0xa2b4, 0xa2b5,
254   0xa2b6, 0xa2b7, 0xa2b8, 0xa147, 0xa146, 0xa1d5, 0xa1d7, 0xa1d6,
255   0xa148, 0xa249, 0xa2cf, 0xa2d0, 0xa2d1, 0xa2d2, 0xa2d3, 0xa2d4,
256   0xa2d5, 0xa2d6, 0xa2d7, 0xa2d8, 0xa2d9, 0xa2da, 0xa2db, 0xa2dc,
257   0xa2dd, 0xa2de, 0xa2df, 0xa2e0, 0xa2e1, 0xa2e2, 0xa2e3, 0xa2e4,
258   0xa2e5, 0xa2e6, 0xa2e7, 0xa2e8, 0xa165, 0xa242, 0xa166, 0xa173,
259   0xa15a, 0xa1a5, 0xa2e9, 0xa2ea, 0xa2eb, 0xa2ec, 0xa2ed, 0xa2ee,
260   0xa2ef, 0xa2f0, 0xa2f1, 0xa2f2, 0xa2f3, 0xa2f4, 0xa2f5, 0xa2f6,
261   0xa2f7, 0xa2f8, 0xa2f9, 0xa2fa, 0xa2fb, 0xa2fc, 0xa2fd, 0xa2fe,
262   0xa340, 0xa341, 0xa342, 0xa343, 0xa161, 0xa159, 0xa162, 0xa1c3
263 };
264
265 #endif
266
267 //------------------------------------------------------------------------
268 // TextString
269 //------------------------------------------------------------------------
270
271 TextString::TextString(GfxState *state, GBool hexCodes1) {
272   double x, y, h;
273
274   state->transform(state->getCurX(), state->getCurY(), &x, &y);
275   h = state->getTransformedFontSize();
276   //~ yMin/yMax computation should use font ascent/descent values
277   yMin = y - 0.95 * h;
278   yMax = yMin + 1.3 * h;
279   col = 0;
280   text = new GString();
281   xRight = NULL;
282   yxNext = NULL;
283   xyNext = NULL;
284   hexCodes = hexCodes1;
285 }
286
287 TextString::~TextString() {
288   delete text;
289   gfree(xRight);
290 }
291
292 void TextString::addChar(GfxState *state, double x, double y,
293                          double dx, double dy,
294                          Guchar c, TextOutputCharSet charSet) {
295   char *charName, *sub;
296   int c1;
297   int i, j, n, m;
298
299   // get current index
300   i = text->getLength();
301
302   // append translated character(s) to string
303   sub = NULL;
304   n = 1;
305   if ((charName = state->getFont()->getCharName(c))) {
306     if ((c1 = generalSubstEncoding.getCharCode(charName)) >= 0) {
307       charName = generalSubst[c1];
308     }
309     switch (charSet) {
310     case textOutASCII7:
311       c1 = ascii7Encoding.getCharCode(charName);
312       break;
313     case textOutLatin1:
314       c1 = isoLatin1Encoding.getCharCode(charName);
315       break;
316     case textOutLatin2:
317       c1 = isoLatin2Encoding.getCharCode(charName);
318       break;
319     case textOutLatin5:
320       c1 = isoLatin5Encoding.getCharCode(charName);
321       break;
322     }
323     if (c1 < 0) {
324       m = strlen(charName);
325       if (hexCodes && m == 3 &&
326           (charName[0] == 'B' || charName[0] == 'C' ||
327            charName[0] == 'G') &&
328           isxdigit(charName[1]) && isxdigit(charName[2])) {
329         sscanf(charName+1, "%x", &c1);
330       } else if (hexCodes && m == 2 &&
331                  isxdigit(charName[0]) && isxdigit(charName[1])) {
332         sscanf(charName, "%x", &c1);
333       } else if (!hexCodes && m >= 2 && m <= 3 &&
334                  isdigit(charName[0]) && isdigit(charName[1])) {
335         c1 = atoi(charName);
336         if (c1 >= 256) {
337           c1 = -1;
338         }
339       } else if (m >= 3 && m <= 5 && isdigit(charName[1])) {
340         c1 = atoi(charName+1);
341         if (c1 >= 256) {
342           c1 = -1;
343         }
344       }
345       //~ this is a kludge -- is there a standard internal encoding
346       //~ used by all/most Type 1 fonts?
347       if (c1 == 262)            // hyphen
348         c1 = 45;
349       else if (c1 == 266)       // emdash
350         c1 = 208;
351       if (c1 >= 0) {
352         charName = isoLatin1Encoding.getCharName(c1);
353         if (charName) {
354           switch (charSet) {
355           case textOutASCII7:
356             c1 = ascii7Encoding.getCharCode(charName);
357             break;
358           case textOutLatin1:
359             // no translation
360             break;
361           case textOutLatin2:
362             c1 = isoLatin2Encoding.getCharCode(charName);
363             break;
364           case textOutLatin5:
365             c1 = isoLatin5Encoding.getCharCode(charName);
366             break;
367           }
368         } else {
369           c1 = -1;
370         }
371       }
372     }
373     switch (charSet) {
374       case textOutASCII7:
375         if (c1 >= 128) {
376           sub = ascii7Subst[c1 - 128];
377           n = strlen(sub);
378         }
379         break;
380       case textOutLatin1:
381         if (c1 >= 256) {
382           sub = isoLatin1Subst[c1 - 256];
383           n = strlen(sub);
384         }
385         break;
386       case textOutLatin2:
387         if (c1 >= 256) {
388           sub = isoLatin2Subst[c1 - 256];
389           n = strlen(sub);
390         }
391         break;
392       case textOutLatin5:
393         if (c1 >= 256) {
394           sub = isoLatin5Subst[c1 - 256];
395           n = strlen(sub);
396         }
397         break;
398     }
399   } else {
400     c1 = -1;
401   }
402   if (sub)
403     text->append(sub);
404   else if (c1 >= ' ')
405     text->append((char)c1);
406   else
407     text->append(' ');
408
409   // update position information
410   if (i+n > ((i+15) & ~15))
411     xRight = (double *)grealloc(xRight, ((i+n+15) & ~15) * sizeof(double));
412   if (i == 0)
413     xMin = x;
414   for (j = 0; j < n; ++j)
415     xRight[i+j] = x + ((j+1) * dx) / n;
416   xMax = x + dx;
417 }
418
419 void TextString::addChar16(GfxState *state, double x, double y,
420                            double dx, double dy,
421                            int c, GfxFontCharSet16 charSet) {
422   int c1, t1, t2;
423   int sub[8];
424   char *p;
425   int *q;
426   int i, j, n;
427
428   // get current index
429   i = text->getLength();
430
431   // convert the 16-bit character
432   c1 = 0;
433   sub[0] = 0;
434   switch (charSet) {
435
436   // convert Adobe-Japan1-2 to JIS X 0208-1983
437   case font16AdobeJapan12:
438 #if JAPANESE_SUPPORT
439     if (c <= 96) {
440       c1 = 0x8080 + japan12Map[c];
441     } else if (c <= 632) {
442       if (c <= 230)
443         c1 = 0;
444       else if (c <= 324)
445         c1 = 0x8080 + japan12Map[c - 230];
446       else if (c <= 421)
447         c1 = 0x8080 + japan12KanaMap1[c - 325];
448       else if (c <= 500)
449         c1 = 0;
450       else if (c <= 598)
451         c1 = 0x8080 + japan12KanaMap2[c - 501];
452       else
453         c1 = 0;
454     } else if (c <= 1124) {
455       if (c <= 779) {
456         if (c <= 726)
457           c1 = 0xa1a1 + (c - 633);
458         else if (c <= 740)
459           c1 = 0xa2a1 + (c - 727);
460         else if (c <= 748)
461           c1 = 0xa2ba + (c - 741);
462         else if (c <= 755)
463           c1 = 0xa2ca + (c - 749);
464         else if (c <= 770)
465           c1 = 0xa2dc + (c - 756);
466         else if (c <= 778)
467           c1 = 0xa2f2 + (c - 771);
468         else
469           c1 = 0xa2fe;
470       } else if (c <= 841) {
471         if (c <= 789)
472           c1 = 0xa3b0 + (c - 780);
473         else if (c <= 815)
474           c1 = 0xa3c1 + (c - 790);
475         else
476           c1 = 0xa3e1 + (c - 816);
477       } else if (c <= 1010) {
478         if (c <= 924)
479           c1 = 0xa4a1 + (c - 842);
480         else
481           c1 = 0xa5a1 + (c - 925);
482       } else {
483         if (c <= 1034)
484           c1 = 0xa6a1 + (c - 1011);
485         else if (c <= 1058)
486           c1 = 0xa6c1 + (c - 1035);
487         else if (c <= 1091)
488           c1 = 0xa7a1 + (c - 1059);
489         else
490           c1 = 0xa7d1 + (c - 1092);
491       }
492     } else if (c <= 4089) {
493       t1 = (c - 1125) / 94;
494       t2 = (c - 1125) % 94;
495       c1 = 0xb0a1 + (t1 << 8) + t2;
496     } else if (c <= 7477) {
497       t1 = (c - 4090) / 94;
498       t2 = (c - 4090) % 94;
499       c1 = 0xd0a1 + (t1 << 8) + t2;
500     } else if (c <= 7554) {
501       c1 = 0;
502     } else if (c <= 7563) {     // circled Arabic numbers 1..9
503       c1 = 0xa3b1 + (c - 7555);
504     } else if (c <= 7574) {     // circled Arabic numbers 10..20
505       t1 = c - 7564 + 10;
506       sub[0] = 0xa3b0 + (t1 / 10);
507       sub[1] = 0xa3b0 + (t1 % 10);
508       sub[2] = 0;
509       c1 = -1;
510     } else if (c <= 7584) {     // Roman numbers I..X
511       for (p = japan12Roman[c - 7575], q = sub; *p; ++p, ++q) {
512         *q = 0xa380 + *p;
513       }
514       *q = 0;
515       c1 = -1;
516     } else if (c <= 7632) {
517       if (c <= 7600) {
518         c1 = 0;
519       } else if (c <= 7606) {
520         for (p = japan12Abbrev1[c - 7601], q = sub; *p; ++p, ++q) {
521           *q = 0xa380 + *p;
522         }
523         *q = 0;
524         c1 = -1;
525       } else {
526         c1 = 0;
527       }
528     } else {
529       c1 = 0;
530     }
531 #if 0 //~
532     if (c1 == 0) {
533       error(-1, "Unsupported Adobe-Japan1-2 character: %d", c);
534     }
535 #endif
536 #endif // JAPANESE_SUPPORT
537     break;
538
539   case font16AdobeGB12:
540 #if CHINESE_GB_SUPPORT
541 #endif
542     break;
543
544   case font16AdobeCNS13:
545 #if CHINESE_CNS_SUPPORT
546     if (c <= 98) {
547       c1 = cns13Map1[c];
548     } else if (c <= 502) {
549       if (c == 247) {
550         c1 = 0xa1f7;
551       } else if (c == 248) {
552         c1 = 0xa1f6;
553       } else {
554         t1 = (c - 99) / 157;
555         t2 = (c - 99) % 157;
556         if (t2 <= 62) {
557           c1 = 0xa140 + (t1 << 8) + t2;
558         } else {
559           c1 = 0xa162 + (t1 << 8) + t2;
560         }
561       }
562     } else if (c <= 505) {
563       c1 = 0xa3bd + (c - 503);
564     } else if (c <= 594) {
565       c1 = 0;
566     } else if (c <= 5995) {
567       if (c == 2431) {
568         c1 = 0xacfe;
569       } else if (c == 4308) {
570         c1 = 0xbe52;
571       } else if (c == 5221) {
572         c1 = 0xc2cb;
573       } else if (c == 5495) {
574         c1 = 0xc456;
575       } else if (c == 5550) {
576         c1 = 0xc3ba;
577       } else if (c == 5551) {
578         c1 = 0xc3b9;
579       } else {
580         if (c >= 2007 && c <= 2430) {
581           t1 = c - 594;
582         } else if (c >= 4309 && c <= 4695) {
583           t1 = c - 596;
584         } else if (c >= 5222 && c <= 5410) {
585           t1 = c - 596;
586         } else if (c >= 5496 && c <= 5641) {
587           t1 = c - 596;
588         } else {
589           t1 = c - 595;
590         }
591         t2 = t1 % 157;
592         t1 /= 157;
593         if (t2 <= 62) {
594           c1 = 0xa440 + (t1 << 8) + t2;
595         } else {
596           c1 = 0xa462 + (t1 << 8) + t2;
597         }
598       }
599     } else if (c <= 13645) {
600       if (c == 6039) {
601         c1 = 0xc9be;
602       } else if (c == 6134) {
603         c1 = 0xcaf7;
604       } else if (c == 8142) {
605         c1 = 0xdadf;
606       } else if (c == 8788) {
607         c1 = 0xd6cc;
608       } else if (c == 8889) {
609         c1 = 0xd77a;
610       } else if (c == 10926) {
611         c1 = 0xebf1;
612       } else if (c == 11073) {
613         c1 = 0xecde;
614       } else if (c == 11361) {
615         c1 = 0xf0cb;
616       } else if (c == 11719) {
617         c1 = 0xf056;
618       } else if (c == 12308) {
619         c1 = 0xeeeb;
620       } else if (c == 12526) {
621         c1 = 0xf4b5;
622       } else if (c == 12640) {
623         c1 = 0xf16b;
624       } else if (c == 12783) {
625         c1 = 0xf268;
626       } else if (c == 12900) {
627         c1 = 0xf663;
628       } else if (c == 13585) {
629         c1 = 0xf9c4;
630       } else if (c == 13641) {
631         c1 = 0xf9c6;
632       } else {
633         if (c >= 6006 && c <= 6038) {
634           t1 = c - 5995;
635         } else if (c >= 6088 && c <= 6133) {
636           t1 = c - 5995;
637         } else if (c >= 6302 && c <= 8250) {
638           t1 = c - 5995;
639         } else if (c >= 8251 && c <= 8888) {
640           t1 = c - 5994;
641         } else if (c >= 8890 && c <= 9288) {
642           t1 = c - 5995;
643         } else if (c >= 9289 && c <= 10925) {
644           t1 = c - 5994;
645         } else if (c >= 10927 && c <= 11072) {
646           t1 = c - 5995;
647         } else if (c >= 11362 && c <= 11477) {
648           t1 = c - 5997;
649         } else if (c >= 11615 && c <= 11718) {
650           t1 = c - 5995;
651         } else if (c >= 11942 && c <= 12139) {
652           t1 = c - 5995;
653         } else if (c >= 12140 && c <= 12221) {
654           t1 = c - 5994;
655         } else if (c >= 12222 && c <= 12307) {
656           t1 = c - 5993;
657         } else if (c >= 12309 && c <= 12316) {
658           t1 = c - 5994;
659         } else if (c >= 12317 && c <= 12469) {
660           t1 = c - 5993;
661         } else if (c >= 12470 && c <= 12525) {
662           t1 = c - 5992;
663         } else if (c >= 12527 && c <= 12639) {
664           t1 = c - 5993;
665         } else if (c >= 12641 && c <= 12782) {
666           t1 = c - 5994;
667         } else if (c >= 12784 && c <= 12828) {
668           t1 = c - 5995;
669         } else if (c >= 12829 && c <= 12899) {
670           t1 = c - 5994;
671         } else if (c >= 12901 && c <= 13094) {
672           t1 = c - 5995;
673         } else if (c >= 13095 && c <= 13584) {
674           t1 = c - 5994;
675         } else if (c >= 13586 && c <= 13628) {
676           t1 = c - 5995;
677         } else if (c == 13629) {
678           t1 = c - 5994;
679         } else if (c >= 13630 && c <= 13640) {
680           t1 = c - 5993;
681         } else if (c >= 13642 && c <= 13645) {
682           t1 = c - 5994;
683         } else {
684           t1 = c - 5996;
685         }
686         t2 = t1 % 157;
687         t1 /= 157;
688         if (t2 <= 62) {
689           c1 = 0xc940 + (t1 << 8) + t2;
690         } else {
691           c1 = 0xc962 + (t1 << 8) + t2;
692         }
693       }
694     } else if (c == 13646) {
695       c1 = 0xa14b;
696     } else if (c == 13647) {
697       c1 = 0xa1e3;
698     } else if (c <= 13742) {
699       c1 = cns13Map2[c - 13648];
700     } else if (c <= 13746) {
701       c1 = 0xa159 + (c - 13743);
702     } else if (c <= 14055) {
703       c1 = 0;
704     } else if (c <= 14062) {
705       c1 = 0xf9d6 + (c - 14056);
706     }
707 #if 1 //~
708     if (c1 == 0) {
709       error(-1, "Unsupported Adobe-CNS1-3 character: %d", c);
710     }
711 #endif
712 #endif
713     break;
714   }
715
716   // append converted character to string
717   if (c1 == 0) {
718     text->append(' ');
719     n = 1;
720   } else if (c1 > 0) {
721     text->append(c1 >> 8);
722     text->append(c1 & 0xff);
723     n = 2;
724   } else {
725     n = 0;
726     for (q = sub; *q; ++q) {
727       text->append(*q >> 8);
728       text->append(*q & 0xff);
729       n += 2;
730     }
731   }
732
733   // update position information
734   if (i+n > ((i+15) & ~15)) {
735     xRight = (double *)grealloc(xRight, ((i+n+15) & ~15) * sizeof(double));
736   }
737   if (i == 0) {
738     xMin = x;
739   }
740   for (j = 0; j < n; ++j) {
741     xRight[i+j] = x + dx;
742   }
743   xMax = x + dx;
744 }
745
746 //------------------------------------------------------------------------
747 // TextPage
748 //------------------------------------------------------------------------
749
750 TextPage::TextPage(TextOutputCharSet charSet, GBool rawOrder) {
751   this->charSet = charSet;
752   this->rawOrder = rawOrder;
753   curStr = NULL;
754   yxStrings = NULL;
755   xyStrings = NULL;
756   yxCur1 = yxCur2 = NULL;
757   nest = 0;
758 }
759
760 TextPage::~TextPage() {
761   clear();
762 }
763
764 void TextPage::beginString(GfxState *state, GString *s, GBool hexCodes) {
765   // This check is needed because Type 3 characters can contain
766   // text-drawing operations.
767   if (curStr) {
768     ++nest;
769     return;
770   }
771
772   curStr = new TextString(state, hexCodes);
773 }
774
775 void TextPage::addChar(GfxState *state, double x, double y,
776                        double dx, double dy, Guchar c) {
777   double x1, y1, w1, h1, dx2, dy2;
778   int n;
779   GBool hexCodes;
780
781   state->transform(x, y, &x1, &y1);
782   state->textTransformDelta(state->getCharSpace(), 0, &dx2, &dy2);
783   dx -= dx2;
784   dy -= dy2;
785   state->transformDelta(dx, dy, &w1, &h1);
786   n = curStr->text->getLength();
787   if (n > 0 &&
788       x1 - curStr->xRight[n-1] > 0.1 * (curStr->yMax - curStr->yMin)) {
789     hexCodes = curStr->hexCodes;
790     endString();
791     beginString(state, NULL, hexCodes);
792   }
793   curStr->addChar(state, x1, y1, w1, h1, c, charSet);
794 }
795
796 void TextPage::addChar16(GfxState *state, double x, double y,
797                          double dx, double dy, int c,
798                          GfxFontCharSet16 charSet) {
799   double x1, y1, w1, h1, dx2, dy2;
800   int n;
801   GBool hexCodes;
802
803   state->transform(x, y, &x1, &y1);
804   state->textTransformDelta(state->getCharSpace(), 0, &dx2, &dy2);
805   dx -= dx2;
806   dy -= dy2;
807   state->transformDelta(dx, dy, &w1, &h1);
808   n = curStr->text->getLength();
809   if (n > 0 &&
810       x1 - curStr->xRight[n-1] > 0.1 * (curStr->yMax - curStr->yMin)) {
811     hexCodes = curStr->hexCodes;
812     endString();
813     beginString(state, NULL, hexCodes);
814   }
815   curStr->addChar16(state, x1, y1, w1, h1, c, charSet);
816 }
817
818 void TextPage::endString() {
819   TextString *p1, *p2;
820   double h, y1, y2;
821
822   if (nest > 0) {
823     --nest;
824     return;
825   }
826
827   // throw away zero-length strings -- they don't have valid xMin/xMax
828   // values, and they're useless anyway
829   if (curStr->text->getLength() == 0) {
830     delete curStr;
831     curStr = NULL;
832     return;
833   }
834
835   // insert string in y-major list
836   h = curStr->yMax - curStr->yMin;
837   y1 = curStr->yMin + 0.5 * h;
838   y2 = curStr->yMin + 0.8 * h;
839   if (rawOrder) {
840     p1 = yxCur1;
841     p2 = NULL;
842   } else if ((!yxCur1 ||
843               (y1 >= yxCur1->yMin &&
844                (y2 >= yxCur1->yMax || curStr->xMax >= yxCur1->xMin))) &&
845              (!yxCur2 ||
846               (y1 < yxCur2->yMin ||
847                (y2 < yxCur2->yMax && curStr->xMax < yxCur2->xMin)))) {
848     p1 = yxCur1;
849     p2 = yxCur2;
850   } else {
851     for (p1 = NULL, p2 = yxStrings; p2; p1 = p2, p2 = p2->yxNext) {
852       if (y1 < p2->yMin || (y2 < p2->yMax && curStr->xMax < p2->xMin))
853         break;
854     }
855     yxCur2 = p2;
856   }
857   yxCur1 = curStr;
858   if (p1)
859     p1->yxNext = curStr;
860   else
861     yxStrings = curStr;
862   curStr->yxNext = p2;
863   curStr = NULL;
864 }
865
866 void TextPage::coalesce() {
867   TextString *str1, *str2;
868   double space, d;
869   int n, i;
870
871 #if 0 //~ for debugging
872   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
873     printf("x=%3d..%3d  y=%3d..%3d  size=%2d '%s'\n",
874            (int)str1->xMin, (int)str1->xMax, (int)str1->yMin, (int)str1->yMax,
875            (int)(str1->yMax - str1->yMin), str1->text->getCString());
876   }
877   printf("\n------------------------------------------------------------\n\n");
878 #endif
879   str1 = yxStrings;
880   while (str1 && (str2 = str1->yxNext)) {
881     space = str1->yMax - str1->yMin;
882     d = str2->xMin - str1->xMax;
883     if (((rawOrder &&
884           ((str2->yMin >= str1->yMin && str2->yMin <= str1->yMax) ||
885            (str2->yMax >= str1->yMin && str2->yMax <= str1->yMax))) ||
886          (!rawOrder && str2->yMin < str1->yMax)) &&
887         d > -0.5 * space && d < space) {
888       n = str1->text->getLength();
889       if (d > 0.1 * space)
890         str1->text->append(' ');
891       str1->text->append(str2->text);
892       str1->xRight = (double *)
893         grealloc(str1->xRight,
894                  ((str1->text->getLength() + 15) & ~15) * sizeof(double));
895       if (d > 0.1 * space)
896         str1->xRight[n++] = str2->xMin;
897       for (i = 0; i < str2->text->getLength(); ++i)
898         str1->xRight[n++] = str2->xRight[i];
899       if (str2->xMax > str1->xMax)
900         str1->xMax = str2->xMax;
901       if (str2->yMax > str1->yMax)
902         str1->yMax = str2->yMax;
903       str1->yxNext = str2->yxNext;
904       delete str2;
905     } else {
906       str1 = str2;
907     }
908   }
909 }
910
911 GBool TextPage::findText(char *s, GBool top, GBool bottom,
912                          double *xMin, double *yMin,
913                          double *xMax, double *yMax) {
914   TextString *str;
915   char *p, *p1, *q;
916   int n, m, i;
917   double x;
918
919   // scan all strings on page
920   n = strlen(s);
921   for (str = yxStrings; str; str = str->yxNext) {
922
923     // check: above top limit?
924     if (!top && (str->yMax < *yMin ||
925                  (str->yMin < *yMin && str->xMax <= *xMin)))
926       continue;
927
928     // check: below bottom limit?
929     if (!bottom && (str->yMin > *yMax ||
930                     (str->yMax > *yMax && str->xMin >= *xMax)))
931       return gFalse;
932
933     // search each position in this string
934     m = str->text->getLength();
935     for (i = 0, p = str->text->getCString(); i <= m - n; ++i, ++p) {
936
937       // check: above top limit?
938       if (!top && str->yMin < *yMin) {
939         x = (((i == 0) ? str->xMin : str->xRight[i-1]) + str->xRight[i]) / 2;
940         if (x < *xMin)
941           continue;
942       }
943
944       // check: below bottom limit?
945       if (!bottom && str->yMax > *yMax) {
946         x = (((i == 0) ? str->xMin : str->xRight[i-1]) + str->xRight[i]) / 2;
947         if (x > *xMax)
948           return gFalse;
949       }
950
951       // compare the strings
952       for (p1 = p, q = s; *q; ++p1, ++q) {
953         if (tolower(*p1) != tolower(*q))
954           break;
955       }
956
957       // found it
958       if (!*q) {
959         *xMin = (i == 0) ? str->xMin : str->xRight[i-1];
960         *xMax = str->xRight[i+n-1];
961         *yMin = str->yMin;
962         *yMax = str->yMax;
963         return gTrue;
964       }
965     }
966   }
967   return gFalse;
968 }
969
970 GString *TextPage::getText(double xMin, double yMin,
971                            double xMax, double yMax) {
972   GString *s;
973   TextString *str1;
974   double x0, x1, x2, y;
975   double xPrev, yPrev;
976   int i1, i2;
977   GBool multiLine;
978
979   s = new GString();
980   xPrev = yPrev = 0;
981   multiLine = gFalse;
982   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
983     y = 0.5 * (str1->yMin + str1->yMax);
984     if (y > yMax)
985       break;
986     if (y > yMin && str1->xMin < xMax && str1->xMax > xMin) {
987       x0 = x1 = x2 = str1->xMin;
988       for (i1 = 0; i1 < str1->text->getLength(); ++i1) {
989         x0 = (i1==0) ? str1->xMin : str1->xRight[i1-1];
990         x1 = str1->xRight[i1];
991         if (0.5 * (x0 + x1) >= xMin)
992           break;
993       }
994       for (i2 = str1->text->getLength() - 1; i2 > i1; --i2) {
995         x1 = (i2==0) ? str1->xMin : str1->xRight[i2-1];
996         x2 = str1->xRight[i2];
997         if (0.5 * (x1 + x2) <= xMax)
998           break;
999       }
1000       if (s->getLength() > 0) {
1001         if (x0 < xPrev || str1->yMin > yPrev) {
1002 #ifdef MACOS
1003           s->append('\r');
1004 #else
1005           s->append('\n');
1006 #endif
1007           multiLine = gTrue;
1008         } else {
1009           s->append("    ");
1010         }
1011       }
1012       s->append(str1->text->getCString() + i1, i2 - i1 + 1);
1013       xPrev = x2;
1014       yPrev = str1->yMax;
1015     }
1016   }
1017   if (multiLine) {
1018 #ifdef MACOS
1019     s->append('\r');
1020 #else
1021     s->append('\n');
1022 #endif
1023   }
1024   return s;
1025 }
1026
1027 void TextPage::dump(FILE *f) {
1028   TextString *str1, *str2, *str3;
1029   double yMin, yMax;
1030   int col1, col2;
1031   double d;
1032
1033   // build x-major list
1034   xyStrings = NULL;
1035   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
1036     for (str2 = NULL, str3 = xyStrings;
1037          str3;
1038          str2 = str3, str3 = str3->xyNext) {
1039       if (str1->xMin < str3->xMin ||
1040           (str1->xMin == str3->xMin && str1->yMin < str3->yMin))
1041         break;
1042     }
1043     if (str2)
1044       str2->xyNext = str1;
1045     else
1046       xyStrings = str1;
1047     str1->xyNext = str3;
1048   }
1049
1050   // do column assignment
1051   for (str1 = xyStrings; str1; str1 = str1->xyNext) {
1052     col1 = 0;
1053     for (str2 = xyStrings; str2 != str1; str2 = str2->xyNext) {
1054       if (str1->xMin >= str2->xMax) {
1055         col2 = str2->col + str2->text->getLength() + 4;
1056         if (col2 > col1)
1057           col1 = col2;
1058       } else if (str1->xMin > str2->xMin) {
1059         col2 = str2->col +
1060                (int)(((str1->xMin - str2->xMin) / (str2->xMax - str2->xMin)) *
1061                      str2->text->getLength());
1062         if (col2 > col1) {
1063           col1 = col2;
1064         }
1065       }
1066     }
1067     str1->col = col1;
1068   }
1069
1070 #if 0 //~ for debugging
1071   fprintf(f, "~~~~~~~~~~\n");
1072   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
1073     fprintf(f, "(%4d,%4d) - (%4d,%4d) [%3d] %s\n",
1074             (int)str1->xMin, (int)str1->yMin, (int)str1->xMax, (int)str1->yMax,
1075             str1->col, str1->text->getCString());
1076   }
1077   fprintf(f, "~~~~~~~~~~\n");
1078 #endif
1079
1080   // output
1081   col1 = 0;
1082   yMax = yxStrings ? yxStrings->yMax : 0;
1083   for (str1 = yxStrings; str1; str1 = str1->yxNext) {
1084
1085     // line this string up with the correct column
1086     if (rawOrder && col1 == 0) {
1087       col1 = str1->col;
1088     } else {
1089       for (; col1 < str1->col; ++col1) {
1090         fputc(' ', f);
1091       }
1092     }
1093
1094     // print the string
1095     fputs(str1->text->getCString(), f);
1096
1097     // increment column
1098     col1 += str1->text->getLength();
1099
1100     // update yMax for this line
1101     if (str1->yMax > yMax)
1102       yMax = str1->yMax;
1103
1104     // if we've hit the end of the line...
1105     if (!(str1->yxNext &&
1106           !(rawOrder && str1->yxNext->yMax < str1->yMin) &&
1107           str1->yxNext->yMin < 0.2*str1->yMin + 0.8*str1->yMax &&
1108           str1->yxNext->xMin >= str1->xMax)) {
1109
1110       // print a return
1111       fputc('\n', f);
1112
1113       // print extra vertical space if necessary
1114       if (str1->yxNext) {
1115
1116         // find yMin for next line
1117         yMin = str1->yxNext->yMin;
1118         for (str2 = str1->yxNext; str2; str2 = str2->yxNext) {
1119           if (str2->yMin < yMin)
1120             yMin = str2->yMin;
1121           if (!(str2->yxNext && str2->yxNext->yMin < str2->yMax &&
1122                 str2->yxNext->xMin >= str2->xMax))
1123             break;
1124         }
1125           
1126         // print the space
1127         d = (int)((yMin - yMax) / (str1->yMax - str1->yMin) + 0.5);
1128         if (rawOrder && d > 2) {
1129           d = 2;
1130         }
1131         for (; d > 0; --d) {
1132           fputc('\n', f);
1133         }
1134       }
1135
1136       // set up for next line
1137       col1 = 0;
1138       yMax = str1->yxNext ? str1->yxNext->yMax : 0;
1139     }
1140   }
1141 }
1142
1143 void TextPage::clear() {
1144   TextString *p1, *p2;
1145
1146   if (curStr) {
1147     delete curStr;
1148     curStr = NULL;
1149   }
1150   for (p1 = yxStrings; p1; p1 = p2) {
1151     p2 = p1->yxNext;
1152     delete p1;
1153   }
1154   yxStrings = NULL;
1155   xyStrings = NULL;
1156   yxCur1 = yxCur2 = NULL;
1157 }
1158
1159 //------------------------------------------------------------------------
1160 // TextOutputDev
1161 //------------------------------------------------------------------------
1162
1163 TextOutputDev::TextOutputDev(char *fileName, TextOutputCharSet charSet,
1164                              GBool rawOrder) {
1165   text = NULL;
1166   this->rawOrder = rawOrder;
1167   ok = gTrue;
1168
1169   // open file
1170   needClose = gFalse;
1171   if (fileName) {
1172     if (!strcmp(fileName, "-")) {
1173       f = stdout;
1174     } else if ((f = fopen(fileName, "w"))) {
1175       needClose = gTrue;
1176     } else {
1177       error(-1, "Couldn't open text file '%s'", fileName);
1178       ok = gFalse;
1179       return;
1180     }
1181   } else {
1182     f = NULL;
1183   }
1184
1185   // set up text object
1186   text = new TextPage(charSet, rawOrder);
1187 }
1188
1189 TextOutputDev::~TextOutputDev() {
1190   if (needClose) {
1191 #ifdef MACOS
1192     ICS_MapRefNumAndAssign((short)f->handle);
1193 #endif
1194     fclose(f);
1195   }
1196   if (text) {
1197     delete text;
1198   }
1199 }
1200
1201 void TextOutputDev::startPage(int pageNum, GfxState *state) {
1202   text->clear();
1203 }
1204
1205 void TextOutputDev::endPage() {
1206   text->coalesce();
1207   if (f) {
1208     text->dump(f);
1209     fputc('\n', f);
1210     fputs("\f\n", f);
1211     fputc('\n', f);
1212   }
1213 }
1214
1215 void TextOutputDev::updateFont(GfxState *state) {
1216   GfxFont *font;
1217   char *charName;
1218   int c;
1219
1220   // look for hex char codes in subsetted font
1221   hexCodes = gFalse;
1222   if ((font = state->getFont()) && !font->is16Bit()) {
1223     for (c = 0; c < 256; ++c) {
1224       if ((charName = font->getCharName(c))) {
1225         if ((charName[0] == 'B' || charName[0] == 'C' ||
1226              charName[0] == 'G') &&
1227             strlen(charName) == 3 &&
1228             isxdigit(charName[1]) && isxdigit(charName[2]) &&
1229             ((charName[1] >= 'a' && charName[1] <= 'f') ||
1230              (charName[1] >= 'A' && charName[1] <= 'F') ||
1231              (charName[2] >= 'a' && charName[2] <= 'f') ||
1232              (charName[2] >= 'A' && charName[2] <= 'F'))) {
1233           hexCodes = gTrue;
1234           break;
1235         } else if ((strlen(charName) == 2) &&
1236                    isxdigit(charName[0]) && isxdigit(charName[1]) &&
1237                    ((charName[0] >= 'a' && charName[0] <= 'f') ||
1238                     (charName[0] >= 'A' && charName[0] <= 'F') ||
1239                     (charName[1] >= 'a' && charName[1] <= 'f') ||
1240                     (charName[1] >= 'A' && charName[1] <= 'F'))) {
1241           hexCodes = gTrue;
1242           break;
1243         }
1244       }
1245     }
1246   }
1247 }
1248
1249 void TextOutputDev::beginString(GfxState *state, GString *s) {
1250   text->beginString(state, s, hexCodes);
1251 }
1252
1253 void TextOutputDev::endString(GfxState *state) {
1254   text->endString();
1255 }
1256
1257 void TextOutputDev::drawChar(GfxState *state, double x, double y,
1258                              double dx, double dy, Guchar c) {
1259   text->addChar(state, x, y, dx, dy, c);
1260 }
1261
1262 void TextOutputDev::drawChar16(GfxState *state, double x, double y,
1263                                double dx, double dy, int c) {
1264   text->addChar16(state, x, y, dx, dy, c, state->getFont()->getCharSet16());
1265 }
1266
1267 GBool TextOutputDev::findText(char *s, GBool top, GBool bottom,
1268                               double *xMin, double *yMin,
1269                               double *xMax, double *yMax) {
1270   return text->findText(s, top, bottom, xMin, yMin, xMax, yMax);
1271 }