Coverage Report

Created: 2026-07-04 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/xpdf-4.06/xpdf/TextOutputDev.h
Line
Count
Source
1
//========================================================================
2
//
3
// TextOutputDev.h
4
//
5
// Copyright 1997-2012 Glyph & Cog, LLC
6
//
7
//========================================================================
8
9
#ifndef TEXTOUTPUTDEV_H
10
#define TEXTOUTPUTDEV_H
11
12
#include <aconf.h>
13
14
#include <stdio.h>
15
#include "gtypes.h"
16
#include "GfxFont.h"
17
#include "OutputDev.h"
18
19
class GList;
20
class UnicodeMap;
21
class UnicodeRemapping;
22
class PDFDoc;
23
24
class TextBlock;
25
class TextChar;
26
class TextGaps;
27
class TextLink;
28
class TextPage;
29
30
//------------------------------------------------------------------------
31
32
typedef void (*TextOutputFunc)(void *stream, const char *text, int len);
33
34
//------------------------------------------------------------------------
35
// TextOutputControl
36
//------------------------------------------------------------------------
37
38
enum TextOutputMode {
39
  textOutReadingOrder,    // format into reading order
40
  textOutPhysLayout,    // maintain original physical layout
41
  textOutSimpleLayout,    // simple one-column physical layout
42
  textOutSimple2Layout,   // simple one-column physical layout
43
  textOutTableLayout,   // similar to PhysLayout, but optimized
44
        //   for tables
45
  textOutLinePrinter,   // strict fixed-pitch/height layout
46
  textOutRawOrder   // keep text in content stream order
47
};
48
49
enum TextOutputOverlapHandling {
50
  textOutIgnoreOverlaps,  // no special handling for overlaps
51
  textOutAppendOverlaps,  // append overlapping text to main text
52
  textOutDiscardOverlaps  // discard overlapping text
53
};
54
55
class TextOutputControl {
56
public:
57
58
  TextOutputControl();
59
0
  ~TextOutputControl() {}
60
61
  TextOutputMode mode;    // formatting mode
62
  double fixedPitch;    // if this is non-zero, assume fixed-pitch
63
        //   characters with this width
64
        //   (only relevant for PhysLayout, Table,
65
        //   and LinePrinter modes)
66
  double fixedLineSpacing;  // fixed line spacing (only relevant for
67
        //   LinePrinter mode)
68
  GBool html;     // enable extra processing for HTML
69
  GBool clipText;   // separate clipped text and add it back
70
        //   in after forming columns
71
  GBool discardDiagonalText;  // discard all text that's not close to
72
        //   0/90/180/270 degrees
73
  GBool discardRotatedText; // discard all text that's not horizontal
74
        //   (0 degrees)
75
  GBool discardInvisibleText; // discard all invisible characters
76
  GBool discardClippedText; // discard all clipped characters
77
  GBool splitRotatedWords;  // do not combine horizontal and
78
        //   non-horizontal chars in a single
79
        //   word
80
  TextOutputOverlapHandling // how to handle overlapping text
81
               overlapHandling;
82
  GBool separateLargeChars; // separate "large" characters from
83
        //   "regular" characters
84
  GBool insertBOM;    // insert a Unicode BOM at the start of
85
        //   the text output
86
  double marginLeft,    // characters outside the margins are
87
         marginRight,   //   discarded
88
         marginTop,
89
         marginBottom;
90
  GBool cmykColors;   // false for RGB, true for CMYK
91
};
92
93
//------------------------------------------------------------------------
94
// TextFontInfo
95
//------------------------------------------------------------------------
96
97
class TextFontInfo {
98
public:
99
100
  // Create a TextFontInfo for the current font in [state].
101
  TextFontInfo(GfxState *state);
102
103
  // Create a dummy TextFontInfo.
104
  TextFontInfo();
105
106
  ~TextFontInfo();
107
108
  GBool matches(GfxState *state);
109
110
  // Get the font name (which may be NULL).
111
0
  GString *getFontName() { return fontName; }
112
113
  // Get font descriptor flags.
114
0
  GBool isFixedWidth() { return flags & fontFixedWidth; }
115
0
  GBool isSerif() { return flags & fontSerif; }
116
0
  GBool isSymbolic() { return flags & fontSymbolic; }
117
0
  GBool isItalic() { return flags & fontItalic; }
118
0
  GBool isBold() { return flags & fontBold; }
119
120
  // Get the width of the 'm' character, if available.
121
0
  double getMWidth() { return mWidth; }
122
123
0
  double getAscent() { return ascent; }
124
0
  double getDescent() { return descent; }
125
126
0
  GBool isProblematic() { return problematic; }
127
128
0
  Ref getFontID() { return fontID; }
129
130
private:
131
132
  Ref fontID;
133
  GString *fontName;
134
  int flags;
135
  double mWidth;
136
  double ascent, descent;
137
  GBool problematic;
138
139
  friend class TextLine;
140
  friend class TextPage;
141
  friend class TextWord;
142
};
143
144
//------------------------------------------------------------------------
145
// TextWord
146
//------------------------------------------------------------------------
147
148
class TextWord {
149
public:
150
151
  TextWord(GList *chars, int start, int lenA,
152
     int rotA, GBool rotatedA, int dirA, GBool spaceAfterA);
153
  ~TextWord();
154
0
  TextWord *copy() { return new TextWord(this); }
155
156
  // Get the TextFontInfo object associated with this word.
157
0
  TextFontInfo *getFontInfo() { return font; }
158
159
0
  int getLength() { return len; }
160
0
  Unicode getChar(int idx) { return text[idx]; }
161
  GString *getText();
162
0
  GString *getFontName() { return font->fontName; }
163
  void getColor(double *r, double *g, double *b)
164
0
    { *r = colorR; *g = colorG; *b = colorB; }
165
  void getCMYKColor(double *c, double *m, double *y, double *k)
166
0
    { *c = colorR; *m = colorG; *y = colorB; *k = colorK; }
167
0
  GBool isInvisible() { return invisible; }
168
  void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
169
0
    { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
170
  void getCharBBox(int charIdx, double *xMinA, double *yMinA,
171
       double *xMaxA, double *yMaxA);
172
0
  double getFontSize() { return fontSize; }
173
0
  int getRotation() { return rot; }
174
0
  GBool isRotated() { return (GBool)rotated; }
175
0
  int getCharPos() { return charPos[0]; }
176
0
  int getCharLen() { return charPos[len] - charPos[0]; }
177
0
  int getDirection() { return dir; }
178
0
  GBool getSpaceAfter() { return spaceAfter; }
179
  double getBaseline();
180
0
  GBool isUnderlined() { return underlined; }
181
  GString *getLinkURI();
182
  int getLinkPage(PDFDoc *doc);
183
184
private:
185
186
  TextWord(TextWord *word);
187
  static int cmpYX(const void *p1, const void *p2);
188
  static int cmpCharPos(const void *p1, const void *p2);
189
190
  double xMin, xMax;    // bounding box x coordinates
191
  double yMin, yMax;    // bounding box y coordinates
192
  Unicode *text;    // the text
193
  int *charPos;     // character position (within content stream)
194
        //   of each char (plus one extra entry for
195
        //   the last char)
196
  double *edge;     // "near" edge x or y coord of each char
197
        //   (plus one extra entry for the last char)
198
  int len;      // number of characters
199
  TextFontInfo *font;   // font information
200
  double fontSize;    // font size
201
  TextLink *link;
202
  double colorR,    // word color (RGB or CMYK)
203
         colorG,
204
         colorB,
205
         colorK;
206
  GBool invisible;    // set for invisible text (render mode 3)
207
208
  // group the byte-size fields to minimize object size
209
  Guchar rot;     // rotation, multiple of 90 degrees
210
        //   (0, 1, 2, or 3)
211
  char rotated;     // set if this word is non-horizontal
212
  char dir;     // character direction (+1 = left-to-right;
213
        //   -1 = right-to-left; 0 = neither)
214
  char spaceAfter;    // set if there is a space between this
215
        //   word and the next word on the line
216
  char underlined;
217
218
  friend class TextBlock;
219
  friend class TextLine;
220
  friend class TextPage;
221
};
222
223
//------------------------------------------------------------------------
224
// TextLine
225
//------------------------------------------------------------------------
226
227
class TextLine {
228
public:
229
230
  TextLine(GList *wordsA, double xMinA, double yMinA,
231
     double xMaxA, double yMaxA, double fontSizeA);
232
  ~TextLine();
233
234
0
  double getXMin() { return xMin; }
235
0
  double getYMin() { return yMin; }
236
0
  double getXMax() { return xMax; }
237
0
  double getYMax() { return yMax; }
238
  double getBaseline();
239
0
  int getRotation() { return rot; }
240
0
  GList *getWords() { return words; }
241
0
  Unicode *getUnicode() { return text; }
242
0
  int getLength() { return len; }
243
0
  double getEdge(int idx) { return edge[idx]; }
244
0
  GBool getHyphenated() { return hyphenated; }
245
246
private:
247
248
  static int cmpX(const void *p1, const void *p2);
249
250
  GList *words;     // [TextWord]
251
  int rot;      // rotation, multiple of 90 degrees
252
        //   (0, 1, 2, or 3)
253
  double xMin, xMax;    // bounding box x coordinates
254
  double yMin, yMax;    // bounding box y coordinates
255
  double fontSize;    // main (max) font size for this line
256
  Unicode *text;    // Unicode text of the line, including
257
        //   spaces between words
258
  double *edge;     // "near" edge x or y coord of each char
259
        //   (plus one extra entry for the last char)
260
  int len;      // number of Unicode chars
261
  GBool hyphenated;   // set if last char is a hyphen
262
  int px;     // x offset (in characters, relative to
263
        //   containing column) in physical layout mode
264
  int pw;     // line width (in characters) in physical
265
        //   layout mode
266
267
  friend class TextSuperLine;
268
  friend class TextPage;
269
  friend class TextParagraph;
270
};
271
272
//------------------------------------------------------------------------
273
// TextParagraph
274
//------------------------------------------------------------------------
275
276
class TextParagraph {
277
public:
278
279
  TextParagraph(GList *linesA, GBool dropCapA);
280
  ~TextParagraph();
281
282
  // Get the list of TextLine objects.
283
0
  GList *getLines() { return lines; }
284
285
0
  GBool hasDropCap() { return dropCap; }
286
287
0
  double getXMin() { return xMin; }
288
0
  double getYMin() { return yMin; }
289
0
  double getXMax() { return xMax; }
290
0
  double getYMax() { return yMax; }
291
292
private:
293
294
  GList *lines;     // [TextLine]
295
  GBool dropCap;    // paragraph starts with a drop capital
296
  double xMin, xMax;    // bounding box x coordinates
297
  double yMin, yMax;    // bounding box y coordinates
298
299
  friend class TextPage;
300
};
301
302
//------------------------------------------------------------------------
303
// TextColumn
304
//------------------------------------------------------------------------
305
306
class TextColumn {
307
public:
308
309
  TextColumn(GList *paragraphsA, double xMinA, double yMinA,
310
       double xMaxA, double yMaxA);
311
  ~TextColumn();
312
313
  // Get the list of TextParagraph objects.
314
0
  GList *getParagraphs() { return paragraphs; }
315
316
0
  double getXMin() { return xMin; }
317
0
  double getYMin() { return yMin; }
318
0
  double getXMax() { return xMax; }
319
0
  double getYMax() { return yMax; }
320
321
  int getRotation();
322
323
private:
324
325
  static int cmpX(const void *p1, const void *p2);
326
  static int cmpY(const void *p1, const void *p2);
327
  static int cmpPX(const void *p1, const void *p2);
328
329
  GList *paragraphs;    // [TextParagraph]
330
  double xMin, xMax;    // bounding box x coordinates
331
  double yMin, yMax;    // bounding box y coordinates
332
  int px, py;     // x, y position (in characters) in physical
333
        //   layout mode
334
  int pw, ph;     // column width, height (in characters) in
335
        //   physical layout mode
336
337
  friend class TextPage;
338
};
339
340
//------------------------------------------------------------------------
341
// TextWordList
342
//------------------------------------------------------------------------
343
344
class TextWordList {
345
public:
346
347
  TextWordList(GList *wordsA, GBool primaryLRA);
348
349
  ~TextWordList();
350
351
  // Return the number of words on the list.
352
  int getLength();
353
354
  // Return the <idx>th word from the list.
355
  TextWord *get(int idx);
356
357
  // Returns true if primary direction is left-to-right, or false if
358
  // right-to-left.
359
0
  GBool getPrimaryLR() { return primaryLR; }
360
361
private:
362
363
  GList *words;     // [TextWord]
364
  GBool primaryLR;
365
};
366
367
//------------------------------------------------------------------------
368
// TextPosition
369
//------------------------------------------------------------------------
370
371
// Position within a TextColumn tree.  The position is in column
372
// [colIdx], paragraph [parIdx], line [lineIdx], before character
373
// [charIdx].
374
class TextPosition {
375
public:
376
377
0
  TextPosition(): colIdx(0), parIdx(0), lineIdx(0), charIdx(0) {}
378
  TextPosition(int colIdxA, int parIdxA, int lineIdxA, int charIdxA):
379
0
    colIdx(colIdxA), parIdx(parIdxA), lineIdx(lineIdxA), charIdx(charIdxA) {}
380
381
  int operator==(TextPosition pos);
382
  int operator!=(TextPosition pos);
383
  int operator<(TextPosition pos);
384
  int operator>(TextPosition pos);
385
386
  int colIdx, parIdx, lineIdx, charIdx;
387
};
388
389
//------------------------------------------------------------------------
390
// TextPage
391
//------------------------------------------------------------------------
392
393
class TextPage {
394
public:
395
396
  TextPage(TextOutputControl *controlA);
397
  ~TextPage();
398
399
  // Write contents of page to a stream.
400
  void write(void *outputStream, TextOutputFunc outputFunc);
401
402
  // Find a string.  If <startAtTop> is true, starts looking at the
403
  // top of the page; else if <startAtLast> is true, starts looking
404
  // immediately after the last find result; else starts looking at
405
  // <xMin>,<yMin>.  If <stopAtBottom> is true, stops looking at the
406
  // bottom of the page; else if <stopAtLast> is true, stops looking
407
  // just before the last find result; else stops looking at
408
  // <xMax>,<yMax>.
409
  GBool findText(Unicode *s, int len,
410
     GBool startAtTop, GBool stopAtBottom,
411
     GBool startAtLast, GBool stopAtLast,
412
     GBool caseSensitive, GBool backward,
413
     GBool wholeWord,
414
     double *xMin, double *yMin,
415
     double *xMax, double *yMax);
416
417
  // Get the text which is inside the specified rectangle.  Multi-line
418
  // text always includes end-of-line markers at the end of each line.
419
  // If <forceEOL> is true, an end-of-line marker will be appended to
420
  // single-line text as well.
421
  GString *getText(double xMin, double yMin,
422
       double xMax, double yMax,
423
       GBool forceEOL = gFalse);
424
425
  // Find a string by character position and length.  If found, sets
426
  // the text bounding rectangle and returns true; otherwise returns
427
  // false.
428
  GBool findCharRange(int pos, int length,
429
          double *xMin, double *yMin,
430
          double *xMax, double *yMax);
431
432
  // Returns true if x,y falls inside a column.
433
  GBool checkPointInside(double x, double y);
434
435
  // Find a point inside a column.  Returns false if x,y fall outside
436
  // all columns.
437
  GBool findPointInside(double x, double y, TextPosition *pos);
438
439
  // Find a point in the nearest column.  Returns false only if there
440
  // are no columns.
441
  GBool findPointNear(double x, double y, TextPosition *pos);
442
443
  // Find the start and end of a word inside a column.  Returns false
444
  // if x,y fall outside all columns.
445
  GBool findWordPoints(double x, double y,
446
           TextPosition *startPos, TextPosition *endPos);
447
448
  // Find the start and end of a line inside a column.  Returns false
449
  // if x,y fall outside all columns.
450
  GBool findLinePoints(double x, double y,
451
           TextPosition *startPos, TextPosition *endPos);
452
453
  // Get the upper point of a TextPosition.
454
  void convertPosToPointUpper(TextPosition *pos, double *x, double *y);
455
456
  // Get the lower point of a TextPosition.
457
  void convertPosToPointLower(TextPosition *pos, double *x, double *y);
458
459
  // Get the upper left corner of the line containing a TextPosition.
460
  void convertPosToPointLeftEdge(TextPosition *pos, double *x, double *y);
461
462
  // Get the lower right corner of the line containing a TextPosition.
463
  void convertPosToPointRightEdge(TextPosition *pos, double *x, double *y);
464
465
  // Get the upper right corner of a column.
466
  void getColumnUpperRight(int colIdx, double *x, double *y);
467
468
  // Get the lower left corner of a column.
469
  void getColumnLowerLeft(int colIdx, double *x, double *y);
470
471
  // Create and return a list of TextColumn objects.
472
  GList *makeColumns();
473
474
  // Get the list of all TextFontInfo objects used on this page.
475
0
  GList *getFonts() { return fonts; }
476
477
  // Build a flat word list, in the specified ordering.
478
  TextWordList *makeWordList();
479
480
  // Build a word list containing only words inside the specified
481
  // rectangle.
482
  TextWordList *makeWordListForRect(double xMin, double yMin,
483
            double xMax, double yMax);
484
485
  // Get the primary rotation of text on the page.
486
0
  int getPrimaryRotation() { return primaryRot; }
487
488
  // Returns true if the primary character direction is left-to-right,
489
  // false if it is right-to-left.
490
  GBool primaryDirectionIsLR();
491
492
  // Get the counter values.
493
0
  int getNumVisibleChars() { return nVisibleChars; }
494
0
  int getNumInvisibleChars() { return nInvisibleChars; }
495
0
  int getNumRemovedDupChars() { return nRemovedDupChars; }
496
497
  // Returns true if any of the fonts used on this page are likely to
498
  // be problematic when converting text to Unicode.
499
0
  GBool problematicForUnicode() { return problematic; }
500
501
  // Add a 'special' character to this TextPage.  This is currently
502
  // used by pdftohtml to insert markers for form fields.
503
  void addSpecialChar(double xMin, double yMin, double xMax, double yMax,
504
          int rot, TextFontInfo *font, double fontSize,
505
          Unicode u);
506
507
  // Remove characters that fall inside a region.
508
  void removeChars(double xMin, double yMin, double xMax, double yMax,
509
       double xOverlapThresh, double yOverlapThresh);
510
511
private:
512
513
  void startPage(GfxState *state);
514
  void clear();
515
  void updateFont(GfxState *state);
516
  void addChar(GfxState *state, double x, double y,
517
         double dx, double dy,
518
         CharCode c, int nBytes, Unicode *u, int uLen);
519
  void incCharCount(int nChars);
520
  void beginActualText(GfxState *state, Unicode *u, int uLen);
521
  void endActualText(GfxState *state);
522
  void addUnderline(double x0, double y0, double x1, double y1);
523
  void addLink(double xMin, double yMin, double xMax, double yMax,
524
         Link *link);
525
526
  // output
527
  void writeReadingOrder(void *outputStream,
528
       TextOutputFunc outputFunc,
529
       UnicodeMap *uMap,
530
       char *space, int spaceLen,
531
       char *eol, int eolLen);
532
  void writePhysLayout(void *outputStream,
533
           TextOutputFunc outputFunc,
534
           UnicodeMap *uMap,
535
           char *space, int spaceLen,
536
           char *eol, int eolLen);
537
  void writeSimpleLayout(void *outputStream,
538
       TextOutputFunc outputFunc,
539
       UnicodeMap *uMap,
540
       char *space, int spaceLen,
541
       char *eol, int eolLen);
542
  void writeSimple2Layout(void *outputStream,
543
        TextOutputFunc outputFunc,
544
        UnicodeMap *uMap,
545
        char *space, int spaceLen,
546
        char *eol, int eolLen);
547
  void writeLinePrinter(void *outputStream,
548
      TextOutputFunc outputFunc,
549
      UnicodeMap *uMap,
550
      char *space, int spaceLen,
551
      char *eol, int eolLen);
552
  void writeRaw(void *outputStream,
553
    TextOutputFunc outputFunc,
554
    UnicodeMap *uMap,
555
    char *space, int spaceLen,
556
    char *eol, int eolLen);
557
  void encodeFragment(Unicode *text, int len, UnicodeMap *uMap,
558
          GBool primaryLR, GString *s);
559
  GBool unicodeEffectiveTypeLOrNum(Unicode u, Unicode left, Unicode right);
560
  GBool unicodeEffectiveTypeR(Unicode u, Unicode left, Unicode right);
561
562
  // analysis
563
  int rotateChars(GList *charsA);
564
  void rotateCharsToZero(GList *charsA);
565
  void rotateUnderlinesAndLinks(int rot);
566
  void unrotateChars(GList *charsA, int rot);
567
  void unrotateCharsFromZero(GList *charsA);
568
  void unrotateColumnsFromZero(GList *columns);
569
  void unrotateColumns(GList *columns, int rot);
570
  void unrotateWords(GList *words, int rot);
571
  GBool checkPrimaryLR(GList *charsA);
572
  void removeDuplicates(GList *charsA, int rot);
573
  GList *separateOverlappingText(GList *charsA);
574
  TextColumn *buildOverlappingTextColumn(GList *overlappingChars);
575
  TextBlock *splitChars(GList *charsA);
576
  TextBlock *split(GList *charsA, int rot);
577
  GList *getChars(GList *charsA, double xMin, double yMin,
578
      double xMax, double yMax);
579
  void findGaps(GList *charsA, int rot,
580
    double *xMinOut, double *yMinOut,
581
    double *xMaxOut, double *yMaxOut,
582
    double *avgFontSizeOut, double *minFontSizeOut,
583
    GList *splitLines,
584
    TextGaps *horizGaps, TextGaps *vertGaps);
585
  void mergeSplitLines(GList *charsA, int rot, GList *splitLines);
586
  void tagBlock(TextBlock *blk);
587
  void insertLargeChars(GList *largeChars, TextBlock *blk);
588
  void insertLargeCharsInFirstLeaf(GList *largeChars, TextBlock *blk);
589
  void insertLargeCharInLeaf(TextChar *ch, TextBlock *blk);
590
  void insertIntoTree(TextBlock *subtree, TextBlock *primaryTree,
591
          GBool doReorder);
592
  void reorderBlocks(TextBlock *blk);
593
  void insertColumnIntoTree(TextBlock *column, TextBlock *tree);
594
  void insertClippedChars(GList *clippedChars, TextBlock *tree);
595
  TextBlock *findClippedCharLeaf(TextChar *ch, TextBlock *tree);
596
  GList *buildColumns(TextBlock *tree, GBool primaryLR);
597
  void buildColumns2(TextBlock *blk, GList *columns, GBool primaryLR);
598
  TextColumn *buildColumn(TextBlock *tree);
599
  double getLineIndent(TextLine *line, TextBlock *blk);
600
  double getAverageLineSpacing(GList *lines);
601
  double getLineSpacing(TextLine *line0, TextLine *line1);
602
  void buildLines(TextBlock *blk, GList *lines, GBool splitSuperLines);
603
  GList *buildSimple2Columns(GList *charsA);
604
  GList *buildSimple2Lines(GList *charsA, int rot);
605
  TextLine *buildLine(TextBlock *blk);
606
  TextLine *buildLine(GList *charsA, int rot,
607
          double xMin, double yMin, double xMax, double yMax);
608
  void getLineChars(TextBlock *blk, GList *charsA);
609
  double computeWordSpacingThreshold(GList *charsA, int rot);
610
  void adjustCombiningChars(GList *charsA, int rot);
611
  int getCharDirection(TextChar *ch);
612
  int getCharDirection(TextChar *ch, TextChar *left, TextChar *right);
613
  int assignPhysLayoutPositions(GList *columns);
614
  void assignLinePhysPositions(GList *columns);
615
  void computeLinePhysWidth(TextLine *line, UnicodeMap *uMap);
616
  int assignColumnPhysPositions(GList *columns);
617
  void buildSuperLines(TextBlock *blk, GList *superLines);
618
  void assignSimpleLayoutPositions(GList *superLines, UnicodeMap *uMap);
619
  void generateUnderlinesAndLinks(GList *columns);
620
  void findPointInColumn(TextColumn *col, double x, double y,
621
       TextPosition *pos);
622
  void buildFindCols();
623
624
  // debug
625
#if 0 //~debug
626
  void dumpChars(GList *charsA);
627
  void dumpTree(TextBlock *tree, int indent = 0);
628
  void dumpColumns(GList *columns, GBool dumpWords = gFalse);
629
  void dumpUnderlines();
630
#endif
631
632
  // word list
633
  TextWordList *makeWordListForChars(GList *charList);
634
635
  TextOutputControl control;  // formatting parameters
636
637
  UnicodeRemapping *remapping;
638
  Unicode *uBuf;
639
  int uBufSize;
640
641
  double pageWidth, pageHeight; // width and height of current page
642
  int charPos;      // next character position (within content
643
        //   stream)
644
  TextFontInfo *curFont;  // current font
645
  double curFontSize;   // current font size
646
  int curRot;     // current rotation
647
  GBool diagonal;   // set if rotation is not close to
648
        //   0/90/180/270 degrees
649
  GBool rotated;    // set if text is not horizontal (0 degrees)
650
  int nTinyChars;   // number of "tiny" chars seen so far
651
  Unicode *actualText;    // current "ActualText" span
652
  int actualTextLen;
653
  double actualTextX0,
654
         actualTextY0,
655
         actualTextX1,
656
         actualTextY1;
657
  int actualTextNBytes;
658
659
  GList *chars;     // [TextChar]
660
  GList *fonts;     // all font info objects used on this
661
        //   page [TextFontInfo]
662
  int primaryRot;   // primary rotation
663
664
  GList *underlines;    // [TextUnderline]
665
  GList *links;     // [TextLink]
666
667
  int nVisibleChars;    // number of visible chars on the page
668
  int nInvisibleChars;    // number of invisible chars on the page
669
  int nRemovedDupChars;   // number of duplicate chars removed
670
671
  GList *findCols;    // text used by the findText**/findPoint**
672
        //   functions [TextColumn]
673
  double lastFindXMin,    // coordinates of the last "find" result
674
         lastFindYMin;
675
  GBool haveLastFind;
676
677
  GBool problematic;    // true if any of the fonts used on this
678
        //   page are marked as problematic for
679
        //   Unicode conversion
680
681
  friend class TextOutputDev;
682
};
683
684
//------------------------------------------------------------------------
685
// TextOutputDev
686
//------------------------------------------------------------------------
687
688
class TextOutputDev: public OutputDev {
689
public:
690
691
  // Open a text output file.  If <fileName> is NULL, no file is
692
  // written (this is useful, e.g., for searching text).  If
693
  // <physLayoutA> is true, the original physical layout of the text
694
  // is maintained.  If <rawOrder> is true, the text is kept in
695
  // content stream order.
696
  TextOutputDev(char *fileName, TextOutputControl *controlA,
697
    GBool append, GBool fileNameIsUTF8 = gFalse);
698
699
  // Create a TextOutputDev which will write to a generic stream.  If
700
  // <physLayoutA> is true, the original physical layout of the text
701
  // is maintained.  If <rawOrder> is true, the text is kept in
702
  // content stream order.
703
  TextOutputDev(TextOutputFunc func, void *stream,
704
    TextOutputControl *controlA);
705
706
  // Destructor.
707
  virtual ~TextOutputDev();
708
709
  // Check if file was successfully created.
710
0
  virtual GBool isOk() { return ok; }
711
712
  //---- get info about output device
713
714
  // Does this device use upside-down coordinates?
715
  // (Upside-down means (0,0) is the top left corner of the page.)
716
0
  virtual GBool upsideDown() { return gTrue; }
717
718
  // Does this device use drawChar() or drawString()?
719
0
  virtual GBool useDrawChar() { return gTrue; }
720
721
  // Does this device use beginType3Char/endType3Char?  Otherwise,
722
  // text in Type 3 fonts will be drawn with drawChar/drawString.
723
0
  virtual GBool interpretType3Chars() { return gFalse; }
724
725
  // Does this device need non-text content?
726
0
  virtual GBool needNonText() { return gFalse; }
727
728
  // Does this device require incCharCount to be called for text on
729
  // non-shown layers?
730
0
  virtual GBool needCharCount() { return gTrue; }
731
732
  //----- initialization and control
733
734
  // Start a page.
735
  virtual void startPage(int pageNum, GfxState *state);
736
737
  // End a page.
738
  virtual void endPage();
739
740
  //----- save/restore graphics state
741
  virtual void restoreState(GfxState *state);
742
743
  //----- update text state
744
  virtual void updateFont(GfxState *state);
745
746
  //----- text drawing
747
  virtual void beginString(GfxState *state, GString *s);
748
  virtual void endString(GfxState *state);
749
  virtual void drawChar(GfxState *state, double x, double y,
750
      double dx, double dy,
751
      double originX, double originY,
752
      CharCode c, int nBytes, Unicode *u, int uLen,
753
      GBool fill, GBool stroke, GBool makePath);
754
  virtual void incCharCount(int nChars);
755
  virtual void beginActualText(GfxState *state, Unicode *u, int uLen);
756
  virtual void endActualText(GfxState *state);
757
758
  //----- path painting
759
  virtual void stroke(GfxState *state);
760
  virtual void fill(GfxState *state);
761
  virtual void eoFill(GfxState *state);
762
763
  //----- link borders
764
  virtual void processLink(Link *link);
765
766
  //----- special access
767
768
  // Find a string.  If <startAtTop> is true, starts looking at the
769
  // top of the page; else if <startAtLast> is true, starts looking
770
  // immediately after the last find result; else starts looking at
771
  // <xMin>,<yMin>.  If <stopAtBottom> is true, stops looking at the
772
  // bottom of the page; else if <stopAtLast> is true, stops looking
773
  // just before the last find result; else stops looking at
774
  // <xMax>,<yMax>.
775
  GBool findText(Unicode *s, int len,
776
     GBool startAtTop, GBool stopAtBottom,
777
     GBool startAtLast, GBool stopAtLast,
778
     GBool caseSensitive, GBool backward,
779
     GBool wholeWord,
780
     double *xMin, double *yMin,
781
     double *xMax, double *yMax);
782
783
  // Get the text which is inside the specified rectangle.
784
  GString *getText(double xMin, double yMin,
785
       double xMax, double yMax);
786
787
  // Find a string by character position and length.  If found, sets
788
  // the text bounding rectangle and returns true; otherwise returns
789
  // false.
790
  GBool findCharRange(int pos, int length,
791
          double *xMin, double *yMin,
792
          double *xMax, double *yMax);
793
794
  // Build a flat word list, in content stream order (if
795
  // this->rawOrder is true), physical layout order (if
796
  // this->physLayout is true and this->rawOrder is false), or reading
797
  // order (if both flags are false).
798
  TextWordList *makeWordList();
799
800
  // Build a word list containing only words inside the specified
801
  // rectangle.
802
  TextWordList *makeWordListForRect(double xMin, double yMin,
803
            double xMax, double yMax);
804
805
  // Returns the TextPage object for the last rasterized page,
806
  // transferring ownership to the caller.
807
  TextPage *takeText();
808
809
  // Turn extra processing for HTML conversion on or off.
810
0
  void enableHTMLExtras(GBool html) { control.html = html; }
811
812
  // Get the counter values.
813
0
  int getNumVisibleChars() { return text->nVisibleChars; }
814
0
  int getNumInvisibleChars() { return text->nInvisibleChars; }
815
0
  int getNumRemovedDupChars() { return text->nRemovedDupChars; }
816
817
private:
818
819
  void generateBOM();
820
  void handleCoveredText();
821
822
  TextOutputFunc outputFunc;  // output function
823
  void *outputStream;   // output stream
824
  GBool needClose;    // need to close the output file?
825
        //   (only if outputStream is a FILE*)
826
  TextPage *text;   // text for the current page
827
  TextOutputControl control;  // formatting parameters
828
  GBool ok;     // set up ok?
829
};
830
831
#endif