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