3  * © 2016 and later: Unicode, Inc. and others. 
   4  * License & terms of use: http://www.unicode.org/copyright.html#License 
   6  * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved 
  10 #include "unicode/utypes.h" 
  11 #include "unicode/uchar.h" 
  12 #include "unicode/ubidi.h" 
  13 #include "unicode/ustring.h" 
  15 #include "layout/LETypes.h" 
  17 #include "layout/loengine.h" 
  18 #include "layout/playout.h" 
  19 #include "layout/plruns.h" 
  27  * Move the line below out of this comment 
  28  * to add a locale run to the pl_paragraphs 
  30 #define TEST_LOCALE "zh_TW" 
  39 #define CH_LSEP 0x2028 
  40 #define CH_PSEP 0x2029 
  44     pl_paragraph    
**fParagraphLayout
; 
  46     le_int32          fParagraphCount
; 
  47     le_int32          fParagraphMax
; 
  48     le_int32          fParagraphGrow
; 
  62     UBiDiLevel        fParagraphLevel
; 
  65 typedef struct pf_object pf_object
; 
  68 static LEUnicode 
*skipLineEnd(LEUnicode 
*ptr
) 
  70     if (ptr
[0] == CH_CR 
&& ptr
[1] == CH_LF
) { 
  77 static le_int32 
findFontRun(const pl_fontRuns 
*fontRuns
, le_int32 offset
) 
  79     le_int32 runCount 
= pl_getFontRunCount(fontRuns
); 
  82     for (run 
= 0; run 
< runCount
; run 
+= 1) { 
  83         if (pl_getFontRunLimit(fontRuns
, run
) > offset
) { 
  91 static void subsetFontRuns(const pl_fontRuns 
*fontRuns
, le_int32 start
, le_int32 limit
, pl_fontRuns 
*sub
) 
  93     le_int32 startRun 
= findFontRun(fontRuns
, start
); 
  94     le_int32 endRun   
= findFontRun(fontRuns
, limit 
- 1); 
  97     pl_resetFontRuns(sub
); 
  99     for (run 
= startRun
; run 
<= endRun
; run 
+= 1) { 
 100         const le_font 
*runFont 
= pl_getFontRunFont(fontRuns
, run
); 
 101         le_int32 runLimit 
= pl_getFontRunLimit(fontRuns
, run
) - start
; 
 104             runLimit 
= limit 
- start
; 
 107         pl_addFontRun(sub
, runFont
, runLimit
); 
 111 pf_flow 
*pf_create(const LEUnicode chars
[], le_int32 charCount
, const pl_fontRuns 
*fontRuns
, LEErrorCode 
*status
) 
 115     le_int32 descent 
= 0; 
 116     le_int32 leading 
= 0; 
 117         pl_localeRuns 
*locales 
= NULL
; 
 120     static const LEUnicode separators
[] = {CH_LF
, CH_CR
, CH_LSEP
, CH_PSEP
, 0x0000}; 
 122         if (LE_FAILURE(*status
)) { 
 126     flow 
= NEW_ARRAY(pf_object
, 1); 
 128     flow
->fParagraphLayout 
= NULL
; 
 129     flow
->fParagraphCount  
= 0; 
 130     flow
->fParagraphMax    
= PARA_GROW
; 
 131     flow
->fParagraphGrow   
= PARA_GROW
; 
 132     flow
->fLineCount       
= 0; 
 133     flow
->fLinesMax        
= LINE_GROW
; 
 134     flow
->fLinesGrow       
= LINE_GROW
; 
 137     flow
->fLineHeight      
= -1; 
 141     flow
->fParagraphLevel  
= UBIDI_DEFAULT_LTR
; 
 143     fr 
= pl_openEmptyFontRuns(0); 
 146     locales 
= pl_openEmptyLocaleRuns(0); 
 149     flow
->fLines 
= NEW_ARRAY(pl_line 
*, flow
->fLinesMax
); 
 150     flow
->fParagraphLayout 
= NEW_ARRAY(pl_paragraph 
*, flow
->fParagraphMax
); 
 152     flow
->fChars 
= NEW_ARRAY(LEUnicode
, charCount 
+ 1); 
 153     LE_ARRAY_COPY(flow
->fChars
, chars
, charCount
); 
 154     flow
->fChars
[charCount
] = 0; 
 156     pStart 
= &flow
->fChars
[0]; 
 158     while (*pStart 
!= 0) { 
 159         LEUnicode 
*pEnd 
= u_strpbrk(pStart
, separators
); 
 160         le_int32 pAscent
, pDescent
, pLeading
; 
 161         pl_paragraph 
*paragraphLayout 
= NULL
; 
 164             pEnd 
= &flow
->fChars
[charCount
]; 
 167         if (pEnd 
!= pStart
) { 
 168             subsetFontRuns(fontRuns
, pStart 
- flow
->fChars
, pEnd 
- flow
->fChars
, fr
); 
 171             pl_resetLocaleRuns(locales
); 
 172             pl_addLocaleRun(locales
, TEST_LOCALE
, pEnd 
- pStart
); 
 175             paragraphLayout 
= pl_create(pStart
, pEnd 
- pStart
, fr
, NULL
, NULL
, locales
, flow
->fParagraphLevel
, FALSE
, status
); 
 177             if (LE_FAILURE(*status
)) { 
 178                 break; /* return? something else? */ 
 181             if (flow
->fParagraphLevel 
== UBIDI_DEFAULT_LTR
) { 
 182                 flow
->fParagraphLevel 
= pl_getParagraphLevel(paragraphLayout
); 
 185             pAscent  
= pl_getAscent(paragraphLayout
); 
 186             pDescent 
= pl_getDescent(paragraphLayout
); 
 187             pLeading 
= pl_getLeading(paragraphLayout
); 
 189             if (pAscent 
> ascent
) { 
 193             if (pDescent 
> descent
) { 
 197             if (pLeading 
> leading
) { 
 202         if (flow
->fParagraphCount 
>= flow
->fParagraphMax
) { 
 203             flow
->fParagraphLayout 
= (pl_paragraph 
**) GROW_ARRAY(flow
->fParagraphLayout
, flow
->fParagraphMax 
+ flow
->fParagraphGrow
); 
 204             flow
->fParagraphMax 
+= flow
->fParagraphGrow
; 
 207         flow
->fParagraphLayout
[flow
->fParagraphCount
++] = paragraphLayout
; 
 213         pStart 
= skipLineEnd(pEnd
); 
 216     flow
->fLineHeight 
= ascent 
+ descent 
+ leading
; 
 217     flow
->fAscent     
= ascent
; 
 219     pl_closeLocaleRuns(locales
); 
 220     pl_closeFontRuns(fr
); 
 222     return (pf_flow 
*) flow
; 
 225 void pf_close(pf_flow 
*flow
) 
 227     pf_object 
*obj 
= (pf_object 
*) flow
; 
 230     for (i 
= 0; i 
< obj
->fLineCount
; i 
+= 1) { 
 231         DELETE_ARRAY(obj
->fLines
[i
]); 
 234     DELETE_ARRAY(obj
->fLines
); 
 236     for (i 
= 0; i 
< obj
->fParagraphCount
; i 
+= 1) { 
 237         pl_close(obj
->fParagraphLayout
[i
]); 
 240     DELETE_ARRAY(obj
->fParagraphLayout
); 
 242     DELETE_ARRAY(obj
->fChars
); 
 248 le_int32 
pf_getAscent(pf_flow 
*flow
) 
 250     pf_object 
*obj 
= (pf_object 
*) flow
; 
 255 le_int32 
pf_getLineHeight(pf_flow 
*flow
) 
 257     pf_object 
*obj 
= (pf_object 
*) flow
; 
 259     return obj
->fLineHeight
; 
 262 le_int32 
pf_getLineCount(pf_flow 
*flow
) 
 264     pf_object 
*obj 
= (pf_object 
*) flow
; 
 266     return obj
->fLineCount
; 
 269 static void addLine(pf_object 
*obj
, pl_line 
*line
) 
 271     if (obj
->fLineCount 
>= obj
->fLinesMax
) { 
 272         obj
->fLines 
= (pl_line 
**) GROW_ARRAY(obj
->fLines
, obj
->fLinesMax 
+ obj
->fLinesGrow
); 
 273         obj
->fLinesMax 
+= obj
->fLinesGrow
; 
 276     obj
->fLines
[obj
->fLineCount
++] = line
; 
 279 void pf_breakLines(pf_flow 
*flow
, le_int32 width
, le_int32 height
) 
 281     pf_object 
*obj 
= (pf_object 
*) flow
; 
 286     obj
->fHeight 
= height
; 
 288     /* don't re-break if the width hasn't changed */ 
 289     if (obj
->fWidth 
== width
) { 
 295     lineWidth 
= (float) (width 
- 2 * MARGIN
); 
 297     /* Free the old Lines... */ 
 298     for (li 
= 0; li 
< obj
->fLineCount
; li 
+= 1) { 
 299         pl_closeLine(obj
->fLines
[li
]); 
 304     for (p 
= 0; p 
< obj
->fParagraphCount
; p 
+= 1) { 
 305         pl_paragraph 
*paragraphLayout 
= obj
->fParagraphLayout
[p
]; 
 307         if (paragraphLayout 
!= NULL
) { 
 308             pl_reflow(paragraphLayout
); 
 309             while ((line 
= pl_nextLine(paragraphLayout
, lineWidth
)) != NULL
) { 
 318 void pf_draw(pf_flow 
*flow
, rs_surface 
*surface
, le_int32 firstLine
, le_int32 lastLine
) 
 320     pf_object 
*obj 
= (pf_object 
*) flow
; 
 326     for (li 
= firstLine
; li 
<= lastLine
; li 
+= 1) { 
 327         const pl_line 
*line 
= obj
->fLines
[li
]; 
 330             le_int32 runCount 
= pl_countLineRuns(line
); 
 333                     if (obj
->fParagraphLevel 
== UBIDI_RTL
) { 
 334                             le_int32 lastX 
= pl_getLineWidth(line
); 
 336                             x 
= (obj
->fWidth 
- lastX 
- MARGIN
); 
 340             for (run 
= 0; run 
< runCount
; run 
+= 1) { 
 341                 const pl_visualRun 
*visualRun 
= pl_getLineVisualRun(line
, run
); 
 342                 le_int32 glyphCount 
= pl_getVisualRunGlyphCount(visualRun
); 
 343                 const le_font 
*font 
= pl_getVisualRunFont(visualRun
); 
 344                 const LEGlyphID 
*glyphs 
= pl_getVisualRunGlyphs(visualRun
); 
 345                 const float *positions 
= pl_getVisualRunPositions(visualRun
); 
 347                 rs_drawGlyphs(surface
, font
, glyphs
, glyphCount
, positions
, x
, y
, obj
->fWidth
, obj
->fHeight
); 
 351         y 
+= obj
->fLineHeight
; 
 355 pf_flow 
*pf_factory(const char *fileName
, const le_font 
*font
, gs_guiSupport 
*guiSupport
) 
 357     LEErrorCode status  
= LE_NO_ERROR
; 
 359     const UChar 
*text 
= uc_readFile(fileName
, guiSupport
, &charCount
); 
 360     pl_fontRuns 
*fontRuns
; 
 361     pf_flow 
*result 
= NULL
; 
 367     fontRuns 
= pl_openEmptyFontRuns(0); 
 369     pl_addFontRun(fontRuns
, font
, charCount
); 
 371     result 
= pf_create(text
, charCount
, fontRuns
, &status
); 
 373         if (LE_FAILURE(status
)) { 
 378     pl_closeFontRuns(fontRuns
);