]> www.fi.muni.cz Git - evince.git/blob - pdf/xpdf/TextOutputDev.h
Show a wait cursor while the page is rendering
[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   // End the current page.
358   void endPage();
359
360   // Update the current font.
361   void updateFont(GfxState *state);
362
363   // Begin a new word.
364   void beginWord(GfxState *state, double x0, double y0);
365
366   // Add a character to the current word.
367   void addChar(GfxState *state, double x, double y,
368                double dx, double dy,
369                CharCode c, Unicode *u, int uLen);
370
371   // End the current word, sorting it into the list of words.
372   void endWord();
373
374   // Add a word, sorting it into the list of words.
375   void addWord(TextWord *word);
376
377   // Coalesce strings that look like parts of the same line.
378   void coalesce(GBool physLayout);
379
380   // Find a string.  If <startAtTop> is true, starts looking at the
381   // top of the page; else if <startAtLast> is true, starts looking
382   // immediately after the last find result; else starts looking at
383   // <xMin>,<yMin>.  If <stopAtBottom> is true, stops looking at the
384   // bottom of the page; else if <stopAtLast> is true, stops looking
385   // just before the last find result; else stops looking at
386   // <xMax>,<yMax>.
387   GBool findText(Unicode *s, int len,
388                  GBool startAtTop, GBool stopAtBottom,
389                  GBool startAtLast, GBool stopAtLast,
390                  double *xMin, double *yMin,
391                  double *xMax, double *yMax);
392
393   // Get the text which is inside the specified rectangle.
394   GString *getText(double xMin, double yMin,
395                    double xMax, double yMax);
396
397   // Find a string by character position and length.  If found, sets
398   // the text bounding rectangle and returns true; otherwise returns
399   // false.
400   GBool findCharRange(int pos, int length,
401                       double *xMin, double *yMin,
402                       double *xMax, double *yMax);
403
404   // Dump contents of page to a file.
405   void dump(void *outputStream, TextOutputFunc outputFunc,
406             GBool physLayout);
407
408 #if TEXTOUT_WORD_LIST
409   // Build a flat word list, in content stream order (if
410   // this->rawOrder is true), physical layout order (if <physLayout>
411   // is true and this->rawOrder is false), or reading order (if both
412   // flags are false).
413   TextWordList *makeWordList(GBool physLayout);
414 #endif
415
416 private:
417
418   void clear();
419   void assignColumns(TextLineFrag *frags, int nFrags, int rot);
420   int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GString *s);
421
422   GBool rawOrder;               // keep text in content stream order
423
424   double pageWidth, pageHeight; // width and height of current page
425   TextWord *curWord;            // currently active string
426   int charPos;                  // next character position (within content
427                                 //   stream)
428   TextFontInfo *curFont;        // current font
429   double curFontSize;           // current font size
430   int nest;                     // current nesting level (for Type 3 fonts)
431   int nTinyChars;               // number of "tiny" chars seen so far
432   GBool lastCharOverlap;        // set if the last added char overlapped the
433                                 //   previous char
434
435   TextPool *pools[4];           // a "pool" of TextWords for each rotation
436   TextFlow *flows;              // linked list of flows
437   TextBlock **blocks;           // array of blocks, in yx order
438   int nBlocks;                  // number of blocks
439   int primaryRot;               // primary rotation
440   GBool primaryLR;              // primary direction (true means L-to-R,
441                                 //   false means R-to-L)
442   TextWord *rawWords;           // list of words, in raw order (only if
443                                 //   rawOrder is set)
444   TextWord *rawLastWord;        // last word on rawWords list
445
446   GList *fonts;                 // all font info objects used on this
447                                 //   page [TextFontInfo]
448
449   double lastFindXMin,          // coordinates of the last "find" result
450          lastFindYMin;
451   GBool haveLastFind;
452
453   friend class TextLine;
454   friend class TextLineFrag;
455   friend class TextBlock;
456   friend class TextFlow;
457   friend class TextWordList;
458 };
459
460 //------------------------------------------------------------------------
461 // TextOutputDev
462 //------------------------------------------------------------------------
463
464 class TextOutputDev: public OutputDev {
465 public:
466
467   // Open a text output file.  If <fileName> is NULL, no file is
468   // written (this is useful, e.g., for searching text).  If
469   // <physLayoutA> is true, the original physical layout of the text
470   // is maintained.  If <rawOrder> is true, the text is kept in
471   // content stream order.
472   TextOutputDev(char *fileName, GBool physLayoutA,
473                 GBool rawOrderA, GBool append);
474
475   // Create a TextOutputDev which will write to a generic stream.  If
476   // <physLayoutA> is true, the original physical layout of the text
477   // is maintained.  If <rawOrder> is true, the text is kept in
478   // content stream order.
479   TextOutputDev(TextOutputFunc func, void *stream,
480                 GBool physLayoutA, GBool rawOrderA);
481
482   // Destructor.
483   virtual ~TextOutputDev();
484
485   // Check if file was successfully created.
486   virtual GBool isOk() { return ok; }
487
488   //---- get info about output device
489
490   // Does this device use upside-down coordinates?
491   // (Upside-down means (0,0) is the top left corner of the page.)
492   virtual GBool upsideDown() { return gTrue; }
493
494   // Does this device use drawChar() or drawString()?
495   virtual GBool useDrawChar() { return gTrue; }
496
497   // Does this device use beginType3Char/endType3Char?  Otherwise,
498   // text in Type 3 fonts will be drawn with drawChar/drawString.
499   virtual GBool interpretType3Chars() { return gFalse; }
500
501   // Does this device need non-text content?
502   virtual GBool needNonText() { return gFalse; }
503
504   //----- initialization and control
505
506   // Start a page.
507   virtual void startPage(int pageNum, GfxState *state);
508
509   // End a page.
510   virtual void endPage();
511
512   //----- update text state
513   virtual void updateFont(GfxState *state);
514
515   //----- text drawing
516   virtual void beginString(GfxState *state, GString *s);
517   virtual void endString(GfxState *state);
518   virtual void drawChar(GfxState *state, double x, double y,
519                         double dx, double dy,
520                         double originX, double originY,
521                         CharCode c, Unicode *u, int uLen);
522
523   //----- special access
524
525   // Find a string.  If <startAtTop> is true, starts looking at the
526   // top of the page; else if <startAtLast> is true, starts looking
527   // immediately after the last find result; else starts looking at
528   // <xMin>,<yMin>.  If <stopAtBottom> is true, stops looking at the
529   // bottom of the page; else if <stopAtLast> is true, stops looking
530   // just before the last find result; else stops looking at
531   // <xMax>,<yMax>.
532   GBool findText(Unicode *s, int len,
533                  GBool startAtTop, GBool stopAtBottom,
534                  GBool startAtLast, GBool stopAtLast,
535                  double *xMin, double *yMin,
536                  double *xMax, double *yMax);
537
538   // Get the text which is inside the specified rectangle.
539   GString *getText(double xMin, double yMin,
540                    double xMax, double yMax);
541
542   // Find a string by character position and length.  If found, sets
543   // the text bounding rectangle and returns true; otherwise returns
544   // false.
545   GBool findCharRange(int pos, int length,
546                       double *xMin, double *yMin,
547                       double *xMax, double *yMax);
548
549 #if TEXTOUT_WORD_LIST
550   // Build a flat word list, in content stream order (if
551   // this->rawOrder is true), physical layout order (if
552   // this->physLayout is true and this->rawOrder is false), or reading
553   // order (if both flags are false).
554   TextWordList *makeWordList();
555 #endif
556
557 private:
558
559   TextOutputFunc outputFunc;    // output function
560   void *outputStream;           // output stream
561   GBool needClose;              // need to close the output file?
562                                 //   (only if outputStream is a FILE*)
563   TextPage *text;               // text for the current page
564   GBool physLayout;             // maintain original physical layout when
565                                 //   dumping text
566   GBool rawOrder;               // keep text in content stream order
567   GBool ok;                     // set up ok?
568 };
569
570 #endif