• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4  **********************************************************************
5  *   Copyright (C) 2002-2014, International Business Machines
6  *   Corporation and others.  All Rights Reserved.
7  **********************************************************************
8  */
9 
10 /*
11  * paragraphLayout doesn't make much sense without
12  * BreakIterator...
13  */
14 #include "layout/LETypes.h"
15 #include "layout/LEScripts.h"
16 #include "layout/LELanguages.h"
17 #include "layout/LayoutEngine.h"
18 #include "layout/LEFontInstance.h"
19 
20 #include "unicode/ubidi.h"
21 #include "unicode/uchriter.h"
22 #include "unicode/brkiter.h"
23 
24 #if ! UCONFIG_NO_BREAK_ITERATION
25 #include "LXUtilities.h"
26 #include "usc_impl.h" /* this is currently private! */
27 #include "cstring.h"  /* this too! */
28 
29 #include "layout/ParagraphLayout.h"
30 
31 U_NAMESPACE_BEGIN
32 
33 #define ARRAY_SIZE(array) (sizeof array  / sizeof array[0])
34 
35 /* Leave this copyright notice here! It needs to go somewhere in this library. */
36 static const char copyright[] = U_COPYRIGHT_STRING;
37 
38 class StyleRuns
39 {
40 public:
41     StyleRuns(const RunArray *styleRunArrays[], le_int32 styleCount);
42 
43     ~StyleRuns();
44 
45     le_int32 getRuns(le_int32 runLimits[], le_int32 styleIndices[]);
46 
47 private:
48     le_int32 fStyleCount;
49     le_int32 fRunCount;
50 
51     le_int32 *fRunLimits;
52     le_int32 *fStyleIndices;
53 };
54 
StyleRuns(const RunArray * styleRunArrays[],le_int32 styleCount)55 StyleRuns::StyleRuns(const RunArray *styleRunArrays[], le_int32 styleCount)
56     : fStyleCount(styleCount), fRunCount(0), fRunLimits(NULL), fStyleIndices(NULL)
57 {
58     le_int32 maxRunCount = 0;
59     le_int32 style, run, runStyle;
60     le_int32 *currentRun = LE_NEW_ARRAY(le_int32, styleCount);
61 
62     for (int i = 0; i < styleCount; i += 1) {
63         maxRunCount += styleRunArrays[i]->getCount();
64     }
65 
66     maxRunCount -= styleCount - 1;
67 
68     fRunLimits    = LE_NEW_ARRAY(le_int32, maxRunCount);
69     fStyleIndices = LE_NEW_ARRAY(le_int32, maxRunCount * styleCount);
70 
71     for (style = 0; style < styleCount; style += 1) {
72         currentRun[style] = 0;
73     }
74 
75     run = 0;
76     runStyle = 0;
77 
78     /*
79      * Since the last run limit for each style run must be
80      * the same, all the styles will hit the last limit at
81      * the same time, so we know when we're done when the first
82      * style hits the last limit.
83      */
84     while (currentRun[0] < styleRunArrays[0]->getCount()) {
85         fRunLimits[run] = 0x7FFFFFFF;
86 
87         // find the minimum run limit for all the styles
88         for (style = 0; style < styleCount; style += 1) {
89             if (styleRunArrays[style]->getLimit(currentRun[style]) < fRunLimits[run]) {
90                 fRunLimits[run] = styleRunArrays[style]->getLimit(currentRun[style]);
91             }
92         }
93 
94         // advance all styles whose current run is at this limit to the next run
95         for (style = 0; style < styleCount; style += 1) {
96             fStyleIndices[runStyle++] = currentRun[style];
97 
98             if (styleRunArrays[style]->getLimit(currentRun[style]) == fRunLimits[run]) {
99                 currentRun[style] += 1;
100             }
101         }
102 
103         run += 1;
104     }
105 
106     fRunCount = run;
107     LE_DELETE_ARRAY(currentRun);
108 }
109 
~StyleRuns()110 StyleRuns::~StyleRuns()
111 {
112     fRunCount = 0;
113 
114     LE_DELETE_ARRAY(fStyleIndices);
115     fStyleIndices = NULL;
116 
117     LE_DELETE_ARRAY(fRunLimits);
118     fRunLimits = NULL;
119 }
120 
getRuns(le_int32 runLimits[],le_int32 styleIndices[])121 le_int32 StyleRuns::getRuns(le_int32 runLimits[], le_int32 styleIndices[])
122 {
123     if (runLimits != NULL) {
124         LE_ARRAY_COPY(runLimits, fRunLimits, fRunCount);
125     }
126 
127     if (styleIndices != NULL) {
128         LE_ARRAY_COPY(styleIndices, fStyleIndices, fRunCount * fStyleCount);
129     }
130 
131     return fRunCount;
132 }
133 
134 /*
135  * NOTE: This table only has "TRUE" values for
136  * those scripts which the LayoutEngine can currently
137  * process, rather for all scripts which require
138  * complex processing for correct rendering.
139  */
140 static const le_bool complexTable[] = {
141     FALSE , /* Zyyy */
142     FALSE,  /* Qaai */
143     TRUE,   /* Arab */
144     FALSE,  /* Armn */
145     TRUE,   /* Beng */
146     FALSE,  /* Bopo */
147     FALSE,  /* Cher */
148     FALSE,  /* Copt=Qaac */
149     FALSE,  /* Cyrl */
150     FALSE,  /* Dsrt */
151     TRUE,   /* Deva */
152     FALSE,  /* Ethi */
153     FALSE,  /* Geor */
154     FALSE,  /* Goth */
155     FALSE,  /* Grek */
156     TRUE,   /* Gujr */
157     TRUE,   /* Guru */
158     FALSE,  /* Hani */
159     FALSE,  /* Hang */
160     TRUE,   /* Hebr */
161     FALSE,  /* Hira */
162     TRUE,   /* Knda */
163     FALSE,  /* Kana */
164     FALSE,  /* Khmr */
165     FALSE,  /* Laoo */
166     FALSE,  /* Latn */
167     TRUE,   /* Mlym */
168     FALSE,  /* Mong */
169     FALSE,  /* Mymr */
170     FALSE,  /* Ogam */
171     FALSE,  /* Ital */
172     TRUE,   /* Orya */
173     FALSE,  /* Runr */
174     FALSE,  /* Sinh */
175     FALSE,  /* Syrc */
176     TRUE,   /* Taml */
177     TRUE,   /* Telu */
178     FALSE,  /* Thaa */
179     TRUE,   /* Thai */
180     FALSE,  /* Tibt */
181     FALSE,  /* Cans */
182     FALSE,  /* Yiii */
183     FALSE,  /* Tglg */
184     FALSE,  /* Hano */
185     FALSE,  /* Buhd */
186     FALSE,  /* Tagb */
187     FALSE,  /* Brai */
188     FALSE,  /* Cprt */
189     FALSE,  /* Limb */
190     FALSE,  /* Linb */
191     FALSE,  /* Osma */
192     FALSE,  /* Shaw */
193     FALSE,  /* Tale */
194     FALSE,  /* Ugar */
195     FALSE,  /* Hrkt */
196     FALSE,  /* Bugi */
197     FALSE,  /* Glag */
198     FALSE,  /* Khar */
199     FALSE,  /* Sylo */
200     FALSE,  /* Talu */
201     FALSE,  /* Tfng */
202     FALSE,  /* Xpeo */
203     FALSE,  /* Bali */
204     FALSE,  /* Batk */
205     FALSE,  /* Blis */
206     FALSE,  /* Brah */
207     FALSE,  /* Cham */
208     FALSE,  /* Cirt */
209     FALSE,  /* Cyrs */
210     FALSE,  /* Egyd */
211     FALSE,  /* Egyh */
212     FALSE,  /* Egyp */
213     FALSE,  /* Geok */
214     FALSE,  /* Hans */
215     FALSE,  /* Hant */
216     FALSE,  /* Hmng */
217     FALSE,  /* Hung */
218     FALSE,  /* Inds */
219     FALSE,  /* Java */
220     FALSE,  /* Kali */
221     FALSE,  /* Latf */
222     FALSE,  /* Latg */
223     FALSE,  /* Lepc */
224     FALSE,  /* Lina */
225     FALSE,  /* Mand */
226     FALSE,  /* Maya */
227     FALSE,  /* Mero */
228     FALSE,  /* Nkoo */
229     FALSE,  /* Orkh */
230     FALSE,  /* Perm */
231     FALSE,  /* Phag */
232     FALSE,  /* Phnx */
233     FALSE,  /* Plrd */
234     FALSE,  /* Roro */
235     FALSE,  /* Sara */
236     FALSE,  /* Syre */
237     FALSE,  /* Syrj */
238     FALSE,  /* Syrn */
239     FALSE,  /* Teng */
240     FALSE,  /* Taii */
241     FALSE,  /* Visp */
242     FALSE,  /* Xsux */
243     FALSE,  /* Zxxx */
244     FALSE,  /* Zzzz */
245     FALSE,  /* Cari */
246     FALSE,  /* Jpan */
247     FALSE,  /* Lana */
248     FALSE,  /* Lyci */
249     FALSE,  /* Lydi */
250     FALSE,  /* Olck */
251     FALSE,  /* Rjng */
252     FALSE,  /* Saur */
253     FALSE,  /* Sgnw */
254     FALSE,  /* Sund */
255     FALSE,  /* Moon */
256     FALSE,  /* Mtei */
257     FALSE,  /* Armi */
258     FALSE,  /* Avst */
259     FALSE,  /* Cakm */
260     FALSE,  /* Kore */
261     FALSE,  /* Kthi */
262     FALSE,  /* Mani */
263     FALSE,  /* Phli */
264     FALSE,  /* Phlp */
265     FALSE,  /* Phlv */
266     FALSE,  /* Prti */
267     FALSE,  /* Samr */
268     FALSE,  /* Tavt */
269     FALSE,  /* Zmth */
270     FALSE,  /* Zsym */
271     FALSE,  /* Bamu */
272     FALSE,  /* Lisu */
273     FALSE,  /* Nkgb */
274     FALSE   /* Sarb */
275 };
276 
277 
278 const char ParagraphLayout::fgClassID = 0;
279 
fillMissingCharToGlyphMapValues(le_int32 * charToGlyphMap,le_int32 charCount)280 static void fillMissingCharToGlyphMapValues(le_int32 *charToGlyphMap,
281                                             le_int32 charCount) {
282     le_int32 lastValidGlyph = -1;
283     le_int32 ch;
284     for (ch = 0; ch <= charCount; ch += 1) {
285         if (charToGlyphMap[ch] == -1) {
286             charToGlyphMap[ch] = lastValidGlyph;
287         } else {
288             lastValidGlyph = charToGlyphMap[ch];
289         }
290     }
291 }
292 
293 /*
294  * How to deal with composite fonts:
295  *
296  * Don't store the client's FontRuns; we'll need to compute sub-font FontRuns using Doug's
297  * LEFontInstance method. Do that by intersecting the client's FontRuns with fScriptRuns. Use
298  * that to compute fFontRuns, and then intersect fFontRuns, fScriptRuns and fLevelRuns. Doing
299  * it in this order means we do a two-way intersection and a three-way intersection.
300  *
301  * An optimization would be to only do this if there's at least one composite font...
302  *
303  * Other notes:
304  *
305  * * Return the sub-fonts as the run fonts... could keep the mapping back to the client's FontRuns
306  *   but that probably makes it more complicated of everyone...
307  *
308  * * Take the LineInfo and LineRun types from Paragraph and use them here, incorporate them into the API.
309  *
310  * * Might want to change the name of the StyleRun type, and make a new one that holds fonts, scripts and levels?
311  *
312  */
ParagraphLayout(const LEUnicode chars[],le_int32 count,const FontRuns * fontRuns,const ValueRuns * levelRuns,const ValueRuns * scriptRuns,const LocaleRuns * localeRuns,UBiDiLevel paragraphLevel,le_bool vertical,LEErrorCode & status)313 ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count,
314                                  const FontRuns   *fontRuns,
315                                  const ValueRuns  *levelRuns,
316                                  const ValueRuns  *scriptRuns,
317                                  const LocaleRuns *localeRuns,
318                                  UBiDiLevel paragraphLevel, le_bool vertical,
319                                  LEErrorCode &status)
320                                  : fChars(chars), fCharCount(count),
321                                    fFontRuns(NULL), fLevelRuns(levelRuns), fScriptRuns(scriptRuns), fLocaleRuns(localeRuns),
322                                    fVertical(vertical), fClientLevels(TRUE), fClientScripts(TRUE), fClientLocales(TRUE), fEmbeddingLevels(NULL),
323                                    fAscent(0), fDescent(0), fLeading(0),
324                                    fGlyphToCharMap(NULL), fCharToMinGlyphMap(NULL), fCharToMaxGlyphMap(NULL), fGlyphWidths(NULL), fGlyphCount(0),
325                                    fParaBidi(NULL), fLineBidi(NULL),
326                                    fStyleRunLimits(NULL), fStyleIndices(NULL), fStyleRunCount(0),
327                                    fBreakIterator(NULL), fLineStart(-1), fLineEnd(0),
328                                  /*fVisualRuns(NULL), fStyleRunInfo(NULL), fVisualRunCount(-1),
329                                    fFirstVisualRun(-1), fLastVisualRun(-1),*/ fVisualRunLastX(0), fVisualRunLastY(0)
330 {
331 
332     if (LE_FAILURE(status)) {
333         fCharCount = -1;
334         return;
335     }
336 
337     (void)copyright;  // Suppress unused variable warning.
338     (void)fVertical;  // Suppress warning for unused field fVertical.
339 
340     // FIXME: should check the limit arrays for consistency...
341 
342     computeLevels(paragraphLevel);
343 
344     if (scriptRuns == NULL) {
345         computeScripts();
346     }
347 
348     if (localeRuns == NULL) {
349         computeLocales();
350     }
351 
352     computeSubFonts(fontRuns, status);
353 
354     if (LE_FAILURE(status)) {
355         //other stuff?
356         fCharCount = -1;
357         return;
358     }
359 
360     // now intersect the font, direction and script runs...
361     const RunArray *styleRunArrays[] = {fFontRuns, fLevelRuns, fScriptRuns, fLocaleRuns};
362     le_int32  styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
363     StyleRuns styleRuns(styleRunArrays, styleCount);
364     LEErrorCode layoutStatus = LE_NO_ERROR;
365 
366     fStyleRunCount = styleRuns.getRuns(NULL, NULL);
367 
368     fStyleRunLimits = LE_NEW_ARRAY(le_int32, fStyleRunCount);
369     fStyleIndices   = LE_NEW_ARRAY(le_int32, fStyleRunCount * styleCount);
370     if ((fStyleRunLimits == NULL) || (fStyleIndices == NULL)) {
371         status = LE_MEMORY_ALLOCATION_ERROR;
372         return;
373     }
374 
375     styleRuns.getRuns(fStyleRunLimits, fStyleIndices);
376 
377     // now build a LayoutEngine for each style run...
378     le_int32 *styleIndices = fStyleIndices;
379     le_int32 run, runStart;
380 
381     fStyleRunInfo = LE_NEW_ARRAY(StyleRunInfo, fStyleRunCount);
382     if (fStyleRunInfo == NULL) {
383         status = LE_MEMORY_ALLOCATION_ERROR;
384         return;
385     }
386     else {
387         // initialize
388         for (run = 0; run < fStyleRunCount; run += 1) {
389             fStyleRunInfo[run].font = NULL;
390             fStyleRunInfo[run].runBase = 0;
391             fStyleRunInfo[run].runLimit = 0;
392             fStyleRunInfo[run].script = (UScriptCode)0;
393             fStyleRunInfo[run].locale = NULL;
394             fStyleRunInfo[run].level = 0;
395             fStyleRunInfo[run].glyphBase = 0;
396             fStyleRunInfo[run].engine = NULL;
397             fStyleRunInfo[run].glyphCount = 0;
398             fStyleRunInfo[run].glyphs = NULL;
399             fStyleRunInfo[run].positions = NULL;
400         }
401     }
402 
403     fGlyphCount = 0;
404     for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
405         fStyleRunInfo[run].font      = fFontRuns->getFont(styleIndices[0]);
406         fStyleRunInfo[run].runBase   = runStart;
407         fStyleRunInfo[run].runLimit  = fStyleRunLimits[run];
408         fStyleRunInfo[run].script    = (UScriptCode) fScriptRuns->getValue(styleIndices[2]);
409         fStyleRunInfo[run].locale    = fLocaleRuns->getLocale(styleIndices[3]);
410         fStyleRunInfo[run].level     = (UBiDiLevel) fLevelRuns->getValue(styleIndices[1]);
411         fStyleRunInfo[run].glyphBase = fGlyphCount;
412 
413         fStyleRunInfo[run].engine = LayoutEngine::layoutEngineFactory(fStyleRunInfo[run].font,
414             fStyleRunInfo[run].script, getLanguageCode(fStyleRunInfo[run].locale), layoutStatus);
415         if (LE_FAILURE(layoutStatus)) {
416             status = layoutStatus;
417             return;
418         }
419 
420         fStyleRunInfo[run].glyphCount = fStyleRunInfo[run].engine->layoutChars(fChars, runStart, fStyleRunLimits[run] - runStart, fCharCount,
421             fStyleRunInfo[run].level & 1, 0, 0, layoutStatus);
422         if (LE_FAILURE(layoutStatus)) {
423             status = layoutStatus;
424             return;
425         }
426 
427         runStart = fStyleRunLimits[run];
428         styleIndices += styleCount;
429         fGlyphCount += fStyleRunInfo[run].glyphCount;
430     }
431 
432     // Make big arrays for the glyph widths, glyph-to-char and char-to-glyph maps,
433     // in logical order. (Both maps need an extra entry for the end of the text.)
434     //
435     // For each layout get the positions and convert them into glyph widths, in
436     // logical order. Get the glyph-to-char mapping, offset by starting index in the
437     // character array. Swap the glyph width and glyph-to-char arrays into logical order.
438     // Finally, fill in the char-to-glyph mappings.
439     fGlyphWidths       = LE_NEW_ARRAY(float, fGlyphCount);
440     fGlyphToCharMap    = LE_NEW_ARRAY(le_int32, fGlyphCount + 1);
441     fCharToMinGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
442     fCharToMaxGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
443     if ((fGlyphWidths == NULL) || (fGlyphToCharMap == NULL) ||
444         (fCharToMinGlyphMap == NULL) || (fCharToMaxGlyphMap == NULL)) {
445         status = LE_MEMORY_ALLOCATION_ERROR;
446         return;
447     }
448 
449     le_int32 glyph;
450 
451     for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
452         LayoutEngine *engine = fStyleRunInfo[run].engine;
453         le_int32 glyphCount  = fStyleRunInfo[run].glyphCount;
454         le_int32 glyphBase   = fStyleRunInfo[run].glyphBase;
455 
456         fStyleRunInfo[run].glyphs = LE_NEW_ARRAY(LEGlyphID, glyphCount);
457         fStyleRunInfo[run].positions = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
458         if ((fStyleRunInfo[run].glyphs == NULL) ||
459             (fStyleRunInfo[run].positions == NULL)) {
460             status = LE_MEMORY_ALLOCATION_ERROR;
461             return;
462         }
463 
464         engine->getGlyphs(fStyleRunInfo[run].glyphs, layoutStatus);
465         if (LE_FAILURE(layoutStatus)) {
466             status = layoutStatus;
467             return;
468         }
469 
470         engine->getGlyphPositions(fStyleRunInfo[run].positions, layoutStatus);
471         if (LE_FAILURE(layoutStatus)) {
472             status = layoutStatus;
473             return;
474         }
475 
476         engine->getCharIndices(&fGlyphToCharMap[glyphBase], runStart, layoutStatus);
477         if (LE_FAILURE(layoutStatus)) {
478             status = layoutStatus;
479             return;
480         }
481 
482         for (glyph = 0; glyph < glyphCount; glyph += 1) {
483             fGlyphWidths[glyphBase + glyph] = fStyleRunInfo[run].positions[glyph * 2 + 2] - fStyleRunInfo[run].positions[glyph * 2];
484         }
485 
486         if ((fStyleRunInfo[run].level & 1) != 0) {
487             LXUtilities::reverse(&fGlyphWidths[glyphBase], glyphCount);
488             LXUtilities::reverse(&fGlyphToCharMap[glyphBase], glyphCount);
489         }
490 
491         runStart = fStyleRunLimits[run];
492 
493         delete engine;
494         fStyleRunInfo[run].engine = NULL;
495     }
496 
497     fGlyphToCharMap[fGlyphCount] = fCharCount;
498 
499     // Initialize the char-to-glyph maps to -1 so that we can later figure out
500     // whether any of the entries in the map aren't filled in below.
501     le_int32 chIndex;
502     for (chIndex = 0; chIndex <= fCharCount; chIndex += 1) {
503         fCharToMinGlyphMap[chIndex] = -1;
504         fCharToMaxGlyphMap[chIndex] = -1;
505     }
506 
507     for (glyph = fGlyphCount - 1; glyph >= 0; glyph -= 1) {
508         le_int32 ch = fGlyphToCharMap[glyph];
509 
510         fCharToMinGlyphMap[ch] = glyph;
511     }
512 
513     fCharToMinGlyphMap[fCharCount] = fGlyphCount;
514 
515     for (glyph = 0; glyph < fGlyphCount; glyph += 1) {
516         le_int32 ch = fGlyphToCharMap[glyph];
517 
518         fCharToMaxGlyphMap[ch] = glyph;
519     }
520 
521     fCharToMaxGlyphMap[fCharCount] = fGlyphCount;
522 
523     // Now fill in the missing values in the char-to-glyph maps.
524     fillMissingCharToGlyphMapValues(fCharToMinGlyphMap, fCharCount);
525     fillMissingCharToGlyphMapValues(fCharToMaxGlyphMap, fCharCount);
526 }
527 
~ParagraphLayout()528 ParagraphLayout::~ParagraphLayout()
529 {
530     delete (FontRuns *) fFontRuns;
531 
532     if (! fClientLevels) {
533         delete (ValueRuns *) fLevelRuns;
534         fLevelRuns = NULL;
535 
536         fClientLevels = TRUE;
537     }
538 
539     if (! fClientScripts) {
540         delete (ValueRuns *) fScriptRuns;
541         fScriptRuns = NULL;
542 
543         fClientScripts = TRUE;
544     }
545 
546     if (! fClientLocales) {
547         delete (LocaleRuns *) fLocaleRuns;
548         fLocaleRuns = NULL;
549 
550         fClientLocales = TRUE;
551     }
552 
553     if (fEmbeddingLevels != NULL) {
554         LE_DELETE_ARRAY(fEmbeddingLevels);
555         fEmbeddingLevels = NULL;
556     }
557 
558     if (fGlyphToCharMap != NULL) {
559         LE_DELETE_ARRAY(fGlyphToCharMap);
560         fGlyphToCharMap = NULL;
561     }
562 
563     if (fCharToMinGlyphMap != NULL) {
564         LE_DELETE_ARRAY(fCharToMinGlyphMap);
565         fCharToMinGlyphMap = NULL;
566     }
567 
568     if (fCharToMaxGlyphMap != NULL) {
569         LE_DELETE_ARRAY(fCharToMaxGlyphMap);
570         fCharToMaxGlyphMap = NULL;
571     }
572 
573     if (fGlyphWidths != NULL) {
574         LE_DELETE_ARRAY(fGlyphWidths);
575         fGlyphWidths = NULL;
576     }
577 
578     if (fParaBidi != NULL) {
579         ubidi_close(fParaBidi);
580         fParaBidi = NULL;
581     }
582 
583     if (fLineBidi != NULL) {
584         ubidi_close(fLineBidi);
585         fLineBidi = NULL;
586     }
587 
588     if (fStyleRunCount > 0) {
589         le_int32 run;
590 
591         LE_DELETE_ARRAY(fStyleRunLimits);
592         LE_DELETE_ARRAY(fStyleIndices);
593 
594         for (run = 0; run < fStyleRunCount; run += 1) {
595             LE_DELETE_ARRAY(fStyleRunInfo[run].glyphs);
596             LE_DELETE_ARRAY(fStyleRunInfo[run].positions);
597 
598             fStyleRunInfo[run].glyphs    = NULL;
599             fStyleRunInfo[run].positions = NULL;
600         }
601 
602         LE_DELETE_ARRAY(fStyleRunInfo);
603 
604         fStyleRunLimits = NULL;
605         fStyleIndices   = NULL;
606         fStyleRunInfo        = NULL;
607         fStyleRunCount  = 0;
608     }
609 
610     if (fBreakIterator != NULL) {
611         delete fBreakIterator;
612         fBreakIterator = NULL;
613     }
614 }
615 
616 
isComplex(const LEUnicode chars[],le_int32 count)617 le_bool ParagraphLayout::isComplex(const LEUnicode chars[], le_int32 count)
618 {
619     UErrorCode scriptStatus = U_ZERO_ERROR;
620     UScriptCode scriptCode  = USCRIPT_INVALID_CODE;
621     UScriptRun *sr = uscript_openRun(chars, count, &scriptStatus);
622     le_bool result = FALSE;
623 
624     while (uscript_nextRun(sr, NULL, NULL, &scriptCode)) {
625         if (isComplex(scriptCode)) {
626             result = TRUE;
627             break;
628         }
629     }
630 
631     uscript_closeRun(sr);
632     return result;
633 }
634 
getAscent() const635 le_int32 ParagraphLayout::getAscent() const
636 {
637     if (fAscent <= 0 && fCharCount > 0) {
638         ((ParagraphLayout *) this)->computeMetrics();
639     }
640 
641     return fAscent;
642 }
643 
getDescent() const644 le_int32 ParagraphLayout::getDescent() const
645 {
646     if (fAscent <= 0 && fCharCount > 0) {
647         ((ParagraphLayout *) this)->computeMetrics();
648     }
649 
650     return fDescent;
651 }
652 
getLeading() const653 le_int32 ParagraphLayout::getLeading() const
654 {
655     if (fAscent <= 0 && fCharCount > 0) {
656         ((ParagraphLayout *) this)->computeMetrics();
657     }
658 
659     return fLeading;
660 }
661 
isDone() const662 le_bool ParagraphLayout::isDone() const
663 {
664     return fLineEnd >= fCharCount;
665 }
666 
nextLine(float width)667 ParagraphLayout::Line *ParagraphLayout::nextLine(float width)
668 {
669     if (isDone()) {
670         return NULL;
671     }
672 
673     fLineStart = fLineEnd;
674 
675     if (width > 0) {
676         le_int32 glyph    = fCharToMinGlyphMap[fLineStart];
677         float widthSoFar  = 0;
678 
679         while (glyph < fGlyphCount && widthSoFar + fGlyphWidths[glyph] <= width) {
680             widthSoFar += fGlyphWidths[glyph++];
681         }
682 
683         // If no glyphs fit on the line, force one to fit.
684         //
685         // (There shouldn't be any zero width glyphs at the
686         // start of a line unless the paragraph consists of
687         // only zero width glyphs, because otherwise the zero
688         // width glyphs will have been included on the end of
689         // the previous line...)
690         if (widthSoFar == 0 && glyph < fGlyphCount) {
691             glyph += 1;
692         }
693 
694         fLineEnd = previousBreak(fGlyphToCharMap[glyph]);
695 
696         // If this break is at or before the last one,
697         // find a glyph, starting at the one which didn't
698         // fit, that produces a break after the last one.
699         while (fLineEnd <= fLineStart) {
700             fLineEnd = fGlyphToCharMap[glyph++];
701         }
702     } else {
703         fLineEnd = fCharCount;
704     }
705 
706     return computeVisualRuns();
707 }
708 
computeLevels(UBiDiLevel paragraphLevel)709 void ParagraphLayout::computeLevels(UBiDiLevel paragraphLevel)
710 {
711     UErrorCode bidiStatus = U_ZERO_ERROR;
712 
713     if (fLevelRuns != NULL) {
714         le_int32 ch;
715         le_int32 run;
716 
717         fEmbeddingLevels = LE_NEW_ARRAY(UBiDiLevel, fCharCount);
718 
719         for (ch = 0, run = 0; run < fLevelRuns->getCount(); run += 1) {
720             UBiDiLevel runLevel = (UBiDiLevel) fLevelRuns->getValue(run) | UBIDI_LEVEL_OVERRIDE;
721             le_int32   runLimit = fLevelRuns->getLimit(run);
722 
723             while (ch < runLimit) {
724                 fEmbeddingLevels[ch++] = runLevel;
725             }
726         }
727     }
728 
729     fParaBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
730     ubidi_setPara(fParaBidi, fChars, fCharCount, paragraphLevel, fEmbeddingLevels, &bidiStatus);
731 
732     if (fLevelRuns == NULL) {
733         le_int32 levelRunCount = ubidi_countRuns(fParaBidi, &bidiStatus);
734         ValueRuns *levelRuns = new ValueRuns(levelRunCount);
735 
736         le_int32 logicalStart = 0;
737         le_int32 run;
738         le_int32 limit;
739         UBiDiLevel level;
740 
741         for (run = 0; run < levelRunCount; run += 1) {
742             ubidi_getLogicalRun(fParaBidi, logicalStart, &limit, &level);
743             levelRuns->add(level, limit);
744             logicalStart = limit;
745         }
746 
747         fLevelRuns    = levelRuns;
748         fClientLevels = FALSE;
749     }
750 }
751 
computeScripts()752 void ParagraphLayout::computeScripts()
753 {
754     UErrorCode scriptStatus = U_ZERO_ERROR;
755     UScriptRun *sr = uscript_openRun(fChars, fCharCount, &scriptStatus);
756     ValueRuns  *scriptRuns = new ValueRuns(0);
757     le_int32 limit;
758     UScriptCode script;
759 
760     while (uscript_nextRun(sr, NULL, &limit, &script)) {
761         scriptRuns->add(script, limit);
762     }
763 
764     uscript_closeRun(sr);
765 
766     fScriptRuns    = scriptRuns;
767     fClientScripts = FALSE;
768 }
769 
computeLocales()770 void ParagraphLayout::computeLocales()
771 {
772     LocaleRuns *localeRuns = new LocaleRuns(0);
773     const Locale *defaultLocale = &Locale::getDefault();
774 
775     localeRuns->add(defaultLocale, fCharCount);
776 
777     fLocaleRuns    = localeRuns;
778     fClientLocales = FALSE;
779 }
780 
computeSubFonts(const FontRuns * fontRuns,LEErrorCode & status)781 void ParagraphLayout::computeSubFonts(const FontRuns *fontRuns, LEErrorCode &status)
782 {
783     if (LE_FAILURE(status)) {
784         return;
785     }
786 
787     const RunArray *styleRunArrays[] = {fontRuns, fScriptRuns};
788     le_int32 styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
789     StyleRuns styleRuns(styleRunArrays, styleCount);
790     le_int32 styleRunCount = styleRuns.getRuns(NULL, NULL);
791     le_int32 *styleRunLimits = LE_NEW_ARRAY(le_int32, styleRunCount);
792     le_int32 *styleIndices = LE_NEW_ARRAY(le_int32, styleRunCount * styleCount);
793     FontRuns *subFontRuns  = new FontRuns(0);
794     le_int32  run, offset, *si;
795 
796     styleRuns.getRuns(styleRunLimits, styleIndices);
797 
798     si = styleIndices;
799     offset = 0;
800 
801     for (run = 0; run < styleRunCount; run += 1) {
802         const LEFontInstance *runFont = fontRuns->getFont(si[0]);
803         le_int32 script = fScriptRuns->getValue(si[1]);
804 
805         while (offset < styleRunLimits[run]) {
806             const LEFontInstance *subFont = runFont->getSubFont(fChars, &offset, styleRunLimits[run], script, status);
807 
808             if (LE_FAILURE(status)) {
809                 delete subFontRuns;
810                 goto cleanUp;
811             }
812 
813             subFontRuns->add(subFont, offset);
814         }
815 
816         si += styleCount;
817     }
818 
819     fFontRuns = subFontRuns;
820 
821 cleanUp:
822     LE_DELETE_ARRAY(styleIndices);
823     LE_DELETE_ARRAY(styleRunLimits);
824 }
825 
computeMetrics()826 void ParagraphLayout::computeMetrics()
827 {
828     le_int32 i, count = fFontRuns->getCount();
829     le_int32 maxDL = 0;
830 
831     for (i = 0; i < count; i += 1) {
832         const LEFontInstance *font = fFontRuns->getFont(i);
833         le_int32 ascent  = font->getAscent();
834         le_int32 descent = font->getDescent();
835         le_int32 leading = font->getLeading();
836         le_int32 dl      = descent + leading;
837 
838         if (ascent > fAscent) {
839             fAscent = ascent;
840         }
841 
842         if (descent > fDescent) {
843             fDescent = descent;
844         }
845 
846         if (leading > fLeading) {
847             fLeading = leading;
848         }
849 
850         if (dl > maxDL) {
851             maxDL = dl;
852         }
853     }
854 
855     fLeading = maxDL - fDescent;
856 }
857 
858 #if 1
859 struct LanguageMap
860 {
861     const char *localeCode;
862     le_int32 languageCode;
863 };
864 
865 static const LanguageMap languageMap[] =
866 {
867     {"afr", afkLanguageCode}, // Afrikaans
868     {"ara", araLanguageCode}, // Arabic
869     {"asm", asmLanguageCode}, // Assamese
870     {"bel", belLanguageCode}, // Belarussian
871     {"ben", benLanguageCode}, // Bengali
872     {"bod", tibLanguageCode}, // Tibetan
873     {"bul", bgrLanguageCode}, // Bulgarian
874     {"cat", catLanguageCode}, // Catalan
875     {"ces", csyLanguageCode}, // Czech
876     {"che", cheLanguageCode}, // Chechen
877     {"cop", copLanguageCode}, // Coptic
878     {"cym", welLanguageCode}, // Welsh
879     {"dan", danLanguageCode}, // Danish
880     {"deu", deuLanguageCode}, // German
881     {"dzo", dznLanguageCode}, // Dzongkha
882     {"ell", ellLanguageCode}, // Greek
883     {"eng", engLanguageCode}, // English
884     {"est", etiLanguageCode}, // Estonian
885     {"eus", euqLanguageCode}, // Basque
886     {"fas", farLanguageCode}, // Farsi
887     {"fin", finLanguageCode}, // Finnish
888     {"fra", fraLanguageCode}, // French
889     {"gle", gaeLanguageCode}, // Irish Gaelic
890     {"guj", gujLanguageCode}, // Gujarati
891     {"hau", hauLanguageCode}, // Hausa
892     {"heb", iwrLanguageCode}, // Hebrew
893     {"hin", hinLanguageCode}, // Hindi
894     {"hrv", hrvLanguageCode}, // Croatian
895     {"hun", hunLanguageCode}, // Hungarian
896     {"hye", hyeLanguageCode}, // Armenian
897     {"ind", indLanguageCode}, // Indonesian
898     {"ita", itaLanguageCode}, // Italian
899     {"jpn", janLanguageCode}, // Japanese
900     {"kan", kanLanguageCode}, // Kannada
901     {"kas", kshLanguageCode}, // Kashmiri
902     {"khm", khmLanguageCode}, // Khmer
903     {"kok", kokLanguageCode}, // Konkani
904     {"kor", korLanguageCode}, // Korean
905 //  {"mal_XXX", malLanguageCode}, // Malayalam - Traditional
906     {"mal", mlrLanguageCode}, // Malayalam - Reformed
907     {"mar", marLanguageCode}, // Marathi
908     {"mlt", mtsLanguageCode}, // Maltese
909     {"mni", mniLanguageCode}, // Manipuri
910     {"mon", mngLanguageCode}, // Mongolian
911     {"nep", nepLanguageCode}, // Nepali
912     {"ori", oriLanguageCode}, // Oriya
913     {"pol", plkLanguageCode}, // Polish
914     {"por", ptgLanguageCode}, // Portuguese
915     {"pus", pasLanguageCode}, // Pashto
916     {"ron", romLanguageCode}, // Romanian
917     {"rus", rusLanguageCode}, // Russian
918     {"san", sanLanguageCode}, // Sanskrit
919     {"sin", snhLanguageCode}, // Sinhalese
920     {"slk", skyLanguageCode}, // Slovak
921     {"snd", sndLanguageCode}, // Sindhi
922     {"slv", slvLanguageCode}, // Slovenian
923     {"spa", espLanguageCode}, // Spanish
924     {"sqi", sqiLanguageCode}, // Albanian
925     {"srp", srbLanguageCode}, // Serbian
926     {"swe", sveLanguageCode}, // Swedish
927     {"syr", syrLanguageCode}, // Syriac
928     {"tam", tamLanguageCode}, // Tamil
929     {"tel", telLanguageCode}, // Telugu
930     {"tha", thaLanguageCode}, // Thai
931     {"tur", trkLanguageCode}, // Turkish
932     {"urd", urdLanguageCode}, // Urdu
933     {"yid", jiiLanguageCode}, // Yiddish
934 //  {"zhp", zhpLanguageCode}, // Chinese - Phonetic
935     {"zho", zhsLanguageCode}, // Chinese
936     {"zho_CHN", zhsLanguageCode}, // Chinese - China
937     {"zho_HKG", zhsLanguageCode}, // Chinese - Hong Kong
938     {"zho_MAC", zhtLanguageCode}, // Chinese - Macao
939     {"zho_SGP", zhsLanguageCode}, // Chinese - Singapore
940     {"zho_TWN", zhtLanguageCode}  // Chinese - Taiwan
941 };
942 
943 static const le_int32 languageMapCount = ARRAY_SIZE(languageMap);
944 
getLanguageCode(const Locale * locale)945 le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
946 {
947     char code[8] = {0, 0, 0, 0, 0, 0, 0, 0};
948     const char *language = locale->getISO3Language();
949     const char *country  = locale->getISO3Country();
950 
951     uprv_strcat(code, language);
952 
953     if ((uprv_strcmp(language, "zho") == 0) && country != NULL) {
954         uprv_strcat(code, "_");
955         uprv_strcat(code, country);
956     }
957 
958     for (le_int32 i = 0; i < languageMapCount; i += 1) {
959         if (uprv_strcmp(code, languageMap[i].localeCode) == 0) {
960             return languageMap[i].languageCode;
961         }
962     }
963 
964     return nullLanguageCode;
965 }
966 #else
967 
968 // TODO - dummy implementation for right now...
getLanguageCode(const Locale * locale)969 le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
970 {
971     return nullLanguageCode;
972 }
973 #endif
974 
isComplex(UScriptCode script)975 le_bool ParagraphLayout::isComplex(UScriptCode script)
976 {
977     if (script < 0 || script >= ARRAY_SIZE(complexTable)) {
978         return FALSE;
979     }
980 
981     return complexTable[script];
982 }
983 
previousBreak(le_int32 charIndex)984 le_int32 ParagraphLayout::previousBreak(le_int32 charIndex)
985 {
986     // skip over any whitespace or control characters,
987     // because they can hang in the margin.
988     while (charIndex < fCharCount &&
989            (u_isWhitespace(fChars[charIndex]) ||
990             u_iscntrl(fChars[charIndex]))) {
991         charIndex += 1;
992     }
993 
994     // Create the BreakIterator if we don't already have one
995     if (fBreakIterator == NULL) {
996         Locale thai("th");
997         UCharCharacterIterator *iter = new UCharCharacterIterator(fChars, fCharCount);
998         UErrorCode status = U_ZERO_ERROR;
999 
1000         fBreakIterator = BreakIterator::createLineInstance(thai, status);
1001         fBreakIterator->adoptText(iter);
1002     }
1003 
1004     // return the break location that's at or before
1005     // the character we stopped on. Note: if we're
1006     // on a break, the "+ 1" will cause preceding to
1007     // back up to it.
1008     return fBreakIterator->preceding(charIndex + 1);
1009 }
1010 
computeVisualRuns()1011 ParagraphLayout::Line *ParagraphLayout::computeVisualRuns()
1012 {
1013     UErrorCode bidiStatus = U_ZERO_ERROR;
1014     le_int32 dirRunCount, visualRun;
1015 
1016     fVisualRunLastX = 0;
1017     fVisualRunLastY = 0;
1018     fFirstVisualRun = getCharRun(fLineStart);
1019     fLastVisualRun  = getCharRun(fLineEnd - 1);
1020 
1021     if (fLineBidi == NULL) {
1022         fLineBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
1023     }
1024 
1025     ubidi_setLine(fParaBidi, fLineStart, fLineEnd, fLineBidi, &bidiStatus);
1026     dirRunCount = ubidi_countRuns(fLineBidi, &bidiStatus);
1027 
1028     Line *line = new Line();
1029 
1030     for (visualRun = 0; visualRun < dirRunCount; visualRun += 1) {
1031         le_int32 relStart, run, runLength;
1032         UBiDiDirection runDirection = ubidi_getVisualRun(fLineBidi, visualRun, &relStart, &runLength);
1033         le_int32 runStart = fLineStart + relStart;
1034         le_int32 runEnd   = runStart + runLength - 1;
1035         le_int32 firstRun = getCharRun(runStart);
1036         le_int32 lastRun  = getCharRun(runEnd);
1037         le_int32 startRun = (runDirection == UBIDI_LTR)? firstRun : lastRun;
1038         le_int32 stopRun  = (runDirection == UBIDI_LTR)? lastRun + 1 : firstRun - 1;
1039         le_int32 dir      = (runDirection == UBIDI_LTR)?  1 : -1;
1040 
1041         for (run = startRun; run != stopRun; run += dir) {
1042             le_int32 firstChar = (run == firstRun)? runStart : fStyleRunInfo[run].runBase;
1043             le_int32 lastChar  = (run == lastRun)?  runEnd   : fStyleRunInfo[run].runLimit - 1;
1044 
1045             appendRun(line, run, firstChar, lastChar);
1046         }
1047     }
1048 
1049     return line;
1050 }
1051 
appendRun(ParagraphLayout::Line * line,le_int32 run,le_int32 firstChar,le_int32 lastChar)1052 void ParagraphLayout::appendRun(ParagraphLayout::Line *line, le_int32 run, le_int32 firstChar, le_int32 lastChar)
1053 {
1054     le_int32 glyphBase = fStyleRunInfo[run].glyphBase;
1055     le_int32 inGlyph, outGlyph;
1056 
1057     // Get the glyph indices for all the characters between firstChar and lastChar,
1058     // make the minimum one be leftGlyph and the maximum one be rightGlyph.
1059     // (need to do this to handle local reorderings like Indic left matras)
1060     le_int32 leftGlyph  = fGlyphCount;
1061     le_int32 rightGlyph = -1;
1062     le_int32 ch;
1063 
1064     for (ch = firstChar; ch <= lastChar; ch += 1) {
1065         le_int32 minGlyph = fCharToMinGlyphMap[ch];
1066         le_int32 maxGlyph = fCharToMaxGlyphMap[ch];
1067 
1068         if (minGlyph < leftGlyph) {
1069             leftGlyph = minGlyph;
1070         }
1071 
1072         if (maxGlyph > rightGlyph) {
1073             rightGlyph = maxGlyph;
1074         }
1075     }
1076 
1077     if ((fStyleRunInfo[run].level & 1) != 0) {
1078         le_int32 swap = rightGlyph;
1079         le_int32 last = glyphBase + fStyleRunInfo[run].glyphCount - 1;
1080 
1081         // Here, we want to remove the glyphBase bias...
1082         rightGlyph = last - leftGlyph;
1083         leftGlyph  = last - swap;
1084     } else {
1085         rightGlyph -= glyphBase;
1086         leftGlyph  -= glyphBase;
1087     }
1088 
1089     // Set the position bias for the glyphs. If we're at the start of
1090     // a line, we want the first glyph to be at x = 0, even if it comes
1091     // from the middle of a layout. If we've got a right-to-left run, we
1092     // want the left-most glyph to start at the final x position of the
1093     // previous run, even though this glyph may be in the middle of the
1094     // run.
1095     fVisualRunLastX -= fStyleRunInfo[run].positions[leftGlyph * 2];
1096 
1097     // Make rightGlyph be the glyph just to the right of
1098     // the run's glyphs
1099     rightGlyph += 1;
1100 
1101     UBiDiDirection direction  = ((fStyleRunInfo[run].level & 1) == 0)? UBIDI_LTR : UBIDI_RTL;
1102     le_int32   glyphCount     = rightGlyph - leftGlyph;
1103     LEGlyphID *glyphs         = LE_NEW_ARRAY(LEGlyphID, glyphCount);
1104     float     *positions      = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
1105     le_int32  *glyphToCharMap = LE_NEW_ARRAY(le_int32, glyphCount);
1106 
1107     LE_ARRAY_COPY(glyphs, &fStyleRunInfo[run].glyphs[leftGlyph], glyphCount);
1108 
1109     for (outGlyph = 0, inGlyph = leftGlyph * 2; inGlyph <= rightGlyph * 2; inGlyph += 2, outGlyph += 2) {
1110         positions[outGlyph]     = fStyleRunInfo[run].positions[inGlyph] + fVisualRunLastX;
1111         positions[outGlyph + 1] = fStyleRunInfo[run].positions[inGlyph + 1] + fVisualRunLastY;
1112     }
1113 
1114     // Save the ending position of this run
1115     // to use for the start of the next run
1116     fVisualRunLastX = positions[outGlyph - 2];
1117     fVisualRunLastY = positions[outGlyph - 1];
1118 
1119     if ((fStyleRunInfo[run].level & 1) == 0) {
1120         for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
1121             glyphToCharMap[outGlyph] = fGlyphToCharMap[glyphBase + inGlyph];
1122         }
1123     } else {
1124         // Because fGlyphToCharMap is stored in logical order to facilitate line breaking,
1125         // we need to map the physical glyph indices to logical indices while we copy the
1126         // character indices.
1127         le_int32 base = glyphBase + fStyleRunInfo[run].glyphCount - 1;
1128 
1129         for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
1130             glyphToCharMap[outGlyph] = fGlyphToCharMap[base - inGlyph];
1131         }
1132     }
1133 
1134     line->append(fStyleRunInfo[run].font, direction, glyphCount, glyphs, positions, glyphToCharMap);
1135 }
1136 
getCharRun(le_int32 charIndex)1137 le_int32 ParagraphLayout::getCharRun(le_int32 charIndex)
1138 {
1139     if (charIndex < 0 || charIndex > fCharCount) {
1140         return -1;
1141     }
1142 
1143     le_int32 run;
1144 
1145     // NOTE: as long as fStyleRunLimits is well-formed
1146     // the above range check guarantees that we'll never
1147     // fall off the end of the array.
1148     run = 0;
1149     while (charIndex >= fStyleRunLimits[run]) {
1150         run += 1;
1151     }
1152 
1153     return run;
1154 }
1155 
1156 
1157 const char ParagraphLayout::Line::fgClassID = 0;
1158 
1159 #define INITIAL_RUN_CAPACITY 4
1160 #define RUN_CAPACITY_GROW_LIMIT 16
1161 
~Line()1162 ParagraphLayout::Line::~Line()
1163 {
1164     le_int32 i;
1165 
1166     for (i = 0; i < fRunCount; i += 1) {
1167         delete fRuns[i];
1168     }
1169 
1170     LE_DELETE_ARRAY(fRuns);
1171 }
1172 
getAscent() const1173 le_int32 ParagraphLayout::Line::getAscent() const
1174 {
1175     if (fAscent <= 0) {
1176         ((ParagraphLayout::Line *)this)->computeMetrics();
1177     }
1178 
1179     return fAscent;
1180 }
1181 
getDescent() const1182 le_int32 ParagraphLayout::Line::getDescent() const
1183 {
1184     if (fAscent <= 0) {
1185         ((ParagraphLayout::Line *)this)->computeMetrics();
1186     }
1187 
1188     return fDescent;
1189 }
1190 
getLeading() const1191 le_int32 ParagraphLayout::Line::getLeading() const
1192 {
1193     if (fAscent <= 0) {
1194         ((ParagraphLayout::Line *)this)->computeMetrics();
1195     }
1196 
1197     return fLeading;
1198 }
1199 
getWidth() const1200 le_int32 ParagraphLayout::Line::getWidth() const
1201 {
1202     const VisualRun *lastRun = getVisualRun(fRunCount - 1);
1203 
1204     if (lastRun == NULL) {
1205         return 0;
1206     }
1207 
1208     le_int32 glyphCount = lastRun->getGlyphCount();
1209     const float *positions = lastRun->getPositions();
1210 
1211     return (le_int32) positions[glyphCount * 2];
1212 }
1213 
getVisualRun(le_int32 runIndex) const1214 const ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(le_int32 runIndex) const
1215 {
1216     if (runIndex < 0 || runIndex >= fRunCount) {
1217         return NULL;
1218     }
1219 
1220     return fRuns[runIndex];
1221 }
1222 
append(const LEFontInstance * font,UBiDiDirection direction,le_int32 glyphCount,const LEGlyphID glyphs[],const float positions[],const le_int32 glyphToCharMap[])1223 void ParagraphLayout::Line::append(const LEFontInstance *font, UBiDiDirection direction, le_int32 glyphCount,
1224                                    const LEGlyphID glyphs[], const float positions[], const le_int32 glyphToCharMap[])
1225 {
1226     if (fRunCount >= fRunCapacity) {
1227         if (fRunCapacity == 0) {
1228             fRunCapacity = INITIAL_RUN_CAPACITY;
1229             fRuns = LE_NEW_ARRAY(ParagraphLayout::VisualRun *, fRunCapacity);
1230         } else {
1231             fRunCapacity += (fRunCapacity < RUN_CAPACITY_GROW_LIMIT? fRunCapacity : RUN_CAPACITY_GROW_LIMIT);
1232             fRuns = (ParagraphLayout::VisualRun **) LE_GROW_ARRAY(fRuns, fRunCapacity);
1233         }
1234     }
1235 
1236     fRuns[fRunCount++] = new ParagraphLayout::VisualRun(font, direction, glyphCount, glyphs, positions, glyphToCharMap);
1237 }
1238 
computeMetrics()1239 void ParagraphLayout::Line::computeMetrics()
1240 {
1241     le_int32 maxDL = 0;
1242 
1243     for (le_int32 i = 0; i < fRunCount; i += 1) {
1244         le_int32 ascent  = fRuns[i]->getAscent();
1245         le_int32 descent = fRuns[i]->getDescent();
1246         le_int32 leading = fRuns[i]->getLeading();
1247         le_int32 dl      = descent + leading;
1248 
1249         if (ascent > fAscent) {
1250             fAscent = ascent;
1251         }
1252 
1253         if (descent > fDescent) {
1254             fDescent = descent;
1255         }
1256 
1257         if (leading > fLeading) {
1258             fLeading = leading;
1259         }
1260 
1261         if (dl > maxDL) {
1262             maxDL = dl;
1263         }
1264     }
1265 
1266     fLeading = maxDL - fDescent;
1267 }
1268 
1269 const char ParagraphLayout::VisualRun::fgClassID = 0;
1270 
~VisualRun()1271 ParagraphLayout::VisualRun::~VisualRun()
1272 {
1273     LE_DELETE_ARRAY(fGlyphToCharMap);
1274     LE_DELETE_ARRAY(fPositions);
1275     LE_DELETE_ARRAY(fGlyphs);
1276 }
1277 
1278 U_NAMESPACE_END
1279 
1280 #endif
1281 
1282