From 40199873919fc9478e1766acbbb6b6d795f41c68 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Wed, 4 Jan 2012 08:13:44 -0600 Subject: [PATCH] usp10: Move GSUB functions to opentype.c. --- dlls/usp10/opentype.c | 809 ++++++++++++++++++++++++++++++++++++++++++ dlls/usp10/shape.c | 841 +------------------------------------------- dlls/usp10/usp10_internal.h | 7 + 3 files changed, 827 insertions(+), 830 deletions(-) diff --git a/dlls/usp10/opentype.c b/dlls/usp10/opentype.c index 377558afbd2..c30d5131ede 100644 --- a/dlls/usp10/opentype.c +++ b/dlls/usp10/opentype.c @@ -105,6 +105,178 @@ typedef struct { GDEF_ClassRangeRecord ClassRangeRecord[1]; } GDEF_ClassDefFormat2; +/* These are all structures needed for the GSUB table */ + +typedef struct { + DWORD version; + WORD ScriptList; + WORD FeatureList; + WORD LookupList; +} GSUB_Header; + +typedef struct { + CHAR ScriptTag[4]; + WORD Script; +} GSUB_ScriptRecord; + +typedef struct { + WORD ScriptCount; + GSUB_ScriptRecord ScriptRecord[1]; +} GSUB_ScriptList; + +typedef struct { + CHAR LangSysTag[4]; + WORD LangSys; +} GSUB_LangSysRecord; + +typedef struct { + WORD DefaultLangSys; + WORD LangSysCount; + GSUB_LangSysRecord LangSysRecord[1]; +} GSUB_Script; + +typedef struct { + WORD LookupOrder; /* Reserved */ + WORD ReqFeatureIndex; + WORD FeatureCount; + WORD FeatureIndex[1]; +} GSUB_LangSys; + +typedef struct { + CHAR FeatureTag[4]; + WORD Feature; +} GSUB_FeatureRecord; + +typedef struct { + WORD FeatureCount; + GSUB_FeatureRecord FeatureRecord[1]; +} GSUB_FeatureList; + +typedef struct { + WORD FeatureParams; /* Reserved */ + WORD LookupCount; + WORD LookupListIndex[1]; +} GSUB_Feature; + +typedef struct { + WORD LookupCount; + WORD Lookup[1]; +} GSUB_LookupList; + +typedef struct { + WORD LookupType; + WORD LookupFlag; + WORD SubTableCount; + WORD SubTable[1]; +} GSUB_LookupTable; + +typedef struct { + WORD CoverageFormat; + WORD GlyphCount; + WORD GlyphArray[1]; +} GSUB_CoverageFormat1; + +typedef struct { + WORD Start; + WORD End; + WORD StartCoverageIndex; +} GSUB_RangeRecord; + +typedef struct { + WORD CoverageFormat; + WORD RangeCount; + GSUB_RangeRecord RangeRecord[1]; +} GSUB_CoverageFormat2; + +typedef struct { + WORD SubstFormat; /* = 1 */ + WORD Coverage; + WORD DeltaGlyphID; +} GSUB_SingleSubstFormat1; + +typedef struct { + WORD SubstFormat; /* = 2 */ + WORD Coverage; + WORD GlyphCount; + WORD Substitute[1]; +}GSUB_SingleSubstFormat2; + +typedef struct { + WORD SubstFormat; /* = 1 */ + WORD Coverage; + WORD SequenceCount; + WORD Sequence[1]; +}GSUB_MultipleSubstFormat1; + +typedef struct { + WORD GlyphCount; + WORD Substitute[1]; +}GSUB_Sequence; + +typedef struct { + WORD SubstFormat; /* = 1 */ + WORD Coverage; + WORD LigSetCount; + WORD LigatureSet[1]; +}GSUB_LigatureSubstFormat1; + +typedef struct { + WORD LigatureCount; + WORD Ligature[1]; +}GSUB_LigatureSet; + +typedef struct{ + WORD LigGlyph; + WORD CompCount; + WORD Component[1]; +}GSUB_Ligature; + +typedef struct{ + WORD SequenceIndex; + WORD LookupListIndex; + +}GSUB_SubstLookupRecord; + +typedef struct{ + WORD SubstFormat; /* = 1 */ + WORD Coverage; + WORD ChainSubRuleSetCount; + WORD ChainSubRuleSet[1]; +}GSUB_ChainContextSubstFormat1; + +typedef struct { + WORD SubstFormat; /* = 3 */ + WORD BacktrackGlyphCount; + WORD Coverage[1]; +}GSUB_ChainContextSubstFormat3_1; + +typedef struct{ + WORD InputGlyphCount; + WORD Coverage[1]; +}GSUB_ChainContextSubstFormat3_2; + +typedef struct{ + WORD LookaheadGlyphCount; + WORD Coverage[1]; +}GSUB_ChainContextSubstFormat3_3; + +typedef struct{ + WORD SubstCount; + GSUB_SubstLookupRecord SubstLookupRecord[1]; +}GSUB_ChainContextSubstFormat3_4; + +typedef struct { + WORD SubstFormat; /* = 1 */ + WORD Coverage; + WORD AlternateSetCount; + WORD AlternateSet[1]; +} GSUB_AlternateSubstFormat1; + +typedef struct{ + WORD GlyphCount; + WORD Alternate[1]; +} GSUB_AlternateSet; + /********** * CMAP **********/ @@ -306,3 +478,640 @@ void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGly pGlyphProp[i].sva.fClusterStart = 0; } } + +/********** + * GSUB + **********/ +static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count); + +static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph) +{ + const GSUB_CoverageFormat1* cf1; + + cf1 = table; + + if (GET_BE_WORD(cf1->CoverageFormat) == 1) + { + int count = GET_BE_WORD(cf1->GlyphCount); + int i; + TRACE("Coverage Format 1, %i glyphs\n",count); + for (i = 0; i < count; i++) + if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) + return i; + return -1; + } + else if (GET_BE_WORD(cf1->CoverageFormat) == 2) + { + const GSUB_CoverageFormat2* cf2; + int i; + int count; + cf2 = (const GSUB_CoverageFormat2*)cf1; + + count = GET_BE_WORD(cf2->RangeCount); + TRACE("Coverage Format 2, %i ranges\n",count); + for (i = 0; i < count; i++) + { + if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) + return -1; + if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) && + (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End))) + { + return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) + + glyph - GET_BE_WORD(cf2->RangeRecord[i].Start)); + } + } + return -1; + } + else + ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat)); + + return -1; +} + +static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +{ + int j; + TRACE("Single Substitution Subtable\n"); + + for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) + { + int offset; + const GSUB_SingleSubstFormat1 *ssf1; + offset = GET_BE_WORD(look->SubTable[j]); + ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset); + if (GET_BE_WORD(ssf1->SubstFormat) == 1) + { + int offset = GET_BE_WORD(ssf1->Coverage); + TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID)); + if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1) + { + TRACE(" Glyph 0x%x ->",glyphs[glyph_index]); + glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID); + TRACE(" 0x%x\n",glyphs[glyph_index]); + return glyph_index + write_dir; + } + } + else + { + const GSUB_SingleSubstFormat2 *ssf2; + INT index; + INT offset; + + ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1; + offset = GET_BE_WORD(ssf1->Coverage); + TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount)); + index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]); + TRACE(" Coverage index %i\n",index); + if (index != -1) + { + if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index])) + return GSUB_E_NOGLYPH; + + TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]); + glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]); + TRACE("0x%x\n",glyphs[glyph_index]); + return glyph_index + write_dir; + } + } + } + return GSUB_E_NOGLYPH; +} + +static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +{ + int j; + TRACE("Multiple Substitution Subtable\n"); + + for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) + { + int offset, index; + const GSUB_MultipleSubstFormat1 *msf1; + offset = GET_BE_WORD(look->SubTable[j]); + msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset); + + offset = GET_BE_WORD(msf1->Coverage); + index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]); + if (index != -1) + { + const GSUB_Sequence *seq; + int sub_count; + int j; + offset = GET_BE_WORD(msf1->Sequence[index]); + seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset); + sub_count = GET_BE_WORD(seq->GlyphCount); + TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1)); + + for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--) + glyphs[j] =glyphs[j-(sub_count-1)]; + + for (j = 0; j < sub_count; j++) + if (write_dir < 0) + glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]); + else + glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]); + + *glyph_count = *glyph_count + (sub_count - 1); + + if (TRACE_ON(uniscribe)) + { + for (j = 0; j < sub_count; j++) + TRACE(" 0x%x",glyphs[glyph_index+j]); + TRACE("\n"); + } + + return glyph_index + (sub_count * write_dir); + } + } + return GSUB_E_NOGLYPH; +} + +static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +{ + int j; + TRACE("Alternate Substitution Subtable\n"); + + for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) + { + int offset; + const GSUB_AlternateSubstFormat1 *asf1; + INT index; + + offset = GET_BE_WORD(look->SubTable[j]); + asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset); + offset = GET_BE_WORD(asf1->Coverage); + + index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]); + if (index != -1) + { + const GSUB_AlternateSet *as; + offset = GET_BE_WORD(asf1->AlternateSet[index]); + as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset); + FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount)); + if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0])) + return GSUB_E_NOGLYPH; + + TRACE(" Glyph 0x%x ->",glyphs[glyph_index]); + glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]); + TRACE(" 0x%x\n",glyphs[glyph_index]); + return glyph_index + write_dir; + } + } + return GSUB_E_NOGLYPH; +} + +static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +{ + int j; + + TRACE("Ligature Substitution Subtable\n"); + for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) + { + const GSUB_LigatureSubstFormat1 *lsf1; + int offset,index; + + offset = GET_BE_WORD(look->SubTable[j]); + lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset); + offset = GET_BE_WORD(lsf1->Coverage); + index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]); + TRACE(" Coverage index %i\n",index); + if (index != -1) + { + const GSUB_LigatureSet *ls; + int k, count; + + offset = GET_BE_WORD(lsf1->LigatureSet[index]); + ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset); + count = GET_BE_WORD(ls->LigatureCount); + TRACE(" LigatureSet has %i members\n",count); + for (k = 0; k < count; k++) + { + const GSUB_Ligature *lig; + int CompCount,l,CompIndex; + + offset = GET_BE_WORD(ls->Ligature[k]); + lig = (const GSUB_Ligature*)((const BYTE*)ls+offset); + CompCount = GET_BE_WORD(lig->CompCount) - 1; + CompIndex = glyph_index+write_dir; + for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++) + { + int CompGlyph; + CompGlyph = GET_BE_WORD(lig->Component[l]); + if (CompGlyph != glyphs[CompIndex]) + break; + CompIndex += write_dir; + } + if (l == CompCount) + { + int replaceIdx = glyph_index; + if (write_dir < 0) + replaceIdx = glyph_index - CompCount; + + TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount); + glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph); + TRACE("0x%x\n",glyphs[replaceIdx]); + if (CompCount > 0) + { + int j; + for (j = replaceIdx + 1; j < *glyph_count; j++) + glyphs[j] =glyphs[j+CompCount]; + *glyph_count = *glyph_count - CompCount; + } + return replaceIdx + write_dir; + } + } + } + } + return GSUB_E_NOGLYPH; +} + +static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +{ + int j; + BOOL done = FALSE; + + TRACE("Chaining Contextual Substitution Subtable\n"); + for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++) + { + const GSUB_ChainContextSubstFormat1 *ccsf1; + int offset; + int dirLookahead = write_dir; + int dirBacktrack = -1 * write_dir; + + offset = GET_BE_WORD(look->SubTable[j]); + ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset); + if (GET_BE_WORD(ccsf1->SubstFormat) == 1) + { + FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n"); + continue; + } + else if (GET_BE_WORD(ccsf1->SubstFormat) == 2) + { + FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n"); + continue; + } + else if (GET_BE_WORD(ccsf1->SubstFormat) == 3) + { + int k; + int indexGlyphs; + const GSUB_ChainContextSubstFormat3_1 *ccsf3_1; + const GSUB_ChainContextSubstFormat3_2 *ccsf3_2; + const GSUB_ChainContextSubstFormat3_3 *ccsf3_3; + const GSUB_ChainContextSubstFormat3_4 *ccsf3_4; + int newIndex = glyph_index; + + ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1; + + TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n"); + + for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++) + { + offset = GET_BE_WORD(ccsf3_1->Coverage[k]); + if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1) + break; + } + if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)) + continue; + TRACE("Matched Backtrack\n"); + + ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1))); + + indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount); + for (k = 0; k < indexGlyphs; k++) + { + offset = GET_BE_WORD(ccsf3_2->Coverage[k]); + if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1) + break; + } + if (k != indexGlyphs) + continue; + TRACE("Matched IndexGlyphs\n"); + + ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1))); + + for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++) + { + offset = GET_BE_WORD(ccsf3_3->Coverage[k]); + if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1) + break; + } + if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)) + continue; + TRACE("Matched LookAhead\n"); + + ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1))); + + if (GET_BE_WORD(ccsf3_4->SubstCount)) + { + for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++) + { + int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex); + int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir; + + TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex); + newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count); + if (newIndex == -1) + { + ERR("Chain failed to generate a glyph\n"); + continue; + } + } + return newIndex; + } + else return GSUB_E_NOGLYPH; + } + } + return -1; +} + +static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +{ + int offset; + const GSUB_LookupTable *look; + + offset = GET_BE_WORD(lookup->Lookup[lookup_index]); + look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset); + TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount)); + switch(GET_BE_WORD(look->LookupType)) + { + case 1: + return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count); + case 2: + return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count); + case 3: + return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count); + case 4: + return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count); + case 6: + return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count); + default: + FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType)); + } + return GSUB_E_NOGLYPH; +} + +INT OpenType_apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +{ + const GSUB_Header *header = (const GSUB_Header *)table; + const GSUB_LookupList *lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList)); + + return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count); +} + +static void GSUB_initialize_script_cache(ScriptCache *psc) +{ + int i; + + if (!psc->script_count) + { + const GSUB_ScriptList *script; + const GSUB_Header* header = (const GSUB_Header*)psc->GSUB_Table; + script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList)); + psc->script_count = GET_BE_WORD(script->ScriptCount); + TRACE("initializing %i scripts in this font\n",psc->script_count); + psc->scripts = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LoadedScript) * psc->script_count); + for (i = 0; i < psc->script_count; i++) + { + int offset = GET_BE_WORD(script->ScriptRecord[i].Script); + psc->scripts[i].tag = MS_MAKE_TAG(script->ScriptRecord[i].ScriptTag[0], script->ScriptRecord[i].ScriptTag[1], script->ScriptRecord[i].ScriptTag[2], script->ScriptRecord[i].ScriptTag[3]); + psc->scripts[i].table = ((const BYTE*)script + offset); + } + } +} + +HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table) +{ + int i; + HRESULT rc = S_OK; + + GSUB_initialize_script_cache(psc); + *pcTags = psc->script_count; + + if (!searchingFor && cMaxTags < *pcTags) + rc = E_OUTOFMEMORY; + else if (searchingFor) + rc = USP_E_SCRIPT_NOT_IN_FONT; + + for (i = 0; i < psc->script_count; i++) + { + if (i < cMaxTags) + pScriptTags[i] = psc->scripts[i].tag; + + if (searchingFor) + { + if (searchingFor == psc->scripts[i].tag) + { + pScriptTags[0] = psc->scripts[i].tag; + *pcTags = 1; + if (script_table) + *script_table = psc->scripts[i].table; + rc = S_OK; + break; + } + } + } + return rc; +} + +static void GSUB_initialize_language_cache(LoadedScript *script) +{ + int i; + + if (!script->language_count) + { + const GSUB_Script* table = script->table; + script->language_count = GET_BE_WORD(table->LangSysCount); + script->default_language.tag = MS_MAKE_TAG('d','f','l','t'); + script->default_language.table = (const BYTE*)table + GET_BE_WORD(table->DefaultLangSys); + + TRACE("Deflang %p, LangCount %i\n",script->default_language.table, script->language_count); + + script->languages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LoadedLanguage) * script->language_count); + + for (i = 0; i < script->language_count; i++) + { + int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys); + script->languages[i].tag = MS_MAKE_TAG(table->LangSysRecord[i].LangSysTag[0], table->LangSysRecord[i].LangSysTag[1], table->LangSysRecord[i].LangSysTag[2], table->LangSysRecord[i].LangSysTag[3]); + script->languages[i].table = ((const BYTE*)table + offset); + } + } +} + +HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table) +{ + int i; + HRESULT rc = S_OK; + LoadedScript *script = NULL; + + GSUB_initialize_script_cache(psc); + + for (i = 0; i < psc->script_count; i++) + { + if (psc->scripts[i].tag == script_tag) + { + script = &psc->scripts[i]; + break; + } + } + + if (!script) + return E_INVALIDARG; + + GSUB_initialize_language_cache(script); + + if (!searchingFor && cMaxTags < script->language_count) + rc = E_OUTOFMEMORY; + else if (searchingFor) + rc = E_INVALIDARG; + + *pcTags = script->language_count; + + for (i = 0; i < script->language_count; i++) + { + if (i < cMaxTags) + pLanguageTags[i] = script->languages[i].tag; + + if (searchingFor) + { + if (searchingFor == script->languages[i].tag) + { + pLanguageTags[0] = script->languages[i].tag; + *pcTags = 1; + if (language_table) + *language_table = script->languages[i].table; + rc = S_OK; + break; + } + } + } + + if (script->default_language.table) + { + if (i < cMaxTags) + pLanguageTags[i] = script->default_language.tag; + + if (searchingFor && FAILED(rc)) + { + pLanguageTags[0] = script->default_language.tag; + if (language_table) + *language_table = script->default_language.table; + } + i++; + *pcTags = (*pcTags) + 1; + } + + return rc; +} + + +static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *language) +{ + int i; + + if (!language->feature_count) + { + const GSUB_LangSys *lang= language->table; + const GSUB_Header *header = (const GSUB_Header *)table; + const GSUB_FeatureList *feature_list; + + language->feature_count = GET_BE_WORD(lang->FeatureCount); + TRACE("%i features\n",language->feature_count); + + language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count); + + feature_list = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList)); + + for (i = 0; i < language->feature_count; i++) + { + const GSUB_Feature *feature; + int j; + int index = GET_BE_WORD(lang->FeatureIndex[i]); + + language->features[i].tag = MS_MAKE_TAG(feature_list->FeatureRecord[index].FeatureTag[0], feature_list->FeatureRecord[index].FeatureTag[1], feature_list->FeatureRecord[index].FeatureTag[2], feature_list->FeatureRecord[index].FeatureTag[3]); + language->features[i].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature)); + feature = (const GSUB_Feature*)language->features[i].feature; + language->features[i].lookup_count = GET_BE_WORD(feature->LookupCount); + language->features[i].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[i].lookup_count); + for (j = 0; j < language->features[i].lookup_count; j++) + language->features[i].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]); + } + } +} + +HRESULT OpenType_GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG language_tag, BOOL filtered, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags, LoadedFeature** feature) +{ + int i; + HRESULT rc = S_OK; + LoadedScript *script = NULL; + LoadedLanguage *language = NULL; + + GSUB_initialize_script_cache(psc); + + for (i = 0; i < psc->script_count; i++) + { + if (psc->scripts[i].tag == script_tag) + { + script = &psc->scripts[i]; + break; + } + } + + if (!script) + { + *pcTags = 0; + if (!filtered) + return S_OK; + else + return E_INVALIDARG; + } + + GSUB_initialize_language_cache(script); + + if (script->default_language.table && script->default_language.tag == language_tag) + language = &script->default_language; + else + { + for (i = 0; i < script->language_count; i++) + { + if (script->languages[i].tag == language_tag) + { + language = &script->languages[i]; + break; + } + } + } + + if (!language) + { + *pcTags = 0; + return S_OK; + } + + GSUB_initialize_feature_cache(psc->GSUB_Table, language); + + *pcTags = language->feature_count; + + if (!searchingFor && cMaxTags < *pcTags) + rc = E_OUTOFMEMORY; + else if (searchingFor) + rc = E_INVALIDARG; + + for (i = 0; i < language->feature_count; i++) + { + if (i < cMaxTags) + pFeatureTags[i] = language->features[i].tag; + + if (searchingFor) + { + if (searchingFor == language->features[i].tag) + { + pFeatureTags[0] = language->features[i].tag; + *pcTags = 1; + if (feature) + *feature = &language->features[i]; + rc = S_OK; + break; + } + } + } + return rc; +} diff --git a/dlls/usp10/shape.c b/dlls/usp10/shape.c index 151f9a4a48d..5f71d6cff19 100644 --- a/dlls/usp10/shape.c +++ b/dlls/usp10/shape.c @@ -100,194 +100,6 @@ enum joined_forms { Afx }; -#ifdef WORDS_BIGENDIAN -#define GET_BE_WORD(x) (x) -#define GET_BE_DWORD(x) (x) -#else -#define GET_BE_WORD(x) RtlUshortByteSwap(x) -#define GET_BE_DWORD(x) RtlUlongByteSwap(x) -#endif - -/* These are all structures needed for the GSUB table */ -#define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B') -#define GSUB_E_NOFEATURE -2 -#define GSUB_E_NOGLYPH -1 - -typedef struct { - DWORD version; - WORD ScriptList; - WORD FeatureList; - WORD LookupList; -} GSUB_Header; - -typedef struct { - CHAR ScriptTag[4]; - WORD Script; -} GSUB_ScriptRecord; - -typedef struct { - WORD ScriptCount; - GSUB_ScriptRecord ScriptRecord[1]; -} GSUB_ScriptList; - -typedef struct { - CHAR LangSysTag[4]; - WORD LangSys; -} GSUB_LangSysRecord; - -typedef struct { - WORD DefaultLangSys; - WORD LangSysCount; - GSUB_LangSysRecord LangSysRecord[1]; -} GSUB_Script; - -typedef struct { - WORD LookupOrder; /* Reserved */ - WORD ReqFeatureIndex; - WORD FeatureCount; - WORD FeatureIndex[1]; -} GSUB_LangSys; - -typedef struct { - CHAR FeatureTag[4]; - WORD Feature; -} GSUB_FeatureRecord; - -typedef struct { - WORD FeatureCount; - GSUB_FeatureRecord FeatureRecord[1]; -} GSUB_FeatureList; - -typedef struct { - WORD FeatureParams; /* Reserved */ - WORD LookupCount; - WORD LookupListIndex[1]; -} GSUB_Feature; - -typedef struct { - WORD LookupCount; - WORD Lookup[1]; -} GSUB_LookupList; - -typedef struct { - WORD LookupType; - WORD LookupFlag; - WORD SubTableCount; - WORD SubTable[1]; -} GSUB_LookupTable; - -typedef struct { - WORD CoverageFormat; - WORD GlyphCount; - WORD GlyphArray[1]; -} GSUB_CoverageFormat1; - -typedef struct { - WORD Start; - WORD End; - WORD StartCoverageIndex; -} GSUB_RangeRecord; - -typedef struct { - WORD CoverageFormat; - WORD RangeCount; - GSUB_RangeRecord RangeRecord[1]; -} GSUB_CoverageFormat2; - -typedef struct { - WORD SubstFormat; /* = 1 */ - WORD Coverage; - WORD DeltaGlyphID; -} GSUB_SingleSubstFormat1; - -typedef struct { - WORD SubstFormat; /* = 2 */ - WORD Coverage; - WORD GlyphCount; - WORD Substitute[1]; -}GSUB_SingleSubstFormat2; - -typedef struct { - WORD SubstFormat; /* = 1 */ - WORD Coverage; - WORD SequenceCount; - WORD Sequence[1]; -}GSUB_MultipleSubstFormat1; - -typedef struct { - WORD GlyphCount; - WORD Substitute[1]; -}GSUB_Sequence; - -typedef struct { - WORD SubstFormat; /* = 1 */ - WORD Coverage; - WORD LigSetCount; - WORD LigatureSet[1]; -}GSUB_LigatureSubstFormat1; - -typedef struct { - WORD LigatureCount; - WORD Ligature[1]; -}GSUB_LigatureSet; - -typedef struct{ - WORD LigGlyph; - WORD CompCount; - WORD Component[1]; -}GSUB_Ligature; - -typedef struct{ - WORD SequenceIndex; - WORD LookupListIndex; - -}GSUB_SubstLookupRecord; - -typedef struct{ - WORD SubstFormat; /* = 1 */ - WORD Coverage; - WORD ChainSubRuleSetCount; - WORD ChainSubRuleSet[1]; -}GSUB_ChainContextSubstFormat1; - -typedef struct { - WORD SubstFormat; /* = 3 */ - WORD BacktrackGlyphCount; - WORD Coverage[1]; -}GSUB_ChainContextSubstFormat3_1; - -typedef struct{ - WORD InputGlyphCount; - WORD Coverage[1]; -}GSUB_ChainContextSubstFormat3_2; - -typedef struct{ - WORD LookaheadGlyphCount; - WORD Coverage[1]; -}GSUB_ChainContextSubstFormat3_3; - -typedef struct{ - WORD SubstCount; - GSUB_SubstLookupRecord SubstLookupRecord[1]; -}GSUB_ChainContextSubstFormat3_4; - -typedef struct { - WORD SubstFormat; /* = 1 */ - WORD Coverage; - WORD AlternateSetCount; - WORD AlternateSet[1]; -} GSUB_AlternateSubstFormat1; - -typedef struct{ - WORD GlyphCount; - WORD Alternate[1]; -} GSUB_AlternateSet; - -static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count); -static HRESULT GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table); -static HRESULT GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table); -static HRESULT GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG language_tag, BOOL filtered, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags, LoadedFeature** feature); - typedef struct tagVowelComponents { WCHAR base; @@ -661,379 +473,6 @@ static const ScriptShapeData ShapingData[] = extern scriptData scriptInformation[]; -static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph) -{ - const GSUB_CoverageFormat1* cf1; - - cf1 = table; - - if (GET_BE_WORD(cf1->CoverageFormat) == 1) - { - int count = GET_BE_WORD(cf1->GlyphCount); - int i; - TRACE("Coverage Format 1, %i glyphs\n",count); - for (i = 0; i < count; i++) - if (glyph == GET_BE_WORD(cf1->GlyphArray[i])) - return i; - return -1; - } - else if (GET_BE_WORD(cf1->CoverageFormat) == 2) - { - const GSUB_CoverageFormat2* cf2; - int i; - int count; - cf2 = (const GSUB_CoverageFormat2*)cf1; - - count = GET_BE_WORD(cf2->RangeCount); - TRACE("Coverage Format 2, %i ranges\n",count); - for (i = 0; i < count; i++) - { - if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start)) - return -1; - if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) && - (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End))) - { - return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) + - glyph - GET_BE_WORD(cf2->RangeRecord[i].Start)); - } - } - return -1; - } - else - ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat)); - - return -1; -} - -static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) -{ - int j; - TRACE("Single Substitution Subtable\n"); - - for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) - { - int offset; - const GSUB_SingleSubstFormat1 *ssf1; - offset = GET_BE_WORD(look->SubTable[j]); - ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset); - if (GET_BE_WORD(ssf1->SubstFormat) == 1) - { - int offset = GET_BE_WORD(ssf1->Coverage); - TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID)); - if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1) - { - TRACE(" Glyph 0x%x ->",glyphs[glyph_index]); - glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID); - TRACE(" 0x%x\n",glyphs[glyph_index]); - return glyph_index + write_dir; - } - } - else - { - const GSUB_SingleSubstFormat2 *ssf2; - INT index; - INT offset; - - ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1; - offset = GET_BE_WORD(ssf1->Coverage); - TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount)); - index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]); - TRACE(" Coverage index %i\n",index); - if (index != -1) - { - if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index])) - return GSUB_E_NOGLYPH; - - TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]); - glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]); - TRACE("0x%x\n",glyphs[glyph_index]); - return glyph_index + write_dir; - } - } - } - return GSUB_E_NOGLYPH; -} - -static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) -{ - int j; - TRACE("Multiple Substitution Subtable\n"); - - for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) - { - int offset, index; - const GSUB_MultipleSubstFormat1 *msf1; - offset = GET_BE_WORD(look->SubTable[j]); - msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset); - - offset = GET_BE_WORD(msf1->Coverage); - index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]); - if (index != -1) - { - const GSUB_Sequence *seq; - int sub_count; - int j; - offset = GET_BE_WORD(msf1->Sequence[index]); - seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset); - sub_count = GET_BE_WORD(seq->GlyphCount); - TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1)); - - for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--) - glyphs[j] =glyphs[j-(sub_count-1)]; - - for (j = 0; j < sub_count; j++) - if (write_dir < 0) - glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]); - else - glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]); - - *glyph_count = *glyph_count + (sub_count - 1); - - if (TRACE_ON(uniscribe)) - { - for (j = 0; j < sub_count; j++) - TRACE(" 0x%x",glyphs[glyph_index+j]); - TRACE("\n"); - } - - return glyph_index + (sub_count * write_dir); - } - } - return GSUB_E_NOGLYPH; -} - -static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) -{ - int j; - TRACE("Alternate Substitution Subtable\n"); - - for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) - { - int offset; - const GSUB_AlternateSubstFormat1 *asf1; - INT index; - - offset = GET_BE_WORD(look->SubTable[j]); - asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset); - offset = GET_BE_WORD(asf1->Coverage); - - index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]); - if (index != -1) - { - const GSUB_AlternateSet *as; - offset = GET_BE_WORD(asf1->AlternateSet[index]); - as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset); - FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount)); - if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0])) - return GSUB_E_NOGLYPH; - - TRACE(" Glyph 0x%x ->",glyphs[glyph_index]); - glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]); - TRACE(" 0x%x\n",glyphs[glyph_index]); - return glyph_index + write_dir; - } - } - return GSUB_E_NOGLYPH; -} - -static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) -{ - int j; - - TRACE("Ligature Substitution Subtable\n"); - for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++) - { - const GSUB_LigatureSubstFormat1 *lsf1; - int offset,index; - - offset = GET_BE_WORD(look->SubTable[j]); - lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset); - offset = GET_BE_WORD(lsf1->Coverage); - index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]); - TRACE(" Coverage index %i\n",index); - if (index != -1) - { - const GSUB_LigatureSet *ls; - int k, count; - - offset = GET_BE_WORD(lsf1->LigatureSet[index]); - ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset); - count = GET_BE_WORD(ls->LigatureCount); - TRACE(" LigatureSet has %i members\n",count); - for (k = 0; k < count; k++) - { - const GSUB_Ligature *lig; - int CompCount,l,CompIndex; - - offset = GET_BE_WORD(ls->Ligature[k]); - lig = (const GSUB_Ligature*)((const BYTE*)ls+offset); - CompCount = GET_BE_WORD(lig->CompCount) - 1; - CompIndex = glyph_index+write_dir; - for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++) - { - int CompGlyph; - CompGlyph = GET_BE_WORD(lig->Component[l]); - if (CompGlyph != glyphs[CompIndex]) - break; - CompIndex += write_dir; - } - if (l == CompCount) - { - int replaceIdx = glyph_index; - if (write_dir < 0) - replaceIdx = glyph_index - CompCount; - - TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount); - glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph); - TRACE("0x%x\n",glyphs[replaceIdx]); - if (CompCount > 0) - { - int j; - for (j = replaceIdx + 1; j < *glyph_count; j++) - glyphs[j] =glyphs[j+CompCount]; - *glyph_count = *glyph_count - CompCount; - } - return replaceIdx + write_dir; - } - } - } - } - return GSUB_E_NOGLYPH; -} - -static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) -{ - int j; - BOOL done = FALSE; - - TRACE("Chaining Contextual Substitution Subtable\n"); - for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++) - { - const GSUB_ChainContextSubstFormat1 *ccsf1; - int offset; - int dirLookahead = write_dir; - int dirBacktrack = -1 * write_dir; - - offset = GET_BE_WORD(look->SubTable[j]); - ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset); - if (GET_BE_WORD(ccsf1->SubstFormat) == 1) - { - FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n"); - continue; - } - else if (GET_BE_WORD(ccsf1->SubstFormat) == 2) - { - FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n"); - continue; - } - else if (GET_BE_WORD(ccsf1->SubstFormat) == 3) - { - int k; - int indexGlyphs; - const GSUB_ChainContextSubstFormat3_1 *ccsf3_1; - const GSUB_ChainContextSubstFormat3_2 *ccsf3_2; - const GSUB_ChainContextSubstFormat3_3 *ccsf3_3; - const GSUB_ChainContextSubstFormat3_4 *ccsf3_4; - int newIndex = glyph_index; - - ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1; - - TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n"); - - for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++) - { - offset = GET_BE_WORD(ccsf3_1->Coverage[k]); - if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1) - break; - } - if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)) - continue; - TRACE("Matched Backtrack\n"); - - ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1))); - - indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount); - for (k = 0; k < indexGlyphs; k++) - { - offset = GET_BE_WORD(ccsf3_2->Coverage[k]); - if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1) - break; - } - if (k != indexGlyphs) - continue; - TRACE("Matched IndexGlyphs\n"); - - ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1))); - - for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++) - { - offset = GET_BE_WORD(ccsf3_3->Coverage[k]); - if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1) - break; - } - if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)) - continue; - TRACE("Matched LookAhead\n"); - - ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1))); - - if (GET_BE_WORD(ccsf3_4->SubstCount)) - { - for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++) - { - int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex); - int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir; - - TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex); - newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count); - if (newIndex == -1) - { - ERR("Chain failed to generate a glyph\n"); - continue; - } - } - return newIndex; - } - else return GSUB_E_NOGLYPH; - } - } - return -1; -} - -static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) -{ - int offset; - const GSUB_LookupTable *look; - - offset = GET_BE_WORD(lookup->Lookup[lookup_index]); - look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset); - TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount)); - switch(GET_BE_WORD(look->LookupType)) - { - case 1: - return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count); - case 2: - return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count); - case 3: - return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count); - case 4: - return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count); - case 6: - return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count); - default: - FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType)); - } - return GSUB_E_NOGLYPH; -} - -static INT apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) -{ - const GSUB_Header *header = (const GSUB_Header *)table; - const GSUB_LookupList *lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList)); - - return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count); -} - static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) { int i; @@ -1042,7 +481,7 @@ static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature TRACE("%i lookups\n", feature->lookup_count); for (i = 0; i < feature->lookup_count; i++) { - out_index = apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count); + out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count); if (out_index != GSUB_E_NOGLYPH) break; } @@ -1122,13 +561,13 @@ static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCac language = MS_MAKE_TAG('d','f','l','t'); attempt--; - GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature); + OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature); } while(attempt && !feature); /* try in the default (latin) table */ if (!feature) - GSUB_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature); + OpenType_GSUB_GetFontFeatureTags(psc, MS_MAKE_TAG('l','a','t','n'), MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature); } TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature); @@ -1150,11 +589,11 @@ static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCach static VOID *load_gsub_table(HDC hdc) { VOID* GSUB_Table = NULL; - int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0); + int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0); if (length != GDI_ERROR) { GSUB_Table = HeapAlloc(GetProcessHeap(),0,length); - GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length); + GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length); TRACE("Loaded GSUB table of %i bytes\n",length); } return GSUB_Table; @@ -1322,7 +761,7 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W INT nextIndex; INT prevCount = *pcGlyphs; - nextIndex = apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs); + nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs); if (*pcGlyphs != prevCount) { UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust); @@ -1343,7 +782,7 @@ static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc) HRESULT hr; int count = 0; - hr = GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL); + hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL); return(SUCCEEDED(hr)); } @@ -3432,264 +2871,6 @@ HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANA return USP_E_SCRIPT_NOT_IN_FONT; } -static void GSUB_initialize_script_cache(ScriptCache *psc) -{ - int i; - - if (!psc->script_count) - { - const GSUB_ScriptList *script; - const GSUB_Header* header = (const GSUB_Header*)psc->GSUB_Table; - script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList)); - psc->script_count = GET_BE_WORD(script->ScriptCount); - TRACE("initializing %i scripts in this font\n",psc->script_count); - psc->scripts = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LoadedScript) * psc->script_count); - for (i = 0; i < psc->script_count; i++) - { - int offset = GET_BE_WORD(script->ScriptRecord[i].Script); - psc->scripts[i].tag = MS_MAKE_TAG(script->ScriptRecord[i].ScriptTag[0], script->ScriptRecord[i].ScriptTag[1], script->ScriptRecord[i].ScriptTag[2], script->ScriptRecord[i].ScriptTag[3]); - psc->scripts[i].table = ((const BYTE*)script + offset); - } - } -} - -static HRESULT GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table) -{ - int i; - HRESULT rc = S_OK; - - GSUB_initialize_script_cache(psc); - *pcTags = psc->script_count; - - if (!searchingFor && cMaxTags < *pcTags) - rc = E_OUTOFMEMORY; - else if (searchingFor) - rc = USP_E_SCRIPT_NOT_IN_FONT; - - for (i = 0; i < psc->script_count; i++) - { - if (i < cMaxTags) - pScriptTags[i] = psc->scripts[i].tag; - - if (searchingFor) - { - if (searchingFor == psc->scripts[i].tag) - { - pScriptTags[0] = psc->scripts[i].tag; - *pcTags = 1; - if (script_table) - *script_table = psc->scripts[i].table; - rc = S_OK; - break; - } - } - } - return rc; -} - -static void GSUB_initialize_language_cache(LoadedScript *script) -{ - int i; - - if (!script->language_count) - { - const GSUB_Script* table = script->table; - script->language_count = GET_BE_WORD(table->LangSysCount); - script->default_language.tag = MS_MAKE_TAG('d','f','l','t'); - script->default_language.table = (const BYTE*)table + GET_BE_WORD(table->DefaultLangSys); - - TRACE("Deflang %p, LangCount %i\n",script->default_language.table, script->language_count); - - script->languages = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(LoadedLanguage) * script->language_count); - - for (i = 0; i < script->language_count; i++) - { - int offset = GET_BE_WORD(table->LangSysRecord[i].LangSys); - script->languages[i].tag = MS_MAKE_TAG(table->LangSysRecord[i].LangSysTag[0], table->LangSysRecord[i].LangSysTag[1], table->LangSysRecord[i].LangSysTag[2], table->LangSysRecord[i].LangSysTag[3]); - script->languages[i].table = ((const BYTE*)table + offset); - } - } -} - -static HRESULT GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table) -{ - int i; - HRESULT rc = S_OK; - LoadedScript *script = NULL; - - GSUB_initialize_script_cache(psc); - - for (i = 0; i < psc->script_count; i++) - { - if (psc->scripts[i].tag == script_tag) - { - script = &psc->scripts[i]; - break; - } - } - - if (!script) - return E_INVALIDARG; - - GSUB_initialize_language_cache(script); - - if (!searchingFor && cMaxTags < script->language_count) - rc = E_OUTOFMEMORY; - else if (searchingFor) - rc = E_INVALIDARG; - - *pcTags = script->language_count; - - for (i = 0; i < script->language_count; i++) - { - if (i < cMaxTags) - pLanguageTags[i] = script->languages[i].tag; - - if (searchingFor) - { - if (searchingFor == script->languages[i].tag) - { - pLanguageTags[0] = script->languages[i].tag; - *pcTags = 1; - if (language_table) - *language_table = script->languages[i].table; - rc = S_OK; - break; - } - } - } - - if (script->default_language.table) - { - if (i < cMaxTags) - pLanguageTags[i] = script->default_language.tag; - - if (searchingFor && FAILED(rc)) - { - pLanguageTags[0] = script->default_language.tag; - if (language_table) - *language_table = script->default_language.table; - } - i++; - *pcTags = (*pcTags) + 1; - } - - return rc; -} - -static void GSUB_initialize_feature_cache(LPCVOID table, LoadedLanguage *language) -{ - int i; - - if (!language->feature_count) - { - const GSUB_LangSys *lang= language->table; - const GSUB_Header *header = (const GSUB_Header *)table; - const GSUB_FeatureList *feature_list; - - language->feature_count = GET_BE_WORD(lang->FeatureCount); - TRACE("%i features\n",language->feature_count); - - language->features = HeapAlloc(GetProcessHeap(),0,sizeof(LoadedFeature)*language->feature_count); - - feature_list = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList)); - - for (i = 0; i < language->feature_count; i++) - { - const GSUB_Feature *feature; - int j; - int index = GET_BE_WORD(lang->FeatureIndex[i]); - - language->features[i].tag = MS_MAKE_TAG(feature_list->FeatureRecord[index].FeatureTag[0], feature_list->FeatureRecord[index].FeatureTag[1], feature_list->FeatureRecord[index].FeatureTag[2], feature_list->FeatureRecord[index].FeatureTag[3]); - language->features[i].feature = ((const BYTE*)feature_list + GET_BE_WORD(feature_list->FeatureRecord[index].Feature)); - feature = (const GSUB_Feature*)language->features[i].feature; - language->features[i].lookup_count = GET_BE_WORD(feature->LookupCount); - language->features[i].lookups = HeapAlloc(GetProcessHeap(),0,sizeof(WORD) * language->features[i].lookup_count); - for (j = 0; j < language->features[i].lookup_count; j++) - language->features[i].lookups[j] = GET_BE_WORD(feature->LookupListIndex[j]); - } - } -} - -static HRESULT GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG language_tag, BOOL filtered, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags, LoadedFeature** feature) -{ - int i; - HRESULT rc = S_OK; - LoadedScript *script = NULL; - LoadedLanguage *language = NULL; - - GSUB_initialize_script_cache(psc); - - for (i = 0; i < psc->script_count; i++) - { - if (psc->scripts[i].tag == script_tag) - { - script = &psc->scripts[i]; - break; - } - } - - if (!script) - { - *pcTags = 0; - if (!filtered) - return S_OK; - else - return E_INVALIDARG; - } - - GSUB_initialize_language_cache(script); - - if (script->default_language.table && script->default_language.tag == language_tag) - language = &script->default_language; - else - { - for (i = 0; i < script->language_count; i++) - { - if (script->languages[i].tag == language_tag) - { - language = &script->languages[i]; - break; - } - } - } - - if (!language) - { - *pcTags = 0; - return S_OK; - } - - GSUB_initialize_feature_cache(psc->GSUB_Table, language); - - *pcTags = language->feature_count; - - if (!searchingFor && cMaxTags < *pcTags) - rc = E_OUTOFMEMORY; - else if (searchingFor) - rc = E_INVALIDARG; - - for (i = 0; i < language->feature_count; i++) - { - if (i < cMaxTags) - pFeatureTags[i] = language->features[i].tag; - - if (searchingFor) - { - if (searchingFor == language->features[i].tag) - { - pFeatureTags[0] = language->features[i].tag; - *pcTags = 1; - if (feature) - *feature = &language->features[i]; - rc = S_OK; - break; - } - } - } - return rc; -} - HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags) @@ -3703,7 +2884,7 @@ HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc, if (psa && scriptInformation[psa->eScript].scriptTag) searching = scriptInformation[psa->eScript].scriptTag; - hr = GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL); + hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL); if (FAILED(hr)) *pcTags = 0; return hr; @@ -3724,11 +2905,11 @@ HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc, if (psa && psc->userLang != 0) searching = psc->userLang; - hr = GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL); + hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL); if (FAILED(hr)) { fellback = TRUE; - hr = GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL); + hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL); } if (FAILED(hr) || fellback) @@ -3755,7 +2936,7 @@ HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc, filter = TRUE; } - hr = GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL); + hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL); if (FAILED(hr)) *pcTags = 0; diff --git a/dlls/usp10/usp10_internal.h b/dlls/usp10/usp10_internal.h index 2df8a69519d..02beaf628dc 100644 --- a/dlls/usp10/usp10_internal.h +++ b/dlls/usp10/usp10_internal.h @@ -125,6 +125,9 @@ #define GLYPH_BLOCK_MASK (GLYPH_BLOCK_SIZE - 1) #define GLYPH_MAX 65536 +#define GSUB_E_NOFEATURE -2 +#define GSUB_E_NOGLYPH -1 + typedef struct { OPENTYPE_TAG tag; LPCVOID feature; @@ -223,3 +226,7 @@ void BREAK_line(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWORD pgi, DWORD flags) DECLSPEC_HIDDEN; void OpenType_GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp) DECLSPEC_HIDDEN; +INT OpenType_apply_GSUB_lookup(LPCVOID table, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) DECLSPEC_HIDDEN; +HRESULT OpenType_GSUB_GetFontScriptTags(ScriptCache *psc, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags, LPCVOID* script_table) DECLSPEC_HIDDEN; +HRESULT OpenType_GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pLanguageTags, int *pcTags, LPCVOID* language_table) DECLSPEC_HIDDEN; +HRESULT OpenType_GSUB_GetFontFeatureTags(ScriptCache *psc, OPENTYPE_TAG script_tag, OPENTYPE_TAG language_tag, BOOL filtered, OPENTYPE_TAG searchingFor, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags, LoadedFeature** feature) DECLSPEC_HIDDEN; -- 2.11.4.GIT