]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/TextOutputDev.h
b501907b4a257868566c632fe01dee88e4de0179
[evince.git] / pdf / xpdf / TextOutputDev.h
1 //========================================================================
2 //
3 // TextOutputDev.h
4 //
5 // Copyright 1997-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #ifndef TEXTOUTPUTDEV_H
10 #define TEXTOUTPUTDEV_H
11
12 #include <aconf.h>
13
14 #ifdef USE_GCC_PRAGMAS
15 #pragma interface
16 #endif
17
18 #include <stdio.h>
19 #include "gtypes.h"
20 #include "GfxFont.h"
21 #include "OutputDev.h"
22
23 class GString;
24 class GList;
25 class GfxFont;
26 class GfxState;
27 class UnicodeMap;
28
29 //------------------------------------------------------------------------
30
31 typedef void (*TextOutputFunc)(void *stream, char *text, int len);
32
33 //------------------------------------------------------------------------
34 // TextFontInfo
35 //------------------------------------------------------------------------
36
37 class TextFontInfo {
38 public:
39
40   TextFontInfo(GfxState *state);
41   ~TextFontInfo();
42
43   GBool matches(GfxState *state);
44
45 private:
46
47   GfxFont *gfxFont;
48 #if TEXTOUT_WORD_LIST
49   GString *fontName;
50 #endif
51
52   friend class TextWord;
53   friend class TextPage;
54 };
55
56 //------------------------------------------------------------------------
57 // TextWord
58 //------------------------------------------------------------------------
59
60 class TextWord {
61 public:
62
63   // Constructor.
64   TextWord(GfxState *state, int rotA, double x0, double y0,
65            int charPosA, TextFontInfo *fontA, double fontSize);
66
67   // Destructor.
68   ~TextWord();
69
70   // Add a character to the word.
71   void addChar(GfxState *state, double x, double y,
72                double dx, double dy, Unicode u);
73
74   // Merge <word> onto the end of <this>.
75   void merge(TextWord *word);
76
77   // Compares <this> to <word>, returning -1 (<), 0 (=), or +1 (>),
78   // based on a primary-axis comparison, e.g., x ordering if rot=0.
79   int primaryCmp(TextWord *word);
80
81   // Return the distance along the primary axis between <this> and
82   // <word>.
83   double primaryDelta(TextWord *word);
84
85   static int cmpYX(const void *p1, const void *p2);
86
87 #if TEXTOUT_WORD_LIST
88   int getLength() { return len; }
89   Unicode getChar(int idx) { return text[idx]; }
90   GString *getText();
91   GString *getFontName() { return font->fontName; }
92   void getColor(double *r, double *g, double *b)
93     { *r = colorR; *g = colorG; *b = colorB; }
94   void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
95     { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
96   int getCharPos() { return charPos; }
97   int getCharLen() { return charLen; }
98 #endif
99
100 private:
101
102   int rot;                      // rotation, multiple of 90 degrees
103                                 //   (0, 1, 2, or 3)
104   double xMin, xMax;            // bounding box x coordinates
105   double yMin, yMax;            // bounding box y coordinates
106   double base;                  // baseline x or y coordinate
107   Unicode *text;                // the text
108   double *edge;                 // "near" edge x or y coord of each char
109                                 //   (plus one extra entry for the last char)
110   int len;                      // length of text and edge arrays
111   int size;                     // size of text and edge arrays
112   int charPos;                  // character position (within content stream)
113   int charLen;                  // number of content stream characters in
114                                 //   this word
115   TextFontInfo *font;           // font information
116   double fontSize;              // font size
117   GBool spaceAfter;             // set if there is a space between this
118                                 //   word and the next word on the line
119   TextWord *next;               // next word in line
120
121 #if TEXTOUT_WORD_LIST
122   double colorR,                // word color
123          colorG,
124          colorB;
125 #endif
126
127   friend class TextPool;
128   friend class TextLine;
129   friend class TextBlock;
130   friend class TextFlow;
131   friend class TextWordList;
132   friend class TextPage;
133 };
134
135 //------------------------------------------------------------------------
136 // TextPool
137 //------------------------------------------------------------------------
138
139 class TextPool {
140 public:
141
142   TextPool();
143   ~TextPool();
144
145   TextWord *getPool(int baseIdx) { return pool[baseIdx - minBaseIdx]; }
146   void setPool(int baseIdx, TextWord *p) { pool[baseIdx - minBaseIdx] = p; }
147
148   int getBaseIdx(double base);
149
150   void addWord(TextWord *word);
151
152 private:
153
154   int minBaseIdx;               // min baseline bucket index
155   int maxBaseIdx;               // max baseline bucket index
156   TextWord **pool;              // array of linked lists, one for each
157                                 //   baseline value (multiple of 4 pts)
158   TextWord *cursor;             // pointer to last-accessed word
159   int cursorBaseIdx;            // baseline bucket index of last-accessed word
160
161   friend class TextBlock;
162   friend class TextPage;
163 };
164
165 //------------------------------------------------------------------------
166 // TextLine
167 //------------------------------------------------------------------------
168
169 class TextLine {
170 public:
171
172   TextLine(TextBlock *blkA, int rotA, double baseA);
173   ~TextLine();
174
175   void addWord(TextWord *word);
176
177   // Return the distance along the primary axis between <this> and
178   // <line>.
179   double primaryDelta(TextLine *line);
180
181   // Compares <this> to <line>, returning -1 (<), 0 (=), or +1 (>),
182   // based on a primary-axis comparison, e.g., x ordering if rot=0.
183   int primaryCmp(TextLine *line);
184
185   // Compares <this> to <line>, returning -1 (<), 0 (=), or +1 (>),
186   // based on a secondary-axis comparison of the baselines, e.g., y
187   // ordering if rot=0.
188   int secondaryCmp(TextLine *line);
189
190   int cmpYX(TextLine *line);
191
192   static int cmpXY(const void *p1, const void *p2);
193
194   void coalesce(UnicodeMap *uMap);
195
196 private:
197
198   TextBlock *blk;               // parent block
199   int rot;                      // text rotation
200   double xMin, xMax;            // bounding box x coordinates
201   double yMin, yMax;            // bounding box y coordinates
202   double base;                  // baseline x or y coordinate
203   TextWord *words;              // words in this line
204   TextWord *lastWord;           // last word in this line
205   Unicode *text;                // Unicode text of the line, including
206                                 //   spaces between words
207   double *edge;                 // "near" edge x or y coord of each char
208                                 //   (plus one extra entry for the last char)
209   int *col;                     // starting column number of each Unicode char
210   int len;                      // number of Unicode chars
211   int convertedLen;             // total number of converted characters
212   GBool hyphenated;             // set if last char is a hyphen
213   TextLine *next;               // next line in block
214
215   friend class TextLineFrag;
216   friend class TextBlock;
217   friend class TextFlow;
218   friend class TextWordList;
219   friend class TextPage;
220 };
221
222 //------------------------------------------------------------------------
223 // TextBlock
224 //------------------------------------------------------------------------
225
226 class TextBlock {
227 public:
228
229   TextBlock(TextPage *pageA, int rotA);
230   ~TextBlock();
231
232   void addWord(TextWord *word);
233
234   void coalesce(UnicodeMap *uMap);
235
236   // Update this block's priMin and priMax values, looking at <blk>.
237   void updatePriMinMax(TextBlock *blk);
238
239   static int cmpXYPrimaryRot(const void *p1, const void *p2);
240
241   static int cmpYXPrimaryRot(const void *p1, const void *p2);
242
243   int primaryCmp(TextBlock *blk);
244
245   double secondaryDelta(TextBlock *blk);
246
247   // Returns true if <this> is below <blk>, relative to the page's
248   // primary rotation.
249   GBool isBelow(TextBlock *blk);
250
251 private:
252
253   TextPage *page;               // the parent page
254   int rot;                      // text rotation
255   double xMin, xMax;            // bounding box x coordinates
256   double yMin, yMax;            // bounding box y coordinates
257   double priMin, priMax;        // whitespace bounding box along primary axis
258
259   TextPool *pool;               // pool of words (used only until lines
260                                 //   are built)
261   TextLine *lines;              // linked list of lines
262   TextLine *curLine;            // most recently added line
263   int nLines;                   // number of lines
264   int charCount;                // number of characters in the block
265   int col;                      // starting column
266   int nColumns;                 // number of columns in the block
267
268   TextBlock *next;
269   TextBlock *stackNext;
270
271   friend class TextLine;
272   friend class TextLineFrag;
273   friend class TextFlow;
274   friend class TextWordList;
275   friend class TextPage;
276 };
277
278 //------------------------------------------------------------------------
279 // TextFlow
280 //------------------------------------------------------------------------
281
282 class TextFlow {
283 public:
284
285   TextFlow(TextPage *pageA, TextBlock *blk);
286   ~TextFlow();
287
288   // Add a block to the end of this flow.
289   void addBlock(TextBlock *blk);
290
291   // Returns true if <blk> fits below <prevBlk> in the flow, i.e., (1)
292   // it uses a font no larger than the last block added to the flow,
293   // and (2) it fits within the flow's [priMin, priMax] along the
294   // primary axis.
295   GBool blockFits(TextBlock *blk, TextBlock *prevBlk);
296
297 private:
298
299   TextPage *page;               // the parent page
300   double xMin, xMax;            // bounding box x coordinates
301   double yMin, yMax;            // bounding box y coordinates
302   double priMin, priMax;        // whitespace bounding box along primary axis
303   TextBlock *blocks;            // blocks in flow
304   TextBlock *lastBlk;           // last block in this flow
305   TextFlow *next;
306
307   friend class TextWordList;
308   friend class TextPage;
309 };
310
311 #if TEXTOUT_WORD_LIST
312
313 //------------------------------------------------------------------------
314 // TextWordList
315 //------------------------------------------------------------------------
316
317 class TextWordList {
318 public:
319
320   // Build a flat word list, in content stream order (if
321   // text->rawOrder is true), physical layout order (if <physLayout>
322   // is true and text->rawOrder is false), or reading order (if both
323   // flags are false).
324   TextWordList(TextPage *text, GBool physLayout);
325
326   ~TextWordList();
327
328   // Return the number of words on the list.
329   int getLength();
330
331   // Return the <idx>th word from the list.
332   TextWord *get(int idx);
333
334 private:
335
336   GList *words;
337 };
338
339 #endif // TEXTOUT_WORD_LIST
340
341 //------------------------------------------------------------------------
342 // TextPage
343 //------------------------------------------------------------------------
344
345 class TextPage {
346 public:
347
348   // Constructor.
349   TextPage(GBool rawOrderA);
350
351   // Destructor.
352   ~TextPage();
353
354   // Start a new page.
355   void startPage(GfxState *state);
356
357   // Update the current font.
358   void updateFont(GfxState *state);
359
360   // Begin a new word.
361   void beginWord(GfxState *state, double x0, double y0);
362
363   // Add a character to the current word.
364   void addChar(GfxState *state, double x, double y,
365                double dx, double dy,
366                CharCode c, Unicode *u, int uLen);
367
368   // End the current word, sorting it into the list of words.
369   void endWord();
370
371   // Add a word, sorting it into the list of words.
372   void addWord(TextWord *word);
373
374   // Coalesce strings that look like parts of the same line.
375   void coalesce(GBool physLayout);
376
377   // Find a string.  If <startAtTop> is true, starts looking at the
378   // top of the page; else if <startAtLast> is true, starts looking
379   // immediately after the last find result; else starts looking at
380   // <xMin>,<yMin>.  If <stopAtBottom> is true, stops looking at the
381   // bottom of the page; else if <stopAtLast> is true, stops looking
382   // just before the last find result; else stops looking at
383   // <xMax>,<yMax>.
384   GBool findText(Unicode *s, int len,
385                  GBool startAtTop, GBool stopAtBottom,
386                  GBool startAtLast, GBool stopAtLast,
387                  double *xMin, double *yMin,
388                  double *xMax, double *yMax);
389
390   // Get the text which is inside the specified rectangle.
391   GString *getText(double xMin, double yMin,
392                    double xMax, double yMax);
393
394   // Find a string by character position and length.  If found, sets
395   // the text bounding rectangle and returns true; otherwise returns
396   // false.
397   GBool findCharRange(int pos, int length,
398                       double *xMin, double *yMin,
399                       double *xMax, double *yMax);
400
401   // Dump contents of page to a file.
402   void dump(void *outputStream, TextOutputFunc outputFunc,
403             GBool physLayout);
404
405 #if TEXTOUT_WORD_LIST
406   // Build a flat word list, in content stream order (if
407   // this->rawOrder is true), physical layout order (if <physLayout>
408   // is true and this->rawOrder is false), or reading order (if both
409   // flags are false).
410   TextWordList *makeWordList(GBool physLayout);
411 #endif
412
413 private:
414
415   void clear();
416   void assignColumns(TextLineFrag *frags, int nFrags, int rot);
417   int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GString *s);
418
419   GBool rawOrder;               // keep text in content stream order
420
421   double pageWidth, pageHeight; // width and height of current page
422   TextWord *curWord;            // currently active string
423   int charPos;                  // next character position (within content
424                                 //   stream)
425   TextFontInfo *curFont;        // current font
426   double curFontSize;           // current font size
427   int nest;                     // current nesting level (for Type 3 fonts)
428   int nTinyChars;               // number of "tiny" chars seen so far
429
430   TextPool *pools[4];           // a "pool" of TextWords for each rotation
431   TextFlow *flows;              // linked list of flows
432   TextBlock **blocks;           // array of blocks, in yx order
433   int nBlocks;                  // number of blocks
434   int primaryRot;               // primary rotation
435   GBool primaryLR;              // primary direction (true means L-to-R,
436                                 //   false means R-to-L)
437   TextWord *rawWords;           // list of words, in raw order (only if
438                                 //   rawOrder is set)
439   TextWord *rawLastWord;        // last word on rawWords list
440
441   GList *fonts;                 // all font info objects used on this
442                                 //   page [TextFontInfo]
443
444   double lastFindXMin,          // coordinates of the last "find" result
445          lastFindYMin;
446   GBool haveLastFind;
447
448   friend class TextLine;
449   friend class TextLineFrag;
450   friend class TextBlock;
451   friend class TextFlow;
452   friend class TextWordList;
453 };
454
455 //------------------------------------------------------------------------
456 // TextOutputDev
457 //------------------------------------------------------------------------
458
459 class TextOutputDev: public OutputDev {
460 public:
461
462   // Open a text output file.  If <fileName> is NULL, no file is
463   // written (this is useful, e.g., for searching text).  If
464   // <physLayoutA> is true, the original physical layout of the text
465   // is maintained.  If <rawOrder> is true, the text is kept in
466   // content stream order.
467   TextOutputDev(char *fileName, GBool physLayoutA,
468                 GBool rawOrderA, GBool append);
469
470   // Create a TextOutputDev which will write to a generic stream.  If
471   // <physLayoutA> is true, the original physical layout of the text
472   // is maintained.  If <rawOrder> is true, the text is kept in
473   // content stream order.
474   TextOutputDev(TextOutputFunc func, void *stream,
475                 GBool physLayoutA, GBool rawOrderA);
476
477   // Destructor.
478   virtual ~TextOutputDev();
479
480   // Check if file was successfully created.
481   virtual GBool isOk() { return ok; }
482
483   //---- get info about output device
484
485   // Does this device use upside-down coordinates?
486   // (Upside-down means (0,0) is the top left corner of the page.)
487   virtual GBool upsideDown() { return gTrue; }
488
489   // Does this device use drawChar() or drawString()?
490   virtual GBool useDrawChar() { return gTrue; }
491
492   // Does this device use beginType3Char/endType3Char?  Otherwise,
493   // text in Type 3 fonts will be drawn with drawChar/drawString.
494   virtual GBool interpretType3Chars() { return gFalse; }
495
496   // Does this device need non-text content?
497   virtual GBool needNonText() { return gFalse; }
498
499   //----- initialization and control
500
501   // Start a page.
502   virtual void startPage(int pageNum, GfxState *state);
503
504   // End a page.
505   virtual void endPage();
506
507   //----- update text state
508   virtual void updateFont(GfxState *state);
509
510   //----- text drawing
511   virtual void beginString(GfxState *state, GString *s);
512   virtual void endString(GfxState *state);
513   virtual void drawChar(GfxState *state, double x, double y,
514                         double dx, double dy,
515                         double originX, double originY,
516                         CharCode c, Unicode *u, int uLen);
517
518   //----- special access
519
520   // Find a string.  If <startAtTop> is true, starts looking at the
521   // top of the page; else if <startAtLast> is true, starts looking
522   // immediately after the last find result; else starts looking at
523   // <xMin>,<yMin>.  If <stopAtBottom> is true, stops looking at the
524   // bottom of the page; else if <stopAtLast> is true, stops looking
525   // just before the last find result; else stops looking at
526   // <xMax>,<yMax>.
527   GBool findText(Unicode *s, int len,
528                  GBool startAtTop, GBool stopAtBottom,
529                  GBool startAtLast, GBool stopAtLast,
530                  double *xMin, double *yMin,
531                  double *xMax, double *yMax);
532
533   // Get the text which is inside the specified rectangle.
534   GString *getText(double xMin, double yMin,
535                    double xMax, double yMax);
536
537   // Find a string by character position and length.  If found, sets
538   // the text bounding rectangle and returns true; otherwise returns
539   // false.
540   GBool findCharRange(int pos, int length,
541                       double *xMin, double *yMin,
542                       double *xMax, double *yMax);
543
544 #if TEXTOUT_WORD_LIST
545   // Build a flat word list, in content stream order (if
546   // this->rawOrder is true), physical layout order (if
547   // this->physLayout is true and this->rawOrder is false), or reading
548   // order (if both flags are false).
549   TextWordList *makeWordList();
550 #endif
551
552 private:
553
554   TextOutputFunc outputFunc;    // output function
555   void *outputStream;           // output stream
556   GBool needClose;              // need to close the output file?
557                                 //   (only if outputStream is a FILE*)
558   TextPage *text;               // text for the current page
559   GBool physLayout;             // maintain original physical layout when
560                                 //   dumping text
561   GBool rawOrder;               // keep text in content stream order
562   GBool ok;                     // set up ok?
563 };
564
565 #endif