3 * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
7 #include "unicode/utypes.h"
8 #include "unicode/uchar.h"
9 #include "unicode/ubidi.h"
10 #include "unicode/ustring.h"
12 #include "layout/LETypes.h"
14 #include "layout/loengine.h"
15 #include "layout/playout.h"
16 #include "layout/plruns.h"
24 * Move the line below out of this comment
25 * to add a locale run to the pl_paragraphs
27 #define TEST_LOCALE "zh_TW"
36 #define CH_LSEP 0x2028
37 #define CH_PSEP 0x2029
41 pl_paragraph
**fParagraphLayout
;
43 le_int32 fParagraphCount
;
44 le_int32 fParagraphMax
;
45 le_int32 fParagraphGrow
;
59 UBiDiLevel fParagraphLevel
;
62 typedef struct pf_object pf_object
;
65 static LEUnicode
*skipLineEnd(LEUnicode
*ptr
)
67 if (ptr
[0] == CH_CR
&& ptr
[1] == CH_LF
) {
74 static le_int32
findFontRun(const pl_fontRuns
*fontRuns
, le_int32 offset
)
76 le_int32 runCount
= pl_getFontRunCount(fontRuns
);
79 for (run
= 0; run
< runCount
; run
+= 1) {
80 if (pl_getFontRunLimit(fontRuns
, run
) > offset
) {
88 static void subsetFontRuns(const pl_fontRuns
*fontRuns
, le_int32 start
, le_int32 limit
, pl_fontRuns
*sub
)
90 le_int32 startRun
= findFontRun(fontRuns
, start
);
91 le_int32 endRun
= findFontRun(fontRuns
, limit
- 1);
94 pl_resetFontRuns(sub
);
96 for (run
= startRun
; run
<= endRun
; run
+= 1) {
97 const le_font
*runFont
= pl_getFontRunFont(fontRuns
, run
);
98 le_int32 runLimit
= pl_getFontRunLimit(fontRuns
, run
) - start
;
101 runLimit
= limit
- start
;
104 pl_addFontRun(sub
, runFont
, runLimit
);
108 pf_flow
*pf_create(const LEUnicode chars
[], le_int32 charCount
, const pl_fontRuns
*fontRuns
, LEErrorCode
*status
)
112 le_int32 descent
= 0;
113 le_int32 leading
= 0;
114 pl_localeRuns
*locales
= NULL
;
117 static const LEUnicode separators
[] = {CH_LF
, CH_CR
, CH_LSEP
, CH_PSEP
, 0x0000};
119 if (LE_FAILURE(*status
)) {
123 flow
= NEW_ARRAY(pf_object
, 1);
125 flow
->fParagraphLayout
= NULL
;
126 flow
->fParagraphCount
= 0;
127 flow
->fParagraphMax
= PARA_GROW
;
128 flow
->fParagraphGrow
= PARA_GROW
;
129 flow
->fLineCount
= 0;
130 flow
->fLinesMax
= LINE_GROW
;
131 flow
->fLinesGrow
= LINE_GROW
;
134 flow
->fLineHeight
= -1;
138 flow
->fParagraphLevel
= UBIDI_DEFAULT_LTR
;
140 fr
= pl_openEmptyFontRuns(0);
143 locales
= pl_openEmptyLocaleRuns(0);
146 flow
->fLines
= NEW_ARRAY(pl_line
*, flow
->fLinesMax
);
147 flow
->fParagraphLayout
= NEW_ARRAY(pl_paragraph
*, flow
->fParagraphMax
);
149 flow
->fChars
= NEW_ARRAY(LEUnicode
, charCount
+ 1);
150 LE_ARRAY_COPY(flow
->fChars
, chars
, charCount
);
151 flow
->fChars
[charCount
] = 0;
153 pStart
= &flow
->fChars
[0];
155 while (*pStart
!= 0) {
156 LEUnicode
*pEnd
= u_strpbrk(pStart
, separators
);
157 le_int32 pAscent
, pDescent
, pLeading
;
158 pl_paragraph
*paragraphLayout
= NULL
;
161 pEnd
= &flow
->fChars
[charCount
];
164 if (pEnd
!= pStart
) {
165 subsetFontRuns(fontRuns
, pStart
- flow
->fChars
, pEnd
- flow
->fChars
, fr
);
168 pl_resetLocaleRuns(locales
);
169 pl_addLocaleRun(locales
, TEST_LOCALE
, pEnd
- pStart
);
172 paragraphLayout
= pl_create(pStart
, pEnd
- pStart
, fr
, NULL
, NULL
, locales
, flow
->fParagraphLevel
, FALSE
, status
);
174 if (LE_FAILURE(*status
)) {
175 break; /* return? something else? */
178 if (flow
->fParagraphLevel
== UBIDI_DEFAULT_LTR
) {
179 flow
->fParagraphLevel
= pl_getParagraphLevel(paragraphLayout
);
182 pAscent
= pl_getAscent(paragraphLayout
);
183 pDescent
= pl_getDescent(paragraphLayout
);
184 pLeading
= pl_getLeading(paragraphLayout
);
186 if (pAscent
> ascent
) {
190 if (pDescent
> descent
) {
194 if (pLeading
> leading
) {
199 if (flow
->fParagraphCount
>= flow
->fParagraphMax
) {
200 flow
->fParagraphLayout
= (pl_paragraph
**) GROW_ARRAY(flow
->fParagraphLayout
, flow
->fParagraphMax
+ flow
->fParagraphGrow
);
201 flow
->fParagraphMax
+= flow
->fParagraphGrow
;
204 flow
->fParagraphLayout
[flow
->fParagraphCount
++] = paragraphLayout
;
210 pStart
= skipLineEnd(pEnd
);
213 flow
->fLineHeight
= ascent
+ descent
+ leading
;
214 flow
->fAscent
= ascent
;
216 pl_closeLocaleRuns(locales
);
217 pl_closeFontRuns(fr
);
219 return (pf_flow
*) flow
;
222 void pf_close(pf_flow
*flow
)
224 pf_object
*obj
= (pf_object
*) flow
;
227 for (i
= 0; i
< obj
->fLineCount
; i
+= 1) {
228 DELETE_ARRAY(obj
->fLines
[i
]);
231 DELETE_ARRAY(obj
->fLines
);
233 for (i
= 0; i
< obj
->fParagraphCount
; i
+= 1) {
234 pl_close(obj
->fParagraphLayout
[i
]);
237 DELETE_ARRAY(obj
->fParagraphLayout
);
239 DELETE_ARRAY(obj
->fChars
);
245 le_int32
pf_getAscent(pf_flow
*flow
)
247 pf_object
*obj
= (pf_object
*) flow
;
252 le_int32
pf_getLineHeight(pf_flow
*flow
)
254 pf_object
*obj
= (pf_object
*) flow
;
256 return obj
->fLineHeight
;
259 le_int32
pf_getLineCount(pf_flow
*flow
)
261 pf_object
*obj
= (pf_object
*) flow
;
263 return obj
->fLineCount
;
266 static void addLine(pf_object
*obj
, pl_line
*line
)
268 if (obj
->fLineCount
>= obj
->fLinesMax
) {
269 obj
->fLines
= (pl_line
**) GROW_ARRAY(obj
->fLines
, obj
->fLinesMax
+ obj
->fLinesGrow
);
270 obj
->fLinesMax
+= obj
->fLinesGrow
;
273 obj
->fLines
[obj
->fLineCount
++] = line
;
276 void pf_breakLines(pf_flow
*flow
, le_int32 width
, le_int32 height
)
278 pf_object
*obj
= (pf_object
*) flow
;
283 obj
->fHeight
= height
;
285 /* don't re-break if the width hasn't changed */
286 if (obj
->fWidth
== width
) {
292 lineWidth
= (float) (width
- 2 * MARGIN
);
294 /* Free the old Lines... */
295 for (li
= 0; li
< obj
->fLineCount
; li
+= 1) {
296 pl_closeLine(obj
->fLines
[li
]);
301 for (p
= 0; p
< obj
->fParagraphCount
; p
+= 1) {
302 pl_paragraph
*paragraphLayout
= obj
->fParagraphLayout
[p
];
304 if (paragraphLayout
!= NULL
) {
305 pl_reflow(paragraphLayout
);
306 while ((line
= pl_nextLine(paragraphLayout
, lineWidth
)) != NULL
) {
315 void pf_draw(pf_flow
*flow
, rs_surface
*surface
, le_int32 firstLine
, le_int32 lastLine
)
317 pf_object
*obj
= (pf_object
*) flow
;
323 for (li
= firstLine
; li
<= lastLine
; li
+= 1) {
324 const pl_line
*line
= obj
->fLines
[li
];
327 le_int32 runCount
= pl_countLineRuns(line
);
330 if (obj
->fParagraphLevel
== UBIDI_RTL
) {
331 le_int32 lastX
= pl_getLineWidth(line
);
333 x
= (obj
->fWidth
- lastX
- MARGIN
);
337 for (run
= 0; run
< runCount
; run
+= 1) {
338 const pl_visualRun
*visualRun
= pl_getLineVisualRun(line
, run
);
339 le_int32 glyphCount
= pl_getVisualRunGlyphCount(visualRun
);
340 const le_font
*font
= pl_getVisualRunFont(visualRun
);
341 const LEGlyphID
*glyphs
= pl_getVisualRunGlyphs(visualRun
);
342 const float *positions
= pl_getVisualRunPositions(visualRun
);
344 rs_drawGlyphs(surface
, font
, glyphs
, glyphCount
, positions
, x
, y
, obj
->fWidth
, obj
->fHeight
);
348 y
+= obj
->fLineHeight
;
352 pf_flow
*pf_factory(const char *fileName
, const le_font
*font
, gs_guiSupport
*guiSupport
)
354 LEErrorCode status
= LE_NO_ERROR
;
356 const UChar
*text
= uc_readFile(fileName
, guiSupport
, &charCount
);
357 pl_fontRuns
*fontRuns
;
358 pf_flow
*result
= NULL
;
364 fontRuns
= pl_openEmptyFontRuns(0);
366 pl_addFontRun(fontRuns
, font
, charCount
);
368 result
= pf_create(text
, charCount
, fontRuns
, &status
);
370 if (LE_FAILURE(status
)) {
375 pl_closeFontRuns(fontRuns
);