From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 7ffcfa8070c..a8ab12b9430 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -245,7 +245,7 @@ struct dwrite_fontfallback IDWriteFontFallback1 IDWriteFontFallback1_iface; LONG refcount; IDWriteFactory7 *factory; - IDWriteFontCollection1 *systemcollection; + IDWriteFontCollection *systemcollection; struct fallback_mapping *mappings; UINT32 mappings_count; }; @@ -2228,7 +2228,7 @@ HRESULT create_system_fontfallback(IDWriteFactory7 *factory, IDWriteFontFallback fallback->factory = factory; fallback->mappings = (struct fallback_mapping *)fontfallback_neutral_data; fallback->mappings_count = ARRAY_SIZE(fontfallback_neutral_data); - IDWriteFactory5_GetSystemFontCollection((IDWriteFactory5 *)fallback->factory, FALSE, &fallback->systemcollection, FALSE); + IDWriteFactory_GetSystemFontCollection((IDWriteFactory *)fallback->factory, &fallback->systemcollection, FALSE);
*ret = &fallback->IDWriteFontFallback1_iface;
@@ -2238,7 +2238,7 @@ HRESULT create_system_fontfallback(IDWriteFactory7 *factory, IDWriteFontFallback void release_system_fontfallback(IDWriteFontFallback1 *iface) { struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface); - IDWriteFontCollection1_Release(fallback->systemcollection); + IDWriteFontCollection_Release(fallback->systemcollection); free(fallback); }
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 96 +++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 38 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index a8ab12b9430..2f5f1e1d7fe 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -240,6 +240,12 @@ static const struct fallback_mapping fontfallback_neutral_data[] = { #undef MAPPING_RANGE };
+struct fallback_data +{ + struct fallback_mapping *mappings; + size_t count; +}; + struct dwrite_fontfallback { IDWriteFontFallback1 IDWriteFontFallback1_iface; @@ -255,11 +261,31 @@ struct dwrite_fontfallback_builder IDWriteFontFallbackBuilder IDWriteFontFallbackBuilder_iface; LONG refcount; IDWriteFactory7 *factory; - struct fallback_mapping *mappings; - size_t size; - size_t count; + struct fallback_data data; + size_t mappings_size; };
+static void release_fallback_mapping(struct fallback_mapping *mapping) +{ + unsigned int i; + + free(mapping->ranges); + for (i = 0; i < mapping->families_count; ++i) + free(mapping->families[i]); + free(mapping->families); + if (mapping->collection) + IDWriteFontCollection_Release(mapping->collection); +} + +static void release_fallback_data(struct fallback_data *data) +{ + size_t i; + + for (i = 0; i < data->count; ++i) + release_fallback_mapping(&data->mappings[i]); + free(data->mappings); +} + struct dwrite_numbersubstitution { IDWriteNumberSubstitution IDWriteNumberSubstitution_iface; @@ -2327,76 +2353,70 @@ static ULONG WINAPI fontfallbackbuilder_AddRef(IDWriteFontFallbackBuilder *iface
static ULONG WINAPI fontfallbackbuilder_Release(IDWriteFontFallbackBuilder *iface) { - struct dwrite_fontfallback_builder *fallbackbuilder = impl_from_IDWriteFontFallbackBuilder(iface); - ULONG refcount = InterlockedDecrement(&fallbackbuilder->refcount); - size_t i; + struct dwrite_fontfallback_builder *builder = impl_from_IDWriteFontFallbackBuilder(iface); + ULONG refcount = InterlockedDecrement(&builder->refcount);
TRACE("%p, refcount %ld.\n", iface, refcount);
if (!refcount) { - for (i = 0; i < fallbackbuilder->count; ++i) - { - struct fallback_mapping *mapping = &fallbackbuilder->mappings[i]; - UINT32 j; - - for (j = 0; j < mapping->families_count; j++) - free(mapping->families[j]); - free(mapping->families); - - if (mapping->collection) - IDWriteFontCollection_Release(mapping->collection); - free(mapping->ranges); - free(mapping->locale); - } - - IDWriteFactory7_Release(fallbackbuilder->factory); - free(fallbackbuilder->mappings); - free(fallbackbuilder); + IDWriteFactory7_Release(builder->factory); + release_fallback_data(&builder->data); + free(builder); }
return refcount; }
static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder *iface, - const DWRITE_UNICODE_RANGE *ranges, UINT32 ranges_count, WCHAR const **target_families, UINT32 families_count, - IDWriteFontCollection *collection, WCHAR const *locale, WCHAR const *base_family, FLOAT scale) + const DWRITE_UNICODE_RANGE *ranges, UINT32 ranges_count, WCHAR const **families, UINT32 families_count, + IDWriteFontCollection *collection, WCHAR const *locale_name, WCHAR const *base_family, float scale) { - struct dwrite_fontfallback_builder *fallbackbuilder = impl_from_IDWriteFontFallbackBuilder(iface); + struct dwrite_fontfallback_builder *builder = impl_from_IDWriteFontFallbackBuilder(iface); struct fallback_mapping *mapping; UINT32 i;
- TRACE("%p, %p, %u, %p, %u, %p, %s, %s, %f.\n", iface, ranges, ranges_count, target_families, families_count, - collection, debugstr_w(locale), debugstr_w(base_family), scale); + TRACE("%p, %p, %u, %p, %u, %p, %s, %s, %f.\n", iface, ranges, ranges_count, families, families_count, + collection, debugstr_w(locale_name), debugstr_w(base_family), scale);
- if (!ranges || ranges_count == 0 || !target_families || families_count == 0 || scale < 0.0f) + if (!ranges || !ranges_count || !families || !families_count || scale < 0.0f) return E_INVALIDARG;
if (base_family) FIXME("base family ignored.\n");
- if (!dwrite_array_reserve((void **)&fallbackbuilder->mappings, &fallbackbuilder->size, fallbackbuilder->count + 1, - sizeof(*fallbackbuilder->mappings))) + if (!dwrite_array_reserve((void **)&builder->data.mappings, &builder->mappings_size, + builder->data.count + 1, sizeof(*builder->data.mappings))) { return E_OUTOFMEMORY; }
- mapping = &fallbackbuilder->mappings[fallbackbuilder->count++]; + mapping = &builder->data.mappings[builder->data.count]; + memset(mapping, 0, sizeof(*mapping)); + + if (!(mapping->ranges = calloc(ranges_count, sizeof(*mapping->ranges)))) + goto failed;
- mapping->ranges = calloc(ranges_count, sizeof(*mapping->ranges)); - memcpy(mapping->ranges, ranges, sizeof(*mapping->ranges) * ranges_count); mapping->ranges_count = ranges_count; - mapping->families = calloc(families_count, sizeof(*mapping->families)); + memcpy(mapping->ranges, ranges, sizeof(*mapping->ranges) * ranges_count); + + if (!(mapping->families = calloc(families_count, sizeof(*mapping->families)))) + goto failed; mapping->families_count = families_count; for (i = 0; i < families_count; i++) - mapping->families[i] = wcsdup(target_families[i]); + if (!(mapping->families[i] = wcsdup(families[i]))) goto failed; mapping->collection = collection; if (mapping->collection) IDWriteFontCollection_AddRef(mapping->collection); - mapping->locale = wcsdup(locale); + mapping->locale = wcsdup(locale_name); mapping->scale = scale;
+ builder->data.count++; return S_OK; + +failed: + release_fallback_mapping(mapping); + return E_OUTOFMEMORY; }
static HRESULT WINAPI fontfallbackbuilder_AddMappings(IDWriteFontFallbackBuilder *iface, IDWriteFontFallback *fallback)
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 2f5f1e1d7fe..1522d7638bc 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -2374,7 +2374,7 @@ static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder { struct dwrite_fontfallback_builder *builder = impl_from_IDWriteFontFallbackBuilder(iface); struct fallback_mapping *mapping; - UINT32 i; + unsigned int i, count;
TRACE("%p, %p, %u, %p, %u, %p, %s, %s, %f.\n", iface, ranges, ranges_count, families, families_count, collection, debugstr_w(locale_name), debugstr_w(base_family), scale); @@ -2397,8 +2397,22 @@ static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder if (!(mapping->ranges = calloc(ranges_count, sizeof(*mapping->ranges)))) goto failed;
- mapping->ranges_count = ranges_count; - memcpy(mapping->ranges, ranges, sizeof(*mapping->ranges) * ranges_count); + /* Filter ranges that won't be usable. */ + for (i = 0, count = 0; i < ranges_count; ++i) + { + if (ranges[i].first > ranges[i].last) continue; + if (ranges[i].first > 0x10ffff) continue; + mapping->ranges[count].first = ranges[i].first; + mapping->ranges[count].last = min(ranges[i].last, 0x10ffff); + count++; + } + if (!count) + { + release_fallback_mapping(mapping); + return S_OK; + } + + mapping->ranges_count = count;
if (!(mapping->families = calloc(families_count, sizeof(*mapping->families)))) goto failed;
From: Nikolay Sivov nsivov@codeweavers.com
Each locale entry contains a "list" of its mappings.
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 93 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 4 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 1522d7638bc..c6c4fa2d654 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -220,16 +220,78 @@ static const DWRITE_UNICODE_RANGE cjk_ranges[] = { 0x4e00, 0x9fff }, /* CJK Unified Ideographs */ };
-struct fallback_mapping { +struct fallback_mapping +{ DWRITE_UNICODE_RANGE *ranges; UINT32 ranges_count; WCHAR **families; UINT32 families_count; IDWriteFontCollection *collection; - WCHAR *locale; - FLOAT scale; + float scale; +}; + +struct fallback_locale +{ + struct list entry; + WCHAR name[LOCALE_NAME_MAX_LENGTH]; + struct + { + size_t *data; + size_t count; + size_t size; + } ranges; };
+static void fallback_locale_list_destroy(struct list *locales) +{ + struct fallback_locale *cur, *cur2; + + LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, locales, struct fallback_locale, entry) + { + list_remove(&cur->entry); + free(cur->ranges.data); + free(cur); + } +} + +static HRESULT fallback_locale_add_mapping(struct fallback_locale *locale, size_t index) +{ + size_t count = locale->ranges.count; + + /* Append to last range, or start a new one. */ + if (count && locale->ranges.data[count - 1] == (index - 1)) + { + locale->ranges.data[count - 1] = index; + return S_OK; + } + + if (!dwrite_array_reserve((void **)&locale->ranges.data, &locale->ranges.size, count + 2, + sizeof(*locale->ranges.data))) + { + return E_OUTOFMEMORY; + } + + locale->ranges.data[count] = locale->ranges.data[count + 1] = index; + locale->ranges.count += 2; + + return S_OK; +} + +/* TODO: potentially needs improvement to consider partially matching locale names. */ +static struct fallback_locale * font_fallback_get_locale(const struct list *locales, + const WCHAR *locale_name) +{ + struct fallback_locale *locale, *neutral = NULL; + + LIST_FOR_EACH_ENTRY(locale, locales, struct fallback_locale, entry) + { + if (!wcsicmp(locale->name, locale_name)) return locale; + if (!*locale->name) neutral = locale; + } + + return neutral; +} + static const struct fallback_mapping fontfallback_neutral_data[] = { #define MAPPING_RANGE(ranges, families) \ { (DWRITE_UNICODE_RANGE *)ranges, ARRAY_SIZE(ranges), \ @@ -244,6 +306,7 @@ struct fallback_data { struct fallback_mapping *mappings; size_t count; + struct list locales; };
struct dwrite_fontfallback @@ -284,6 +347,7 @@ static void release_fallback_data(struct fallback_data *data) for (i = 0; i < data->count; ++i) release_fallback_mapping(&data->mappings[i]); free(data->mappings); + fallback_locale_list_destroy(&data->locales); }
struct dwrite_numbersubstitution @@ -2368,12 +2432,26 @@ static ULONG WINAPI fontfallbackbuilder_Release(IDWriteFontFallbackBuilder *ifac return refcount; }
+static struct fallback_locale * fallback_builder_add_locale(struct dwrite_fontfallback_builder *builder, + const WCHAR *locale_name) +{ + struct fallback_locale *locale; + + if (!locale_name) locale_name = L""; + if ((locale = font_fallback_get_locale(&builder->data.locales, locale_name))) return locale; + if (!(locale = calloc(1, sizeof(*locale)))) return NULL; + lstrcpynW(locale->name, locale_name, ARRAY_SIZE(locale->name)); + list_add_tail(&builder->data.locales, &locale->entry); + return locale; +} + static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder *iface, const DWRITE_UNICODE_RANGE *ranges, UINT32 ranges_count, WCHAR const **families, UINT32 families_count, IDWriteFontCollection *collection, WCHAR const *locale_name, WCHAR const *base_family, float scale) { struct dwrite_fontfallback_builder *builder = impl_from_IDWriteFontFallbackBuilder(iface); struct fallback_mapping *mapping; + struct fallback_locale *locale; unsigned int i, count;
TRACE("%p, %p, %u, %p, %u, %p, %s, %s, %f.\n", iface, ranges, ranges_count, families, families_count, @@ -2394,6 +2472,11 @@ static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder mapping = &builder->data.mappings[builder->data.count]; memset(mapping, 0, sizeof(*mapping));
+ /* Append new mapping, link to its locale node. */ + + if (!(locale = fallback_builder_add_locale(builder, locale_name))) + return E_FAIL; + if (!(mapping->ranges = calloc(ranges_count, sizeof(*mapping->ranges)))) goto failed;
@@ -2422,9 +2505,10 @@ static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder mapping->collection = collection; if (mapping->collection) IDWriteFontCollection_AddRef(mapping->collection); - mapping->locale = wcsdup(locale_name); mapping->scale = scale;
+ if (FAILED(fallback_locale_add_mapping(locale, builder->data.count))) goto failed; + builder->data.count++; return S_OK;
@@ -2485,6 +2569,7 @@ HRESULT create_fontfallback_builder(IDWriteFactory7 *factory, IDWriteFontFallbac builder->refcount = 1; builder->factory = factory; IDWriteFactory7_AddRef(builder->factory); + list_init(&builder->data.locales);
*ret = &builder->IDWriteFontFallbackBuilder_iface; return S_OK;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index c6c4fa2d654..e4a52fa95a6 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -2452,7 +2452,7 @@ static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder struct dwrite_fontfallback_builder *builder = impl_from_IDWriteFontFallbackBuilder(iface); struct fallback_mapping *mapping; struct fallback_locale *locale; - unsigned int i, count; + unsigned int i, j, m, count;
TRACE("%p, %p, %u, %p, %u, %p, %s, %s, %f.\n", iface, ranges, ranges_count, families, families_count, collection, debugstr_w(locale_name), debugstr_w(base_family), scale); @@ -2502,12 +2502,47 @@ static HRESULT WINAPI fontfallbackbuilder_AddMapping(IDWriteFontFallbackBuilder mapping->families_count = families_count; for (i = 0; i < families_count; i++) if (!(mapping->families[i] = wcsdup(families[i]))) goto failed; + mapping->scale = scale; + + if (FAILED(fallback_locale_add_mapping(locale, builder->data.count))) goto failed; + + /* Mappings with explicit collections take priority, for that reduce existing mappings ranges + by newly added ranges. */ + mapping->collection = collection; if (mapping->collection) + { IDWriteFontCollection_AddRef(mapping->collection); - mapping->scale = scale;
- if (FAILED(fallback_locale_add_mapping(locale, builder->data.count))) goto failed; + for (m = 0; m < builder->data.count; ++m) + { + struct fallback_mapping *c = &builder->data.mappings[m]; + if (c->collection) continue; + for (i = 0; i < count; ++i) + { + const DWRITE_UNICODE_RANGE *new_range = &mapping->ranges[i]; + + for (j = 0; j < c->ranges_count; ++j) + { + DWRITE_UNICODE_RANGE *range = &c->ranges[j]; + + /* In case existing ranges intersect, disable or reduce them */ + if (range->first >= new_range->first && range->last <= new_range->last) + { + range->first = range->last = ~0u; + } + else if (range->first >= new_range->first && range->first <= new_range->last) + { + range->first = new_range->last; + } + else if (range->last >= new_range->first && range->last <= new_range->last) + { + range->last = new_range->first; + } + } + } + } + }
builder->data.count++; return S_OK;
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 108 ++++++++++++++++++++++++++++++++++--- dlls/dwrite/tests/layout.c | 4 +- 2 files changed, 102 insertions(+), 10 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index e4a52fa95a6..3d5aca98826 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -317,6 +317,8 @@ struct dwrite_fontfallback IDWriteFontCollection *systemcollection; struct fallback_mapping *mappings; UINT32 mappings_count; + struct fallback_data data; + size_t mappings_size; };
struct dwrite_fontfallback_builder @@ -2352,6 +2354,9 @@ static ULONG WINAPI customfontfallback_Release(IDWriteFontFallback1 *iface) if (!refcount) { IDWriteFactory7_Release(fallback->factory); + if (fallback->systemcollection) + IDWriteFontCollection_Release(fallback->systemcollection); + release_fallback_data(&fallback->data); free(fallback); }
@@ -2559,26 +2564,113 @@ static HRESULT WINAPI fontfallbackbuilder_AddMappings(IDWriteFontFallbackBuilder return E_NOTIMPL; }
-static HRESULT WINAPI fontfallbackbuilder_CreateFontFallback(IDWriteFontFallbackBuilder *iface, - IDWriteFontFallback **ret) +static HRESULT fallbackbuilder_init_fallback_data(const struct dwrite_fontfallback_builder *builder, + struct fallback_data *data) { - struct dwrite_fontfallback_builder *fallbackbuilder = impl_from_IDWriteFontFallbackBuilder(iface); - struct dwrite_fontfallback *fallback; + struct fallback_locale *iter, *locale; + size_t i, j;
- TRACE("%p, %p.\n", iface, ret); + /* Duplicate locales list. */ + list_init(&data->locales); + LIST_FOR_EACH_ENTRY(iter, &builder->data.locales, struct fallback_locale, entry) + { + if (!(locale = calloc(1, sizeof(*locale)))) goto failed; + wcscpy(locale->name, iter->name); + locale->ranges.count = iter->ranges.count; + locale->ranges.size = iter->ranges.count; + if (!(locale->ranges.data = malloc(iter->ranges.count * sizeof(*iter->ranges.data)))) + { + free(locale); + goto failed; + } + memcpy(locale->ranges.data, iter->ranges.data, iter->ranges.count * sizeof(*iter->ranges.data)); + list_add_tail(&data->locales, &locale->entry); + }
- *ret = NULL; + /* Duplicate mappings. */ + if (!(data->mappings = calloc(builder->data.count, sizeof(*data->mappings)))) + goto failed; + + data->count = builder->data.count; + for (i = 0; i < data->count; ++i) + { + struct fallback_mapping *src = &builder->data.mappings[i]; + struct fallback_mapping *dst = &data->mappings[i]; + + if (!(dst->ranges = calloc(src->ranges_count, sizeof(*src->ranges)))) goto failed; + memcpy(dst->ranges, src->ranges, src->ranges_count * sizeof(*src->ranges)); + dst->ranges_count = src->ranges_count; + + if (!(dst->families = calloc(src->families_count, sizeof(*src->families)))) goto failed; + dst->families_count = src->families_count; + for (j = 0; j < src->families_count; ++j) + { + if (!(dst->families[j] = wcsdup(src->families[j]))) goto failed; + } + + dst->collection = src->collection; + if (dst->collection) + IDWriteFontCollection_AddRef(dst->collection); + dst->scale = src->scale; + } + + return S_OK; + +failed: + + return E_OUTOFMEMORY; +} + +static HRESULT fallbackbuilder_create_fallback(struct dwrite_fontfallback_builder *builder, struct dwrite_fontfallback **ret) +{ + struct dwrite_fontfallback *fallback; + HRESULT hr;
if (!(fallback = calloc(1, sizeof(*fallback)))) return E_OUTOFMEMORY;
fallback->IDWriteFontFallback1_iface.lpVtbl = &customfontfallbackvtbl; fallback->refcount = 1; - fallback->factory = fallbackbuilder->factory; + fallback->factory = builder->factory; IDWriteFactory7_AddRef(fallback->factory); + if (FAILED(hr = IDWriteFactory_GetSystemFontCollection((IDWriteFactory *)fallback->factory, + &fallback->systemcollection, FALSE))) + { + goto done; + } + + if (FAILED(hr = fallbackbuilder_init_fallback_data(builder, &fallback->data))) + { + goto done; + } + + *ret = fallback;
- *ret = (IDWriteFontFallback *)&fallback->IDWriteFontFallback1_iface; return S_OK; + +done: + + IDWriteFontFallback1_Release(&fallback->IDWriteFontFallback1_iface); + return hr; +} + +static HRESULT WINAPI fontfallbackbuilder_CreateFontFallback(IDWriteFontFallbackBuilder *iface, + IDWriteFontFallback **ret) +{ + struct dwrite_fontfallback_builder *builder = impl_from_IDWriteFontFallbackBuilder(iface); + struct dwrite_fontfallback *fallback; + HRESULT hr; + + TRACE("%p, %p.\n", iface, ret); + + *ret = NULL; + + if (SUCCEEDED(hr = fallbackbuilder_create_fallback(builder, &fallback))) + { + *ret = (IDWriteFontFallback *)&fallback->IDWriteFontFallback1_iface; + } + + return hr; }
static const IDWriteFontFallbackBuilderVtbl fontfallbackbuildervtbl = diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index 24ec3be7585..31bccfca3be 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -4861,14 +4861,14 @@ static void test_FontFallbackBuilder(void) EXPECT_REF(builder, 1); hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - EXPECT_REF(factory2, 3); + todo_wine EXPECT_REF(factory2, 3); EXPECT_REF(fallback, 1); EXPECT_REF(builder, 1);
IDWriteFontFallback_AddRef(fallback); EXPECT_REF(builder, 1); EXPECT_REF(fallback, 2); - EXPECT_REF(factory2, 3); + todo_wine EXPECT_REF(factory2, 3); IDWriteFontFallback_Release(fallback);
/* New instance is created every time, even if mappings have not changed. */
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 20 ++++++++++++++------ dlls/dwrite/dwrite_private.h | 4 ++-- dlls/dwrite/layout.c | 14 ++++++-------- 3 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 3d5aca98826..0769dada355 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -2129,15 +2129,16 @@ static const struct fallback_mapping *find_fallback_mapping(struct dwrite_fontfa return NULL; }
-HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *name, - DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, IDWriteFont **font) +HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *name, DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, REFIID riid, void **obj) { IDWriteFontFamily *family; BOOL exists = FALSE; + IDWriteFont *font; HRESULT hr; UINT32 i;
- *font = NULL; + *obj = NULL;
hr = IDWriteFontCollection_FindFamilyName(collection, name, &i, &exists); if (FAILED(hr)) @@ -2150,8 +2151,15 @@ HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *nam if (FAILED(hr)) return hr;
- hr = IDWriteFontFamily_GetFirstMatchingFont(family, weight, stretch, style, font); + hr = IDWriteFontFamily_GetFirstMatchingFont(family, weight, stretch, style, &font); IDWriteFontFamily_Release(family); + + if (SUCCEEDED(hr)) + { + hr = IDWriteFont_QueryInterface(font, riid, obj); + IDWriteFont_Release(font); + } + return hr; }
@@ -2200,7 +2208,7 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback, /* Now let's see what fallback can handle. Pick first font that could be created. */ for (i = 0; i < mapping->families_count; i++) { hr = create_matching_font((IDWriteFontCollection *)fallback->systemcollection, mapping->families[i], - weight, style, stretch, mapped_font); + weight, style, stretch, &IID_IDWriteFont, (void **)mapped_font); if (hr == S_OK) { TRACE("Created fallback font using family %s.\n", debugstr_w(mapping->families[i])); break; @@ -2255,7 +2263,7 @@ static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback1 *iface, ID goto done;
if (basefamily && *basefamily) { - hr = create_matching_font(basecollection, basefamily, weight, style, stretch, ret_font); + hr = create_matching_font(basecollection, basefamily, weight, style, stretch, &IID_IDWriteFont, (void **)ret_font); if (FAILED(hr)) goto done;
diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index edb005b8b58..a46d5fe7d96 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -324,8 +324,8 @@ extern BOOL lb_is_newline_char(WCHAR) DECLSPEC_HIDDEN; extern HRESULT create_system_fontfallback(IDWriteFactory7 *factory, IDWriteFontFallback1 **fallback) DECLSPEC_HIDDEN; extern void release_system_fontfallback(IDWriteFontFallback1 *fallback) DECLSPEC_HIDDEN; extern HRESULT create_fontfallback_builder(IDWriteFactory7 *factory, IDWriteFontFallbackBuilder **builder) DECLSPEC_HIDDEN; -extern HRESULT create_matching_font(IDWriteFontCollection*,const WCHAR*,DWRITE_FONT_WEIGHT,DWRITE_FONT_STYLE,DWRITE_FONT_STRETCH, - IDWriteFont**) DECLSPEC_HIDDEN; +extern HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *family, DWRITE_FONT_WEIGHT weight, + DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, REFIID riid, void **obj) DECLSPEC_HIDDEN; extern HRESULT create_fontfacereference(IDWriteFactory7 *factory, IDWriteFontFile *file, UINT32 face_index, DWRITE_FONT_SIMULATIONS simulations, DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 axis_values_count, IDWriteFontFaceReference1 **reference) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c index ba80c3f70e8..60fcb8cc71a 100644 --- a/dlls/dwrite/layout.c +++ b/dlls/dwrite/layout.c @@ -682,7 +682,8 @@ static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout) collection = range->collection ? range->collection : sys_collection;
if (FAILED(hr = create_matching_font(collection, range->fontfamily, range->weight, range->style, - range->stretch, &font))) { + range->stretch, &IID_IDWriteFont, (void **)&font))) + { WARN("%s: failed to create matching font for non visual run, family %s, collection %p\n", debugstr_rundescr(&run->descr), debugstr_w(range->fontfamily), range->collection); break; @@ -1828,14 +1829,11 @@ static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, U HRESULT hr;
range = get_layout_range_by_pos(layout, pos); - hr = create_matching_font(range->collection, - range->fontfamily, - range->weight, - range->style, - range->stretch, - &font); - if (FAILED(hr)) + if (FAILED(hr = create_matching_font(range->collection, range->fontfamily, range->weight, range->style, + range->stretch, &IID_IDWriteFont, (void **)&font))) + { return hr; + } hr = IDWriteFont_CreateFontFace(font, &fontface); IDWriteFont_Release(font); if (FAILED(hr))
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 252 +++++++++++++++++++++++++++++++++++-- dlls/dwrite/tests/layout.c | 33 ++--- 2 files changed, 255 insertions(+), 30 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 0769dada355..4b666b8ca46 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -220,6 +220,95 @@ static const DWRITE_UNICODE_RANGE cjk_ranges[] = { 0x4e00, 0x9fff }, /* CJK Unified Ideographs */ };
+struct text_source_context +{ + IDWriteTextAnalysisSource *source; + + UINT32 position; + UINT32 length; + UINT32 consumed; + + UINT32 chunk_length; + const WCHAR *text; + UINT32 cursor; + HRESULT status; + BOOL end; + + UINT32 ch; +}; + +static void text_source_read_more(struct text_source_context *context) +{ + if ((context->chunk_length - context->cursor) > 1) return; + + context->position += context->cursor; + context->cursor = 0; + if (FAILED(context->status = IDWriteTextAnalysisSource_GetTextAtPosition(context->source, context->position, + &context->text, &context->chunk_length))) + { + context->end = TRUE; + } +} + +static void text_source_get_u32_char(struct text_source_context *context) +{ + const WCHAR *text; + UINT32 available; + + /* Make sure to have full pair of surrogates */ + text_source_read_more(context); + + available = context->chunk_length - context->cursor; + text = context->text + context->cursor; + + if (available > 1 && IS_HIGH_SURROGATE(*text) && IS_LOW_SURROGATE(*(text + 1))) + { + context->cursor += 2; + context->consumed += 2; + context->ch = 0x10000 + ((*text - 0xd800) << 10) + *(text + 1) - 0xdc00; + return; + } + + context->cursor++; + context->consumed++; + context->ch = *text; +} + +static HRESULT text_source_context_init(struct text_source_context *context, IDWriteTextAnalysisSource *source, + UINT32 position, UINT32 length) +{ + memset(context, 0, sizeof(*context)); + context->source = source; + context->position = position; + context->length = length; + + return IDWriteTextAnalysisSource_GetTextAtPosition(source, position, &context->text, &context->chunk_length); +} + +static BOOL text_source_get_next_u32_char(struct text_source_context *context) +{ + if (context->consumed == context->length) + { + context->ch = 0; + context->end = TRUE; + } + else if (context->cursor < context->chunk_length) + { + text_source_get_u32_char(context); + } + else + { + text_source_read_more(context); + /* Normal end-of-text condition. */ + if (!context->text || !context->chunk_length) + context->end = TRUE; + else + text_source_get_u32_char(context); + } + + return context->end; +} + struct fallback_mapping { DWRITE_UNICODE_RANGE *ranges; @@ -352,6 +441,38 @@ static void release_fallback_data(struct fallback_data *data) fallback_locale_list_destroy(&data->locales); }
+static const struct fallback_mapping * find_fallback_mapping(const struct fallback_data *fallback, + const struct fallback_locale *locale, UINT32 ch) +{ + const struct fallback_mapping *mapping; + size_t i, j, r; + + for (i = 0; i < locale->ranges.count; i += 2) + { + size_t start = locale->ranges.data[i], end = locale->ranges.data[i + 1]; + for (j = start; j <= end; ++j) + { + mapping = &fallback->mappings[j]; + for (r = 0; r < mapping->ranges_count; ++r) + { + const DWRITE_UNICODE_RANGE *range = &mapping->ranges[r]; + if (range->first <= ch && range->last >= ch) return mapping; + } + } + } + + mapping = NULL; + + /* Mapping wasn't found for specific locale, try with neutral one. This will only recurse once. */ + if (*locale->name) + { + locale = font_fallback_get_locale(&fallback->locales, L""); + mapping = find_fallback_mapping(fallback, locale, ch); + } + + return mapping; +} + struct dwrite_numbersubstitution { IDWriteNumberSubstitution IDWriteNumberSubstitution_iface; @@ -2114,7 +2235,7 @@ static int __cdecl compare_mapping_range(const void *a, const void *b) return 0; }
-static const struct fallback_mapping *find_fallback_mapping(struct dwrite_fontfallback *fallback, UINT32 ch) +static const struct fallback_mapping *find_fallback_mapping_system(struct dwrite_fontfallback *fallback, UINT32 ch) { UINT32 i;
@@ -2129,6 +2250,89 @@ static const struct fallback_mapping *find_fallback_mapping(struct dwrite_fontfa return NULL; }
+static UINT32 fallback_font_get_supported_length(IDWriteFont3 *font, IDWriteTextAnalysisSource *source, UINT32 position, + UINT32 length) +{ + struct text_source_context context; + UINT32 mapped = 0; + + text_source_context_init(&context, source, position, length); + while (!text_source_get_next_u32_char(&context)) + { + if (!IDWriteFont3_HasCharacter(font, context.ch)) break; + mapped++; + } + + return mapped; +} + +static HRESULT fallback_map_characters(const struct dwrite_fontfallback *fallback, IDWriteTextAnalysisSource *source, + UINT32 position, UINT32 text_length, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, + DWRITE_FONT_STRETCH stretch, IDWriteFont **ret_font, UINT32 *ret_length, float *scale) +{ + const struct fallback_mapping *mapping = NULL; + struct text_source_context context; + const WCHAR *locale_name = NULL; + struct fallback_locale *locale; + UINT32 i, length = 0, mapped; + IDWriteFont3 *font; + HRESULT hr; + + /* We will try to map as much of given input as GetLocaleName() says. It's assumed that returned length covers + whole span of characters set with that locale, so callback is only used once. */ + if (FAILED(hr = IDWriteTextAnalysisSource_GetLocaleName(source, position, &length, &locale_name))) + return hr; + + length = length ? min(length, text_length) : text_length; + if (!locale_name) locale_name = L""; + + /* Lookup locale entry once, if specific locale is missing neutral one will be returned. */ + locale = font_fallback_get_locale(&fallback->data.locales, locale_name); + + if (FAILED(hr = text_source_context_init(&context, source, position, length))) return hr; + + /* Find a mapping for given locale. */ + text_source_get_next_u32_char(&context); + if (!(mapping = find_fallback_mapping(&fallback->data, locale, context.ch))) + { + *ret_font = NULL; + *ret_length = 0; + + return S_OK; + } + + while (!text_source_get_next_u32_char(&context)) + { + if (find_fallback_mapping(&fallback->data, locale, context.ch) != mapping) break; + } + + /* Go through families in the mapping, use first family that supports some of the input. */ + for (i = 0; i < mapping->families_count; ++i) + { + if (SUCCEEDED(create_matching_font(mapping->collection ? mapping->collection : fallback->systemcollection, + mapping->families[i], weight, style, stretch, &IID_IDWriteFont3, (void **)&font))) + { + if (!(mapped = fallback_font_get_supported_length(font, source, position, length))) + { + IDWriteFont3_Release(font); + continue; + } + + *ret_font = (IDWriteFont *)font; + *ret_length = mapped; + *scale = mapping->scale; + + return S_OK; + } + } + + /* Mapping was found, but either font couldn't be created or there's no font that supports given input. */ + *ret_font = NULL; + *ret_length = length; + + return S_OK; +} + HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *name, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, REFIID riid, void **obj) { @@ -2163,7 +2367,7 @@ HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *nam return hr; }
-static HRESULT fallback_map_characters(IDWriteFont *font, const WCHAR *text, UINT32 length, UINT32 *mapped_length) +static HRESULT fallback_map_characters_system(IDWriteFont *font, const WCHAR *text, UINT32 length, UINT32 *mapped_length) { HRESULT hr = S_OK; UINT32 i; @@ -2199,7 +2403,7 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback,
*mapped_font = NULL;
- mapping = find_fallback_mapping(fallback, text[0]); + mapping = find_fallback_mapping_system(fallback, text[0]); if (!mapping) { WARN("No mapping range for %#x.\n", text[0]); return E_FAIL; @@ -2220,7 +2424,7 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback, return E_FAIL; }
- hr = fallback_map_characters(*mapped_font, text, length, mapped_length); + hr = fallback_map_characters_system(*mapped_font, text, length, mapped_length); if (FAILED(hr)) WARN("Mapping with fallback family %s failed, hr %#lx.\n", debugstr_w(mapping->families[i]), hr);
@@ -2267,7 +2471,7 @@ static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback1 *iface, ID if (FAILED(hr)) goto done;
- hr = fallback_map_characters(*ret_font, text, length, mapped_length); + hr = fallback_map_characters_system(*ret_font, text, length, mapped_length); if (FAILED(hr)) goto done; } @@ -2372,14 +2576,42 @@ static ULONG WINAPI customfontfallback_Release(IDWriteFontFallback1 *iface) }
static HRESULT WINAPI customfontfallback_MapCharacters(IDWriteFontFallback1 *iface, IDWriteTextAnalysisSource *source, - UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily, - DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, UINT32 *mapped_length, - IDWriteFont **ret_font, FLOAT *scale) + UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily, + DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, UINT32 *mapped_length, + IDWriteFont **ret_font, float *scale) { - FIXME("%p, %p, %u, %u, %p, %s, %u, %u, %u, %p, %p, %p.\n", iface, source, position, length, + struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface); + IDWriteFont3 *font; + + TRACE("%p, %p, %u, %u, %p, %s, %u, %u, %u, %p, %p, %p.\n", iface, source, position, length, basecollection, debugstr_w(basefamily), weight, style, stretch, mapped_length, ret_font, scale);
- return E_NOTIMPL; + *mapped_length = 0; + *ret_font = NULL; + *scale = 1.0f; + + if (!length) + return S_OK; + + if (!basecollection) + basecollection = fallback->systemcollection; + + if (basefamily && *basefamily) + { + if (SUCCEEDED(create_matching_font(basecollection, basefamily, weight, style, stretch, + &IID_IDWriteFont, (void **)&font))) + { + if ((*mapped_length = fallback_font_get_supported_length(font, source, position, length))) + { + *ret_font = (IDWriteFont *)font; + *scale = 1.0f; + return S_OK; + } + IDWriteFont3_Release(font); + } + } + + return fallback_map_characters(fallback, source, position, length, weight, style, stretch, ret_font, mapped_length, scale); }
static HRESULT WINAPI customfontfallback1_MapCharacters(IDWriteFontFallback1 *iface, IDWriteTextAnalysisSource *source, diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index 31bccfca3be..bcc5303ab61 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -4937,12 +4937,11 @@ static void test_FontFallbackBuilder(void) font = (void*)0xdeadbeef; hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); -todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(mappedlength == 1, "got %u\n", mappedlength); - ok(scale == 1.0f, "got %f\n", scale); - ok(font == NULL, "got %p\n", font); -} + ok(mappedlength == 1, "Unexpected length %u.\n", mappedlength); + ok(scale == 1.0f, "Unexpected scale %f.\n", scale); + ok(!font, "Unexpected font instance %p.\n", font); + IDWriteFontFallback_Release(fallback);
/* remap with custom collection */ @@ -4959,12 +4958,10 @@ todo_wine { font = NULL; hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); -todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(mappedlength == 1, "got %u\n", mappedlength); - ok(scale == 5.0f, "got %f\n", scale); - ok(font != NULL, "got %p\n", font); -} + ok(mappedlength == 1, "Unexpected length %u.\n", mappedlength); + ok(scale == 5.0f, "Unexpected scale %f.\n", scale); + ok(font != NULL, "Expected font instance %p.\n", font); if (font) IDWriteFont_Release(font);
@@ -4984,12 +4981,10 @@ todo_wine { font = NULL; hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); -todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(mappedlength == 1, "got %u\n", mappedlength); - ok(scale == 5.0f, "got %f\n", scale); - ok(font != NULL, "got %p\n", font); -} + ok(mappedlength == 1, "Unexpected length %u.\n", mappedlength); + ok(scale == 5.0f, "Unexpected scale %f.\n", scale); + ok(font != NULL, "Expected font instance %p.\n", font); if (font) IDWriteFont_Release(font);
@@ -5010,12 +5005,10 @@ todo_wine { font = NULL; hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); -todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(mappedlength == 1, "got %u\n", mappedlength); - ok(scale == 5.0f, "got %f\n", scale); - ok(font != NULL, "got %p\n", font); -} + ok(mappedlength == 1, "Unexpected length %u.\n", mappedlength); + ok(scale == 5.0f, "Unexpected scale %f.\n", scale); + ok(font != NULL, "Expected font instance %p.\n", font); if (font) IDWriteFont_Release(font);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 402 +++++++++++++++-------------------- dlls/dwrite/dwrite_private.h | 1 + dlls/dwrite/layout.c | 30 ++- dlls/dwrite/main.c | 1 + dlls/dwrite/tests/layout.c | 50 ++--- 5 files changed, 217 insertions(+), 267 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index 4b666b8ca46..f0295eed48c 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -210,16 +210,19 @@ const char *debugstr_sa_script(UINT16 script) return script < Script_LastId ? debugstr_tag(dwritescripts_properties[script].props.isoScriptCode) : "undefined"; }
-/* system font falback configuration */ -static const WCHAR *cjk_families[] = { L"Meiryo" }; - -static const DWRITE_UNICODE_RANGE cjk_ranges[] = +static const struct fallback_description +{ + const char *ranges; + const WCHAR *families; + const WCHAR *locale; +} +system_fallback_config[] = { - { 0x3000, 0x30ff }, /* CJK Symbols and Punctuation, Hiragana, Katakana */ - { 0x31f0, 0x31ff }, /* Katakana Phonetic Extensions */ - { 0x4e00, 0x9fff }, /* CJK Unified Ideographs */ + { "3000-30FF, 31F0-31FF, 4E00-9FFF", L"Meiryo" }, };
+static struct fallback_data system_fallback; + struct text_source_context { IDWriteTextAnalysisSource *source; @@ -381,16 +384,6 @@ static struct fallback_locale * font_fallback_get_locale(const struct list *loca return neutral; }
-static const struct fallback_mapping fontfallback_neutral_data[] = { -#define MAPPING_RANGE(ranges, families) \ - { (DWRITE_UNICODE_RANGE *)ranges, ARRAY_SIZE(ranges), \ - (WCHAR **)families, ARRAY_SIZE(families) } - - MAPPING_RANGE(cjk_ranges, cjk_families), - -#undef MAPPING_RANGE -}; - struct fallback_data { struct fallback_mapping *mappings; @@ -404,8 +397,6 @@ struct dwrite_fontfallback LONG refcount; IDWriteFactory7 *factory; IDWriteFontCollection *systemcollection; - struct fallback_mapping *mappings; - UINT32 mappings_count; struct fallback_data data; size_t mappings_size; }; @@ -2222,34 +2213,6 @@ static ULONG WINAPI fontfallback_Release(IDWriteFontFallback1 *iface) return IDWriteFactory7_Release(fallback->factory); }
-static int __cdecl compare_mapping_range(const void *a, const void *b) -{ - UINT32 ch = *(UINT32 *)a; - DWRITE_UNICODE_RANGE *range = (DWRITE_UNICODE_RANGE *)b; - - if (ch > range->last) - return 1; - else if (ch < range->first) - return -1; - else - return 0; -} - -static const struct fallback_mapping *find_fallback_mapping_system(struct dwrite_fontfallback *fallback, UINT32 ch) -{ - UINT32 i; - - for (i = 0; i < fallback->mappings_count; i++) { - struct fallback_mapping *mapping = &fallback->mappings[i]; - - if (bsearch(&ch, mapping->ranges, mapping->ranges_count, sizeof(*mapping->ranges), - compare_mapping_range) != NULL) - return mapping; - } - - return NULL; -} - static UINT32 fallback_font_get_supported_length(IDWriteFont3 *font, IDWriteTextAnalysisSource *source, UINT32 position, UINT32 length) { @@ -2272,12 +2235,16 @@ static HRESULT fallback_map_characters(const struct dwrite_fontfallback *fallbac { const struct fallback_mapping *mapping = NULL; struct text_source_context context; + const struct fallback_data *data; const WCHAR *locale_name = NULL; struct fallback_locale *locale; UINT32 i, length = 0, mapped; IDWriteFont3 *font; HRESULT hr;
+ /* ~0u is a marker for system fallback data */ + data = fallback->data.count == ~0u ? &system_fallback : &fallback->data; + /* We will try to map as much of given input as GetLocaleName() says. It's assumed that returned length covers whole span of characters set with that locale, so callback is only used once. */ if (FAILED(hr = IDWriteTextAnalysisSource_GetLocaleName(source, position, &length, &locale_name))) @@ -2287,13 +2254,13 @@ static HRESULT fallback_map_characters(const struct dwrite_fontfallback *fallbac if (!locale_name) locale_name = L"";
/* Lookup locale entry once, if specific locale is missing neutral one will be returned. */ - locale = font_fallback_get_locale(&fallback->data.locales, locale_name); + locale = font_fallback_get_locale(&data->locales, locale_name);
if (FAILED(hr = text_source_context_init(&context, source, position, length))) return hr;
/* Find a mapping for given locale. */ text_source_get_next_u32_char(&context); - if (!(mapping = find_fallback_mapping(&fallback->data, locale, context.ch))) + if (!(mapping = find_fallback_mapping(data, locale, context.ch))) { *ret_font = NULL; *ret_length = 0; @@ -2303,7 +2270,7 @@ static HRESULT fallback_map_characters(const struct dwrite_fontfallback *fallbac
while (!text_source_get_next_u32_char(&context)) { - if (find_fallback_mapping(&fallback->data, locale, context.ch) != mapping) break; + if (find_fallback_mapping(data, locale, context.ch) != mapping) break; }
/* Go through families in the mapping, use first family that supports some of the input. */ @@ -2367,136 +2334,46 @@ HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *nam return hr; }
-static HRESULT fallback_map_characters_system(IDWriteFont *font, const WCHAR *text, UINT32 length, UINT32 *mapped_length) -{ - HRESULT hr = S_OK; - UINT32 i; - - for (i = 0; i < length; i++) { - UINT16 script = get_char_script(text[i]); - BOOL exists; - - if (script == Script_Unknown || script == Script_Common) { - ++*mapped_length; - continue; - } - - /* stop on first unsupported character */ - exists = FALSE; - hr = IDWriteFont_HasCharacter(font, text[i], &exists); - if (hr == S_OK && exists) - ++*mapped_length; - else - break; - } - - return hr; -} - -static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback, const WCHAR *text, UINT32 length, - DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, UINT32 *mapped_length, - IDWriteFont **mapped_font) -{ - const struct fallback_mapping *mapping; - HRESULT hr; - UINT32 i; - - *mapped_font = NULL; - - mapping = find_fallback_mapping_system(fallback, text[0]); - if (!mapping) { - WARN("No mapping range for %#x.\n", text[0]); - return E_FAIL; - } - - /* Now let's see what fallback can handle. Pick first font that could be created. */ - for (i = 0; i < mapping->families_count; i++) { - hr = create_matching_font((IDWriteFontCollection *)fallback->systemcollection, mapping->families[i], - weight, style, stretch, &IID_IDWriteFont, (void **)mapped_font); - if (hr == S_OK) { - TRACE("Created fallback font using family %s.\n", debugstr_w(mapping->families[i])); - break; - } - } - - if (!*mapped_font) { - WARN("Failed to create fallback font.\n"); - return E_FAIL; - } - - hr = fallback_map_characters_system(*mapped_font, text, length, mapped_length); - if (FAILED(hr)) - WARN("Mapping with fallback family %s failed, hr %#lx.\n", debugstr_w(mapping->families[i]), hr); - - if (!*mapped_length) { - IDWriteFont_Release(*mapped_font); - *mapped_font = NULL; - } - - return *mapped_length ? S_OK : E_FAIL; -} - static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback1 *iface, IDWriteTextAnalysisSource *source, - UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily, - DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, UINT32 *mapped_length, - IDWriteFont **ret_font, FLOAT *scale) + UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily, + DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, UINT32 *mapped_length, + IDWriteFont **ret_font, float *scale) { struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface); - WCHAR *buff = NULL; - const WCHAR *text; - HRESULT hr; + IDWriteFont3 *font;
- TRACE("%p, %p, %u, %u, %p, %s, %u, %u, %u, %p, %p, %p.\n", iface, source, position, length, basecollection, - debugstr_w(basefamily), weight, style, stretch, mapped_length, ret_font, scale); + TRACE("%p, %p, %u, %u, %p, %s, %u, %u, %u, %p, %p, %p.\n", iface, source, position, length, + basecollection, debugstr_w(basefamily), weight, style, stretch, mapped_length, ret_font, scale);
*mapped_length = 0; - *scale = 1.0f; *ret_font = NULL; + *scale = 1.0f;
if (!source) return E_INVALIDARG;
- if (length == 0) + if (!length) return S_OK;
if (!basecollection) - basecollection = (IDWriteFontCollection*)fallback->systemcollection; - - hr = get_text_source_ptr(source, position, length, &text, &buff); - if (FAILED(hr)) - goto done; - - if (basefamily && *basefamily) { - hr = create_matching_font(basecollection, basefamily, weight, style, stretch, &IID_IDWriteFont, (void **)ret_font); - if (FAILED(hr)) - goto done; - - hr = fallback_map_characters_system(*ret_font, text, length, mapped_length); - if (FAILED(hr)) - goto done; - } - - if (!*mapped_length) { - IDWriteFont *mapped_font; + basecollection = fallback->systemcollection;
- hr = fallback_get_fallback_font(fallback, text, length, weight, style, stretch, mapped_length, &mapped_font); - if (FAILED(hr)) { - /* fallback wasn't found, keep base font if any, so we can get at least some visual output */ - if (*ret_font) { - *mapped_length = length; - hr = S_OK; + if (basefamily && *basefamily) + { + if (SUCCEEDED(create_matching_font(basecollection, basefamily, weight, style, stretch, + &IID_IDWriteFont, (void **)&font))) + { + if ((*mapped_length = fallback_font_get_supported_length(font, source, position, length))) + { + *ret_font = (IDWriteFont *)font; + *scale = 1.0f; + return S_OK; } - } - else { - if (*ret_font) - IDWriteFont_Release(*ret_font); - *ret_font = mapped_font; + IDWriteFont3_Release(font); } }
-done: - free(buff); - return hr; + return fallback_map_characters(fallback, source, position, length, weight, style, stretch, ret_font, mapped_length, scale); }
static HRESULT WINAPI fontfallback1_MapCharacters(IDWriteFontFallback1 *iface, IDWriteTextAnalysisSource *source, @@ -2519,26 +2396,6 @@ static const IDWriteFontFallback1Vtbl fontfallbackvtbl = fontfallback1_MapCharacters, };
-HRESULT create_system_fontfallback(IDWriteFactory7 *factory, IDWriteFontFallback1 **ret) -{ - struct dwrite_fontfallback *fallback; - - *ret = NULL; - - if (!(fallback = calloc(1, sizeof(*fallback)))) - return E_OUTOFMEMORY; - - fallback->IDWriteFontFallback1_iface.lpVtbl = &fontfallbackvtbl; - fallback->factory = factory; - fallback->mappings = (struct fallback_mapping *)fontfallback_neutral_data; - fallback->mappings_count = ARRAY_SIZE(fontfallback_neutral_data); - IDWriteFactory_GetSystemFontCollection((IDWriteFactory *)fallback->factory, &fallback->systemcollection, FALSE); - - *ret = &fallback->IDWriteFontFallback1_iface; - - return S_OK; -} - void release_system_fontfallback(IDWriteFontFallback1 *iface) { struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface); @@ -2575,63 +2432,13 @@ static ULONG WINAPI customfontfallback_Release(IDWriteFontFallback1 *iface) return refcount; }
-static HRESULT WINAPI customfontfallback_MapCharacters(IDWriteFontFallback1 *iface, IDWriteTextAnalysisSource *source, - UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily, - DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, UINT32 *mapped_length, - IDWriteFont **ret_font, float *scale) -{ - struct dwrite_fontfallback *fallback = impl_from_IDWriteFontFallback1(iface); - IDWriteFont3 *font; - - TRACE("%p, %p, %u, %u, %p, %s, %u, %u, %u, %p, %p, %p.\n", iface, source, position, length, - basecollection, debugstr_w(basefamily), weight, style, stretch, mapped_length, ret_font, scale); - - *mapped_length = 0; - *ret_font = NULL; - *scale = 1.0f; - - if (!length) - return S_OK; - - if (!basecollection) - basecollection = fallback->systemcollection; - - if (basefamily && *basefamily) - { - if (SUCCEEDED(create_matching_font(basecollection, basefamily, weight, style, stretch, - &IID_IDWriteFont, (void **)&font))) - { - if ((*mapped_length = fallback_font_get_supported_length(font, source, position, length))) - { - *ret_font = (IDWriteFont *)font; - *scale = 1.0f; - return S_OK; - } - IDWriteFont3_Release(font); - } - } - - return fallback_map_characters(fallback, source, position, length, weight, style, stretch, ret_font, mapped_length, scale); -} - -static HRESULT WINAPI customfontfallback1_MapCharacters(IDWriteFontFallback1 *iface, IDWriteTextAnalysisSource *source, - UINT32 position, UINT32 length, IDWriteFontCollection *basecollection, const WCHAR *basefamily, - DWRITE_FONT_AXIS_VALUE const *axis_values, UINT32 values_count, UINT32 *mapped_length, FLOAT *scale, - IDWriteFontFace5 **ret_fontface) -{ - FIXME("%p, %p, %u, %u, %p, %s, %p, %u, %p, %p, %p.\n", iface, source, position, length, basecollection, - debugstr_w(basefamily), axis_values, values_count, mapped_length, scale, ret_fontface); - - return E_NOTIMPL; -} - static const IDWriteFontFallback1Vtbl customfontfallbackvtbl = { fontfallback_QueryInterface, customfontfallback_AddRef, customfontfallback_Release, - customfontfallback_MapCharacters, - customfontfallback1_MapCharacters, + fontfallback_MapCharacters, + fontfallback1_MapCharacters, };
static HRESULT WINAPI fontfallbackbuilder_QueryInterface(IDWriteFontFallbackBuilder *iface, REFIID riid, void **obj) @@ -2923,7 +2730,7 @@ static const IDWriteFontFallbackBuilderVtbl fontfallbackbuildervtbl = fontfallbackbuilder_CreateFontFallback, };
-HRESULT create_fontfallback_builder(IDWriteFactory7 *factory, IDWriteFontFallbackBuilder **ret) +static HRESULT create_fontfallback_builder_internal(IDWriteFactory7 *factory, struct dwrite_fontfallback_builder **ret) { struct dwrite_fontfallback_builder *builder;
@@ -2938,6 +2745,131 @@ HRESULT create_fontfallback_builder(IDWriteFactory7 *factory, IDWriteFontFallbac IDWriteFactory7_AddRef(builder->factory); list_init(&builder->data.locales);
- *ret = &builder->IDWriteFontFallbackBuilder_iface; + *ret = builder; + + return S_OK; +} + +HRESULT create_fontfallback_builder(IDWriteFactory7 *factory, IDWriteFontFallbackBuilder **ret) +{ + struct dwrite_fontfallback_builder *builder; + HRESULT hr; + + *ret = NULL; + + if (SUCCEEDED(hr = create_fontfallback_builder_internal(factory, &builder))) + *ret = &builder->IDWriteFontFallbackBuilder_iface; + + return hr; +} + +static void system_fallback_parse_ranges(const char *str, DWRITE_UNICODE_RANGE *ranges, + unsigned int max_count, unsigned int *ret) +{ + unsigned int count = 0; + char *end; + + while (*str && count < max_count) + { + ranges[count].first = ranges[count].last = strtoul(str, &end, 16); + if (*end == '-') + { + str = end + 1; + ranges[count].last = strtoul(str, &end, 16); + } + if (*end == ',') str = end + 1; + count++; + } + + *ret = count; +} + +static void system_fallback_parse_families(WCHAR *str, WCHAR **families, unsigned int max_count, + unsigned int *ret) +{ + unsigned int count = 0; + WCHAR *family, *ctx; + + family = wcstok_s(str, L",", &ctx); + while (family && count < max_count) + { + while (*family == ' ') family++; + families[count++] = family; + family = wcstok_s(NULL, L",", &ctx); + } + + *ret = count; +} + +static INIT_ONCE init_system_fallback_once = INIT_ONCE_STATIC_INIT; + +/* Particular factory instance used for initialization is not important, it won't be referenced by + created fallback data. */ +static BOOL WINAPI dwrite_system_fallback_initonce(INIT_ONCE *once, void *param, void **context) +{ + struct dwrite_fontfallback_builder *builder; + IDWriteFontFallbackBuilder *builder_iface; + unsigned int range_count, families_count; + IDWriteFactory7 *factory = param; + DWRITE_UNICODE_RANGE ranges[16]; + WCHAR *families[4], *str; + HRESULT hr; + size_t i; + + if (FAILED(create_fontfallback_builder_internal(factory, &builder))) return FALSE; + builder_iface = &builder->IDWriteFontFallbackBuilder_iface; + + for (i = 0; i < ARRAY_SIZE(system_fallback_config); ++i) + { + const struct fallback_description *entry = &system_fallback_config[i]; + + system_fallback_parse_ranges(entry->ranges, ranges, ARRAY_SIZE(ranges), &range_count); + + /* TODO: reuse the buffer */ + str = wcsdup(entry->families); + system_fallback_parse_families(str, families, ARRAY_SIZE(families), &families_count); + + if (FAILED(hr = IDWriteFontFallbackBuilder_AddMapping(builder_iface, ranges, range_count, + (const WCHAR **)families, families_count, NULL, entry->locale, NULL, 1.0f))) + { + WARN("Failed to add mapping, hr %#lx.\n", hr); + } + + free(str); + } + + hr = fallbackbuilder_init_fallback_data(builder, &system_fallback); + IDWriteFontFallbackBuilder_Release(builder_iface); + + return hr == S_OK; +} + +void release_system_fallback_data(void) +{ + release_fallback_data(&system_fallback); +} + +HRESULT create_system_fontfallback(IDWriteFactory7 *factory, IDWriteFontFallback1 **ret) +{ + struct dwrite_fontfallback *fallback; + + *ret = NULL; + + if (!InitOnceExecuteOnce(&init_system_fallback_once, dwrite_system_fallback_initonce, factory, NULL)) + { + WARN("Failed to initialize system fallback data.\n"); + return E_FAIL; + } + + if (!(fallback = calloc(1, sizeof(*fallback)))) + return E_OUTOFMEMORY; + + fallback->IDWriteFontFallback1_iface.lpVtbl = &fontfallbackvtbl; + fallback->factory = factory; + fallback->data.count = ~0u; + IDWriteFactory_GetSystemFontCollection((IDWriteFactory *)fallback->factory, &fallback->systemcollection, FALSE); + + *ret = &fallback->IDWriteFontFallback1_iface; + return S_OK; } diff --git a/dlls/dwrite/dwrite_private.h b/dlls/dwrite/dwrite_private.h index a46d5fe7d96..f274c8acb0f 100644 --- a/dlls/dwrite/dwrite_private.h +++ b/dlls/dwrite/dwrite_private.h @@ -323,6 +323,7 @@ extern HRESULT create_colorglyphenum(D2D1_POINT_2F origin, const DWRITE_GLYPH_RU extern BOOL lb_is_newline_char(WCHAR) DECLSPEC_HIDDEN; extern HRESULT create_system_fontfallback(IDWriteFactory7 *factory, IDWriteFontFallback1 **fallback) DECLSPEC_HIDDEN; extern void release_system_fontfallback(IDWriteFontFallback1 *fallback) DECLSPEC_HIDDEN; +extern void release_system_fallback_data(void) DECLSPEC_HIDDEN; extern HRESULT create_fontfallback_builder(IDWriteFactory7 *factory, IDWriteFontFallbackBuilder **builder) DECLSPEC_HIDDEN; extern HRESULT create_matching_font(IDWriteFontCollection *collection, const WCHAR *family, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STYLE style, DWRITE_FONT_STRETCH stretch, REFIID riid, void **obj) DECLSPEC_HIDDEN; diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c index 60fcb8cc71a..447b3d5176b 100644 --- a/dlls/dwrite/layout.c +++ b/dlls/dwrite/layout.c @@ -643,7 +643,7 @@ static HRESULT layout_itemize(struct dwrite_textlayout *layout)
static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout) { - IDWriteFontCollection *sys_collection; + IDWriteFontCollection *sys_collection, *collection; IDWriteFontFallback *fallback = NULL; struct layout_range *range; struct layout_run *r; @@ -675,12 +675,10 @@ static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout) continue;
range = get_layout_range_by_pos(layout, run->descr.textPosition); + collection = range->collection ? range->collection : sys_collection;
- if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) { - IDWriteFontCollection *collection; - - collection = range->collection ? range->collection : sys_collection; - + if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) + { if (FAILED(hr = create_matching_font(collection, range->fontfamily, range->weight, range->style, range->stretch, &IID_IDWriteFont, (void **)&font))) { @@ -702,8 +700,9 @@ static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout)
length = run->descr.stringLength;
- while (length) { - UINT32 mapped_length; + while (length) + { + UINT32 mapped_length = 0; FLOAT scale;
run = &r->u.regular; @@ -726,6 +725,21 @@ static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout) goto fatal; }
+ if (!mapped_length) + { + if (FAILED(create_matching_font(range->collection, range->fontfamily, range->weight, range->style, + range->stretch, &IID_IDWriteFont3, (void **)&font))) + { + if (FAILED(hr = create_matching_font(sys_collection, L"Tahoma", range->weight, range->style, + range->stretch, &IID_IDWriteFont3, (void **)&font))) + { + WARN("Failed to create last resort font, hr %#lx.\n", hr); + goto fatal; + } + } + mapped_length = run->descr.stringLength; + } + hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace); IDWriteFont_Release(font); if (FAILED(hr)) { diff --git a/dlls/dwrite/main.c b/dlls/dwrite/main.c index c869ec3df54..8cc5d4dccf7 100644 --- a/dlls/dwrite/main.c +++ b/dlls/dwrite/main.c @@ -55,6 +55,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved) case DLL_PROCESS_DETACH: if (reserved) break; release_shared_factory(shared_factory); + release_system_fallback_data(); if (unixlib_handle) UNIX_CALL(process_detach, NULL); } return TRUE; diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index bcc5303ab61..9d6dca91b39 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -2672,9 +2672,9 @@ if (0) { /* crashes on native */ count = 0; hr = IDWriteTextLayout1_GetClusterMetrics(layout1, clusters, 4, &count); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(count == 3, "Unexpected cluster count %u.\n", count); + todo_wine ok(count == 3, "Unexpected cluster count %u.\n", count); ok(clusters[0].length == 1, "got %u\n", clusters[0].length); - ok(clusters[1].length == 2, "got %u\n", clusters[1].length); + todo_wine ok(clusters[1].length == 2, "got %u\n", clusters[1].length); ok(clusters[2].length == 1, "got %u\n", clusters[2].length);
/* pair kerning flag participates in itemization - combining characters @@ -4639,10 +4639,9 @@ static void test_MapCharacters(void) font = NULL; hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); -todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(mappedlength == 1, "got %u\n", mappedlength); -} ok(scale == 1.0f, "got %f\n", scale); todo_wine ok(font != NULL, "got %p\n", font); @@ -4656,10 +4655,10 @@ if (font) { font = NULL; hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); -todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(mappedlength == 3, "got %u\n", mappedlength); -} + ok(scale == 1.0f, "got %f\n", scale); todo_wine ok(font != NULL, "got %p\n", font); @@ -4673,10 +4672,9 @@ if (font) { font = NULL; hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); -todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(mappedlength == 1, "got %u\n", mappedlength); -} ok(scale == 1.0f, "got %f\n", scale); todo_wine ok(font != NULL, "got %p\n", font); @@ -4689,10 +4687,9 @@ if (font) { font = NULL; hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 1, 2, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); -todo_wine { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine ok(mappedlength == 1, "got %u\n", mappedlength); -} ok(scale == 1.0f, "got %f\n", scale); todo_wine ok(font != NULL, "got %p\n", font); @@ -4731,17 +4728,21 @@ if (font) { ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(mappedlength == 1, "got %u\n", mappedlength); ok(scale == 1.0f, "got %f\n", scale); + todo_wine ok(font != NULL, "got %p\n", font);
- exists = FALSE; - hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists); - ok(hr == S_OK && exists, "Unexpected hr %#lx, exists %d.\n", hr, exists); - hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW)); - ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine - ok(lstrcmpW(buffW, L"Tahoma"), "Unexpected string %s.\n", wine_dbgstr_w(buffW)); - IDWriteLocalizedStrings_Release(strings); - IDWriteFont_Release(font); + if (font) + { + exists = FALSE; + hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists); + ok(hr == S_OK && exists, "Unexpected hr %#lx, exists %d.\n", hr, exists); + hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW)); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + todo_wine + ok(lstrcmpW(buffW, L"Tahoma"), "Unexpected string %s.\n", wine_dbgstr_w(buffW)); + IDWriteLocalizedStrings_Release(strings); + IDWriteFont_Release(font); + }
IDWriteFontFallback_Release(fallback); IDWriteFactory2_Release(factory2); @@ -4802,14 +4803,17 @@ static void test_system_fallback(void)
for (i = 0; i < ARRAY_SIZE(tests); ++i) { + font = NULL; + g_source = tests[i].text; hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &length, &font, &scale); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); if (hr != S_OK) continue; + todo_wine ok(length == 1, "Unexpected length %u\n", length); ok(scale == 1.0f, "got %f\n", scale); + if (!font) continue;
get_font_name(font, name, ARRAY_SIZE(name)); todo_wine @@ -5054,21 +5058,17 @@ static void test_fallback(void)
count = 0; hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count); -todo_wine { ok(hr == S_OK, "Failed to get cluster metrics, hr %#lx.\n", hr); ok(count == 4, "Unexpected count %u.\n", count); -} for (i = 0, width = 0.0; i < count; i++) width += clusters[i].width;
memset(&metrics, 0xcc, sizeof(metrics)); hr = IDWriteTextLayout_GetMetrics(layout, &metrics); ok(hr == S_OK, "Failed to get layout metrics, hr %#lx.\n", hr); -todo_wine { ok(metrics.width > 0.0 && metrics.width == width, "Unexpected width %.2f, expected %.2f.\n", metrics.width, width); ok(metrics.height > 0.0, "Unexpected height %.2f.\n", metrics.height); ok(metrics.lineCount == 1, "Unexpected line count %u.\n", metrics.lineCount); -} IDWriteTextLayout_Release(layout); IDWriteTextFormat_Release(format);
@@ -5367,6 +5367,7 @@ static void test_SetUnderline(void) count = 0; hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, ARRAY_SIZE(clusters), &count); ok(hr == S_OK, "Failed to get cluster metrics, hr %#lx.\n", hr); + todo_wine ok(count == 3, "Unexpected cluster count %u.\n", count);
range.startPosition = 0; @@ -5377,6 +5378,7 @@ static void test_SetUnderline(void) count = 0; hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, ARRAY_SIZE(clusters), &count); ok(hr == S_OK, "Failed to get cluster metrics, hr %#lx.\n", hr); + todo_wine ok(count == 3, "Unexpected cluster count %u.\n", count);
flush_sequence(sequences, RENDERER_ID);
From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/dwrite/analyzer.c | 4 ++++ dlls/dwrite/layout.c | 2 +- dlls/dwrite/tests/layout.c | 24 +++++++++--------------- 3 files changed, 14 insertions(+), 16 deletions(-)
diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c index f0295eed48c..595d8806159 100644 --- a/dlls/dwrite/analyzer.c +++ b/dlls/dwrite/analyzer.c @@ -218,6 +218,10 @@ static const struct fallback_description } system_fallback_config[] = { + /* Latin, Combining Diacritical Marks */ + { "0000-007F, 0080-00FF, 0100-017F, 0180-024F, " + "0250-02AF, 02B0-02FF, 0300-036F", L"Tahoma" }, + { "3000-30FF, 31F0-31FF, 4E00-9FFF", L"Meiryo" }, };
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c index 447b3d5176b..2260e204c3f 100644 --- a/dlls/dwrite/layout.c +++ b/dlls/dwrite/layout.c @@ -725,7 +725,7 @@ static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout) goto fatal; }
- if (!mapped_length) + if (!font) { if (FAILED(create_matching_font(range->collection, range->fontfamily, range->weight, range->style, range->stretch, &IID_IDWriteFont3, (void **)&font))) diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index 9d6dca91b39..5e7e1b16d27 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -4640,14 +4640,12 @@ static void test_MapCharacters(void) hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(mappedlength == 1, "got %u\n", mappedlength); ok(scale == 1.0f, "got %f\n", scale); - todo_wine ok(font != NULL, "got %p\n", font); -if (font) { - IDWriteFont_Release(font); -} + if (font) + IDWriteFont_Release(font); + /* same Latin text, full length */ g_source = L"abc"; mappedlength = 0; @@ -4656,15 +4654,13 @@ if (font) { hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(mappedlength == 3, "got %u\n", mappedlength);
ok(scale == 1.0f, "got %f\n", scale); - todo_wine ok(font != NULL, "got %p\n", font); -if (font) { - IDWriteFont_Release(font); -} + if (font) + IDWriteFont_Release(font); + /* string 'a\x3058b' */ g_source = str2W; mappedlength = 0; @@ -4673,14 +4669,12 @@ if (font) { hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(mappedlength == 1, "got %u\n", mappedlength); ok(scale == 1.0f, "got %f\n", scale); - todo_wine ok(font != NULL, "got %p\n", font); -if (font) { - IDWriteFont_Release(font); -} + if (font) + IDWriteFont_Release(font); + g_source = str2W; mappedlength = 0; scale = 0.0f;
This merge request was approved by Nikolay Sivov.