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