+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
/*
**********************************************************************
- * Copyright (C) 2002-2003, International Business Machines
+ * Copyright (C) 2002-2014, International Business Machines
* Corporation and others. All Rights Reserved.
**********************************************************************
*/
* BreakIterator...
*/
#include "layout/LETypes.h"
+#include "layout/LEScripts.h"
#include "layout/LELanguages.h"
#include "layout/LayoutEngine.h"
#include "layout/LEFontInstance.h"
#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:
}
/*
- * 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:
*
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);
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...
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) {
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;
}
// 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];
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()
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) {
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) {
}
}
-
+
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();
}
le_int32 ParagraphLayout::getDescent() const
{
- if (fAscent <= 0) {
+ if (fAscent <= 0 && fCharCount > 0) {
((ParagraphLayout *) this)->computeMetrics();
}
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) {
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;
}
fLevelRuns = levelRuns;
- fClientLevels = false;
+ fClientLevels = FALSE;
}
}
uscript_closeRun(sr);
fScriptRuns = scriptRuns;
- fClientScripts = false;
+ fClientScripts = FALSE;
}
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);
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);
}
fFontRuns = subFontRuns;
+cleanUp:
LE_DELETE_ARRAY(styleIndices);
LE_DELETE_ARRAY(styleRunLimits);
}
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
return nullLanguageCode;
}
-#elif
+#else
// TODO - dummy implementation for right now...
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];
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;
}
}
// 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;
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];
}
}
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) {
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
-