• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  **********************************************************************
3  *   Copyright (C) 2002-2010, 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     // FIXME: should check the limit arrays for consistency...
336 
337     computeLevels(paragraphLevel);
338 
339     if (scriptRuns == NULL) {
340         computeScripts();
341     }
342 
343     if (localeRuns == NULL) {
344         computeLocales();
345     }
346 
347     computeSubFonts(fontRuns, status);
348 
349     if (LE_FAILURE(status)) {
350         //other stuff?
351         fCharCount = -1;
352         return;
353     }
354 
355     // now intersect the font, direction and script runs...
356     const RunArray *styleRunArrays[] = {fFontRuns, fLevelRuns, fScriptRuns, fLocaleRuns};
357     le_int32  styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
358     StyleRuns styleRuns(styleRunArrays, styleCount);
359     LEErrorCode layoutStatus = LE_NO_ERROR;
360 
361     fStyleRunCount = styleRuns.getRuns(NULL, NULL);
362 
363     fStyleRunLimits = LE_NEW_ARRAY(le_int32, fStyleRunCount);
364     fStyleIndices   = LE_NEW_ARRAY(le_int32, fStyleRunCount * styleCount);
365     if ((fStyleRunLimits == NULL) || (fStyleIndices == NULL)) {
366         status = LE_MEMORY_ALLOCATION_ERROR;
367         return;
368     }
369 
370     styleRuns.getRuns(fStyleRunLimits, fStyleIndices);
371 
372     // now build a LayoutEngine for each style run...
373     le_int32 *styleIndices = fStyleIndices;
374     le_int32 run, runStart;
375 
376     fStyleRunInfo = LE_NEW_ARRAY(StyleRunInfo, fStyleRunCount);
377     if (fStyleRunInfo == NULL) {
378         status = LE_MEMORY_ALLOCATION_ERROR;
379         return;
380     }
381     else {
382         // initialize
383         for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
384             fStyleRunInfo[run].font = NULL;
385             fStyleRunInfo[run].runBase = 0;
386             fStyleRunInfo[run].runLimit = 0;
387             fStyleRunInfo[run].script = (UScriptCode)0;
388             fStyleRunInfo[run].locale = NULL;
389             fStyleRunInfo[run].level = 0;
390             fStyleRunInfo[run].glyphBase = 0;
391             fStyleRunInfo[run].engine = NULL;
392             fStyleRunInfo[run].glyphCount = 0;
393             fStyleRunInfo[run].glyphs = NULL;
394             fStyleRunInfo[run].positions = NULL;
395         }
396     }
397 
398     fGlyphCount = 0;
399     for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
400         fStyleRunInfo[run].font      = fFontRuns->getFont(styleIndices[0]);
401         fStyleRunInfo[run].runBase   = runStart;
402         fStyleRunInfo[run].runLimit  = fStyleRunLimits[run];
403         fStyleRunInfo[run].script    = (UScriptCode) fScriptRuns->getValue(styleIndices[2]);
404         fStyleRunInfo[run].locale    = fLocaleRuns->getLocale(styleIndices[3]);
405         fStyleRunInfo[run].level     = (UBiDiLevel) fLevelRuns->getValue(styleIndices[1]);
406         fStyleRunInfo[run].glyphBase = fGlyphCount;
407 
408         fStyleRunInfo[run].engine = LayoutEngine::layoutEngineFactory(fStyleRunInfo[run].font,
409             fStyleRunInfo[run].script, getLanguageCode(fStyleRunInfo[run].locale), layoutStatus);
410         if (LE_FAILURE(layoutStatus)) {
411             status = layoutStatus;
412             return;
413         }
414 
415         fStyleRunInfo[run].glyphCount = fStyleRunInfo[run].engine->layoutChars(fChars, runStart, fStyleRunLimits[run] - runStart, fCharCount,
416             fStyleRunInfo[run].level & 1, 0, 0, layoutStatus);
417         if (LE_FAILURE(layoutStatus)) {
418             status = layoutStatus;
419             return;
420         }
421 
422         runStart = fStyleRunLimits[run];
423         styleIndices += styleCount;
424         fGlyphCount += fStyleRunInfo[run].glyphCount;
425     }
426 
427     // Make big arrays for the glyph widths, glyph-to-char and char-to-glyph maps,
428     // in logical order. (Both maps need an extra entry for the end of the text.)
429     //
430     // For each layout get the positions and convert them into glyph widths, in
431     // logical order. Get the glyph-to-char mapping, offset by starting index in the
432     // character array. Swap the glyph width and glyph-to-char arrays into logical order.
433     // Finally, fill in the char-to-glyph mappings.
434     fGlyphWidths       = LE_NEW_ARRAY(float, fGlyphCount);
435     fGlyphToCharMap    = LE_NEW_ARRAY(le_int32, fGlyphCount + 1);
436     fCharToMinGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
437     fCharToMaxGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1);
438     if ((fGlyphWidths == NULL) || (fGlyphToCharMap == NULL) ||
439         (fCharToMinGlyphMap == NULL) || (fCharToMaxGlyphMap == NULL)) {
440         status = LE_MEMORY_ALLOCATION_ERROR;
441         return;
442     }
443 
444     le_int32 glyph;
445 
446     for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) {
447         LayoutEngine *engine = fStyleRunInfo[run].engine;
448         le_int32 glyphCount  = fStyleRunInfo[run].glyphCount;
449         le_int32 glyphBase   = fStyleRunInfo[run].glyphBase;
450 
451         fStyleRunInfo[run].glyphs = LE_NEW_ARRAY(LEGlyphID, glyphCount);
452         fStyleRunInfo[run].positions = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
453         if ((fStyleRunInfo[run].glyphs == NULL) ||
454             (fStyleRunInfo[run].positions == NULL)) {
455             status = LE_MEMORY_ALLOCATION_ERROR;
456             return;
457         }
458 
459         engine->getGlyphs(fStyleRunInfo[run].glyphs, layoutStatus);
460         if (LE_FAILURE(layoutStatus)) {
461             status = layoutStatus;
462             return;
463         }
464 
465         engine->getGlyphPositions(fStyleRunInfo[run].positions, layoutStatus);
466         if (LE_FAILURE(layoutStatus)) {
467             status = layoutStatus;
468             return;
469         }
470 
471         engine->getCharIndices(&fGlyphToCharMap[glyphBase], runStart, layoutStatus);
472         if (LE_FAILURE(layoutStatus)) {
473             status = layoutStatus;
474             return;
475         }
476 
477         for (glyph = 0; glyph < glyphCount; glyph += 1) {
478             fGlyphWidths[glyphBase + glyph] = fStyleRunInfo[run].positions[glyph * 2 + 2] - fStyleRunInfo[run].positions[glyph * 2];
479         }
480 
481         if ((fStyleRunInfo[run].level & 1) != 0) {
482             LXUtilities::reverse(&fGlyphWidths[glyphBase], glyphCount);
483             LXUtilities::reverse(&fGlyphToCharMap[glyphBase], glyphCount);
484         }
485 
486         runStart = fStyleRunLimits[run];
487 
488         delete engine;
489         fStyleRunInfo[run].engine = NULL;
490     }
491 
492     fGlyphToCharMap[fGlyphCount] = fCharCount;
493 
494     // Initialize the char-to-glyph maps to -1 so that we can later figure out
495     // whether any of the entries in the map aren't filled in below.
496     le_int32 chIndex;
497     for (chIndex = 0; chIndex <= fCharCount; chIndex += 1) {
498         fCharToMinGlyphMap[chIndex] = -1;
499         fCharToMaxGlyphMap[chIndex] = -1;
500     }
501 
502     for (glyph = fGlyphCount - 1; glyph >= 0; glyph -= 1) {
503         le_int32 ch = fGlyphToCharMap[glyph];
504 
505         fCharToMinGlyphMap[ch] = glyph;
506     }
507 
508     fCharToMinGlyphMap[fCharCount] = fGlyphCount;
509 
510     for (glyph = 0; glyph < fGlyphCount; glyph += 1) {
511         le_int32 ch = fGlyphToCharMap[glyph];
512 
513         fCharToMaxGlyphMap[ch] = glyph;
514     }
515 
516     fCharToMaxGlyphMap[fCharCount] = fGlyphCount;
517 
518     // Now fill in the missing values in the char-to-glyph maps.
519     fillMissingCharToGlyphMapValues(fCharToMinGlyphMap, fCharCount);
520     fillMissingCharToGlyphMapValues(fCharToMaxGlyphMap, fCharCount);
521 }
522 
~ParagraphLayout()523 ParagraphLayout::~ParagraphLayout()
524 {
525     delete (FontRuns *) fFontRuns;
526 
527     if (! fClientLevels) {
528         delete (ValueRuns *) fLevelRuns;
529         fLevelRuns = NULL;
530 
531         fClientLevels = TRUE;
532     }
533 
534     if (! fClientScripts) {
535         delete (ValueRuns *) fScriptRuns;
536         fScriptRuns = NULL;
537 
538         fClientScripts = TRUE;
539     }
540 
541     if (! fClientLocales) {
542         delete (LocaleRuns *) fLocaleRuns;
543         fLocaleRuns = NULL;
544 
545         fClientLocales = TRUE;
546     }
547 
548     if (fEmbeddingLevels != NULL) {
549         LE_DELETE_ARRAY(fEmbeddingLevels);
550         fEmbeddingLevels = NULL;
551     }
552 
553     if (fGlyphToCharMap != NULL) {
554         LE_DELETE_ARRAY(fGlyphToCharMap);
555         fGlyphToCharMap = NULL;
556     }
557 
558     if (fCharToMinGlyphMap != NULL) {
559         LE_DELETE_ARRAY(fCharToMinGlyphMap);
560         fCharToMinGlyphMap = NULL;
561     }
562 
563     if (fCharToMaxGlyphMap != NULL) {
564         LE_DELETE_ARRAY(fCharToMaxGlyphMap);
565         fCharToMaxGlyphMap = NULL;
566     }
567 
568     if (fGlyphWidths != NULL) {
569         LE_DELETE_ARRAY(fGlyphWidths);
570         fGlyphWidths = NULL;
571     }
572 
573     if (fParaBidi != NULL) {
574         ubidi_close(fParaBidi);
575         fParaBidi = NULL;
576     }
577 
578     if (fLineBidi != NULL) {
579         ubidi_close(fLineBidi);
580         fLineBidi = NULL;
581     }
582 
583     if (fStyleRunCount > 0) {
584         le_int32 run;
585 
586         LE_DELETE_ARRAY(fStyleRunLimits);
587         LE_DELETE_ARRAY(fStyleIndices);
588 
589         for (run = 0; run < fStyleRunCount; run += 1) {
590             LE_DELETE_ARRAY(fStyleRunInfo[run].glyphs);
591             LE_DELETE_ARRAY(fStyleRunInfo[run].positions);
592 
593             fStyleRunInfo[run].glyphs    = NULL;
594             fStyleRunInfo[run].positions = NULL;
595         }
596 
597         LE_DELETE_ARRAY(fStyleRunInfo);
598 
599         fStyleRunLimits = NULL;
600         fStyleIndices   = NULL;
601         fStyleRunInfo        = NULL;
602         fStyleRunCount  = 0;
603     }
604 
605     if (fBreakIterator != NULL) {
606         delete fBreakIterator;
607         fBreakIterator = NULL;
608     }
609 }
610 
611 
isComplex(const LEUnicode chars[],le_int32 count)612 le_bool ParagraphLayout::isComplex(const LEUnicode chars[], le_int32 count)
613 {
614     UErrorCode scriptStatus = U_ZERO_ERROR;
615     UScriptCode scriptCode  = USCRIPT_INVALID_CODE;
616     UScriptRun *sr = uscript_openRun(chars, count, &scriptStatus);
617     le_bool result = FALSE;
618 
619     while (uscript_nextRun(sr, NULL, NULL, &scriptCode)) {
620         if (isComplex(scriptCode)) {
621             result = TRUE;
622             break;
623         }
624     }
625 
626     uscript_closeRun(sr);
627     return result;
628 }
629 
getAscent() const630 le_int32 ParagraphLayout::getAscent() const
631 {
632     if (fAscent <= 0 && fCharCount > 0) {
633         ((ParagraphLayout *) this)->computeMetrics();
634     }
635 
636     return fAscent;
637 }
638 
getDescent() const639 le_int32 ParagraphLayout::getDescent() const
640 {
641     if (fAscent <= 0 && fCharCount > 0) {
642         ((ParagraphLayout *) this)->computeMetrics();
643     }
644 
645     return fDescent;
646 }
647 
getLeading() const648 le_int32 ParagraphLayout::getLeading() const
649 {
650     if (fAscent <= 0 && fCharCount > 0) {
651         ((ParagraphLayout *) this)->computeMetrics();
652     }
653 
654     return fLeading;
655 }
656 
isDone() const657 le_bool ParagraphLayout::isDone() const
658 {
659     return fLineEnd >= fCharCount;
660 }
661 
nextLine(float width)662 ParagraphLayout::Line *ParagraphLayout::nextLine(float width)
663 {
664     if (isDone()) {
665         return NULL;
666     }
667 
668     fLineStart = fLineEnd;
669 
670     if (width > 0) {
671         le_int32 glyph    = fCharToMinGlyphMap[fLineStart];
672         float widthSoFar  = 0;
673 
674         while (glyph < fGlyphCount && widthSoFar + fGlyphWidths[glyph] <= width) {
675             widthSoFar += fGlyphWidths[glyph++];
676         }
677 
678         // If no glyphs fit on the line, force one to fit.
679         //
680         // (There shouldn't be any zero width glyphs at the
681         // start of a line unless the paragraph consists of
682         // only zero width glyphs, because otherwise the zero
683         // width glyphs will have been included on the end of
684         // the previous line...)
685         if (widthSoFar == 0 && glyph < fGlyphCount) {
686             glyph += 1;
687         }
688 
689         fLineEnd = previousBreak(fGlyphToCharMap[glyph]);
690 
691         // If this break is at or before the last one,
692         // find a glyph, starting at the one which didn't
693         // fit, that produces a break after the last one.
694         while (fLineEnd <= fLineStart) {
695             fLineEnd = fGlyphToCharMap[glyph++];
696         }
697     } else {
698         fLineEnd = fCharCount;
699     }
700 
701     return computeVisualRuns();
702 }
703 
computeLevels(UBiDiLevel paragraphLevel)704 void ParagraphLayout::computeLevels(UBiDiLevel paragraphLevel)
705 {
706     UErrorCode bidiStatus = U_ZERO_ERROR;
707 
708     if (fLevelRuns != NULL) {
709         le_int32 ch;
710         le_int32 run;
711 
712         fEmbeddingLevels = LE_NEW_ARRAY(UBiDiLevel, fCharCount);
713 
714         for (ch = 0, run = 0; run < fLevelRuns->getCount(); run += 1) {
715             UBiDiLevel runLevel = (UBiDiLevel) fLevelRuns->getValue(run) | UBIDI_LEVEL_OVERRIDE;
716             le_int32   runLimit = fLevelRuns->getLimit(run);
717 
718             while (ch < runLimit) {
719                 fEmbeddingLevels[ch++] = runLevel;
720             }
721         }
722     }
723 
724     fParaBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
725     ubidi_setPara(fParaBidi, fChars, fCharCount, paragraphLevel, fEmbeddingLevels, &bidiStatus);
726 
727     if (fLevelRuns == NULL) {
728         le_int32 levelRunCount = ubidi_countRuns(fParaBidi, &bidiStatus);
729         ValueRuns *levelRuns = new ValueRuns(levelRunCount);
730 
731         le_int32 logicalStart = 0;
732         le_int32 run;
733         le_int32 limit;
734         UBiDiLevel level;
735 
736         for (run = 0; run < levelRunCount; run += 1) {
737             ubidi_getLogicalRun(fParaBidi, logicalStart, &limit, &level);
738             levelRuns->add(level, limit);
739             logicalStart = limit;
740         }
741 
742         fLevelRuns    = levelRuns;
743         fClientLevels = FALSE;
744     }
745 }
746 
computeScripts()747 void ParagraphLayout::computeScripts()
748 {
749     UErrorCode scriptStatus = U_ZERO_ERROR;
750     UScriptRun *sr = uscript_openRun(fChars, fCharCount, &scriptStatus);
751     ValueRuns  *scriptRuns = new ValueRuns(0);
752     le_int32 limit;
753     UScriptCode script;
754 
755     while (uscript_nextRun(sr, NULL, &limit, &script)) {
756         scriptRuns->add(script, limit);
757     }
758 
759     uscript_closeRun(sr);
760 
761     fScriptRuns    = scriptRuns;
762     fClientScripts = FALSE;
763 }
764 
computeLocales()765 void ParagraphLayout::computeLocales()
766 {
767     LocaleRuns *localeRuns = new LocaleRuns(0);
768     const Locale *defaultLocale = &Locale::getDefault();
769 
770     localeRuns->add(defaultLocale, fCharCount);
771 
772     fLocaleRuns    = localeRuns;
773     fClientLocales = FALSE;
774 }
775 
computeSubFonts(const FontRuns * fontRuns,LEErrorCode & status)776 void ParagraphLayout::computeSubFonts(const FontRuns *fontRuns, LEErrorCode &status)
777 {
778     if (LE_FAILURE(status)) {
779         return;
780     }
781 
782     const RunArray *styleRunArrays[] = {fontRuns, fScriptRuns};
783     le_int32 styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0];
784     StyleRuns styleRuns(styleRunArrays, styleCount);
785     le_int32 styleRunCount = styleRuns.getRuns(NULL, NULL);
786     le_int32 *styleRunLimits = LE_NEW_ARRAY(le_int32, styleRunCount);
787     le_int32 *styleIndices = LE_NEW_ARRAY(le_int32, styleRunCount * styleCount);
788     FontRuns *subFontRuns  = new FontRuns(0);
789     le_int32  run, offset, *si;
790 
791     styleRuns.getRuns(styleRunLimits, styleIndices);
792 
793     si = styleIndices;
794     offset = 0;
795 
796     for (run = 0; run < styleRunCount; run += 1) {
797         const LEFontInstance *runFont = fontRuns->getFont(si[0]);
798         le_int32 script = fScriptRuns->getValue(si[1]);
799 
800         while (offset < styleRunLimits[run]) {
801             const LEFontInstance *subFont = runFont->getSubFont(fChars, &offset, styleRunLimits[run], script, status);
802 
803             if (LE_FAILURE(status)) {
804                 delete subFontRuns;
805                 goto cleanUp;
806             }
807 
808             subFontRuns->add(subFont, offset);
809         }
810 
811         si += styleCount;
812     }
813 
814     fFontRuns = subFontRuns;
815 
816 cleanUp:
817     LE_DELETE_ARRAY(styleIndices);
818     LE_DELETE_ARRAY(styleRunLimits);
819 }
820 
computeMetrics()821 void ParagraphLayout::computeMetrics()
822 {
823     le_int32 i, count = fFontRuns->getCount();
824     le_int32 maxDL = 0;
825 
826     for (i = 0; i < count; i += 1) {
827         const LEFontInstance *font = fFontRuns->getFont(i);
828         le_int32 ascent  = font->getAscent();
829         le_int32 descent = font->getDescent();
830         le_int32 leading = font->getLeading();
831         le_int32 dl      = descent + leading;
832 
833         if (ascent > fAscent) {
834             fAscent = ascent;
835         }
836 
837         if (descent > fDescent) {
838             fDescent = descent;
839         }
840 
841         if (leading > fLeading) {
842             fLeading = leading;
843         }
844 
845         if (dl > maxDL) {
846             maxDL = dl;
847         }
848     }
849 
850     fLeading = maxDL - fDescent;
851 }
852 
853 #if 1
854 struct LanguageMap
855 {
856     const char *localeCode;
857     le_int32 languageCode;
858 };
859 
860 static const LanguageMap languageMap[] =
861 {
862     {"afr", afkLanguageCode}, // Afrikaans
863     {"ara", araLanguageCode}, // Arabic
864     {"asm", asmLanguageCode}, // Assamese
865     {"bel", belLanguageCode}, // Belarussian
866     {"ben", benLanguageCode}, // Bengali
867     {"bod", tibLanguageCode}, // Tibetan
868     {"bul", bgrLanguageCode}, // Bulgarian
869     {"cat", catLanguageCode}, // Catalan
870     {"ces", csyLanguageCode}, // Czech
871     {"che", cheLanguageCode}, // Chechen
872     {"cop", copLanguageCode}, // Coptic
873     {"cym", welLanguageCode}, // Welsh
874     {"dan", danLanguageCode}, // Danish
875     {"deu", deuLanguageCode}, // German
876     {"dzo", dznLanguageCode}, // Dzongkha
877     {"ell", ellLanguageCode}, // Greek
878     {"eng", engLanguageCode}, // English
879     {"est", etiLanguageCode}, // Estonian
880     {"eus", euqLanguageCode}, // Basque
881     {"fas", farLanguageCode}, // Farsi
882     {"fin", finLanguageCode}, // Finnish
883     {"fra", fraLanguageCode}, // French
884     {"gle", gaeLanguageCode}, // Irish Gaelic
885     {"guj", gujLanguageCode}, // Gujarati
886     {"hau", hauLanguageCode}, // Hausa
887     {"heb", iwrLanguageCode}, // Hebrew
888     {"hin", hinLanguageCode}, // Hindi
889     {"hrv", hrvLanguageCode}, // Croatian
890     {"hun", hunLanguageCode}, // Hungarian
891     {"hye", hyeLanguageCode}, // Armenian
892     {"ind", indLanguageCode}, // Indonesian
893     {"ita", itaLanguageCode}, // Italian
894     {"jpn", janLanguageCode}, // Japanese
895     {"kan", kanLanguageCode}, // Kannada
896     {"kas", kshLanguageCode}, // Kashmiri
897     {"khm", khmLanguageCode}, // Khmer
898     {"kok", kokLanguageCode}, // Konkani
899     {"kor", korLanguageCode}, // Korean
900 //  {"mal_XXX", malLanguageCode}, // Malayalam - Traditional
901     {"mal", mlrLanguageCode}, // Malayalam - Reformed
902     {"mar", marLanguageCode}, // Marathi
903     {"mlt", mtsLanguageCode}, // Maltese
904     {"mni", mniLanguageCode}, // Manipuri
905     {"mon", mngLanguageCode}, // Mongolian
906     {"nep", nepLanguageCode}, // Nepali
907     {"ori", oriLanguageCode}, // Oriya
908     {"pol", plkLanguageCode}, // Polish
909     {"por", ptgLanguageCode}, // Portuguese
910     {"pus", pasLanguageCode}, // Pashto
911     {"ron", romLanguageCode}, // Romanian
912     {"rus", rusLanguageCode}, // Russian
913     {"san", sanLanguageCode}, // Sanskrit
914     {"sin", snhLanguageCode}, // Sinhalese
915     {"slk", skyLanguageCode}, // Slovak
916     {"snd", sndLanguageCode}, // Sindhi
917     {"slv", slvLanguageCode}, // Slovenian
918     {"spa", espLanguageCode}, // Spanish
919     {"sqi", sqiLanguageCode}, // Albanian
920     {"srp", srbLanguageCode}, // Serbian
921     {"swe", sveLanguageCode}, // Swedish
922     {"syr", syrLanguageCode}, // Syriac
923     {"tam", tamLanguageCode}, // Tamil
924     {"tel", telLanguageCode}, // Telugu
925     {"tha", thaLanguageCode}, // Thai
926     {"tur", trkLanguageCode}, // Turkish
927     {"urd", urdLanguageCode}, // Urdu
928     {"yid", jiiLanguageCode}, // Yiddish
929 //  {"zhp", zhpLanguageCode}, // Chinese - Phonetic
930     {"zho", zhsLanguageCode}, // Chinese
931     {"zho_CHN", zhsLanguageCode}, // Chinese - China
932     {"zho_HKG", zhsLanguageCode}, // Chinese - Hong Kong
933     {"zho_MAC", zhtLanguageCode}, // Chinese - Macao
934     {"zho_SGP", zhsLanguageCode}, // Chinese - Singapore
935     {"zho_TWN", zhtLanguageCode}  // Chinese - Taiwan
936 };
937 
938 static const le_int32 languageMapCount = ARRAY_SIZE(languageMap);
939 
getLanguageCode(const Locale * locale)940 le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
941 {
942     char code[8] = {0, 0, 0, 0, 0, 0, 0, 0};
943     const char *language = locale->getISO3Language();
944     const char *country  = locale->getISO3Country();
945 
946     uprv_strcat(code, language);
947 
948     if ((uprv_strcmp(language, "zho") == 0) && country != NULL) {
949         uprv_strcat(code, "_");
950         uprv_strcat(code, country);
951     }
952 
953     for (le_int32 i = 0; i < languageMapCount; i += 1) {
954         if (uprv_strcmp(code, languageMap[i].localeCode) == 0) {
955             return languageMap[i].languageCode;
956         }
957     }
958 
959     return nullLanguageCode;
960 }
961 #else
962 
963 // TODO - dummy implementation for right now...
getLanguageCode(const Locale * locale)964 le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
965 {
966     return nullLanguageCode;
967 }
968 #endif
969 
isComplex(UScriptCode script)970 le_bool ParagraphLayout::isComplex(UScriptCode script)
971 {
972     if (script < 0 || script >= (UScriptCode) scriptCodeCount) {
973         return FALSE;
974     }
975 
976     return complexTable[script];
977 }
978 
previousBreak(le_int32 charIndex)979 le_int32 ParagraphLayout::previousBreak(le_int32 charIndex)
980 {
981     // skip over any whitespace or control characters,
982     // because they can hang in the margin.
983     while (charIndex < fCharCount &&
984            (u_isWhitespace(fChars[charIndex]) ||
985             u_iscntrl(fChars[charIndex]))) {
986         charIndex += 1;
987     }
988 
989     // Create the BreakIterator if we don't already have one
990     if (fBreakIterator == NULL) {
991         Locale thai("th");
992         UCharCharacterIterator *iter = new UCharCharacterIterator(fChars, fCharCount);
993         UErrorCode status = U_ZERO_ERROR;
994 
995         fBreakIterator = BreakIterator::createLineInstance(thai, status);
996         fBreakIterator->adoptText(iter);
997     }
998 
999     // return the break location that's at or before
1000     // the character we stopped on. Note: if we're
1001     // on a break, the "+ 1" will cause preceding to
1002     // back up to it.
1003     return fBreakIterator->preceding(charIndex + 1);
1004 }
1005 
computeVisualRuns()1006 ParagraphLayout::Line *ParagraphLayout::computeVisualRuns()
1007 {
1008     UErrorCode bidiStatus = U_ZERO_ERROR;
1009     le_int32 dirRunCount, visualRun;
1010 
1011     fVisualRunLastX = 0;
1012     fVisualRunLastY = 0;
1013     fFirstVisualRun = getCharRun(fLineStart);
1014     fLastVisualRun  = getCharRun(fLineEnd - 1);
1015 
1016     if (fLineBidi == NULL) {
1017         fLineBidi = ubidi_openSized(fCharCount, 0, &bidiStatus);
1018     }
1019 
1020     ubidi_setLine(fParaBidi, fLineStart, fLineEnd, fLineBidi, &bidiStatus);
1021     dirRunCount = ubidi_countRuns(fLineBidi, &bidiStatus);
1022 
1023     Line *line = new Line();
1024 
1025     for (visualRun = 0; visualRun < dirRunCount; visualRun += 1) {
1026         le_int32 relStart, run, runLength;
1027         UBiDiDirection runDirection = ubidi_getVisualRun(fLineBidi, visualRun, &relStart, &runLength);
1028         le_int32 runStart = fLineStart + relStart;
1029         le_int32 runEnd   = runStart + runLength - 1;
1030         le_int32 firstRun = getCharRun(runStart);
1031         le_int32 lastRun  = getCharRun(runEnd);
1032         le_int32 startRun = (runDirection == UBIDI_LTR)? firstRun : lastRun;
1033         le_int32 stopRun  = (runDirection == UBIDI_LTR)? lastRun + 1 : firstRun - 1;
1034         le_int32 dir      = (runDirection == UBIDI_LTR)?  1 : -1;
1035 
1036         for (run = startRun; run != stopRun; run += dir) {
1037             le_int32 firstChar = (run == firstRun)? runStart : fStyleRunInfo[run].runBase;
1038             le_int32 lastChar  = (run == lastRun)?  runEnd   : fStyleRunInfo[run].runLimit - 1;
1039 
1040             appendRun(line, run, firstChar, lastChar);
1041         }
1042     }
1043 
1044     return line;
1045 }
1046 
appendRun(ParagraphLayout::Line * line,le_int32 run,le_int32 firstChar,le_int32 lastChar)1047 void ParagraphLayout::appendRun(ParagraphLayout::Line *line, le_int32 run, le_int32 firstChar, le_int32 lastChar)
1048 {
1049     le_int32 glyphBase = fStyleRunInfo[run].glyphBase;
1050     le_int32 inGlyph, outGlyph;
1051 
1052     // Get the glyph indices for all the characters between firstChar and lastChar,
1053     // make the minimum one be leftGlyph and the maximum one be rightGlyph.
1054     // (need to do this to handle local reorderings like Indic left matras)
1055     le_int32 leftGlyph  = fGlyphCount;
1056     le_int32 rightGlyph = -1;
1057     le_int32 ch;
1058 
1059     for (ch = firstChar; ch <= lastChar; ch += 1) {
1060         le_int32 minGlyph = fCharToMinGlyphMap[ch];
1061         le_int32 maxGlyph = fCharToMaxGlyphMap[ch];
1062 
1063         if (minGlyph < leftGlyph) {
1064             leftGlyph = minGlyph;
1065         }
1066 
1067         if (maxGlyph > rightGlyph) {
1068             rightGlyph = maxGlyph;
1069         }
1070     }
1071 
1072     if ((fStyleRunInfo[run].level & 1) != 0) {
1073         le_int32 swap = rightGlyph;
1074         le_int32 last = glyphBase + fStyleRunInfo[run].glyphCount - 1;
1075 
1076         // Here, we want to remove the glyphBase bias...
1077         rightGlyph = last - leftGlyph;
1078         leftGlyph  = last - swap;
1079     } else {
1080         rightGlyph -= glyphBase;
1081         leftGlyph  -= glyphBase;
1082     }
1083 
1084     // Set the position bias for the glyphs. If we're at the start of
1085     // a line, we want the first glyph to be at x = 0, even if it comes
1086     // from the middle of a layout. If we've got a right-to-left run, we
1087     // want the left-most glyph to start at the final x position of the
1088     // previous run, even though this glyph may be in the middle of the
1089     // run.
1090     fVisualRunLastX -= fStyleRunInfo[run].positions[leftGlyph * 2];
1091 
1092     // Make rightGlyph be the glyph just to the right of
1093     // the run's glyphs
1094     rightGlyph += 1;
1095 
1096     UBiDiDirection direction  = ((fStyleRunInfo[run].level & 1) == 0)? UBIDI_LTR : UBIDI_RTL;
1097     le_int32   glyphCount     = rightGlyph - leftGlyph;
1098     LEGlyphID *glyphs         = LE_NEW_ARRAY(LEGlyphID, glyphCount);
1099     float     *positions      = LE_NEW_ARRAY(float, glyphCount * 2 + 2);
1100     le_int32  *glyphToCharMap = LE_NEW_ARRAY(le_int32, glyphCount);
1101 
1102     LE_ARRAY_COPY(glyphs, &fStyleRunInfo[run].glyphs[leftGlyph], glyphCount);
1103 
1104     for (outGlyph = 0, inGlyph = leftGlyph * 2; inGlyph <= rightGlyph * 2; inGlyph += 2, outGlyph += 2) {
1105         positions[outGlyph]     = fStyleRunInfo[run].positions[inGlyph] + fVisualRunLastX;
1106         positions[outGlyph + 1] = fStyleRunInfo[run].positions[inGlyph + 1] + fVisualRunLastY;
1107     }
1108 
1109     // Save the ending position of this run
1110     // to use for the start of the next run
1111     fVisualRunLastX = positions[outGlyph - 2];
1112     fVisualRunLastY = positions[outGlyph - 1];
1113 
1114     if ((fStyleRunInfo[run].level & 1) == 0) {
1115         for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
1116             glyphToCharMap[outGlyph] = fGlyphToCharMap[glyphBase + inGlyph];
1117         }
1118     } else {
1119         // Because fGlyphToCharMap is stored in logical order to facilitate line breaking,
1120         // we need to map the physical glyph indices to logical indices while we copy the
1121         // character indices.
1122         le_int32 base = glyphBase + fStyleRunInfo[run].glyphCount - 1;
1123 
1124         for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) {
1125             glyphToCharMap[outGlyph] = fGlyphToCharMap[base - inGlyph];
1126         }
1127     }
1128 
1129     line->append(fStyleRunInfo[run].font, direction, glyphCount, glyphs, positions, glyphToCharMap);
1130 }
1131 
getCharRun(le_int32 charIndex)1132 le_int32 ParagraphLayout::getCharRun(le_int32 charIndex)
1133 {
1134     if (charIndex < 0 || charIndex > fCharCount) {
1135         return -1;
1136     }
1137 
1138     le_int32 run;
1139 
1140     // NOTE: as long as fStyleRunLimits is well-formed
1141     // the above range check guarantees that we'll never
1142     // fall off the end of the array.
1143     run = 0;
1144     while (charIndex >= fStyleRunLimits[run]) {
1145         run += 1;
1146     }
1147 
1148     return run;
1149 }
1150 
1151 
1152 const char ParagraphLayout::Line::fgClassID = 0;
1153 
1154 #define INITIAL_RUN_CAPACITY 4
1155 #define RUN_CAPACITY_GROW_LIMIT 16
1156 
~Line()1157 ParagraphLayout::Line::~Line()
1158 {
1159     le_int32 i;
1160 
1161     for (i = 0; i < fRunCount; i += 1) {
1162         delete fRuns[i];
1163     }
1164 
1165     LE_DELETE_ARRAY(fRuns);
1166 }
1167 
getAscent() const1168 le_int32 ParagraphLayout::Line::getAscent() const
1169 {
1170     if (fAscent <= 0) {
1171         ((ParagraphLayout::Line *)this)->computeMetrics();
1172     }
1173 
1174     return fAscent;
1175 }
1176 
getDescent() const1177 le_int32 ParagraphLayout::Line::getDescent() const
1178 {
1179     if (fAscent <= 0) {
1180         ((ParagraphLayout::Line *)this)->computeMetrics();
1181     }
1182 
1183     return fDescent;
1184 }
1185 
getLeading() const1186 le_int32 ParagraphLayout::Line::getLeading() const
1187 {
1188     if (fAscent <= 0) {
1189         ((ParagraphLayout::Line *)this)->computeMetrics();
1190     }
1191 
1192     return fLeading;
1193 }
1194 
getWidth() const1195 le_int32 ParagraphLayout::Line::getWidth() const
1196 {
1197     const VisualRun *lastRun = getVisualRun(fRunCount - 1);
1198 
1199     if (lastRun == NULL) {
1200         return 0;
1201     }
1202 
1203     le_int32 glyphCount = lastRun->getGlyphCount();
1204     const float *positions = lastRun->getPositions();
1205 
1206     return (le_int32) positions[glyphCount * 2];
1207 }
1208 
getVisualRun(le_int32 runIndex) const1209 const ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(le_int32 runIndex) const
1210 {
1211     if (runIndex < 0 || runIndex >= fRunCount) {
1212         return NULL;
1213     }
1214 
1215     return fRuns[runIndex];
1216 }
1217 
append(const LEFontInstance * font,UBiDiDirection direction,le_int32 glyphCount,const LEGlyphID glyphs[],const float positions[],const le_int32 glyphToCharMap[])1218 void ParagraphLayout::Line::append(const LEFontInstance *font, UBiDiDirection direction, le_int32 glyphCount,
1219                                    const LEGlyphID glyphs[], const float positions[], const le_int32 glyphToCharMap[])
1220 {
1221     if (fRunCount >= fRunCapacity) {
1222         if (fRunCapacity == 0) {
1223             fRunCapacity = INITIAL_RUN_CAPACITY;
1224             fRuns = LE_NEW_ARRAY(ParagraphLayout::VisualRun *, fRunCapacity);
1225         } else {
1226             fRunCapacity += (fRunCapacity < RUN_CAPACITY_GROW_LIMIT? fRunCapacity : RUN_CAPACITY_GROW_LIMIT);
1227             fRuns = (ParagraphLayout::VisualRun **) LE_GROW_ARRAY(fRuns, fRunCapacity);
1228         }
1229     }
1230 
1231     fRuns[fRunCount++] = new ParagraphLayout::VisualRun(font, direction, glyphCount, glyphs, positions, glyphToCharMap);
1232 }
1233 
computeMetrics()1234 void ParagraphLayout::Line::computeMetrics()
1235 {
1236     le_int32 maxDL = 0;
1237 
1238     for (le_int32 i = 0; i < fRunCount; i += 1) {
1239         le_int32 ascent  = fRuns[i]->getAscent();
1240         le_int32 descent = fRuns[i]->getDescent();
1241         le_int32 leading = fRuns[i]->getLeading();
1242         le_int32 dl      = descent + leading;
1243 
1244         if (ascent > fAscent) {
1245             fAscent = ascent;
1246         }
1247 
1248         if (descent > fDescent) {
1249             fDescent = descent;
1250         }
1251 
1252         if (leading > fLeading) {
1253             fLeading = leading;
1254         }
1255 
1256         if (dl > maxDL) {
1257             maxDL = dl;
1258         }
1259     }
1260 
1261     fLeading = maxDL - fDescent;
1262 }
1263 
1264 const char ParagraphLayout::VisualRun::fgClassID = 0;
1265 
~VisualRun()1266 ParagraphLayout::VisualRun::~VisualRun()
1267 {
1268     LE_DELETE_ARRAY(fGlyphToCharMap);
1269     LE_DELETE_ARRAY(fPositions);
1270     LE_DELETE_ARRAY(fGlyphs);
1271 }
1272 
1273 U_NAMESPACE_END
1274 
1275 #endif
1276 
1277