X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/73c04bcfe1096173b00431f0cdc742894b15eef0..4d9eefca008a7bc544144ef830fa144ce89deaa0:/icuSources/layout/LayoutEngine.cpp diff --git a/icuSources/layout/LayoutEngine.cpp b/icuSources/layout/LayoutEngine.cpp index b211f2d3..ef67b4ed 100644 --- a/icuSources/layout/LayoutEngine.cpp +++ b/icuSources/layout/LayoutEngine.cpp @@ -1,13 +1,11 @@ - /* - * - * (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved - * + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved */ #include "LETypes.h" #include "LEScripts.h" #include "LELanguages.h" +#include "LESwaps.h" #include "LayoutEngine.h" #include "ArabicLayoutEngine.h" @@ -19,6 +17,8 @@ #include "ThaiLayoutEngine.h" #include "TibetanLayoutEngine.h" #include "GXLayoutEngine.h" +#include "GXLayoutEngine2.h" + #include "ScriptAndLanguageTags.h" #include "CharSubstitutionFilter.h" @@ -26,6 +26,7 @@ #include "OpenTypeUtilities.h" #include "GlyphSubstitutionTables.h" +#include "GlyphDefinitionTables.h" #include "MorphTables.h" #include "DefaultCharMapper.h" @@ -34,6 +35,13 @@ U_NAMESPACE_BEGIN +/* Leave this copyright notice here! It needs to go somewhere in this library. */ +static const char copyright[] = U_COPYRIGHT_STRING; + +/* TODO: remove these? */ +const le_int32 LayoutEngine::kTypoFlagKern = LE_Kerning_FEATURE_FLAG; +const le_int32 LayoutEngine::kTypoFlagLiga = LE_Ligatures_FEATURE_FLAG; + const LEUnicode32 DefaultCharMapper::controlChars[] = { 0x0009, 0x000A, 0x000D, /*0x200C, 0x200D,*/ 0x200E, 0x200F, @@ -83,6 +91,37 @@ CharSubstitutionFilter::~CharSubstitutionFilter() // nothing to do } +class CanonMarkFilter : public UMemory, public LEGlyphFilter +{ +private: + const GlyphClassDefinitionTable *classDefTable; + + CanonMarkFilter(const CanonMarkFilter &other); // forbid copying of this class + CanonMarkFilter &operator=(const CanonMarkFilter &other); // forbid copying of this class + +public: + CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable); + virtual ~CanonMarkFilter(); + + virtual le_bool accept(LEGlyphID glyph) const; +}; + +CanonMarkFilter::CanonMarkFilter(const GlyphDefinitionTableHeader *gdefTable) +{ + classDefTable = gdefTable->getMarkAttachClassDefinitionTable(); +} + +CanonMarkFilter::~CanonMarkFilter() +{ + // nothing to do? +} + +le_bool CanonMarkFilter::accept(LEGlyphID glyph) const +{ + le_int32 glyphClass = classDefTable->getGlyphClass(glyph); + + return glyphClass != 0; +} UOBJECT_DEFINE_RTTI_IMPLEMENTATION(LayoutEngine) @@ -99,11 +138,22 @@ static const FeatureMap canonFeatureMap[] = static const le_int32 canonFeatureMapCount = LE_ARRAY_SIZE(canonFeatureMap); -LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags) +LayoutEngine::LayoutEngine(const LEFontInstance *fontInstance, + le_int32 scriptCode, + le_int32 languageCode, + le_int32 typoFlags, + LEErrorCode &success) : fGlyphStorage(NULL), fFontInstance(fontInstance), fScriptCode(scriptCode), fLanguageCode(languageCode), - fTypoFlags(typoFlags) + fTypoFlags(typoFlags), fFilterZeroWidth(TRUE) { + if (LE_FAILURE(success)) { + return; + } + fGlyphStorage = new LEGlyphStorage(); + if (fGlyphStorage == NULL) { + success = LE_MEMORY_ALLOCATION_ERROR; + } } le_int32 LayoutEngine::getGlyphCount() const @@ -144,7 +194,7 @@ void LayoutEngine::getGlyphPosition(le_int32 glyphIndex, float &x, float &y, LEE } le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 offset, le_int32 count, le_int32 max, le_bool rightToLeft, - LEUnicode *&outChars, LEGlyphStorage &/*glyphStorage*/, LEErrorCode &success) + LEUnicode *&outChars, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { return 0; @@ -162,6 +212,11 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off if (canonGSUBTable->coversScript(scriptTag)) { CharSubstitutionFilter *substitutionFilter = new CharSubstitutionFilter(fFontInstance); + if (substitutionFilter == NULL) { + success = LE_MEMORY_ALLOCATION_ERROR; + return 0; + } + const LEUnicode *inChars = &chars[offset]; LEUnicode *reordered = NULL; LEGlyphStorage fakeGlyphStorage; @@ -169,6 +224,7 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off fakeGlyphStorage.allocateGlyphArray(count, rightToLeft, success); if (LE_FAILURE(success)) { + delete substitutionFilter; return 0; } @@ -179,6 +235,7 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off reordered = LE_NEW_ARRAY(LEUnicode, count); if (reordered == NULL) { + delete substitutionFilter; success = LE_MEMORY_ALLOCATION_ERROR; return 0; } @@ -190,6 +247,7 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off fakeGlyphStorage.allocateAuxData(success); if (LE_FAILURE(success)) { + delete substitutionFilter; return 0; } @@ -207,11 +265,31 @@ le_int32 LayoutEngine::characterProcessing(const LEUnicode chars[], le_int32 off LE_DELETE_ARRAY(reordered); } - outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE); + outCharCount = canonGSUBTable->process(fakeGlyphStorage, rightToLeft, scriptTag, langSysTag, NULL, substitutionFilter, canonFeatureMap, canonFeatureMapCount, FALSE, success); + + if (LE_FAILURE(success)) { + delete substitutionFilter; + return 0; + } out = (rightToLeft? outCharCount - 1 : 0); + /* + * The char indices array in fakeGlyphStorage has the correct mapping + * back to the original input characters. Save it in glyphStorage. The + * subsequent call to glyphStoratge.allocateGlyphArray will keep this + * array rather than allocating and initializing a new one. + */ + glyphStorage.adoptCharIndicesArray(fakeGlyphStorage); + outChars = LE_NEW_ARRAY(LEUnicode, outCharCount); + + if (outChars == NULL) { + delete substitutionFilter; + success = LE_MEMORY_ALLOCATION_ERROR; + return 0; + } + for (i = 0; i < outCharCount; i += 1, out += dir) { outChars[out] = (LEUnicode) LE_GET_GLYPH(fakeGlyphStorage[i]); } @@ -238,10 +316,10 @@ le_int32 LayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 offset, l le_int32 outCharCount = characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success); if (outChars != NULL) { - mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, TRUE, glyphStorage, success); + mapCharsToGlyphs(outChars, 0, outCharCount, rightToLeft, rightToLeft, glyphStorage, success); LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... } else { - mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, TRUE, glyphStorage, success); + mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); } return glyphStorage.getGlyphCount(); @@ -276,7 +354,7 @@ void LayoutEngine::positionGlyphs(LEGlyphStorage &glyphStorage, float x, float y glyphStorage.setPosition(glyphCount, x, y, success); } -void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool /*reverse*/, +void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { @@ -288,6 +366,11 @@ void LayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int32 offset return; } + GlyphDefinitionTableHeader *gdefTable = (GlyphDefinitionTableHeader *) CanonShaping::glyphDefinitionTable; + CanonMarkFilter filter(gdefTable); + + adjustMarkGlyphs(&chars[offset], count, reverse, glyphStorage, &filter, success); + if (fTypoFlags & 0x1) { /* kerning enabled */ static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; @@ -319,7 +402,7 @@ void LayoutEngine::adjustMarkGlyphs(LEGlyphStorage &glyphStorage, LEGlyphFilter for (p = 0; p < glyphCount; p += 1) { float next, xAdvance; - + glyphStorage.getGlyphPosition(p + 1, next, ignore, success); xAdvance = next - prev; @@ -361,7 +444,7 @@ void LayoutEngine::adjustMarkGlyphs(const LEUnicode chars[], le_int32 charCount, for (p = 0; p < charCount; p += 1, c += direction) { float next, xAdvance; - + glyphStorage.getGlyphPosition(p + 1, next, ignore, success); xAdvance = next - prev; @@ -382,7 +465,7 @@ const void *LayoutEngine::getFontTable(LETag tableTag) const return fFontInstance->getFontTable(tableTag); } -void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, le_bool filterZeroWidth, +void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le_int32 count, le_bool reverse, le_bool mirror, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { @@ -393,7 +476,7 @@ void LayoutEngine::mapCharsToGlyphs(const LEUnicode chars[], le_int32 offset, le DefaultCharMapper charMapper(TRUE, mirror); - fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, filterZeroWidth, glyphStorage); + fFontInstance->mapCharsToGlyphs(chars, offset, count, reverse, &charMapper, fFilterZeroWidth, glyphStorage); } // Input: characters, font? @@ -416,7 +499,7 @@ le_int32 LayoutEngine::layoutChars(const LEUnicode chars[], le_int32 offset, le_ if (fGlyphStorage->getGlyphCount() > 0) { fGlyphStorage->reset(); } - + glyphCount = computeGlyphs(chars, offset, count, max, rightToLeft, *fGlyphStorage, success); positionGlyphs(*fGlyphStorage, x, y, success); adjustGlyphPositions(chars, offset, count, rightToLeft, *fGlyphStorage, success); @@ -428,17 +511,18 @@ void LayoutEngine::reset() { fGlyphStorage->reset(); } - + LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, LEErrorCode &success) { // 3 -> kerning and ligatures return LayoutEngine::layoutEngineFactory(fontInstance, scriptCode, languageCode, 3, success); } - + LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, le_int32 typoFlags, LEErrorCode &success) { static const le_uint32 gsubTableTag = LE_GSUB_TABLE_TAG; static const le_uint32 mortTableTag = LE_MORT_TABLE_TAG; + static const le_uint32 morxTableTag = LE_MORX_TABLE_TAG; if (LE_FAILURE(success)) { return NULL; @@ -448,8 +532,15 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan LayoutEngine *result = NULL; LETag scriptTag = 0x00000000; LETag languageTag = 0x00000000; + LETag v2ScriptTag = OpenTypeLayoutEngine::getV2ScriptTag(scriptCode); + + // Right now, only invoke V2 processing for Devanagari. TODO: Allow more V2 scripts as they are + // properly tested. - if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) { + if ( v2ScriptTag == dev2ScriptTag && gsubTable != NULL && gsubTable->coversScript( v2ScriptTag )) { + result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, TRUE, gsubTable, success); + } + else if (gsubTable != NULL && gsubTable->coversScript(scriptTag = OpenTypeLayoutEngine::getScriptTag(scriptCode))) { switch (scriptCode) { case bengScriptCode: case devaScriptCode: @@ -461,15 +552,20 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan case tamlScriptCode: case teluScriptCode: case sinhScriptCode: - result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); + result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, FALSE, gsubTable, success); break; case arabScriptCode: - result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); + result = new ArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); + break; + + case hebrScriptCode: + // Disable hebrew ligatures since they have only archaic uses, see ticket #8318 + result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags & ~kTypoFlagLiga, gsubTable, success); break; case hangScriptCode: - result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); + result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; case haniScriptCode: @@ -481,71 +577,84 @@ LayoutEngine *LayoutEngine::layoutEngineFactory(const LEFontInstance *fontInstan case zhtLanguageCode: case zhsLanguageCode: if (gsubTable->coversScriptAndLanguage(scriptTag, languageTag, TRUE)) { - result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); + result = new HanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; } // note: falling through to default case. default: - result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); + result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; } break; case tibtScriptCode: - result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); + result = new TibetanOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; case khmrScriptCode: - result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); + result = new KhmerOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; default: - result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable); + result = new OpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, gsubTable, success); break; } } else { - const MorphTableHeader *morphTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); - - if (morphTable != NULL) { - result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, morphTable); + MorphTableHeader2 *morxTable = (MorphTableHeader2 *)fontInstance->getFontTable(morxTableTag); + if (morxTable != NULL) { + result = new GXLayoutEngine2(fontInstance, scriptCode, languageCode, morxTable, typoFlags, success); } else { - switch (scriptCode) { - case bengScriptCode: - case devaScriptCode: - case gujrScriptCode: - case kndaScriptCode: - case mlymScriptCode: - case oryaScriptCode: - case guruScriptCode: - case tamlScriptCode: - case teluScriptCode: - case sinhScriptCode: - { - result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); - break; - } - - case arabScriptCode: - //case hebrScriptCode: - result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); - break; - - //case hebrScriptCode: - // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); - - case thaiScriptCode: - result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); - break; - - default: - result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); - break; + const MorphTableHeader *mortTable = (MorphTableHeader *) fontInstance->getFontTable(mortTableTag); + if (mortTable != NULL) { // mort + result = new GXLayoutEngine(fontInstance, scriptCode, languageCode, mortTable, success); + } else { + switch (scriptCode) { + case bengScriptCode: + case devaScriptCode: + case gujrScriptCode: + case kndaScriptCode: + case mlymScriptCode: + case oryaScriptCode: + case guruScriptCode: + case tamlScriptCode: + case teluScriptCode: + case sinhScriptCode: + { + result = new IndicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + } + + case arabScriptCode: + //case hebrScriptCode: + result = new UnicodeArabicOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + + //case hebrScriptCode: + // return new HebrewOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags); + + case thaiScriptCode: + result = new ThaiLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + + case hangScriptCode: + result = new HangulOpenTypeLayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + + default: + result = new LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success); + break; + } } } } + if (result && LE_FAILURE(success)) { + delete result; + result = NULL; + } + if (result == NULL) { success = LE_MEMORY_ALLOCATION_ERROR; }