From: समीर सिंह Sameer Singh <lumarzeli30@gmail.com> Check if the current number of glyphs exceed the maximum limit and then return an E_OUTOFMEMORY. Modify the functions to bubble this error so that it can be dealt with. --- dlls/gdi32/uniscribe/opentype.c | 39 +++-- dlls/gdi32/uniscribe/shape.c | 205 ++++++++++++++++---------- dlls/gdi32/uniscribe/usp10.c | 9 +- dlls/gdi32/uniscribe/usp10_internal.h | 5 +- 4 files changed, 164 insertions(+), 94 deletions(-) diff --git a/dlls/gdi32/uniscribe/opentype.c b/dlls/gdi32/uniscribe/opentype.c index b2a72b8c3ff..918762e7773 100644 --- a/dlls/gdi32/uniscribe/opentype.c +++ b/dlls/gdi32/uniscribe/opentype.c @@ -813,7 +813,7 @@ void OpenType_GDEF_UpdateGlyphProps(ScriptCache *psc, const WORD *pwGlyphs, cons /********** * GSUB **********/ -static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count); +static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count, INT max_glyphs); static int GSUB_is_glyph_covered(const void *table, unsigned int glyph) { @@ -924,7 +924,7 @@ static INT GSUB_apply_SingleSubst(const OT_LookupTable *look, WORD *glyphs, INT return GSUB_E_NOGLYPH; } -static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count, INT max_glyphs) { int j; TRACE("Multiple Substitution Subtable\n"); @@ -945,6 +945,9 @@ static INT GSUB_apply_MultipleSubst(const OT_LookupTable *look, WORD *glyphs, IN offset = GET_BE_WORD(msf1->Sequence[index]); seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset); sub_count = GET_BE_WORD(seq->GlyphCount); + if (sub_count-1 > max_glyphs-*glyph_count) + return GSUB_E_OUTOFMEMORY; + TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1)); for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--) @@ -1070,7 +1073,7 @@ static INT GSUB_apply_LigatureSubst(const OT_LookupTable *look, WORD *glyphs, IN return GSUB_E_NOGLYPH; } -static INT GSUB_apply_ContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +static INT GSUB_apply_ContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count, INT max_glyphs) { int j; TRACE("Context Substitution Subtable\n"); @@ -1137,7 +1140,9 @@ static INT GSUB_apply_ContextSubst(const OT_LookupList* lookup, const OT_LookupT } TRACE(" SUBST: %u -> %u %u.\n", l, sequence_index, lookup_index); - newIndex = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count); + newIndex = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count, max_glyphs); + if (newIndex == GSUB_E_OUTOFMEMORY) + return GSUB_E_OUTOFMEMORY; if (newIndex == GSUB_E_NOGLYPH) { ERR(" Chain failed to generate a glyph\n"); @@ -1224,7 +1229,9 @@ static INT GSUB_apply_ContextSubst(const OT_LookupList* lookup, const OT_LookupT } TRACE(" SUBST: %u -> %u %u.\n", l, sequence_index, lookup_index); - newIndex = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count); + newIndex = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count, max_glyphs); + if (newIndex == GSUB_E_OUTOFMEMORY) + return GSUB_E_OUTOFMEMORY; if (newIndex == GSUB_E_NOGLYPH) { ERR(" Chain failed to generate a glyph\n"); @@ -1241,7 +1248,7 @@ static INT GSUB_apply_ContextSubst(const OT_LookupList* lookup, const OT_LookupT return GSUB_E_NOGLYPH; } -static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count, INT max_glyphs) { int j; @@ -1384,7 +1391,9 @@ static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_Lo } TRACE("SUBST: %u -> %u %u.\n", k, sequence_index, lookup_index); - new_index = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count); + new_index = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count, max_glyphs); + if (new_index == GSUB_E_OUTOFMEMORY) + return GSUB_E_OUTOFMEMORY; if (new_index == GSUB_E_NOGLYPH) ERR("Chain failed to generate a glyph.\n"); } @@ -1471,7 +1480,9 @@ static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_Lo } TRACE("SUBST: %u -> %u %u.\n", k, sequence_index, lookup_index); - new_index = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count); + new_index = GSUB_apply_lookup(lookup, lookup_index, glyphs, g, write_dir, glyph_count, max_glyphs); + if (new_index == GSUB_E_OUTOFMEMORY) + return GSUB_E_OUTOFMEMORY; if (new_index == GSUB_E_NOGLYPH) ERR("Chain failed to generate a glyph.\n"); } @@ -1481,7 +1492,7 @@ static INT GSUB_apply_ChainContextSubst(const OT_LookupList* lookup, const OT_Lo return GSUB_E_NOGLYPH; } -static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count) +static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count, INT max_glyphs) { int offset; enum gsub_lookup_type type; @@ -1518,15 +1529,15 @@ static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD case GSUB_LOOKUP_SINGLE: return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count); case GSUB_LOOKUP_MULTIPLE: - return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count); + return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count, max_glyphs); case GSUB_LOOKUP_ALTERNATE: return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count); case GSUB_LOOKUP_LIGATURE: return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count); case GSUB_LOOKUP_CONTEXT: - return GSUB_apply_ContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count); + return GSUB_apply_ContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count, max_glyphs); case GSUB_LOOKUP_CONTEXT_CHAINED: - return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count); + return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count, max_glyphs); case GSUB_LOOKUP_EXTENSION: FIXME("Extension Substitution types not valid here\n"); break; @@ -1537,12 +1548,12 @@ static INT GSUB_apply_lookup(const OT_LookupList* lookup, INT lookup_index, WORD } int OpenType_apply_GSUB_lookup(const void *table, unsigned int lookup_index, WORD *glyphs, - unsigned int glyph_index, int write_dir, int *glyph_count) + unsigned int glyph_index, int write_dir, int *glyph_count, int max_glyphs) { const GSUB_Header *header = (const GSUB_Header *)table; const OT_LookupList *lookup = (const OT_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList)); - return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count); + return GSUB_apply_lookup(lookup, lookup_index, glyphs, glyph_index, write_dir, glyph_count, max_glyphs); } /********** diff --git a/dlls/gdi32/uniscribe/shape.c b/dlls/gdi32/uniscribe/shape.c index a3c026a9982..ec7f5652fef 100644 --- a/dlls/gdi32/uniscribe/shape.c +++ b/dlls/gdi32/uniscribe/shape.c @@ -547,7 +547,7 @@ static const ScriptShapeData ShapingData[] = extern scriptData scriptInformation[]; static int GSUB_apply_feature_all_lookups(const void *header, LoadedFeature *feature, - WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count) + WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count, int max_glyphs) { int i; int out_index = GSUB_E_NOGLYPH; @@ -555,16 +555,18 @@ static int GSUB_apply_feature_all_lookups(const void *header, LoadedFeature *fea TRACE("%i lookups\n", feature->lookup_count); for (i = 0; i < feature->lookup_count; i++) { - out_index = OpenType_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, max_glyphs); if (out_index != GSUB_E_NOGLYPH) break; } if (out_index == GSUB_E_NOGLYPH) TRACE("lookups found no glyphs\n"); - else + else if (out_index != GSUB_E_OUTOFMEMORY) { int out2; - out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count); + out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count, max_glyphs); + if (out2==GSUB_E_OUTOFMEMORY) + return GSUB_E_OUTOFMEMORY; if (out2!=GSUB_E_NOGLYPH) out_index = out2; } @@ -654,7 +656,7 @@ static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache return feature; } -static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, const char* feat) +static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, INT max_glyphs, const char* feat) { LoadedFeature *feature; @@ -663,7 +665,7 @@ static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCach return GSUB_E_NOFEATURE; TRACE("applying feature %s\n",feat); - return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count); + return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count, max_glyphs); } static VOID *load_gsub_table(HDC hdc) @@ -724,7 +726,7 @@ int SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, Script glyphs = calloc(count, 2 * sizeof(*glyphs)); NtGdiGetGlyphIndicesW(hdc, chars, count, glyphs, 0); - rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature); + rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, 2 * count, feature); if (rc > GSUB_E_NOGLYPH) rc = count - glyph_count; else @@ -823,7 +825,7 @@ static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int ch } } -static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *pwOutGlyphs, int write_dir, INT* pcGlyphs, INT cChars, const char* feat, WORD *pwLogClust ) +static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *pwOutGlyphs, int write_dir, INT* pcGlyphs, INT cChars, INT cMaxGlyphs, const char* feat, WORD *pwLogClust ) { if (psc->GSUB_Table) { @@ -849,7 +851,9 @@ static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, W INT nextIndex; INT prevCount = *pcGlyphs; - nextIndex = OpenType_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, cMaxGlyphs); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return GSUB_E_OUTOFMEMORY; if (*pcGlyphs != prevCount) { UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust); @@ -1130,7 +1134,9 @@ static HRESULT ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS INT prevCount = *pcGlyphs; /* Apply CCMP first */ - apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp"); + hr = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, cMaxGlyphs, "ccmp"); + if (hr == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; if (prevCount != *pcGlyphs) { @@ -1140,8 +1146,9 @@ static HRESULT ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS } /* Apply the contextual feature */ - nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]); - + nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, cMaxGlyphs, contextual_features[context_shape[char_index]]); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; if (nextIndex > GSUB_E_NOGLYPH) { UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust); @@ -1405,8 +1412,9 @@ right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) INT prevCount = *pcGlyphs; /* Apply CCMP first */ - apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp"); - + nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, cMaxGlyphs, "ccmp"); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; if (prevCount != *pcGlyphs) { offset = *pcGlyphs - prevCount; @@ -1415,7 +1423,9 @@ right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa))) } /* Apply the contextual feature */ - nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]); + nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, cMaxGlyphs, contextual_features[context_shape[char_index]]); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; if (nextIndex > GSUB_E_NOGLYPH) { UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust); @@ -1557,7 +1567,9 @@ static HRESULT ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYS { INT nextIndex; INT prevCount = *pcGlyphs; - nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]); + nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, cMaxGlyphs, contextual_features[context_shape[char_index]]); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; if (nextIndex > GSUB_E_NOGLYPH) { @@ -2017,18 +2029,21 @@ static inline void shift_syllable_glyph_indices(IndicSyllable *glyph_index, INT glyph_index->pref+= shift; } -static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, LoadedFeature *feature ) +static HRESULT Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, LoadedFeature *feature ) { int index = glyph_index->start; if (!feature) - return; + return S_OK; while(index <= glyph_index->end) { INT nextIndex; INT prevCount = *pcGlyphs; - nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs); + nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs, cMaxGlyphs); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; + if (nextIndex > GSUB_E_NOGLYPH) { UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust); @@ -2038,6 +2053,8 @@ static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *ps else index++; } + + return S_OK; } static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical) @@ -2051,7 +2068,7 @@ static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexi return -1; } -static void Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const char* feature) +static HRESULT Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const char* feature) { INT index, nextIndex; INT count,g_offset; @@ -2063,7 +2080,9 @@ static void Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start)) { INT prevCount = *pcGlyphs; - nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature); + nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, cMaxGlyphs, feature); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; if (nextIndex > GSUB_E_NOGLYPH) { UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust); @@ -2074,22 +2093,26 @@ static void Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, index+=2; index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical); } + return S_OK; } -static void Apply_Indic_Rphf(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index) +static HRESULT Apply_Indic_Rphf(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index) { INT nextIndex; INT prevCount = *pcGlyphs; if (syllable->ralf >= 0) { - nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf"); + nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, cMaxGlyphs, "rphf"); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; if (nextIndex > GSUB_E_NOGLYPH) { UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust); shift_syllable_glyph_indices(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount); } } + return S_OK; } static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical) @@ -2105,7 +2128,7 @@ static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexi return -1; } -static void Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, BOOL modern, const char* feat) +static HRESULT Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, BOOL modern, const char* feat) { INT index, nextIndex; INT count, g_offset=0; @@ -2131,7 +2154,9 @@ static void Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa pwOutGlyphs[index+glyph_index->base+g_offset+1] = g; } - nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat); + nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, cMaxGlyphs, feat); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; if (nextIndex > GSUB_E_NOGLYPH) { UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust); @@ -2148,9 +2173,32 @@ static void Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa index+=2; index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical); } + return S_OK; } -static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, second_reorder_function second_reorder, BOOL modern) +#define APPLY_BASIC(feature) do { \ + TRACE("applying feature %s\n", #feature); \ + hr = Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], \ + pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, \ + lexical, &glyph_indices, (feature)); \ + if (FAILED(hr)) return hr; \ +} while(0) + +#define APPLY_PREBASE(feature) do { \ + hr = Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], \ + pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, \ + lexical, &glyph_indices, (feature)); \ + if (FAILED(hr)) return hr; \ +} while(0) + +#define APPLY_POSTBASE(feature) do { \ + hr = Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], \ + pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, \ + lexical, &glyph_indices, modern, (feature)); \ + if (FAILED(hr)) return hr; \ +} while(0) + +static HRESULT ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust, lexical_function lexical, second_reorder_function second_reorder, BOOL modern) { int c; int overall_shift = 0; @@ -2166,6 +2214,7 @@ static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL); BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL); IndicSyllable glyph_indices; + HRESULT hr = S_OK; for (c = 0; c < syllable_count; c++) { @@ -2175,61 +2224,46 @@ static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, old_end = glyph_indices.end; if (locl) - { - TRACE("applying feature locl\n"); - Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, locl); - } + APPLY_BASIC(locl); if (nukt) - { - TRACE("applying feature nukt\n"); - Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, nukt); - } + APPLY_BASIC(nukt); if (akhn) - { - TRACE("applying feature akhn\n"); - Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, akhn); - } + APPLY_BASIC(akhn); if (rphf) - Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices); - if (rkrf) { - TRACE("applying feature rkrf\n"); - Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, rkrf); + hr = Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, lexical, &glyph_indices); + if (FAILED(hr)) + return hr; } + if (rkrf) + APPLY_BASIC(rkrf); if (pref) - Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, modern, "pref"); + APPLY_POSTBASE("pref"); if (blwf) { if (!modern) - Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, "blwf"); + APPLY_PREBASE("blwf"); - Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, modern, "blwf"); + APPLY_POSTBASE("blwf"); } if (half) - Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, "half"); + APPLY_PREBASE("half"); if (pstf) - { - TRACE("applying feature pstf\n"); - Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, pstf); - } + APPLY_BASIC(pstf); if (vatu) - { - TRACE("applying feature vatu\n"); - Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, vatu); - } + APPLY_BASIC(vatu); if (cjct) - { - TRACE("applying feature cjct\n"); - Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indices, cjct); - } + APPLY_BASIC(cjct); + if (second_reorder) second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indices, lexical); overall_shift += glyph_indices.end - old_end; } + return hr; } static inline int unicode_lex(WCHAR c) @@ -2346,7 +2380,7 @@ static HRESULT ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI /* Step 4: Base Form application to syllables */ NtGdiGetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0); *pcGlyphs = cCount; - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, sinhala_lex, NULL, TRUE); free(input); free(syllables); @@ -2406,7 +2440,7 @@ static HRESULT ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANAL *pcGlyphs = cCount; /* Step 3: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, devanagari_lex, NULL, modern); free(input); free(syllables); @@ -2443,6 +2477,7 @@ static HRESULT ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI int syllable_count = 0; BOOL modern = get_GSUB_Indic2(psa, psc); HRESULT hr = S_OK; + INT out_index; if (*pcGlyphs != cChars) { @@ -2473,13 +2508,19 @@ static HRESULT ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI int gCount = 1; if (index > 0) index++; - apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init"); + out_index = apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, cMaxGlyphs, "init"); + if (out_index == GSUB_E_OUTOFMEMORY) + { + hr = E_OUTOFMEMORY; + goto error; + } } } /* Step 4: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, bengali_lex, NULL, modern); + error: free(input); free(syllables); return hr; @@ -2530,7 +2571,7 @@ static HRESULT ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYS *pcGlyphs = cCount; /* Step 3: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, gurmukhi_lex, NULL, modern); free(input); free(syllables); @@ -2572,7 +2613,7 @@ static HRESULT ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYS *pcGlyphs = cCount; /* Step 2: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, gujarati_lex, NULL, modern); free(input); free(syllables); @@ -2630,7 +2671,7 @@ static HRESULT ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *pcGlyphs = cCount; /* Step 3: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, oriya_lex, NULL, modern); free(input); free(syllables); @@ -2682,7 +2723,7 @@ static HRESULT ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *pcGlyphs = cCount; /* Step 3: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern); free(input); free(syllables); @@ -2733,7 +2774,7 @@ static HRESULT ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *pcGlyphs = cCount; /* Step 3: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern); free(input); free(syllables); @@ -2787,7 +2828,7 @@ static HRESULT ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSI *pcGlyphs = cCount; /* Step 3: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern); free(input); free(syllables); @@ -2834,7 +2875,7 @@ static HRESULT ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALY *pcGlyphs = cCount; /* Step 3: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern); free(input); free(syllables); @@ -2870,7 +2911,7 @@ static HRESULT ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *pcGlyphs = cCount; /* Step 2: Base Form application to syllables */ - ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE); + hr = ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust, khmer_lex, NULL, FALSE); free(input); free(syllables); @@ -2935,7 +2976,9 @@ static HRESULT ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALY { INT nextIndex; INT prevCount = *pcGlyphs; - nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]); + nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, cMaxGlyphs, contextual_features[context_shape[char_index]]); + if (nextIndex == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; if (nextIndex > GSUB_E_NOGLYPH) { @@ -3448,18 +3491,19 @@ HRESULT SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, return hr; } -static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, const TEXTRANGE_PROPERTIES *rpRangeProperties, WORD *pwLogClust) +static HRESULT SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, const TEXTRANGE_PROPERTIES *rpRangeProperties, WORD *pwLogClust) { int i; INT dirL; + INT out_index; if (!rpRangeProperties) - return; + return S_OK; load_ot_tables(hdc, psc); if (!psc->GSUB_Table) - return; + return S_OK; if (scriptInformation[psa->eScript].a.fRTL && (!psa->fLogicalOrder || !psa->fRTL)) dirL = -1; @@ -3469,16 +3513,23 @@ static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYS for (i = 0; i < rpRangeProperties->cotfRecords; i++) { if (rpRangeProperties->potfRecords[i].lParameter > 0) - apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust); + { + out_index = apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, cMaxGlyphs, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust); + if (out_index == GSUB_E_OUTOFMEMORY) + return E_OUTOFMEMORY; + } } + return S_OK; } -void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust) +HRESULT SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust) { +HRESULT hr = S_OK; const TEXTRANGE_PROPERTIES *rpRangeProperties; rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange; - SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust); + hr = SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust); + return hr; } void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD* pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset ) diff --git a/dlls/gdi32/uniscribe/usp10.c b/dlls/gdi32/uniscribe/usp10.c index 2880a5f1434..262df6056b2 100644 --- a/dlls/gdi32/uniscribe/usp10.c +++ b/dlls/gdi32/uniscribe/usp10.c @@ -3192,7 +3192,14 @@ HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc, free(rChars); return hr; } - SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust); + + hr = SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust); + if (FAILED(hr)) + { + free(rChars); + return hr; + } + SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps); for (i = 0; i < cChars; ++i) diff --git a/dlls/gdi32/uniscribe/usp10_internal.h b/dlls/gdi32/uniscribe/usp10_internal.h index d14464796c4..7344a5b514d 100644 --- a/dlls/gdi32/uniscribe/usp10_internal.h +++ b/dlls/gdi32/uniscribe/usp10_internal.h @@ -135,6 +135,7 @@ enum usp10_script #define GSUB_E_NOFEATURE -20 #define GSUB_E_NOGLYPH -10 +#define GSUB_E_OUTOFMEMORY -30 #define FEATURE_ALL_TABLES 0 #define FEATURE_GSUB_TABLE 1 @@ -263,7 +264,7 @@ INT BIDI_ReorderL2vLevel(int level, int *pIndices, const BYTE* plevel, int cch, HRESULT SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust); -void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, +HRESULT SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust); void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, @@ -297,7 +298,7 @@ DWORD OpenType_CMAP_GetGlyphIndex(HDC hdc, ScriptCache *psc, DWORD utf32c, LPWOR void OpenType_GDEF_UpdateGlyphProps(ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD *pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp); int OpenType_apply_GSUB_lookup(const void *table, unsigned int lookup_index, WORD *glyphs, - unsigned int glyph_index, int write_dir, int *glyph_count); + unsigned int glyph_index, int write_dir, int *glyph_count, int max_glyphs); unsigned int OpenType_apply_GPOS_lookup(const ScriptCache *psc, const OUTLINETEXTMETRICW *otm, const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance, unsigned int lookup_index, const WORD *glyphs, unsigned int glyph_index, unsigned int glyph_count, GOFFSET *goffset); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10612