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