• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * © 2016 and later: Unicode, Inc. and others.
4  * License & terms of use: http://www.unicode.org/copyright.html#License
5  *
6  * (C) Copyright IBM Corp. 1998-2007 - All Rights Reserved
7  *
8  */
9 
10 #include "unicode/utypes.h"
11 #include "unicode/uchar.h"
12 #include "unicode/ubidi.h"
13 #include "unicode/ustring.h"
14 
15 #include "layout/LETypes.h"
16 
17 #include "layout/loengine.h"
18 #include "layout/playout.h"
19 #include "layout/plruns.h"
20 
21 #include "pflow.h"
22 
23 #include "arraymem.h"
24 #include "ucreader.h"
25 
26 /*
27  * Move the line below out of this comment
28  * to add a locale run to the pl_paragraphs
29  * that are created.
30 #define TEST_LOCALE "zh_TW"
31  */
32 
33 #define MARGIN 10
34 #define LINE_GROW 32
35 #define PARA_GROW 8
36 
37 #define CH_LF 0x000A
38 #define CH_CR 0x000D
39 #define CH_LSEP 0x2028
40 #define CH_PSEP 0x2029
41 
42 struct pf_object
43 {
44     pl_paragraph    **fParagraphLayout;
45 
46     le_int32          fParagraphCount;
47     le_int32          fParagraphMax;
48     le_int32          fParagraphGrow;
49 
50     le_int32          fLineCount;
51     le_int32          fLinesMax;
52     le_int32          fLinesGrow;
53 
54     pl_line         **fLines;
55 
56    LEUnicode         *fChars;
57 
58     le_int32          fLineHeight;
59     le_int32          fAscent;
60     le_int32          fWidth;
61     le_int32          fHeight;
62     UBiDiLevel        fParagraphLevel;
63 };
64 
65 typedef struct pf_object pf_object;
66 
67 
skipLineEnd(LEUnicode * ptr)68 static LEUnicode *skipLineEnd(LEUnicode *ptr)
69 {
70     if (ptr[0] == CH_CR && ptr[1] == CH_LF) {
71         ptr += 1;
72     }
73 
74     return ptr + 1;
75 }
76 
findFontRun(const pl_fontRuns * fontRuns,le_int32 offset)77 static le_int32 findFontRun(const pl_fontRuns *fontRuns, le_int32 offset)
78 {
79     le_int32 runCount = pl_getFontRunCount(fontRuns);
80     le_int32 run;
81 
82     for (run = 0; run < runCount; run += 1) {
83         if (pl_getFontRunLimit(fontRuns, run) > offset) {
84             return run;
85         }
86     }
87 
88     return -1;
89 }
90 
subsetFontRuns(const pl_fontRuns * fontRuns,le_int32 start,le_int32 limit,pl_fontRuns * sub)91 static void subsetFontRuns(const pl_fontRuns *fontRuns, le_int32 start, le_int32 limit, pl_fontRuns *sub)
92 {
93     le_int32 startRun = findFontRun(fontRuns, start);
94     le_int32 endRun   = findFontRun(fontRuns, limit - 1);
95     le_int32 run;
96 
97     pl_resetFontRuns(sub);
98 
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;
102 
103         if (run == endRun) {
104             runLimit = limit - start;
105         }
106 
107         pl_addFontRun(sub, runFont, runLimit);
108     }
109 }
110 
pf_create(const LEUnicode chars[],le_int32 charCount,const pl_fontRuns * fontRuns,LEErrorCode * status)111 pf_flow *pf_create(const LEUnicode chars[], le_int32 charCount, const pl_fontRuns *fontRuns, LEErrorCode *status)
112 {
113     pf_object *flow;
114     le_int32 ascent  = 0;
115     le_int32 descent = 0;
116     le_int32 leading = 0;
117 	pl_localeRuns *locales = NULL;
118     pl_fontRuns *fr;
119     LEUnicode *pStart;
120     static const LEUnicode separators[] = {CH_LF, CH_CR, CH_LSEP, CH_PSEP, 0x0000};
121 
122 	if (LE_FAILURE(*status)) {
123 		return NULL;
124 	}
125 
126     flow = NEW_ARRAY(pf_object, 1);
127 
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;
135     flow->fLines           = NULL;
136     flow->fChars           = NULL;
137     flow->fLineHeight      = -1;
138     flow->fAscent          = -1;
139     flow->fWidth           = -1;
140     flow->fHeight          = -1;
141     flow->fParagraphLevel  = UBIDI_DEFAULT_LTR;
142 
143     fr = pl_openEmptyFontRuns(0);
144 
145 #ifdef TEST_LOCALE
146     locales = pl_openEmptyLocaleRuns(0);
147 #endif
148 
149     flow->fLines = NEW_ARRAY(pl_line *, flow->fLinesMax);
150     flow->fParagraphLayout = NEW_ARRAY(pl_paragraph *, flow->fParagraphMax);
151 
152     flow->fChars = NEW_ARRAY(LEUnicode, charCount + 1);
153     LE_ARRAY_COPY(flow->fChars, chars, charCount);
154     flow->fChars[charCount] = 0;
155 
156     pStart = &flow->fChars[0];
157 
158     while (*pStart != 0) {
159         LEUnicode *pEnd = u_strpbrk(pStart, separators);
160         le_int32 pAscent, pDescent, pLeading;
161         pl_paragraph *paragraphLayout = NULL;
162 
163         if (pEnd == NULL) {
164             pEnd = &flow->fChars[charCount];
165         }
166 
167         if (pEnd != pStart) {
168             subsetFontRuns(fontRuns, pStart - flow->fChars, pEnd - flow->fChars, fr);
169 
170 #ifdef TEST_LOCALE
171             pl_resetLocaleRuns(locales);
172             pl_addLocaleRun(locales, TEST_LOCALE, pEnd - pStart);
173 #endif
174 
175             paragraphLayout = pl_create(pStart, pEnd - pStart, fr, NULL, NULL, locales, flow->fParagraphLevel, FALSE, status);
176 
177             if (LE_FAILURE(*status)) {
178                 break; /* return? something else? */
179             }
180 
181             if (flow->fParagraphLevel == UBIDI_DEFAULT_LTR) {
182                 flow->fParagraphLevel = pl_getParagraphLevel(paragraphLayout);
183             }
184 
185             pAscent  = pl_getAscent(paragraphLayout);
186             pDescent = pl_getDescent(paragraphLayout);
187             pLeading = pl_getLeading(paragraphLayout);
188 
189             if (pAscent > ascent) {
190                 ascent = pAscent;
191             }
192 
193             if (pDescent > descent) {
194                 descent = pDescent;
195             }
196 
197             if (pLeading > leading) {
198                 leading = pLeading;
199             }
200         }
201 
202         if (flow->fParagraphCount >= flow->fParagraphMax) {
203             flow->fParagraphLayout = (pl_paragraph **) GROW_ARRAY(flow->fParagraphLayout, flow->fParagraphMax + flow->fParagraphGrow);
204             flow->fParagraphMax += flow->fParagraphGrow;
205         }
206 
207         flow->fParagraphLayout[flow->fParagraphCount++] = paragraphLayout;
208 
209         if (*pEnd == 0) {
210             break;
211         }
212 
213         pStart = skipLineEnd(pEnd);
214     }
215 
216     flow->fLineHeight = ascent + descent + leading;
217     flow->fAscent     = ascent;
218 
219     pl_closeLocaleRuns(locales);
220     pl_closeFontRuns(fr);
221 
222     return (pf_flow *) flow;
223 }
224 
pf_close(pf_flow * flow)225 void pf_close(pf_flow *flow)
226 {
227     pf_object *obj = (pf_object *) flow;
228     le_int32 i;
229 
230     for (i = 0; i < obj->fLineCount; i += 1) {
231         DELETE_ARRAY(obj->fLines[i]);
232     }
233 
234     DELETE_ARRAY(obj->fLines);
235 
236     for (i = 0; i < obj->fParagraphCount; i += 1) {
237         pl_close(obj->fParagraphLayout[i]);
238     }
239 
240     DELETE_ARRAY(obj->fParagraphLayout);
241 
242     DELETE_ARRAY(obj->fChars);
243 
244     DELETE_ARRAY(obj);
245 }
246 
247 
pf_getAscent(pf_flow * flow)248 le_int32 pf_getAscent(pf_flow *flow)
249 {
250     pf_object *obj = (pf_object *) flow;
251 
252     return obj->fAscent;
253 }
254 
pf_getLineHeight(pf_flow * flow)255 le_int32 pf_getLineHeight(pf_flow *flow)
256 {
257     pf_object *obj = (pf_object *) flow;
258 
259     return obj->fLineHeight;
260 }
261 
pf_getLineCount(pf_flow * flow)262 le_int32 pf_getLineCount(pf_flow *flow)
263 {
264     pf_object *obj = (pf_object *) flow;
265 
266     return obj->fLineCount;
267 }
268 
addLine(pf_object * obj,pl_line * line)269 static void addLine(pf_object *obj, pl_line *line)
270 {
271     if (obj->fLineCount >= obj->fLinesMax) {
272         obj->fLines = (pl_line **) GROW_ARRAY(obj->fLines, obj->fLinesMax + obj->fLinesGrow);
273         obj->fLinesMax += obj->fLinesGrow;
274     }
275 
276     obj->fLines[obj->fLineCount++] = line;
277 }
278 
pf_breakLines(pf_flow * flow,le_int32 width,le_int32 height)279 void pf_breakLines(pf_flow *flow, le_int32 width, le_int32 height)
280 {
281     pf_object *obj = (pf_object *) flow;
282     le_int32 li, p;
283     float lineWidth;
284     pl_line *line;
285 
286     obj->fHeight = height;
287 
288     /* don't re-break if the width hasn't changed */
289     if (obj->fWidth == width) {
290         return;
291     }
292 
293     obj->fWidth  = width;
294 
295     lineWidth = (float) (width - 2 * MARGIN);
296 
297     /* Free the old Lines... */
298     for (li = 0; li < obj->fLineCount; li += 1) {
299         pl_closeLine(obj->fLines[li]);
300     }
301 
302     obj->fLineCount = 0;
303 
304     for (p = 0; p < obj->fParagraphCount; p += 1) {
305         pl_paragraph *paragraphLayout = obj->fParagraphLayout[p];
306 
307         if (paragraphLayout != NULL) {
308             pl_reflow(paragraphLayout);
309             while ((line = pl_nextLine(paragraphLayout, lineWidth)) != NULL) {
310                 addLine(obj, line);
311             }
312         } else {
313             addLine(obj, NULL);
314         }
315     }
316 }
317 
pf_draw(pf_flow * flow,rs_surface * surface,le_int32 firstLine,le_int32 lastLine)318 void pf_draw(pf_flow *flow, rs_surface *surface, le_int32 firstLine, le_int32 lastLine)
319 {
320     pf_object *obj = (pf_object *) flow;
321     le_int32 li, x, y;
322 
323     x = MARGIN;
324     y = obj->fAscent;
325 
326     for (li = firstLine; li <= lastLine; li += 1) {
327         const pl_line *line = obj->fLines[li];
328 
329         if (line != NULL) {
330             le_int32 runCount = pl_countLineRuns(line);
331             le_int32 run;
332 
333 		    if (obj->fParagraphLevel == UBIDI_RTL) {
334 			    le_int32 lastX = pl_getLineWidth(line);
335 
336 			    x = (obj->fWidth - lastX - MARGIN);
337 		    }
338 
339 
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);
346 
347                 rs_drawGlyphs(surface, font, glyphs, glyphCount, positions, x, y, obj->fWidth, obj->fHeight);
348             }
349         }
350 
351         y += obj->fLineHeight;
352     }
353 }
354 
pf_factory(const char * fileName,const le_font * font,gs_guiSupport * guiSupport)355 pf_flow *pf_factory(const char *fileName, const le_font *font, gs_guiSupport *guiSupport)
356 {
357     LEErrorCode status  = LE_NO_ERROR;
358     le_int32 charCount;
359     const UChar *text = uc_readFile(fileName, guiSupport, &charCount);
360     pl_fontRuns *fontRuns;
361     pf_flow *result = NULL;
362 
363     if (text == NULL) {
364         return NULL;
365     }
366 
367     fontRuns = pl_openEmptyFontRuns(0);
368 
369     pl_addFontRun(fontRuns, font, charCount);
370 
371     result = pf_create(text, charCount, fontRuns, &status);
372 
373 	if (LE_FAILURE(status)) {
374 		pf_close(result);
375 		result = NULL;
376 	}
377 
378     pl_closeFontRuns(fontRuns);
379 
380     DELETE_ARRAY(text);
381 
382     return result;
383 }
384 
385