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