X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/b75a7d8f3b4adbae880cab104ce2c6a50eee4db2..a0b4f637ba1a6c3c5651b61a69303b029bacf7d3:/icuSources/layoutex/ParagraphLayout.cpp diff --git a/icuSources/layoutex/ParagraphLayout.cpp b/icuSources/layoutex/ParagraphLayout.cpp index 027d864b..cc32bc3b 100644 --- a/icuSources/layoutex/ParagraphLayout.cpp +++ b/icuSources/layoutex/ParagraphLayout.cpp @@ -1,6 +1,6 @@ /* ********************************************************************** - * Copyright (C) 2002-2003, International Business Machines + * Copyright (C) 2002-2014, International Business Machines * Corporation and others. All Rights Reserved. ********************************************************************** */ @@ -10,6 +10,7 @@ * BreakIterator... */ #include "layout/LETypes.h" +#include "layout/LEScripts.h" #include "layout/LELanguages.h" #include "layout/LayoutEngine.h" #include "layout/LEFontInstance.h" @@ -29,6 +30,9 @@ U_NAMESPACE_BEGIN #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) +/* Leave this copyright notice here! It needs to go somewhere in this library. */ +static const char copyright[] = U_COPYRIGHT_STRING; + class StyleRuns { public: @@ -126,71 +130,164 @@ le_int32 StyleRuns::getRuns(le_int32 runLimits[], le_int32 styleIndices[]) } /* - * NOTE: This table only has "true" values for + * NOTE: This table only has "TRUE" values for * those scripts which the LayoutEngine can currently * process, rather for all scripts which require * complex processing for correct rendering. */ -static const le_bool complexTable[] = { - false , /* Zyyy */ - false, /* Qaai */ - true, /* Arab */ - false, /* Armn */ - true, /* Beng */ - false, /* Bopo */ - false, /* Cher */ - false, /* Qaac */ - false, /* Cyrl */ - false, /* Dsrt */ - true, /* Deva */ - false, /* Ethi */ - false, /* Geor */ - false, /* Goth */ - false, /* Grek */ - true, /* Gujr */ - true, /* Guru */ - false, /* Hani */ - false, /* Hang */ - true, /* Hebr */ - false, /* Hira */ - true, /* Knda */ - false, /* Kana */ - false, /* Khmr */ - false, /* Laoo */ - false, /* Latn */ - true, /* Mlym */ - false, /* Mong */ - false, /* Mymr */ - false, /* Ogam */ - false, /* Ital */ - true, /* Orya */ - false, /* Runr */ - false, /* Sinh */ - false, /* Syrc */ - true, /* Taml */ - true, /* Telu */ - false, /* Thaa */ - true, /* Thai */ - false, /* Tibt */ - false, /* Cans */ - false, /* Yiii */ - false, /* Tglg */ - false, /* Hano */ - false, /* Buhd */ - false, /* Tagb */ - false, /* Brai */ - false, /* Cprt */ - false, /* Limb */ - false, /* Linb */ - false, /* Osma */ - false, /* Shaw */ - false, /* Tale */ - false /* Ugar */ +static const le_bool complexTable[scriptCodeCount] = { + FALSE , /* Zyyy */ + FALSE, /* Qaai */ + TRUE, /* Arab */ + FALSE, /* Armn */ + TRUE, /* Beng */ + FALSE, /* Bopo */ + FALSE, /* Cher */ + FALSE, /* Copt=Qaac */ + FALSE, /* Cyrl */ + FALSE, /* Dsrt */ + TRUE, /* Deva */ + FALSE, /* Ethi */ + FALSE, /* Geor */ + FALSE, /* Goth */ + FALSE, /* Grek */ + TRUE, /* Gujr */ + TRUE, /* Guru */ + FALSE, /* Hani */ + FALSE, /* Hang */ + TRUE, /* Hebr */ + FALSE, /* Hira */ + TRUE, /* Knda */ + FALSE, /* Kana */ + FALSE, /* Khmr */ + FALSE, /* Laoo */ + FALSE, /* Latn */ + TRUE, /* Mlym */ + FALSE, /* Mong */ + FALSE, /* Mymr */ + FALSE, /* Ogam */ + FALSE, /* Ital */ + TRUE, /* Orya */ + FALSE, /* Runr */ + FALSE, /* Sinh */ + FALSE, /* Syrc */ + TRUE, /* Taml */ + TRUE, /* Telu */ + FALSE, /* Thaa */ + TRUE, /* Thai */ + FALSE, /* Tibt */ + FALSE, /* Cans */ + FALSE, /* Yiii */ + FALSE, /* Tglg */ + FALSE, /* Hano */ + FALSE, /* Buhd */ + FALSE, /* Tagb */ + FALSE, /* Brai */ + FALSE, /* Cprt */ + FALSE, /* Limb */ + FALSE, /* Linb */ + FALSE, /* Osma */ + FALSE, /* Shaw */ + FALSE, /* Tale */ + FALSE, /* Ugar */ + FALSE, /* Hrkt */ + FALSE, /* Bugi */ + FALSE, /* Glag */ + FALSE, /* Khar */ + FALSE, /* Sylo */ + FALSE, /* Talu */ + FALSE, /* Tfng */ + FALSE, /* Xpeo */ + FALSE, /* Bali */ + FALSE, /* Batk */ + FALSE, /* Blis */ + FALSE, /* Brah */ + FALSE, /* Cham */ + FALSE, /* Cirt */ + FALSE, /* Cyrs */ + FALSE, /* Egyd */ + FALSE, /* Egyh */ + FALSE, /* Egyp */ + FALSE, /* Geok */ + FALSE, /* Hans */ + FALSE, /* Hant */ + FALSE, /* Hmng */ + FALSE, /* Hung */ + FALSE, /* Inds */ + FALSE, /* Java */ + FALSE, /* Kali */ + FALSE, /* Latf */ + FALSE, /* Latg */ + FALSE, /* Lepc */ + FALSE, /* Lina */ + FALSE, /* Mand */ + FALSE, /* Maya */ + FALSE, /* Mero */ + FALSE, /* Nkoo */ + FALSE, /* Orkh */ + FALSE, /* Perm */ + FALSE, /* Phag */ + FALSE, /* Phnx */ + FALSE, /* Plrd */ + FALSE, /* Roro */ + FALSE, /* Sara */ + FALSE, /* Syre */ + FALSE, /* Syrj */ + FALSE, /* Syrn */ + FALSE, /* Teng */ + FALSE, /* Taii */ + FALSE, /* Visp */ + FALSE, /* Xsux */ + FALSE, /* Zxxx */ + FALSE, /* Zzzz */ + FALSE, /* Cari */ + FALSE, /* Jpan */ + FALSE, /* Lana */ + FALSE, /* Lyci */ + FALSE, /* Lydi */ + FALSE, /* Olck */ + FALSE, /* Rjng */ + FALSE, /* Saur */ + FALSE, /* Sgnw */ + FALSE, /* Sund */ + FALSE, /* Moon */ + FALSE, /* Mtei */ + FALSE, /* Armi */ + FALSE, /* Avst */ + FALSE, /* Cakm */ + FALSE, /* Kore */ + FALSE, /* Kthi */ + FALSE, /* Mani */ + FALSE, /* Phli */ + FALSE, /* Phlp */ + FALSE, /* Phlv */ + FALSE, /* Prti */ + FALSE, /* Samr */ + FALSE, /* Tavt */ + FALSE, /* Zmth */ + FALSE, /* Zsym */ + FALSE, /* Bamu */ + FALSE, /* Lisu */ + FALSE, /* Nkgb */ + FALSE /* Sarb */ }; const char ParagraphLayout::fgClassID = 0; +static void fillMissingCharToGlyphMapValues(le_int32 *charToGlyphMap, + le_int32 charCount) { + le_int32 lastValidGlyph = -1; + le_int32 ch; + for (ch = 0; ch <= charCount; ch += 1) { + if (charToGlyphMap[ch] == -1) { + charToGlyphMap[ch] = lastValidGlyph; + } else { + lastValidGlyph = charToGlyphMap[ch]; + } + } +} + /* * How to deal with composite fonts: * @@ -216,18 +313,28 @@ ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count, const ValueRuns *levelRuns, const ValueRuns *scriptRuns, const LocaleRuns *localeRuns, - UBiDiLevel paragraphLevel, le_bool vertical) + UBiDiLevel paragraphLevel, le_bool vertical, + LEErrorCode &status) : fChars(chars), fCharCount(count), fFontRuns(NULL), fLevelRuns(levelRuns), fScriptRuns(scriptRuns), fLocaleRuns(localeRuns), - fVertical(vertical), fClientLevels(true), fClientScripts(true), fClientLocales(true), fEmbeddingLevels(NULL), + fVertical(vertical), fClientLevels(TRUE), fClientScripts(TRUE), fClientLocales(TRUE), fEmbeddingLevels(NULL), fAscent(0), fDescent(0), fLeading(0), - fGlyphToCharMap(NULL), fCharToGlyphMap(NULL), fGlyphWidths(NULL), fGlyphCount(0), + fGlyphToCharMap(NULL), fCharToMinGlyphMap(NULL), fCharToMaxGlyphMap(NULL), fGlyphWidths(NULL), fGlyphCount(0), fParaBidi(NULL), fLineBidi(NULL), fStyleRunLimits(NULL), fStyleIndices(NULL), fStyleRunCount(0), fBreakIterator(NULL), fLineStart(-1), fLineEnd(0), /*fVisualRuns(NULL), fStyleRunInfo(NULL), fVisualRunCount(-1), fFirstVisualRun(-1), fLastVisualRun(-1),*/ fVisualRunLastX(0), fVisualRunLastY(0) { + + if (LE_FAILURE(status)) { + fCharCount = -1; + return; + } + + (void)copyright; // Suppress unused variable warning. + (void)fVertical; // Suppress warning for unused field fVertical. + // FIXME: should check the limit arrays for consistency... computeLevels(paragraphLevel); @@ -240,19 +347,29 @@ ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count, computeLocales(); } - computeSubFonts(fontRuns); + computeSubFonts(fontRuns, status); + + if (LE_FAILURE(status)) { + //other stuff? + fCharCount = -1; + return; + } // now intersect the font, direction and script runs... const RunArray *styleRunArrays[] = {fFontRuns, fLevelRuns, fScriptRuns, fLocaleRuns}; le_int32 styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0]; StyleRuns styleRuns(styleRunArrays, styleCount); LEErrorCode layoutStatus = LE_NO_ERROR; - + fStyleRunCount = styleRuns.getRuns(NULL, NULL); fStyleRunLimits = LE_NEW_ARRAY(le_int32, fStyleRunCount); fStyleIndices = LE_NEW_ARRAY(le_int32, fStyleRunCount * styleCount); - + if ((fStyleRunLimits == NULL) || (fStyleIndices == NULL)) { + status = LE_MEMORY_ALLOCATION_ERROR; + return; + } + styleRuns.getRuns(fStyleRunLimits, fStyleIndices); // now build a LayoutEngine for each style run... @@ -260,6 +377,26 @@ ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count, le_int32 run, runStart; fStyleRunInfo = LE_NEW_ARRAY(StyleRunInfo, fStyleRunCount); + if (fStyleRunInfo == NULL) { + status = LE_MEMORY_ALLOCATION_ERROR; + return; + } + else { + // initialize + for (run = 0; run < fStyleRunCount; run += 1) { + fStyleRunInfo[run].font = NULL; + fStyleRunInfo[run].runBase = 0; + fStyleRunInfo[run].runLimit = 0; + fStyleRunInfo[run].script = (UScriptCode)0; + fStyleRunInfo[run].locale = NULL; + fStyleRunInfo[run].level = 0; + fStyleRunInfo[run].glyphBase = 0; + fStyleRunInfo[run].engine = NULL; + fStyleRunInfo[run].glyphCount = 0; + fStyleRunInfo[run].glyphs = NULL; + fStyleRunInfo[run].positions = NULL; + } + } fGlyphCount = 0; for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) { @@ -273,9 +410,17 @@ ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count, fStyleRunInfo[run].engine = LayoutEngine::layoutEngineFactory(fStyleRunInfo[run].font, fStyleRunInfo[run].script, getLanguageCode(fStyleRunInfo[run].locale), layoutStatus); + if (LE_FAILURE(layoutStatus)) { + status = layoutStatus; + return; + } fStyleRunInfo[run].glyphCount = fStyleRunInfo[run].engine->layoutChars(fChars, runStart, fStyleRunLimits[run] - runStart, fCharCount, fStyleRunInfo[run].level & 1, 0, 0, layoutStatus); + if (LE_FAILURE(layoutStatus)) { + status = layoutStatus; + return; + } runStart = fStyleRunLimits[run]; styleIndices += styleCount; @@ -283,48 +428,62 @@ ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count, } // Make big arrays for the glyph widths, glyph-to-char and char-to-glyph maps, - // in logical order. (Both maps need an extra entry for the end of the text.) + // in logical order. (Both maps need an extra entry for the end of the text.) // // For each layout get the positions and convert them into glyph widths, in // logical order. Get the glyph-to-char mapping, offset by starting index in the - // width array, and swap it into logical order. Then fill in the char-to-glyph map - // from this. (charToGlyph[glyphToChar[i]] = i) - fGlyphWidths = LE_NEW_ARRAY(float, fGlyphCount); - fGlyphToCharMap = LE_NEW_ARRAY(le_int32, fGlyphCount + 1); - fCharToGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1); + // character array. Swap the glyph width and glyph-to-char arrays into logical order. + // Finally, fill in the char-to-glyph mappings. + fGlyphWidths = LE_NEW_ARRAY(float, fGlyphCount); + fGlyphToCharMap = LE_NEW_ARRAY(le_int32, fGlyphCount + 1); + fCharToMinGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1); + fCharToMaxGlyphMap = LE_NEW_ARRAY(le_int32, fCharCount + 1); + if ((fGlyphWidths == NULL) || (fGlyphToCharMap == NULL) || + (fCharToMinGlyphMap == NULL) || (fCharToMaxGlyphMap == NULL)) { + status = LE_MEMORY_ALLOCATION_ERROR; + return; + } + + le_int32 glyph; for (runStart = 0, run = 0; run < fStyleRunCount; run += 1) { LayoutEngine *engine = fStyleRunInfo[run].engine; le_int32 glyphCount = fStyleRunInfo[run].glyphCount; le_int32 glyphBase = fStyleRunInfo[run].glyphBase; - le_int32 glyph; fStyleRunInfo[run].glyphs = LE_NEW_ARRAY(LEGlyphID, glyphCount); fStyleRunInfo[run].positions = LE_NEW_ARRAY(float, glyphCount * 2 + 2); + if ((fStyleRunInfo[run].glyphs == NULL) || + (fStyleRunInfo[run].positions == NULL)) { + status = LE_MEMORY_ALLOCATION_ERROR; + return; + } engine->getGlyphs(fStyleRunInfo[run].glyphs, layoutStatus); + if (LE_FAILURE(layoutStatus)) { + status = layoutStatus; + return; + } + engine->getGlyphPositions(fStyleRunInfo[run].positions, layoutStatus); + if (LE_FAILURE(layoutStatus)) { + status = layoutStatus; + return; + } + engine->getCharIndices(&fGlyphToCharMap[glyphBase], runStart, layoutStatus); + if (LE_FAILURE(layoutStatus)) { + status = layoutStatus; + return; + } for (glyph = 0; glyph < glyphCount; glyph += 1) { fGlyphWidths[glyphBase + glyph] = fStyleRunInfo[run].positions[glyph * 2 + 2] - fStyleRunInfo[run].positions[glyph * 2]; - fCharToGlyphMap[fGlyphToCharMap[glyphBase + glyph]] = glyphBase + glyph; } if ((fStyleRunInfo[run].level & 1) != 0) { LXUtilities::reverse(&fGlyphWidths[glyphBase], glyphCount); LXUtilities::reverse(&fGlyphToCharMap[glyphBase], glyphCount); - - // LXUtilities::reverse(&fCharToGlyphMap[runStart], fStyleRunLimits[run] - runStart); - // convert from visual to logical glyph indices - for (glyph = glyphBase; glyph < glyphBase + glyphCount; glyph += 1) { - le_int32 ch = fGlyphToCharMap[glyph]; - le_int32 lastGlyph = glyphBase + glyphCount - 1; - - // both lastGlyph and fCharToGlyphMap[ch] are biased by - // glyphBase, so subtracting them will remove the bias. - fCharToGlyphMap[ch] = lastGlyph - fCharToGlyphMap[ch] + glyphBase; - } } runStart = fStyleRunLimits[run]; @@ -333,8 +492,35 @@ ParagraphLayout::ParagraphLayout(const LEUnicode chars[], le_int32 count, fStyleRunInfo[run].engine = NULL; } - fCharToGlyphMap[fCharCount] = fGlyphCount; fGlyphToCharMap[fGlyphCount] = fCharCount; + + // Initialize the char-to-glyph maps to -1 so that we can later figure out + // whether any of the entries in the map aren't filled in below. + le_int32 chIndex; + for (chIndex = 0; chIndex <= fCharCount; chIndex += 1) { + fCharToMinGlyphMap[chIndex] = -1; + fCharToMaxGlyphMap[chIndex] = -1; + } + + for (glyph = fGlyphCount - 1; glyph >= 0; glyph -= 1) { + le_int32 ch = fGlyphToCharMap[glyph]; + + fCharToMinGlyphMap[ch] = glyph; + } + + fCharToMinGlyphMap[fCharCount] = fGlyphCount; + + for (glyph = 0; glyph < fGlyphCount; glyph += 1) { + le_int32 ch = fGlyphToCharMap[glyph]; + + fCharToMaxGlyphMap[ch] = glyph; + } + + fCharToMaxGlyphMap[fCharCount] = fGlyphCount; + + // Now fill in the missing values in the char-to-glyph maps. + fillMissingCharToGlyphMapValues(fCharToMinGlyphMap, fCharCount); + fillMissingCharToGlyphMapValues(fCharToMaxGlyphMap, fCharCount); } ParagraphLayout::~ParagraphLayout() @@ -345,21 +531,21 @@ ParagraphLayout::~ParagraphLayout() delete (ValueRuns *) fLevelRuns; fLevelRuns = NULL; - fClientLevels = true; + fClientLevels = TRUE; } if (! fClientScripts) { delete (ValueRuns *) fScriptRuns; fScriptRuns = NULL; - fClientScripts = true; + fClientScripts = TRUE; } if (! fClientLocales) { delete (LocaleRuns *) fLocaleRuns; fLocaleRuns = NULL; - fClientLocales = true; + fClientLocales = TRUE; } if (fEmbeddingLevels != NULL) { @@ -372,9 +558,14 @@ ParagraphLayout::~ParagraphLayout() fGlyphToCharMap = NULL; } - if (fCharToGlyphMap != NULL) { - LE_DELETE_ARRAY(fCharToGlyphMap); - fCharToGlyphMap = NULL; + if (fCharToMinGlyphMap != NULL) { + LE_DELETE_ARRAY(fCharToMinGlyphMap); + fCharToMinGlyphMap = NULL; + } + + if (fCharToMaxGlyphMap != NULL) { + LE_DELETE_ARRAY(fCharToMaxGlyphMap); + fCharToMaxGlyphMap = NULL; } if (fGlyphWidths != NULL) { @@ -420,25 +611,28 @@ ParagraphLayout::~ParagraphLayout() } } - + le_bool ParagraphLayout::isComplex(const LEUnicode chars[], le_int32 count) { UErrorCode scriptStatus = U_ZERO_ERROR; UScriptCode scriptCode = USCRIPT_INVALID_CODE; UScriptRun *sr = uscript_openRun(chars, count, &scriptStatus); + le_bool result = FALSE; while (uscript_nextRun(sr, NULL, NULL, &scriptCode)) { if (isComplex(scriptCode)) { - return true; + result = TRUE; + break; } } - return false; + uscript_closeRun(sr); + return result; } le_int32 ParagraphLayout::getAscent() const { - if (fAscent <= 0) { + if (fAscent <= 0 && fCharCount > 0) { ((ParagraphLayout *) this)->computeMetrics(); } @@ -447,7 +641,7 @@ le_int32 ParagraphLayout::getAscent() const le_int32 ParagraphLayout::getDescent() const { - if (fAscent <= 0) { + if (fAscent <= 0 && fCharCount > 0) { ((ParagraphLayout *) this)->computeMetrics(); } @@ -456,23 +650,28 @@ le_int32 ParagraphLayout::getDescent() const le_int32 ParagraphLayout::getLeading() const { - if (fAscent <= 0) { + if (fAscent <= 0 && fCharCount > 0) { ((ParagraphLayout *) this)->computeMetrics(); } return fLeading; } +le_bool ParagraphLayout::isDone() const +{ + return fLineEnd >= fCharCount; +} + ParagraphLayout::Line *ParagraphLayout::nextLine(float width) { - if (fLineEnd >= fCharCount) { + if (isDone()) { return NULL; } fLineStart = fLineEnd; if (width > 0) { - le_int32 glyph = fCharToGlyphMap[fLineStart]; + le_int32 glyph = fCharToMinGlyphMap[fLineStart]; float widthSoFar = 0; while (glyph < fGlyphCount && widthSoFar + fGlyphWidths[glyph] <= width) { @@ -492,10 +691,11 @@ ParagraphLayout::Line *ParagraphLayout::nextLine(float width) fLineEnd = previousBreak(fGlyphToCharMap[glyph]); - // If there's no real break, break at the - // glyph that didn't fit. - if (fLineEnd <= fLineStart) { - fLineEnd = fGlyphToCharMap[glyph]; + // If this break is at or before the last one, + // find a glyph, starting at the one which didn't + // fit, that produces a break after the last one. + while (fLineEnd <= fLineStart) { + fLineEnd = fGlyphToCharMap[glyph++]; } } else { fLineEnd = fCharCount; @@ -543,7 +743,7 @@ void ParagraphLayout::computeLevels(UBiDiLevel paragraphLevel) } fLevelRuns = levelRuns; - fClientLevels = false; + fClientLevels = FALSE; } } @@ -562,7 +762,7 @@ void ParagraphLayout::computeScripts() uscript_closeRun(sr); fScriptRuns = scriptRuns; - fClientScripts = false; + fClientScripts = FALSE; } void ParagraphLayout::computeLocales() @@ -573,11 +773,15 @@ void ParagraphLayout::computeLocales() localeRuns->add(defaultLocale, fCharCount); fLocaleRuns = localeRuns; - fClientLocales = false; + fClientLocales = FALSE; } -void ParagraphLayout::computeSubFonts(const FontRuns *fontRuns) +void ParagraphLayout::computeSubFonts(const FontRuns *fontRuns, LEErrorCode &status) { + if (LE_FAILURE(status)) { + return; + } + const RunArray *styleRunArrays[] = {fontRuns, fScriptRuns}; le_int32 styleCount = sizeof styleRunArrays / sizeof styleRunArrays[0]; StyleRuns styleRuns(styleRunArrays, styleCount); @@ -595,10 +799,14 @@ void ParagraphLayout::computeSubFonts(const FontRuns *fontRuns) for (run = 0; run < styleRunCount; run += 1) { const LEFontInstance *runFont = fontRuns->getFont(si[0]); le_int32 script = fScriptRuns->getValue(si[1]); - LEErrorCode success = LE_NO_ERROR; while (offset < styleRunLimits[run]) { - const LEFontInstance *subFont = runFont->getSubFont(fChars, &offset, styleRunLimits[run], script, success); + const LEFontInstance *subFont = runFont->getSubFont(fChars, &offset, styleRunLimits[run], script, status); + + if (LE_FAILURE(status)) { + delete subFontRuns; + goto cleanUp; + } subFontRuns->add(subFont, offset); } @@ -608,6 +816,7 @@ void ParagraphLayout::computeSubFonts(const FontRuns *fontRuns) fFontRuns = subFontRuns; +cleanUp: LE_DELETE_ARRAY(styleIndices); LE_DELETE_ARRAY(styleRunLimits); } @@ -653,30 +862,71 @@ struct LanguageMap static const LanguageMap languageMap[] = { + {"afr", afkLanguageCode}, // Afrikaans {"ara", araLanguageCode}, // Arabic {"asm", asmLanguageCode}, // Assamese + {"bel", belLanguageCode}, // Belarussian {"ben", benLanguageCode}, // Bengali + {"bod", tibLanguageCode}, // Tibetan + {"bul", bgrLanguageCode}, // Bulgarian + {"cat", catLanguageCode}, // Catalan + {"ces", csyLanguageCode}, // Czech + {"che", cheLanguageCode}, // Chechen + {"cop", copLanguageCode}, // Coptic + {"cym", welLanguageCode}, // Welsh + {"dan", danLanguageCode}, // Danish + {"deu", deuLanguageCode}, // German + {"dzo", dznLanguageCode}, // Dzongkha + {"ell", ellLanguageCode}, // Greek + {"eng", engLanguageCode}, // English + {"est", etiLanguageCode}, // Estonian + {"eus", euqLanguageCode}, // Basque {"fas", farLanguageCode}, // Farsi + {"fin", finLanguageCode}, // Finnish + {"fra", fraLanguageCode}, // French + {"gle", gaeLanguageCode}, // Irish Gaelic {"guj", gujLanguageCode}, // Gujarati + {"hau", hauLanguageCode}, // Hausa {"heb", iwrLanguageCode}, // Hebrew {"hin", hinLanguageCode}, // Hindi + {"hrv", hrvLanguageCode}, // Croatian + {"hun", hunLanguageCode}, // Hungarian + {"hye", hyeLanguageCode}, // Armenian + {"ind", indLanguageCode}, // Indonesian + {"ita", itaLanguageCode}, // Italian {"jpn", janLanguageCode}, // Japanese {"kan", kanLanguageCode}, // Kannada {"kas", kshLanguageCode}, // Kashmiri + {"khm", khmLanguageCode}, // Khmer {"kok", kokLanguageCode}, // Konkani {"kor", korLanguageCode}, // Korean // {"mal_XXX", malLanguageCode}, // Malayalam - Traditional {"mal", mlrLanguageCode}, // Malayalam - Reformed {"mar", marLanguageCode}, // Marathi + {"mlt", mtsLanguageCode}, // Maltese {"mni", mniLanguageCode}, // Manipuri + {"mon", mngLanguageCode}, // Mongolian + {"nep", nepLanguageCode}, // Nepali {"ori", oriLanguageCode}, // Oriya + {"pol", plkLanguageCode}, // Polish + {"por", ptgLanguageCode}, // Portuguese + {"pus", pasLanguageCode}, // Pashto + {"ron", romLanguageCode}, // Romanian + {"rus", rusLanguageCode}, // Russian {"san", sanLanguageCode}, // Sanskrit - {"snd", sndLanguageCode}, // Sindhi {"sin", snhLanguageCode}, // Sinhalese + {"slk", skyLanguageCode}, // Slovak + {"snd", sndLanguageCode}, // Sindhi + {"slv", slvLanguageCode}, // Slovenian + {"spa", espLanguageCode}, // Spanish + {"sqi", sqiLanguageCode}, // Albanian + {"srp", srbLanguageCode}, // Serbian + {"swe", sveLanguageCode}, // Swedish {"syr", syrLanguageCode}, // Syriac {"tam", tamLanguageCode}, // Tamil {"tel", telLanguageCode}, // Telugu {"tha", thaLanguageCode}, // Thai + {"tur", trkLanguageCode}, // Turkish {"urd", urdLanguageCode}, // Urdu {"yid", jiiLanguageCode}, // Yiddish // {"zhp", zhpLanguageCode}, // Chinese - Phonetic @@ -711,7 +961,7 @@ le_int32 ParagraphLayout::getLanguageCode(const Locale *locale) return nullLanguageCode; } -#elif +#else // TODO - dummy implementation for right now... le_int32 ParagraphLayout::getLanguageCode(const Locale *locale) @@ -722,8 +972,8 @@ le_int32 ParagraphLayout::getLanguageCode(const Locale *locale) le_bool ParagraphLayout::isComplex(UScriptCode script) { - if (script < 0 || script >= USCRIPT_CODE_LIMIT) { - return false; + if (script < 0 || script >= (UScriptCode) scriptCodeCount) { + return FALSE; } return complexTable[script]; @@ -810,14 +1060,15 @@ void ParagraphLayout::appendRun(ParagraphLayout::Line *line, le_int32 run, le_in le_int32 ch; for (ch = firstChar; ch <= lastChar; ch += 1) { - le_int32 glyph = fCharToGlyphMap[ch]; + le_int32 minGlyph = fCharToMinGlyphMap[ch]; + le_int32 maxGlyph = fCharToMaxGlyphMap[ch]; - if (glyph < leftGlyph) { - leftGlyph = glyph; + if (minGlyph < leftGlyph) { + leftGlyph = minGlyph; } - if (glyph > rightGlyph) { - rightGlyph = glyph; + if (maxGlyph > rightGlyph) { + rightGlyph = maxGlyph; } } @@ -838,13 +1089,9 @@ void ParagraphLayout::appendRun(ParagraphLayout::Line *line, le_int32 run, le_in // from the middle of a layout. If we've got a right-to-left run, we // want the left-most glyph to start at the final x position of the // previous run, even though this glyph may be in the middle of the - // layout. - if (run == fFirstVisualRun) { - fVisualRunLastX = - fStyleRunInfo[run].positions[leftGlyph * 2]; - } else if ((fStyleRunInfo[run].level & 1) != 0) { - fVisualRunLastX -= fStyleRunInfo[run].positions[leftGlyph * 2]; - } - + // run. + fVisualRunLastX -= fStyleRunInfo[run].positions[leftGlyph * 2]; + // Make rightGlyph be the glyph just to the right of // the run's glyphs rightGlyph += 1; @@ -859,21 +1106,26 @@ void ParagraphLayout::appendRun(ParagraphLayout::Line *line, le_int32 run, le_in for (outGlyph = 0, inGlyph = leftGlyph * 2; inGlyph <= rightGlyph * 2; inGlyph += 2, outGlyph += 2) { positions[outGlyph] = fStyleRunInfo[run].positions[inGlyph] + fVisualRunLastX; - positions[outGlyph + 1] = fStyleRunInfo[run].positions[inGlyph + 1] /* + fVisualRunLastY */; + positions[outGlyph + 1] = fStyleRunInfo[run].positions[inGlyph + 1] + fVisualRunLastY; } // Save the ending position of this run // to use for the start of the next run fVisualRunLastX = positions[outGlyph - 2]; - // fVisualRunLastY = positions[rightGlyph * 2 + 2]; + fVisualRunLastY = positions[outGlyph - 1]; if ((fStyleRunInfo[run].level & 1) == 0) { for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) { glyphToCharMap[outGlyph] = fGlyphToCharMap[glyphBase + inGlyph]; } } else { - for (outGlyph = 0, inGlyph = rightGlyph - 1; inGlyph >= leftGlyph; inGlyph -= 1, outGlyph += 1) { - glyphToCharMap[outGlyph] = fGlyphToCharMap[glyphBase + inGlyph]; + // Because fGlyphToCharMap is stored in logical order to facilitate line breaking, + // we need to map the physical glyph indices to logical indices while we copy the + // character indices. + le_int32 base = glyphBase + fStyleRunInfo[run].glyphCount - 1; + + for (outGlyph = 0, inGlyph = leftGlyph; inGlyph < rightGlyph; inGlyph += 1, outGlyph += 1) { + glyphToCharMap[outGlyph] = fGlyphToCharMap[base - inGlyph]; } } @@ -943,6 +1195,20 @@ le_int32 ParagraphLayout::Line::getLeading() const return fLeading; } +le_int32 ParagraphLayout::Line::getWidth() const +{ + const VisualRun *lastRun = getVisualRun(fRunCount - 1); + + if (lastRun == NULL) { + return 0; + } + + le_int32 glyphCount = lastRun->getGlyphCount(); + const float *positions = lastRun->getPositions(); + + return (le_int32) positions[glyphCount * 2]; +} + const ParagraphLayout::VisualRun *ParagraphLayout::Line::getVisualRun(le_int32 runIndex) const { if (runIndex < 0 || runIndex >= fRunCount) { @@ -1000,8 +1266,14 @@ void ParagraphLayout::Line::computeMetrics() const char ParagraphLayout::VisualRun::fgClassID = 0; +ParagraphLayout::VisualRun::~VisualRun() +{ + LE_DELETE_ARRAY(fGlyphToCharMap); + LE_DELETE_ARRAY(fPositions); + LE_DELETE_ARRAY(fGlyphs); +} + U_NAMESPACE_END #endif -