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
);