| |
| /* |
| * %W% %E% |
| * |
| * (C) Copyright IBM Corp. 1998, 1999, 2000 - All Rights Reserved |
| * |
| */ |
| |
| #include "LETypes.h" |
| #include "LayoutEngine.h" |
| #include "ArabicLayoutEngine.h" |
| //#include "HebrewLayoutEngine.h" |
| #include "IndicLayoutEngine.h" |
| #include "ThaiLayoutEngine.h" |
| #include "GXLayoutEngine.h" |
| #include "ScriptAndLanguageTags.h" |
| |
| #include "OpenTypeUtilities.h" |
| #include "GlyphSubstitutionTables.h" |
| #include "MorphTables.h" |
| |
| #define ARRAY_SIZE(array) (sizeof array / sizeof array[0]) |
| |
| class DefaultCharMapper : public LECharMapper |
| { |
| private: |
| le_bool fFilterControls; |
| le_bool fMirror; |
| |
| static LEUnicode32 controlChars[]; |
| |
| static const le_int32 controlCharsCount; |
| |
| static LEUnicode32 mirroredChars[]; |
| |
| static const le_int32 mirroredCharsCount; |
| |
| public: |
| DefaultCharMapper(le_bool filterControls, le_bool mirror) |
| : fFilterControls(filterControls), fMirror(mirror) |
| { |
| // nothing |
| }; |
| |
| ~DefaultCharMapper() |
| { |
| // nada |
| }; |
| |
| LEUnicode32 mapChar(LEUnicode32 ch); |
| }; |
| |
| LEUnicode32 DefaultCharMapper::controlChars[] = { |
| 0x0009, 0x000A, 0x000D, |
| /*0x200C, 0x200D,*/ 0x200E, 0x200F, |
| 0x2028, 0x2029, 0x202A, 0x202B, 0x202C, 0x202D, 0x202E, |
| 0x206A, 0x206B, 0x206C, 0x206D, 0x206E, 0x206F |
| }; |
| |
| const le_int32 DefaultCharMapper::controlCharsCount = ARRAY_SIZE(controlChars); |
| |
| LEUnicode32 DefaultCharMapper::mirroredChars[] = { |
| 0x0028, 0x0029, // ascii paired punctuation |
| 0x003c, 0x003e, |
| 0x005b, 0x005d, |
| 0x007b, 0x007d, |
| 0x2045, 0x2046, // math symbols (not complete) |
| 0x207d, 0x207e, |
| 0x208d, 0x208e, |
| 0x2264, 0x2265, |
| 0x3008, 0x3009, // chinese paired punctuation |
| 0x300a, 0x300b, |
| 0x300c, 0x300d, |
| 0x300e, 0x300f, |
| 0x3010, 0x3011, |
| 0x3014, 0x3015, |
| 0x3016, 0x3017, |
| 0x3018, 0x3019, |
| 0x301a, 0x301b |
| }; |
| |
| const le_int32 DefaultCharMapper::mirroredCharsCount = ARRAY_SIZE(mirroredChars); |
| |
| LEUnicode32 DefaultCharMapper::mapChar(LEUnicode32 ch) |
| { |
| if (fFilterControls) { |
| le_int32 index = OpenTypeUtilities::search(ch, controlChars, controlCharsCount); |
| |
| if (controlChars[index] == ch) { |
| return 0xFFFF; |
| } |
| } |
| |
| if (fMirror) { |
| le_int32 index = OpenTypeUtilities::search(ch, mirroredChars, mirroredCharsCount); |
| |
| if (mirroredChars[index] == ch) { |
| le_int32 mirrorOffset = ((index & 1) == 0) ? 1 : -1; |
| |
| return mirroredChars[index + mirrorOffset]; |
| } |
| } |
| |
| return ch; |
| } |
| |
| LayoutEngine::LayoutEngine(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode) |
| : fGlyphCount(0), fGlyphs(NULL), fCharIndices(NULL), fPositions(NULL), |
| fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode) |
| { |
| // nothing else to do? |
| } |
| |
| void LayoutEngine::getCharIndices(le_int32 charIndices[], le_int32 indexBase) |
| { |
| le_int32 i; |
| |
| for (i = 0; i < fGlyphCount; i += 1) { |
| charIndices[i] = fCharIndices[i] + indexBase; |
| } |
| } |
| |
| // Copy the glyphs into caller's (32-bit) glyph array, OR in extraBits |
| void LayoutEngine::getGlyphs(le_uint32 glyphs[], le_uint32 extraBits) |
| { |
| le_int32 i; |
| |
| for (i = 0; i < fGlyphCount; i += 1) { |
| glyphs[i] = fGlyphs[i] | extraBits; |
| } |
| }; |
| |
| le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, |
| LEGlyphID *&glyphs, le_int32 *&charIndices) |
| { |
| mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphs, charIndices); |
| |
| return count; |
| } |
| |
| // Input: glyphs |
| // Output: positions |
| void LayoutEngine::positionGlyphs(const LEGlyphID glyphs[], le_int32 glyphCount, float x, float y, float *&positions) |
| { |
| if (positions == NULL) { |
| positions = new float[2 * (glyphCount + 1)]; |
| } |
| |
| le_int32 i; |
| |
| for (i = 0; i < glyphCount; i += 1) { |
| LEPoint advance; |
| |
| positions[i * 2] = x; |
| positions[i * 2 + 1] = y; |
| |
| fFontInstance->getGlyphAdvance(glyphs[i], advance); |
| x += advance.fX; |
| y += advance.fY; |
| } |
| |
| positions[glyphCount * 2] = x; |
| positions[glyphCount * 2 + 1] = y; |
| } |
| |
| void LayoutEngine::adjustMarkGlyphs(const LEGlyphID glyphs[], le_int32 glyphCount, le_bool reverse, LEGlyphFilter *markFilter, |
| float positions[]) |
| { |
| float xAdjust = 0; |
| le_int32 g = 0, direction = 1; |
| le_int32 p; |
| |
| if (reverse) { |
| g = glyphCount - 1; |
| direction = -1; |
| } |
| |
| for (p = 0; p < glyphCount; p += 1, g += direction) { |
| float xAdvance = positions[(p + 1) * 2] - positions[p * 2]; |
| |
| positions[p * 2] += xAdjust; |
| |
| if (markFilter->accept(glyphs[g])) { |
| xAdjust -= xAdvance; |
| } |
| } |
| |
| positions[glyphCount * 2] += xAdjust; |
| } |
| |
| void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, |
| LEGlyphID *&glyphs, le_int32 *&charIndices) |
| { |
| if (glyphs == NULL) { |
| glyphs = new LEGlyphID[count]; |
| } |
| |
| if (charIndices == NULL) { |
| le_int32 i, dir = 1, out = 0; |
| |
| if (reverse) { |
| out = count - 1; |
| dir = -1; |
| } |
| |
| charIndices = new le_int32[count]; |
| |
| for (i = 0; i < count; i += 1, out += dir) { |
| charIndices[out] = i; |
| } |
| } |
| |
| DefaultCharMapper charMapper(true, mirror); |
| |
| fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, glyphs); |
| } |
| |
| // Input: characters, font? |
| // Output: glyphs, positions, char indices |
| // Returns: number of glyphs |
| le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, |
| float x, float y) |
| { |
| fGlyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, fGlyphs, fCharIndices); |
| positionGlyphs(fGlyphs, fGlyphCount, x, y, fPositions); |
| adjustGlyphPositions(chars, offset, count, rightToLeft, fGlyphs, fGlyphCount, fPositions); |
| |
| return fGlyphCount; |
| } |
| |
| void LayoutEngine::reset() |
| { |
| fGlyphCount = 0; |
| |
| if (fGlyphs != NULL) { |
| delete[] fGlyphs; |
| fGlyphs = NULL; |
| } |
| |
| if (fCharIndices != NULL) { |
| delete[] fCharIndices; |
| fCharIndices = NULL; |
| } |
| |
| if (fPositions != NULL) { |
| delete[] fPositions; |
| fPositions = NULL; |
| } |
| } |
| |
| LayoutEngine *LayoutEngine::layoutEngineFactory(LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode) |
| { |
| static le_uint32 gsubTableTag = 0x47535542; // "GSUB" |
| static le_uint32 mortTableTag = 0x6D6F7274; // 'mort' |
| GlyphSubstitutionTableHeader *gsubTable = (GlyphSubstitutionTableHeader *) fontInstance->getFontTable(gsubTableTag); |
| |
| if (gsubTable != NULL && gsubTable->coversScript(OpenTypeLayoutEngine::getScriptTag(scriptCode))) { |
| switch (scriptCode) { |
| case bengScriptCode: |
| case devaScriptCode: |
| case gujrScriptCode: |
| case kndaScriptCode: |
| case mlymScriptCode: |
| case oryaScriptCode: |
| case punjScriptCode: |
| case tamlScriptCode: |
| case teluScriptCode: |
| return new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable); |
| |
| case arabScriptCode: |
| return new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable); |
| |
| default: |
| return new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, gsubTable); |
| break; |
| } |
| } else { |
| MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); |
| |
| if (morphTable != NULL) { |
| return new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable); |
| } else { |
| switch (scriptCode) { |
| case bengScriptCode: |
| case devaScriptCode: |
| case gujrScriptCode: |
| case kndaScriptCode: |
| case mlymScriptCode: |
| case oryaScriptCode: |
| case punjScriptCode: |
| case tamlScriptCode: |
| case teluScriptCode: |
| { |
| const CDACLayout::ScriptInfo *scriptInfo = CDACLayout::getCDACScriptInfo(fontInstance, scriptCode); |
| |
| if (scriptInfo != NULL) { |
| return new CDACOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, scriptInfo); |
| } else { |
| return new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode); |
| } |
| } |
| |
| case arabScriptCode: |
| case hebrScriptCode: |
| return new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode); |
| |
| //case hebrScriptCode: |
| // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode); |
| |
| case thaiScriptCode: |
| return new ThaiLayoutEngine(fontInstance, scriptCode, languageCode); |
| |
| default: |
| break; |
| } |
| } |
| } |
| |
| return new LayoutEngine(fontInstance, scriptCode, languageCode); |
| } |
| |
| LayoutEngine::~LayoutEngine() { |
| reset(); |
| } |
| |