1 /** \file lvtextfm.h
2 
3     \brief Text formatter API
4 
5    CoolReader Engine C-compatible text formatter API
6 
7    (c) Vadim Lopatin, 2000-2006
8    This source code is distributed under the terms of
9    GNU General Public License.
10 
11    See LICENSE file for details.
12 
13 */
14 
15 #ifndef __LVTEXTFM_H_INCLUDED__
16 #define __LVTEXTFM_H_INCLUDED__
17 
18 #include "lvfont.h"
19 #include "lvstring32collection.h"
20 #include "lvbmpbuf.h"
21 #include "textlang.h"
22 
23 #ifdef __cplusplus
24 extern "C" {
25 #endif
26 
27 // src_text_fragment_t flags
28 
29 // Text horizontal alignment
30 #define LTEXT_FLAG_NEWLINE           0x0007  // Mask: next flags are set only on the first fragment following a newline
31 #define LTEXT_ALIGN_LEFT             0x0001  // left-aligned paragraph
32 #define LTEXT_ALIGN_RIGHT            0x0002  // right-aligned paragraph
33 #define LTEXT_ALIGN_CENTER           0x0003  // centered paragraph
34 #define LTEXT_ALIGN_WIDTH            0x0004  // justified paragraph
35 #define LTEXT_LAST_LINE_ALIGN_SHIFT       4  // Shift to map the following flags to the previous ones
36 #define LTEXT_LAST_LINE_ALIGN_LEFT   0x0010  // last line of justified paragraph should be left-aligned
37 #define LTEXT_LAST_LINE_ALIGN_RIGHT  0x0020  // last line of justified paragraph should be right-aligned
38 #define LTEXT_LAST_LINE_ALIGN_CENTER 0x0030  // last line of justified paragraph should be centered
39 #define LTEXT_LAST_LINE_ALIGN_WIDTH  0x0040  // last line of justified paragraph should be justified
40 #define LTEXT_LAST_LINE_IF_NOT_FIRST 0x0080  // previous flag doesn't apply if last line is also the first (standalone line)
41 
42 // Text vertical alignment
43 #define LTEXT_VALIGN_MASK            0x0700  // vertical align flags mask
44 #define LTEXT_VALIGN_BASELINE        0x0000  // baseline vertical align
45 #define LTEXT_VALIGN_SUB             0x0100  // subscript
46 #define LTEXT_VALIGN_SUPER           0x0200  // superscript
47 #define LTEXT_VALIGN_MIDDLE          0x0300  // middle
48 #define LTEXT_VALIGN_BOTTOM          0x0400  // bottom
49 #define LTEXT_VALIGN_TEXT_BOTTOM     0x0500  // text-bottom
50 #define LTEXT_VALIGN_TOP             0x0600  // top
51 #define LTEXT_VALIGN_TEXT_TOP        0x0700  // text-top
52 #define LTEXT_STRUT_CONFINED         0x0800  // text should not overflow/modify its paragraph strut baseline and height
53 
54 // Text decoration
55 #define LTEXT_TD_MASK                0x7000  // text decoration mask
56 #define LTEXT_TD_UNDERLINE           0x1000  // underlined text
57 #define LTEXT_TD_OVERLINE            0x2000  // overlined text
58 #define LTEXT_TD_LINE_THROUGH        0x4000  // striked through text
59     // These 3 above translate to LFNT_DRAW_* equivalents (see lvfntman.h). Keep them in sync.
60 
61 // (Don't waste the 4th bit not used in the 4-bits sets above)
62 #define LTEXT_FLAG_OWNTEXT           0x0008  // store local copy of text instead of pointer
63 #define LTEXT_IS_LINK                0x8000  // source text is a link (to gather in-page footnotes)
64 
65 // Text white-space and hyphenation handling
66 #define LTEXT_FLAG_PREFORMATTED      0x00010000  // text is preformatted (white-space: pre, pre-wrap, break-spaces)
67 #define LTEXT_FLAG_NOWRAP            0x00020000  // text does not allow wrap (white-space: nowrap)
68 #define LTEXT_LOCKED_SPACING         0x00040000  // regular spaces should not change width with text justification
69 #define LTEXT_HYPHENATE              0x00080000  // allow hyphenation
70 
71 // Source object type (when source is not a text node)
72 #define LTEXT_SRC_IS_OBJECT          0x00100000  // object (image)
73 #define LTEXT_SRC_IS_INLINE_BOX      0x00200000  // inlineBox wrapping node
74 #define LTEXT_SRC_IS_FLOAT           0x00400000  // float:'ing node
75 #define LTEXT_SRC_IS_FLOAT_DONE      0x00800000  // float:'ing node (already dealt with)
76 // "clear" handling
77 #define LTEXT_SRC_IS_CLEAR_RIGHT     0x01000000  // text follows <BR style="clear: right">
78 #define LTEXT_SRC_IS_CLEAR_LEFT      0x02000000  // text follows <BR style="clear: left">
79 #define LTEXT_SRC_IS_CLEAR_BOTH      0x03000000  // text follows <BR style="clear: both">
80 #define LTEXT_SRC_IS_CLEAR_LAST      0x04000000  // ignorable text, added when nothing follows <BR style="clear: both">
81 
82 #define LTEXT_FIT_GLYPHS             0x08000000  // Avoid glyph overflows and override at line edges and between text nodes
83 
84 #define LTEXT_LEGACY_RENDERING       0x10000000  // Legacy rendering exceptions: new line processing: set indentation for **each** new line, etc.
85 
86 #define LTEXT__AVAILABLE_BIT_30__    0x20000000
87 #define LTEXT__AVAILABLE_BIT_31__    0x40000000
88 #define LTEXT__AVAILABLE_BIT_32__    0x80000000
89 
90 /** \brief Source text line
91 */
92 typedef struct
93 {
94     void *          object;   /**< \brief pointer to object which represents source */
95     TextLangCfg *   lang_cfg;
96     lInt16          indent;   /**< \brief first line indent (or all but first, when negative) */
97     lInt16          valign_dy; /* drift y from baseline */
98     lInt16          interval; /**< \brief line height in screen pixels */
99     lInt16          letter_spacing; /**< \brief additional letter spacing, pixels */
100     lUInt32         color;    /**< \brief color */
101     lUInt32         bgcolor;  /**< \brief background color */
102     lUInt32         flags;    /**< \brief flags */
103     lUInt16         index;
104     // move unions bottom to simplify debugging
105     union {
106         struct {
107             lvfont_handle   font;     /**< \brief handle of font to draw string */
108             const lChar32 * text;     /**< \brief pointer to unicode text string */
109             lUInt16         len;      /**< \brief number of chars in text */
110             lUInt16         offset;   /**< \brief offset from node start to beginning of line */
111         } t;
112         struct {
113             // (Note: width & height will be stored negative when they are in % unit)
114             lInt16         width;    /**< \brief width of image or inline-block-box */
115             lInt16         height;   /**< \brief height of image or inline-block box */
116             lUInt16        baseline; /**< \brief baseline of inline-block box */
117         } o;
118     };
119 } src_text_fragment_t;
120 
121 
122 /** \brief Formatted word
123 */
124 typedef struct
125 {
126    lUInt16  src_text_index;  /**< \brief index of source text line */
127    lUInt16  width;           /**< \brief word width, pixels, when at line end */
128    lUInt16  min_width;       /**< \brief index of source text line */
129    lInt16   x;               /**< \brief word x position in line */
130    lInt16   y;               /**< \brief baseline y position */
131    lUInt16  flags;           /**< \brief flags */
132    union {
133           /// for text word
134        struct {
135            lUInt16  start;           /**< \brief position of word in source text */
136            lUInt16  len;             /**< \brief number of chars in word */
137        } t;
138        /// for object
139        struct {
140            lUInt16  height;          /**< \brief height of image or inline-block box */
141            lUInt16  baseline;        /**< \brief baseline of inline-block box */
142        } o;
143    };
144    lInt16   added_letter_spacing;    /* letter-spacing (to reduce spacing when justified) to add when drawing this word */
145    lInt16   distinct_glyphs;         /* nb of glyphs in this word that can have letter-spacing added to */
146    lInt16   _top_to_baseline;        /* temporary storage slots when delaying y computation, */
147    lInt16   _baseline_to_bottom;     /* when valign top or bottom */
148    // lUInt16  padding;         /**< \brief not used */
149 } formatted_word_t;
150 
151 // formatted_word_t flags
152 #define LTEXT_WORD_CAN_ADD_SPACE_AFTER       0x0001 /// can add space after this word
153 #define LTEXT_WORD_CAN_BREAK_LINE_AFTER      0x0002 /// can break line after this word (not used anywhere)
154 #define LTEXT_WORD_CAN_HYPH_BREAK_LINE_AFTER 0x0004 /// can break with hyphenation after this word
155 #define LTEXT_WORD_MUST_BREAK_LINE_AFTER     0x0008 /// must break line after this word (not used anywhere)
156 
157 #define LTEXT_WORD_IS_LINK_START             0x0010 /// first word of link flag
158 #define LTEXT_WORD_IS_OBJECT                 0x0020 /// word is an image
159 #define LTEXT_WORD_IS_INLINE_BOX             0x0040 /// word is a inline-block or inline-table wrapping box
160 #define LTEXT_WORD__AVAILABLE_BIT_08__       0x0080
161 
162 #define LTEXT_WORD_DIRECTION_KNOWN           0x0100 /// word has been thru bidi: if next flag is unset, it is LTR.
163 #define LTEXT_WORD_DIRECTION_IS_RTL          0x0200 /// word is RTL
164 #define LTEXT_WORD_BEGINS_PARAGRAPH          0x0400 /// word is the first word of a paragraph
165 #define LTEXT_WORD_ENDS_PARAGRAPH            0x0800 /// word is the last word of a paragraph
166     // These 4 translate (after mask & shift) to LFNT_HINT_* equivalents
167     // (see lvfntman.h). Keep them in sync.
168 #define LTEXT_WORD_DIRECTION_PARA_MASK       0x0F00
169 #define LTEXT_WORD_DIRECTION_PARA_TO_LFNT_SHIFT   8
170 #define WORD_FLAGS_TO_FNT_FLAGS(f) ( (f & LTEXT_WORD_DIRECTION_PARA_MASK)>>LTEXT_WORD_DIRECTION_PARA_TO_LFNT_SHIFT)
171 
172 
173 #define LTEXT_WORD_VALIGN_TOP                0x1000 /// word is to be vertical-align: top
174 #define LTEXT_WORD_VALIGN_BOTTOM             0x2000 /// word is to be vertical-align: bottom
175 #define LTEXT_WORD_STRUT_CONFINED            0x4000 /// word is to be fully contained into strut bounds
176                                                     /// (used only when one of the 2 previous is set)
177 #define LTEXT_WORD__AVAILABLE_BIT_16__       0x8000
178 
179 //#define LTEXT_BACKGROUND_MARK_FLAGS 0xFFFF0000l
180 
181 // formatted_line_t flags
182 #define LTEXT_LINE_SPLIT_AVOID_BEFORE        0x01
183 #define LTEXT_LINE_SPLIT_AVOID_AFTER         0x02
184 #define LTEXT_LINE_IS_BIDI                   0x04
185 #define LTEXT_LINE_PARA_IS_RTL               0x08
186 
187 #define LTEXT_LINE__AVAILABLE_BIT_05__       0x10
188 #define LTEXT_LINE__AVAILABLE_BIT_06__       0x20
189 #define LTEXT_LINE__AVAILABLE_BIT_07__       0x40
190 #define LTEXT_LINE__AVAILABLE_BIT_08__       0x80
191 
192 /** \brief Text formatter formatted line
193 */
194 typedef struct
195 {
196    formatted_word_t * words;       /**< array of words */
197    lInt32             word_count;  /**< number of words */
198    lUInt32            y;           /**< start y position of line */
199    lInt16             x;           /**< start x position */
200    lUInt16            width;       /**< width */
201    lUInt16            height;      /**< height */
202    lUInt16            baseline;    /**< baseline y offset */
203    lUInt8             flags;       /**< flags */
204    lUInt8             align;       /**< alignment */
205 } formatted_line_t;
206 
207 /** \brief Text formatter embedded float
208 */
209 typedef struct
210 {
211    src_text_fragment_t * srctext;     /**< source node */
212    lInt32                y;           /**< start y position of float */
213    lInt16                x;           /**< start x position */
214    lUInt16               width;       /**< width */
215    lUInt32               height;      /**< height */
216    lUInt16               inward_margin; /**< inward margin */
217    css_clear_t           clear;       /**< clear: css property value */
218    bool                  is_right;    /**< is float: right */
219    bool                  to_position; /**< not yet positioned */
220    lString32Collection * links;       /** footnote links found in this float text */
221 } embedded_float_t;
222 
223 /** \brief Bookmark highlight modes.
224 */
225 enum {
226     highlight_mode_none = 0,
227     highlight_mode_solid = 1,
228     highlight_mode_underline = 2
229 };
230 
231 /** \brief Text highlight options for selection, bookmarks, etc.
232 */
233 struct text_highlight_options_t {
234     lUInt32 selectionColor;    /**< selection color */
235     lUInt32 commentColor;      /**< comment bookmark color */
236     lUInt32 correctionColor;   /**< correction bookmark color */
237     int bookmarkHighlightMode; /**< bookmark highlight mode: 0=no highlight, 1=solid fill, 2=underline */
text_highlight_options_ttext_highlight_options_t238     text_highlight_options_t() {
239         selectionColor = 0x80AAAAAA;
240         commentColor = 0xC0FFFF00;
241         correctionColor = 0xC0FF8000;
242         bookmarkHighlightMode = highlight_mode_solid;
243     }
244 };
245 
246 /** \brief Text formatter container
247 */
248 typedef struct
249 {
250    src_text_fragment_t * srctext;       /**< source text lines */
251    lInt32                srctextlen;    /**< number of source text lines */
252    formatted_line_t   ** frmlines;      /**< formatted lines */
253    lInt32                frmlinecount;  /**< formatted lines count*/
254    embedded_float_t   ** floats;        /**< embedded floats */
255    lInt32                floatcount;    /**< embedded floats count*/
256    lUInt32               height;        /**< height of text fragment */
257    lUInt16               width;         /**< width of text fragment */
258    lUInt16               page_height;   /**< max page height */
259 
260     // Each line box starts with a zero-width inline box (called "strut") with
261     // the element's font and line height properties:
262    lUInt16               strut_height;   /**< strut height */
263    lUInt16               strut_baseline; /**< strut baseline */
264 
265    // Image scaling options
266    lInt32                img_zoom_in_mode_block; /**< can zoom in block images: 0=disabled, 1=integer scale, 2=free scale */
267    lInt32                img_zoom_in_scale_block; /**< max scale for block images zoom in: 1, 2, 3 */
268    lInt32                img_zoom_in_mode_inline; /**< can zoom in inline images: 0=disabled, 1=integer scale, 2=free scale */
269    lInt32                img_zoom_in_scale_inline; /**< max scale for inline images zoom in: 1, 2, 3 */
270    lInt32                img_zoom_out_mode_block; /**< can zoom out block images: 0=disabled, 1=integer scale, 2=free scale */
271    lInt32                img_zoom_out_scale_block; /**< max scale for block images zoom out: 1, 2, 3 */
272    lInt32                img_zoom_out_mode_inline; /**< can zoom out inline images: 0=disabled, 1=integer scale, 2=free scale */
273    lInt32                img_zoom_out_scale_inline; /**< max scale for inline images zoom out: 1, 2, 3 */
274 
275    // Space width
276    lInt32                space_width_scale_percent; /**< scale the normal width of all spaces in all fonts by this percent */
277    lInt32                min_space_condensing_percent; /**< min size of space (relative to scaled size) to allow fitting line by reducing of spaces */
278    // For word spacing and justitication
279    lInt32                unused_space_threshold_percent; /**< % (of line width) of unused space on a line to trigger hyphenation,
280                                                               or addition of letter spacing for justification  */
281    lInt32                max_added_letter_spacing_percent; /**< Max allowed added letter spacing (% of font size) */
282 
283    // Highlighting
284    text_highlight_options_t highlight_options; /**< options for selection/bookmark highlighting */
285 
286    // Reusable after it is cached by ldomNode::renderFinalBlock()
287    // (Usually true, except in a single case: first rendering of final block
288    // containing embedded blocks, where we want the first rendering to forward
289    // these embedded blocks individual lines, for page splitting - a second
290    // rendering, with proper inlineBox lines will be needed for drawing.)
291    bool                  is_reusable;
292    // Avoid some work when formatting to only get the block height
293    // (e.g. when full rerendering). This will make is_reusable=true too.
294    bool                  light_formatting;
295 
296 } formatted_text_fragment_t;
297 
298 /**  Alloc & init formatted text buffer
299 
300     \param width is width of formatted text fragment
301 */
302 formatted_text_fragment_t * lvtextAllocFormatter( lUInt16 width );
303 
304 /** Free formatted text buffer
305 
306     dont't forget to call it when object is no longer used
307 
308     \param pbuffer is pointer to formatted text buffer
309 */
310 void lvtextFreeFormatter( formatted_text_fragment_t * pbuffer );
311 
312 /** Add source text line
313 
314     Call this function after lvtextInitFormatter for each source fragment
315 */
316 void lvtextAddSourceLine(
317    formatted_text_fragment_t * pbuffer,
318    lvfont_handle   font,     /* handle of font to draw string */
319    TextLangCfg *   lang_cfg,
320    const lChar32 * text,     /* pointer to unicode text string */
321    lUInt32         len,      /* number of chars in text, 0 for auto(strlen) */
322    lUInt32         color,    /* text color */
323    lUInt32         bgcolor,  /* background color */
324    lUInt32         flags,    /* flags */
325    lInt16          interval, /* line height in screen pixels */
326    lInt16          valign_dy,/* drift y from baseline */
327    lInt16          indent,   /* first line indent (or all but first, when negative) */
328    void *          object,   /* pointer to custom object */
329    lUInt16         offset,    /* offset from node/object start to start of line */
330    lInt16          letter_spacing
331                          );
332 
333 /** Add source object
334 
335     Call this function after lvtextInitFormatter for each source fragment
336 */
337 void lvtextAddSourceObject(
338    formatted_text_fragment_t * pbuffer,
339    TextLangCfg *   lang_cfg,
340    lInt16         width,
341    lInt16         height,
342    lUInt32         flags,     /* flags */
343    lInt16          interval,  /* line height in screen pixels */
344    lInt16          valign_dy, /* drift y from baseline */
345    lInt16          indent,    /* first line indent (or all but first, when negative) */
346    void *          object,    /* pointer to custom object */
347    lInt16          letter_spacing
348                          );
349 
350 
351 #ifdef __cplusplus
352 }
353 
354 class LVDrawBuf;
355 class ldomMarkedRangeList;
356 struct img_scaling_options_t;
357 class BlockFloatFootprint;
358 
359 /* C++ wrapper class */
360 class LFormattedText
361 {
362     friend class LGrayDrawBuf;
363 private:
364     formatted_text_fragment_t * m_pbuffer;
365 public:
GetBuffer()366     formatted_text_fragment_t * GetBuffer() { return m_pbuffer; }
367 
368     /// set strut height and baseline (line boxes starting minimal values)
setStrut(lUInt16 height,lUInt16 baseline)369     void setStrut(lUInt16 height, lUInt16 baseline) {
370         m_pbuffer->strut_height = height;
371         m_pbuffer->strut_baseline = baseline;
372     }
373 
374     /// set image scaling options
375     void setImageScalingOptions( img_scaling_options_t * options );
376 
377     /// set space glyph width scaling percent option (10..500%)
378     // (scale the normal width of all spaces in all fonts by this percent)
379     void setSpaceWidthScalePercent(int spaceWidthScalePercent);
380 
381     /// set space condensing line fitting option (25..100%)
382     // (applies after spaceWidthScalePercent has been applied)
383     void setMinSpaceCondensingPercent(int minSpaceCondensingPercent);
384 
385     /// set unused space threshold percent option (0..20%)
386     void setUnusedSpaceThresholdPercent(int unusedSpaceThresholdPercent);
387 
388     /// set max allowed added letter spacing (0..20% of font size)
389     void setMaxAddedLetterSpacingPercent(int maxAddedLetterSpacingPercent);
390 
391     /// set colors for selection and bookmarks
392     void setHighlightOptions(text_highlight_options_t * options);
393 
Clear()394     void Clear()
395     {
396         lUInt16 width = m_pbuffer->width;
397         lvtextFreeFormatter( m_pbuffer );
398         m_pbuffer = lvtextAllocFormatter( width );
399     }
400 
401     void AddSourceObject(
402                 lUInt32         flags,     /* flags */
403                 lInt16          interval,  /* line height in screen pixels */
404                 lInt16          valign_dy, /* drift y from baseline */
405                 lInt16          indent,    /* first line indent (or all but first, when negative) */
406                 void *          object,    /* pointer to custom object */
407                 TextLangCfg *   lang_cfg,
408                 lInt16          letter_spacing=0
409          );
410 
411     void AddSourceLine(
412            const lChar32 * text,        /* pointer to unicode text string */
413            lUInt32         len,         /* number of chars in text, 0 for auto(strlen) */
414            lUInt32         color,       /* text color */
415            lUInt32         bgcolor,     /* background color */
416            LVFont *        font,        /* font to draw string */
417            TextLangCfg *   lang_cfg,
418            lUInt32         flags,       /* (had default =LTEXT_ALIGN_LEFT|LTEXT_FLAG_OWNTEXT) */
419            lInt16          interval,    /* line height in screen pixels */
420            lInt16          valign_dy=0, /* drift y from baseline */
421            lInt16          indent=0,    /* first line indent (or all but first, when negative) */
422            void *          object=NULL,
423            lUInt32         offset=0,
424            lInt16          letter_spacing=0
425         )
426     {
427         lvtextAddSourceLine(m_pbuffer,
428             font,  //font->GetHandle()
429             lang_cfg,
430             text, len, color, bgcolor,
431             flags, interval, valign_dy, indent, object, (lUInt16)offset, letter_spacing );
432     }
433 
434     lUInt32 Format(lUInt16 width, lUInt16 page_height,
435                         int para_direction=0, // = REND_DIRECTION_UNSET in lvrend.h
436                         int usable_left_overflow=0, int usable_right_overflow=0,
437                         bool hanging_punctuation=false,
438                         BlockFloatFootprint * float_footprint = NULL );
439 
GetSrcCount()440     int GetSrcCount()
441     {
442         return m_pbuffer->srctextlen;
443     }
444 
GetWidth()445     int GetWidth()
446     {
447         return m_pbuffer->width;
448     }
449 
GetSrcInfo(int index)450     const src_text_fragment_t * GetSrcInfo(int index)
451     {
452         return &m_pbuffer->srctext[index];
453     }
454 
GetLineCount()455     int GetLineCount()
456     {
457         return m_pbuffer->frmlinecount;
458     }
459 
GetLineInfo(int index)460     const formatted_line_t * GetLineInfo(int index)
461     {
462         return m_pbuffer->frmlines[index];
463     }
464 
GetFloatCount()465     int GetFloatCount()
466     {
467         return m_pbuffer->floatcount;
468     }
469 
GetFloatInfo(int index)470     const embedded_float_t * GetFloatInfo(int index)
471     {
472         return m_pbuffer->floats[index];
473     }
474 
475     void Draw( LVDrawBuf * buf, int x, int y, ldomMarkedRangeList * marks = NULL,  ldomMarkedRangeList *bookmarks = NULL );
476 
isReusable()477     bool isReusable() { return m_pbuffer->is_reusable; }
requestLightFormatting()478     void requestLightFormatting() { m_pbuffer->light_formatting = true; }
479 
LFormattedText()480     LFormattedText() { m_pbuffer = lvtextAllocFormatter( 0 ); }
481 
~LFormattedText()482     ~LFormattedText() { lvtextFreeFormatter( m_pbuffer ); }
483 };
484 
485 #endif
486 
487 #endif
488