X-Git-Url: https://git.saurik.com/apple/icu.git/blobdiff_plain/73c04bcfe1096173b00431f0cdc742894b15eef0..151279e3792e85d0417b499c229886b3af724f55:/icuSources/layout/OpenTypeLayoutEngine.cpp diff --git a/icuSources/layout/OpenTypeLayoutEngine.cpp b/icuSources/layout/OpenTypeLayoutEngine.cpp index fbbfc0e6..c89c05c0 100644 --- a/icuSources/layout/OpenTypeLayoutEngine.cpp +++ b/icuSources/layout/OpenTypeLayoutEngine.cpp @@ -1,7 +1,7 @@ /* * - * (C) Copyright IBM Corp. 1998-2006 - All Rights Reserved + * (C) Copyright IBM Corp. and others 1998-2013 - All Rights Reserved * */ @@ -10,6 +10,7 @@ #include "LELanguages.h" #include "LayoutEngine.h" +#include "CanonShaping.h" #include "OpenTypeLayoutEngine.h" #include "ScriptAndLanguageTags.h" #include "CharSubstitutionFilter.h" @@ -23,6 +24,8 @@ #include "GDEFMarkFilter.h" +#include "KernTable.h" + U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine) @@ -33,12 +36,30 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine) #define kernFeatureTag LE_KERN_FEATURE_TAG #define markFeatureTag LE_MARK_FEATURE_TAG #define mkmkFeatureTag LE_MKMK_FEATURE_TAG - -// 'dlig' not used at the moment -#define dligFeatureTag 0x646C6967 - -// 'palt' -#define paltFeatureTag 0x70616C74 +#define loclFeatureTag LE_LOCL_FEATURE_TAG +#define caltFeatureTag LE_CALT_FEATURE_TAG + +#define dligFeatureTag LE_DLIG_FEATURE_TAG +#define rligFeatureTag LE_RLIG_FEATURE_TAG +#define paltFeatureTag LE_PALT_FEATURE_TAG + +#define hligFeatureTag LE_HLIG_FEATURE_TAG +#define smcpFeatureTag LE_SMCP_FEATURE_TAG +#define fracFeatureTag LE_FRAC_FEATURE_TAG +#define afrcFeatureTag LE_AFRC_FEATURE_TAG +#define zeroFeatureTag LE_ZERO_FEATURE_TAG +#define swshFeatureTag LE_SWSH_FEATURE_TAG +#define cswhFeatureTag LE_CSWH_FEATURE_TAG +#define saltFeatureTag LE_SALT_FEATURE_TAG +#define naltFeatureTag LE_NALT_FEATURE_TAG +#define rubyFeatureTag LE_RUBY_FEATURE_TAG +#define ss01FeatureTag LE_SS01_FEATURE_TAG +#define ss02FeatureTag LE_SS02_FEATURE_TAG +#define ss03FeatureTag LE_SS03_FEATURE_TAG +#define ss04FeatureTag LE_SS04_FEATURE_TAG +#define ss05FeatureTag LE_SS05_FEATURE_TAG +#define ss06FeatureTag LE_SS06_FEATURE_TAG +#define ss07FeatureTag LE_SS07_FEATURE_TAG #define ccmpFeatureMask 0x80000000UL #define ligaFeatureMask 0x40000000UL @@ -47,53 +68,141 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OpenTypeLayoutEngine) #define paltFeatureMask 0x08000000UL #define markFeatureMask 0x04000000UL #define mkmkFeatureMask 0x02000000UL - -#define minimalFeatures (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask) -#define ligaFeatures (ligaFeatureMask | cligFeatureMask | minimalFeatures) -#define kernFeatures (kernFeatureMask | paltFeatureMask | minimalFeatures) -#define kernAndLigaFeatures (ligaFeatures | kernFeatures) +#define loclFeatureMask 0x01000000UL +#define caltFeatureMask 0x00800000UL + +#define dligFeatureMask 0x00400000UL +#define rligFeatureMask 0x00200000UL +#define hligFeatureMask 0x00100000UL +#define smcpFeatureMask 0x00080000UL +#define fracFeatureMask 0x00040000UL +#define afrcFeatureMask 0x00020000UL +#define zeroFeatureMask 0x00010000UL +#define swshFeatureMask 0x00008000UL +#define cswhFeatureMask 0x00004000UL +#define saltFeatureMask 0x00002000UL +#define naltFeatureMask 0x00001000UL +#define rubyFeatureMask 0x00000800UL +#define ss01FeatureMask 0x00000400UL +#define ss02FeatureMask 0x00000200UL +#define ss03FeatureMask 0x00000100UL +#define ss04FeatureMask 0x00000080UL +#define ss05FeatureMask 0x00000040UL +#define ss06FeatureMask 0x00000020UL +#define ss07FeatureMask 0x00000010UL + +#define minimalFeatures (ccmpFeatureMask | markFeatureMask | mkmkFeatureMask | loclFeatureMask | caltFeatureMask) static const FeatureMap featureMap[] = { {ccmpFeatureTag, ccmpFeatureMask}, {ligaFeatureTag, ligaFeatureMask}, {cligFeatureTag, cligFeatureMask}, - {kernFeatureTag, kernFeatureMask}, + {kernFeatureTag, kernFeatureMask}, {paltFeatureTag, paltFeatureMask}, {markFeatureTag, markFeatureMask}, - {mkmkFeatureTag, mkmkFeatureMask} + {mkmkFeatureTag, mkmkFeatureMask}, + {loclFeatureTag, loclFeatureMask}, + {caltFeatureTag, caltFeatureMask}, + {hligFeatureTag, hligFeatureMask}, + {smcpFeatureTag, smcpFeatureMask}, + {fracFeatureTag, fracFeatureMask}, + {afrcFeatureTag, afrcFeatureMask}, + {zeroFeatureTag, zeroFeatureMask}, + {swshFeatureTag, swshFeatureMask}, + {cswhFeatureTag, cswhFeatureMask}, + {saltFeatureTag, saltFeatureMask}, + {naltFeatureTag, naltFeatureMask}, + {rubyFeatureTag, rubyFeatureMask}, + {ss01FeatureTag, ss01FeatureMask}, + {ss02FeatureTag, ss02FeatureMask}, + {ss03FeatureTag, ss03FeatureMask}, + {ss04FeatureTag, ss04FeatureMask}, + {ss05FeatureTag, ss05FeatureMask}, + {ss06FeatureTag, ss06FeatureMask}, + {ss07FeatureTag, ss07FeatureMask} }; static const le_int32 featureMapCount = LE_ARRAY_SIZE(featureMap); OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable) - : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags), fFeatureMask(minimalFeatures), + le_int32 typoFlags, const GlyphSubstitutionTableHeader *gsubTable, LEErrorCode &success) + : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureMask(minimalFeatures), fFeatureMap(featureMap), fFeatureMapCount(featureMapCount), fFeatureOrder(FALSE), - fGSUBTable(gsubTable), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL), fFilterZeroWidth(TRUE) + fGSUBTable(gsubTable), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) { static const le_uint32 gdefTableTag = LE_GDEF_TABLE_TAG; static const le_uint32 gposTableTag = LE_GPOS_TABLE_TAG; const GlyphPositioningTableHeader *gposTable = (const GlyphPositioningTableHeader *) getFontTable(gposTableTag); - // todo: switch to more flags and bitfield rather than list of feature tags? - switch (typoFlags & ~0x80000000L) { - case 0: break; // default - case 1: fFeatureMask = kernFeatures; break; - case 2: fFeatureMask = ligaFeatures; break; - case 3: fFeatureMask = kernAndLigaFeatures; break; - default: break; + switch (typoFlags & (LE_SS01_FEATURE_FLAG + | LE_SS02_FEATURE_FLAG + | LE_SS03_FEATURE_FLAG + | LE_SS04_FEATURE_FLAG + | LE_SS05_FEATURE_FLAG + | LE_SS06_FEATURE_FLAG + | LE_SS07_FEATURE_FLAG)) { + case LE_SS01_FEATURE_FLAG: + fFeatureMask |= ss01FeatureMask; + break; + case LE_SS02_FEATURE_FLAG: + fFeatureMask |= ss02FeatureMask; + break; + case LE_SS03_FEATURE_FLAG: + fFeatureMask |= ss03FeatureMask; + break; + case LE_SS04_FEATURE_FLAG: + fFeatureMask |= ss04FeatureMask; + break; + case LE_SS05_FEATURE_FLAG: + fFeatureMask |= ss05FeatureMask; + break; + case LE_SS06_FEATURE_FLAG: + fFeatureMask |= ss06FeatureMask; + break; + case LE_SS07_FEATURE_FLAG: + fFeatureMask |= ss07FeatureMask; + break; + } + + if (typoFlags & LE_Kerning_FEATURE_FLAG) { + fFeatureMask |= (kernFeatureMask | paltFeatureMask); + // Convenience. + } + if (typoFlags & LE_Ligatures_FEATURE_FLAG) { + fFeatureMask |= (ligaFeatureMask | cligFeatureMask); + // Convenience TODO: should add: .. dligFeatureMask | rligFeatureMask ? + } + if (typoFlags & LE_CLIG_FEATURE_FLAG) fFeatureMask |= cligFeatureMask; + if (typoFlags & LE_DLIG_FEATURE_FLAG) fFeatureMask |= dligFeatureMask; + if (typoFlags & LE_HLIG_FEATURE_FLAG) fFeatureMask |= hligFeatureMask; + if (typoFlags & LE_LIGA_FEATURE_FLAG) fFeatureMask |= ligaFeatureMask; + if (typoFlags & LE_RLIG_FEATURE_FLAG) fFeatureMask |= rligFeatureMask; + if (typoFlags & LE_SMCP_FEATURE_FLAG) fFeatureMask |= smcpFeatureMask; + if (typoFlags & LE_FRAC_FEATURE_FLAG) fFeatureMask |= fracFeatureMask; + if (typoFlags & LE_AFRC_FEATURE_FLAG) fFeatureMask |= afrcFeatureMask; + if (typoFlags & LE_ZERO_FEATURE_FLAG) fFeatureMask |= zeroFeatureMask; + if (typoFlags & LE_SWSH_FEATURE_FLAG) fFeatureMask |= swshFeatureMask; + if (typoFlags & LE_CSWH_FEATURE_FLAG) fFeatureMask |= cswhFeatureMask; + if (typoFlags & LE_SALT_FEATURE_FLAG) fFeatureMask |= saltFeatureMask; + if (typoFlags & LE_RUBY_FEATURE_FLAG) fFeatureMask |= rubyFeatureMask; + if (typoFlags & LE_NALT_FEATURE_FLAG) { + // Mutually exclusive with ALL other features. http://www.microsoft.com/typography/otspec/features_ko.htm + fFeatureMask = naltFeatureMask; } - if (typoFlags & 0x80000000L) { - fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); + if (typoFlags & LE_CHAR_FILTER_FEATURE_FLAG) { + // This isn't a font feature, but requests a Char Substitution Filter + fSubstitutionFilter = new CharSubstitutionFilter(fontInstance); } setScriptAndLanguageTags(); fGDEFTable = (const GlyphDefinitionTableHeader *) getFontTable(gdefTableTag); - if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) { +// JK patch, 2008-05-30 - see Sinhala bug report and LKLUG font +// if (gposTable != NULL && gposTable->coversScriptAndLanguage(fScriptTag, fLangSysTag)) { + if (gposTable != NULL && gposTable->coversScript(fScriptTag)) { fGPOSTable = gposTable; } } @@ -108,9 +217,9 @@ void OpenTypeLayoutEngine::reset() } OpenTypeLayoutEngine::OpenTypeLayoutEngine(const LEFontInstance *fontInstance, le_int32 scriptCode, le_int32 languageCode, - le_int32 typoFlags) - : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags), fFeatureOrder(FALSE), - fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL), fFilterZeroWidth(TRUE) + le_int32 typoFlags, LEErrorCode &success) + : LayoutEngine(fontInstance, scriptCode, languageCode, typoFlags, success), fFeatureOrder(FALSE), + fGSUBTable(NULL), fGDEFTable(NULL), fGPOSTable(NULL), fSubstitutionFilter(NULL) { setScriptAndLanguageTags(); } @@ -129,10 +238,25 @@ LETag OpenTypeLayoutEngine::getScriptTag(le_int32 scriptCode) if (scriptCode < 0 || scriptCode >= scriptCodeCount) { return 0xFFFFFFFF; } - return scriptTags[scriptCode]; } +LETag OpenTypeLayoutEngine::getV2ScriptTag(le_int32 scriptCode) +{ + switch (scriptCode) { + case bengScriptCode : return bng2ScriptTag; + case devaScriptCode : return dev2ScriptTag; + case gujrScriptCode : return gjr2ScriptTag; + case guruScriptCode : return gur2ScriptTag; + case kndaScriptCode : return knd2ScriptTag; + case mlymScriptCode : return mlm2ScriptTag; + case oryaScriptCode : return ory2ScriptTag; + case tamlScriptCode : return tml2ScriptTag; + case teluScriptCode : return tel2ScriptTag; + default: return nullScriptTag; + } +} + LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode) { if (languageCode < 0 || languageCode >= languageCodeCount) { @@ -145,6 +269,7 @@ LETag OpenTypeLayoutEngine::getLangSysTag(le_int32 languageCode) void OpenTypeLayoutEngine::setScriptAndLanguageTags() { fScriptTag = getScriptTag(fScriptCode); + fScriptTagV2 = getV2ScriptTag(fScriptCode); fLangSysTag = getLangSysTag(fLanguageCode); } @@ -160,20 +285,39 @@ le_int32 OpenTypeLayoutEngine::characterProcessing(const LEUnicode chars[], le_i return 0; } - le_int32 outCharCount = LayoutEngine::characterProcessing(chars, offset, count, max, rightToLeft, outChars, glyphStorage, success); + // This is the cheapest way to get mark reordering only for Hebrew. + // We could just do the mark reordering for all scripts, but most + // of them probably don't need it... Another option would be to + // add a HebrewOpenTypeLayoutEngine subclass, but the only thing it + // would need to do is mark reordering, so that seems like overkill. + if (fScriptCode == hebrScriptCode) { + outChars = LE_NEW_ARRAY(LEUnicode, count); + + if (outChars == NULL) { + success = LE_MEMORY_ALLOCATION_ERROR; + return 0; + } + + if (LE_FAILURE(success)) { + LE_DELETE_ARRAY(outChars); + return 0; + } + + CanonShaping::reorderMarks(&chars[offset], count, rightToLeft, outChars, glyphStorage); + } if (LE_FAILURE(success)) { return 0; } - glyphStorage.allocateGlyphArray(outCharCount, rightToLeft, success); + glyphStorage.allocateGlyphArray(count, rightToLeft, success); glyphStorage.allocateAuxData(success); - for (le_int32 i = 0; i < outCharCount; i += 1) { + for (le_int32 i = 0; i < count; i += 1) { glyphStorage.setAuxData(i, fFeatureMask, success); } - return outCharCount; + return count; } // Input: characters, tags @@ -190,20 +334,52 @@ le_int32 OpenTypeLayoutEngine::glyphProcessing(const LEUnicode chars[], le_int32 return 0; } - mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, fFilterZeroWidth, glyphStorage, success); + mapCharsToGlyphs(chars, offset, count, rightToLeft, rightToLeft, glyphStorage, success); if (LE_FAILURE(success)) { return 0; } - + if (fGSUBTable != NULL) { + if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { + count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, + fFeatureMap, fFeatureMapCount, fFeatureOrder, success); + + } else { count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, - fFeatureMap, fFeatureMapCount, fFeatureOrder); + fFeatureMap, fFeatureMapCount, fFeatureOrder, success); + } } return count; } +// Input: characters, tags +// Output: glyphs, char indices +le_int32 OpenTypeLayoutEngine::glyphSubstitution(le_int32 count, le_int32 max, le_bool rightToLeft, + LEGlyphStorage &glyphStorage, LEErrorCode &success) +{ + if (LE_FAILURE(success)) { + return 0; + } + + if ( count < 0 || max < 0 ) { + success = LE_ILLEGAL_ARGUMENT_ERROR; + return 0; + } + + if (fGSUBTable != NULL) { + if (fScriptTagV2 != nullScriptTag && fGSUBTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { + count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTagV2, fLangSysTag, fGDEFTable, fSubstitutionFilter, + fFeatureMap, fFeatureMapCount, fFeatureOrder, success); + } else { + count = fGSUBTable->process(glyphStorage, rightToLeft, fScriptTag, fLangSysTag, fGDEFTable, fSubstitutionFilter, + fFeatureMap, fFeatureMapCount, fFeatureOrder, success); + } + } + + return count; +} le_int32 OpenTypeLayoutEngine::glyphPostProcessing(LEGlyphStorage &tempGlyphStorage, LEGlyphStorage &glyphStorage, LEErrorCode &success) { if (LE_FAILURE(success)) { @@ -222,7 +398,7 @@ le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 o { LEUnicode *outChars = NULL; LEGlyphStorage fakeGlyphStorage; - le_int32 outCharCount, outGlyphCount, fakeGlyphCount; + le_int32 outCharCount, outGlyphCount; if (LE_FAILURE(success)) { return 0; @@ -240,11 +416,13 @@ le_int32 OpenTypeLayoutEngine::computeGlyphs(const LEUnicode chars[], le_int32 o } if (outChars != NULL) { - fakeGlyphCount = glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success); + // le_int32 fakeGlyphCount = + glyphProcessing(outChars, 0, outCharCount, outCharCount, rightToLeft, fakeGlyphStorage, success); LE_DELETE_ARRAY(outChars); // FIXME: a subclass may have allocated this, in which case this delete might not work... //adjustGlyphs(outChars, 0, outCharCount, rightToLeft, fakeGlyphs, fakeGlyphCount); } else { - fakeGlyphCount = glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success); + // le_int32 fakeGlyphCount = + glyphProcessing(chars, offset, count, max, rightToLeft, fakeGlyphStorage, success); //adjustGlyphs(chars, offset, count, rightToLeft, fakeGlyphs, fakeGlyphCount); } @@ -271,8 +449,11 @@ void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int3 } le_int32 glyphCount = glyphStorage.getGlyphCount(); + if (glyphCount == 0) { + return; + } - if (glyphCount > 0 && fGPOSTable != NULL) { + if (fGPOSTable != NULL) { GlyphPositionAdjustments *adjustments = new GlyphPositionAdjustments(glyphCount); le_int32 i; @@ -295,8 +476,20 @@ void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int3 } #endif - fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, fFontInstance, - fFeatureMap, fFeatureMapCount, fFeatureOrder); + if (fGPOSTable != NULL) { + if (fScriptTagV2 != nullScriptTag && fGPOSTable->coversScriptAndLanguage(fScriptTagV2,fLangSysTag)) { + fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTagV2, fLangSysTag, fGDEFTable, success, fFontInstance, + fFeatureMap, fFeatureMapCount, fFeatureOrder); + + } else { + fGPOSTable->process(glyphStorage, adjustments, reverse, fScriptTag, fLangSysTag, fGDEFTable, success, fFontInstance, + fFeatureMap, fFeatureMapCount, fFeatureOrder); + } + } else if ( fTypoFlags & 0x1 ) { + static const le_uint32 kernTableTag = LE_KERN_TABLE_TAG; + KernTable kt(fFontInstance, getFontTable(kernTableTag)); + kt.process(glyphStorage); + } float xAdjust = 0, yAdjust = 0; @@ -330,6 +523,21 @@ void OpenTypeLayoutEngine::adjustGlyphPositions(const LEUnicode chars[], le_int3 glyphStorage.adjustPosition(glyphCount, xAdjust, -yAdjust, success); delete adjustments; + } else { + // if there was no GPOS table, maybe there's non-OpenType kerning we can use + LayoutEngine::adjustGlyphPositions(chars, offset, count, reverse, glyphStorage, success); + } + + LEGlyphID zwnj = fFontInstance->mapCharToGlyph(0x200C); + + if (zwnj != 0x0000) { + for (le_int32 g = 0; g < glyphCount; g += 1) { + LEGlyphID glyph = glyphStorage[g]; + + if (glyph == zwnj) { + glyphStorage[g] = LE_SET_GLYPH(glyph, 0xFFFF); + } + } } #if 0