Home | History | Annotate | Download | only in layoutex
      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 
     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 
    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 
    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 
    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  */
    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 
    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 
    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 
    630 le_int32 ParagraphLayout::getAscent() const
    631 {
    632     if (fAscent <= 0 && fCharCount > 0) {
    633         ((ParagraphLayout *) this)->computeMetrics();
    634     }
    635 
    636     return fAscent;
    637 }
    638 
    639 le_int32 ParagraphLayout::getDescent() const
    640 {
    641     if (fAscent <= 0 && fCharCount > 0) {
    642         ((ParagraphLayout *) this)->computeMetrics();
    643     }
    644 
    645     return fDescent;
    646 }
    647 
    648 le_int32 ParagraphLayout::getLeading() const
    649 {
    650     if (fAscent <= 0 && fCharCount > 0) {
    651         ((ParagraphLayout *) this)->computeMetrics();
    652     }
    653 
    654     return fLeading;
    655 }
    656 
    657 le_bool ParagraphLayout::isDone() const
    658 {
    659     return fLineEnd >= fCharCount;
    660 }
    661 
    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 
    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 
    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 
    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 
    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 
    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 
    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...
    964 le_int32 ParagraphLayout::getLanguageCode(const Locale *locale)
    965 {
    966     return nullLanguageCode;
    967 }
    968 #endif
    969 
    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 
    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 
   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 
   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 
   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 
   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 
   1168 le_int32 ParagraphLayout::Line::getAscent() const
   1169 {
   1170     if (fAscent <= 0) {
   1171         ((ParagraphLayout::Line *)this)->computeMetrics();
   1172     }
   1173 
   1174     return fAscent;
   1175 }
   1176 
   1177 le_int32 ParagraphLayout::Line::getDescent() const
   1178 {
   1179     if (fAscent <= 0) {
   1180         ((ParagraphLayout::Line *)this)->computeMetrics();
   1181     }
   1182 
   1183     return fDescent;
   1184 }
   1185 
   1186 le_int32 ParagraphLayout::Line::getLeading() const
   1187 {
   1188     if (fAscent <= 0) {
   1189         ((ParagraphLayout::Line *)this)->computeMetrics();
   1190     }
   1191 
   1192     return fLeading;
   1193 }
   1194 
   1195 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 
   1209 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 
   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 
   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 
   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