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