diff --git a/dlls/usp10/shape.c b/dlls/usp10/shape.c index ed9b477728b..58012534ce1 100644 --- a/dlls/usp10/shape.c +++ b/dlls/usp10/shape.c @@ -3878,6 +3878,112 @@ static HRESULT GSUB_GetFontLanguageTags(ScriptCache *psc, OPENTYPE_TAG script_ta 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++) + { + 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)); + } + } +} + +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) @@ -3925,3 +4031,27 @@ HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc, hr = E_INVALIDARG; return hr; } + +HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc, + SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, + OPENTYPE_TAG tagLangSys, int cMaxTags, + OPENTYPE_TAG *pFeatureTags, int *pcTags) +{ + HRESULT hr; + BOOL filter = FALSE; + + if (!psc->GSUB_Table) + psc->GSUB_Table = load_gsub_table(hdc); + + if (psa && scriptInformation[psa->eScript].scriptTag) + { + FIXME("Filtering not implemented\n"); + filter = TRUE; + } + + hr = GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL); + + if (FAILED(hr)) + *pcTags = 0; + return hr; +} diff --git a/dlls/usp10/tests/usp10.c b/dlls/usp10/tests/usp10.c index 7aeb5663668..82297558030 100644 --- a/dlls/usp10/tests/usp10.c +++ b/dlls/usp10/tests/usp10.c @@ -61,6 +61,7 @@ static DWORD (WINAPI *pGetGlyphIndicesW)(HDC hdc, LPCWSTR lpstr, INT count, LPWO static HRESULT (WINAPI *pScriptGetFontScriptTags)( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags); static HRESULT (WINAPI *pScriptGetFontLanguageTags)( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags); +static HRESULT (WINAPI *pScriptGetFontFeatureTags)( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags); static inline void _test_items_ok(LPCWSTR string, DWORD cchString, SCRIPT_CONTROL *Control, SCRIPT_STATE *State, @@ -2873,9 +2874,10 @@ static void test_ScriptGetFontFunctions(HDC hdc) HRESULT hr; pScriptGetFontScriptTags = (void*)GetProcAddress(GetModuleHandleA("usp10.dll"), "ScriptGetFontScriptTags"); pScriptGetFontLanguageTags = (void*)GetProcAddress(GetModuleHandleA("usp10.dll"), "ScriptGetFontLanguageTags"); - if (!pScriptGetFontScriptTags || !pScriptGetFontLanguageTags) + pScriptGetFontFeatureTags = (void*)GetProcAddress(GetModuleHandleA("usp10.dll"), "ScriptGetFontFeatureTags"); + if (!pScriptGetFontScriptTags || !pScriptGetFontLanguageTags || !pScriptGetFontFeatureTags) { - win_skip("ScriptGetFontScriptTags or ScriptGetFontLanguageTags not available on this platform\n"); + win_skip("ScriptGetFontScriptTags,ScriptGetFontLanguageTags or ScriptGetFontFeatureTags not available on this platform\n"); } else { @@ -2936,6 +2938,31 @@ static void test_ScriptGetFontFunctions(HDC hdc) else if (hr == E_OUTOFMEMORY) ok(count == 0, "Count should be 0 with E_OUTOFMEMORY return\n"); + ScriptFreeCache(&sc); + sc = NULL; + + hr = pScriptGetFontFeatureTags(hdc, &sc, NULL, latn_tag, 0x0, 0, NULL, NULL); + ok(hr == E_INVALIDARG,"Incorrect return code\n"); + ok(sc == NULL, "ScriptCache should remain uninitialized\n"); + hr = pScriptGetFontFeatureTags(hdc, &sc, NULL, latn_tag, 0x0, 0, NULL, &count); + ok(hr == E_INVALIDARG,"Incorrect return code\n"); + ok(sc == NULL, "ScriptCache should remain uninitialized\n"); + hr = pScriptGetFontFeatureTags(hdc, &sc, NULL, latn_tag, 0x0, 5, tags, NULL); + ok(hr == E_INVALIDARG,"Incorrect return code\n"); + ok(sc == NULL, "ScriptCache should remain uninitialized\n"); + hr = pScriptGetFontFeatureTags(hdc, &sc, NULL, latn_tag, 0x0, 0, tags, &count); + ok(hr == E_INVALIDARG,"Incorrect return code\n"); + ok(sc == NULL, "ScriptCache should remain uninitialized\n"); + hr = pScriptGetFontFeatureTags(NULL, &sc, NULL, latn_tag, 0x0, 5, tags, &count); + ok(hr == E_PENDING,"Incorrect return code\n"); + ok(sc == NULL, "ScriptCache should remain uninitialized\n"); + hr = pScriptGetFontFeatureTags(hdc, &sc, NULL, latn_tag, 0x0, 5, tags, &count); + ok((hr == S_OK || hr == E_OUTOFMEMORY),"Incorrect return code\n"); + if (hr == S_OK) + ok(count <= 5, "Count should be less or equal to 5 with S_OK return\n"); + else if (hr == E_OUTOFMEMORY) + ok(count == 0, "Count should be 0 with E_OUTOFMEMORY return\n"); + memset(&Control, 0, sizeof(Control)); memset(&State, 0, sizeof(State)); @@ -2950,6 +2977,11 @@ static void test_ScriptGetFontFunctions(HDC hdc) hr = pScriptGetFontLanguageTags(hdc, &sc, &outpItems[0].a, dsrt_tag, 5, tags, &count); ok( hr == E_INVALIDARG || broken(hr == S_OK), "wrong return code\n"); + hr = pScriptGetFontFeatureTags(hdc, &sc, NULL, dsrt_tag, 0x0, 5, tags, &count); + ok( hr == S_OK, "wrong return code\n"); + hr = pScriptGetFontFeatureTags(hdc, &sc, &outpItems[0].a, dsrt_tag, 0x0, 5, tags, &count); + ok( hr == E_INVALIDARG || broken(hr == S_OK), "wrong return code\n"); + ScriptFreeCache(&sc); } } diff --git a/dlls/usp10/usp10.c b/dlls/usp10/usp10.c index 12ac788d863..152db1e5f1d 100644 --- a/dlls/usp10/usp10.c +++ b/dlls/usp10/usp10.c @@ -926,7 +926,12 @@ HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc) heap_free(((ScriptCache *)*psc)->GDEF_Table); heap_free(((ScriptCache *)*psc)->CMAP_Table); for (i = 0; i < ((ScriptCache *)*psc)->script_count; i++) + { + int j; + for (j = 0; j < ((ScriptCache *)*psc)->scripts[i].language_count; j++) + heap_free(((ScriptCache *)*psc)->scripts[i].languages[j].features); heap_free(((ScriptCache *)*psc)->scripts[i].languages); + } heap_free(((ScriptCache *)*psc)->scripts); heap_free(((ScriptCache *)*psc)->features); heap_free(*psc); @@ -3563,3 +3568,12 @@ HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANA return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags); } + +HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags) +{ + HRESULT hr; + if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG; + if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr; + + return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags); +} diff --git a/dlls/usp10/usp10.spec b/dlls/usp10/usp10.spec index 213ee9afba0..4d99134bc8b 100644 --- a/dlls/usp10/usp10.spec +++ b/dlls/usp10/usp10.spec @@ -7,7 +7,7 @@ @ stdcall ScriptFreeCache(ptr) @ stdcall ScriptGetCMap(ptr ptr ptr long long ptr) @ stub ScriptGetFontAlternateGlyphs -@ stub ScriptGetFontFeatureTags +@ stdcall ScriptGetFontFeatureTags(long ptr ptr long long long ptr ptr) @ stdcall ScriptGetFontLanguageTags(long ptr ptr long long ptr ptr) @ stdcall ScriptGetFontProperties(long ptr ptr) @ stdcall ScriptGetFontScriptTags(long ptr ptr long ptr ptr) diff --git a/dlls/usp10/usp10_internal.h b/dlls/usp10/usp10_internal.h index 62307a5239e..5fd5d75e37a 100644 --- a/dlls/usp10/usp10_internal.h +++ b/dlls/usp10/usp10_internal.h @@ -134,6 +134,8 @@ typedef struct { typedef struct { OPENTYPE_TAG tag; LPCVOID table; + INT feature_count; + LoadedFeature *features; } LoadedLanguage; typedef struct { @@ -213,6 +215,7 @@ void SHAPE_CharGlyphProp(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature) DECLSPEC_HIDDEN; HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags) DECLSPEC_HIDDEN; HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags) DECLSPEC_HIDDEN; +HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags) DECLSPEC_HIDDEN; void Indic_ReorderCharacters( HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPWSTR input, int cChars, IndicSyllable **syllables, int *syllable_count, lexical_function lexical_f, reorder_function reorder_f, BOOL modern) DECLSPEC_HIDDEN; void Indic_ParseSyllables( HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, LPCWSTR input, const int cChar, IndicSyllable **syllables, int *syllable_count, lexical_function lex, BOOL modern) DECLSPEC_HIDDEN;