Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dwrite: Make GetMetrics work with empty string and missing fonts #4

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
77 changes: 59 additions & 18 deletions dlls/dwrite/analyzer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2078,6 +2078,7 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback,
IDWriteFont **mapped_font)
{
const struct fallback_mapping *mapping;
IDWriteFontCollection *collection;
HRESULT hr;
UINT32 i;

Expand All @@ -2089,9 +2090,15 @@ static HRESULT fallback_get_fallback_font(struct dwrite_fontfallback *fallback,
return E_FAIL;
}

if (mapping->collection) {
collection = mapping->collection;
} else {
collection = (IDWriteFontCollection *)fallback->systemcollection;
}

/* 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],
hr = create_matching_font(collection, mapping->families[i],
weight, style, stretch, mapped_font);
if (hr == S_OK) {
TRACE("Created fallback font using family %s.\n", debugstr_w(mapping->families[i]));
Expand Down Expand Up @@ -2148,32 +2155,66 @@ static HRESULT WINAPI fontfallback_MapCharacters(IDWriteFontFallback *iface, IDW

if (basefamily && *basefamily) {
hr = create_matching_font(basecollection, basefamily, weight, style, stretch, ret_font);
if (FAILED(hr))
goto done;

hr = fallback_map_characters(*ret_font, text, length, mapped_length);
if (FAILED(hr))
goto done;
if (SUCCEEDED(hr)) {
hr = fallback_map_characters(*ret_font, text, length, mapped_length);
if (FAILED(hr)) {
IDWriteFont_Release(*ret_font);
*ret_font = NULL;
WARN("Mapping with requested family %s failed, hr %#x.\n", debugstr_w(basefamily), hr);
}
}
}

if (!*mapped_length) {
IDWriteFont *mapped_font;
if (*ret_font) {
IDWriteFont_Release(*ret_font);
*ret_font = NULL;
}

hr = fallback_get_fallback_font(fallback, text, length, weight, style, stretch, mapped_length, &mapped_font);
hr = fallback_get_fallback_font(fallback, text, length, weight, style, stretch, mapped_length, ret_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;
}
WARN("Mapping with fallback families failed, hr %#x.\n", hr);
}
else {
if (*ret_font)
IDWriteFont_Release(*ret_font);
*ret_font = mapped_font;
}

/**
* This is a rough hack. We search the system font collection because
* the system fontfallback, which would have been searched above, is not
* fully implemented as it isn't populated with any system fonts. Once
* implemented, the block below can be removed.
* */
if (!*mapped_length) {
IDWriteFontFamily *family;
IDWriteFont *font;
UINT32 i, count = IDWriteFontCollection_GetFontFamilyCount((IDWriteFontCollection *)fallback->systemcollection);
for (i = 0; i < count; i++) {
hr = IDWriteFontCollection_GetFontFamily((IDWriteFontCollection *)fallback->systemcollection, i, &family);
if (FAILED(hr)) {
ERR("Failed to get font family.\n");
continue;
}

hr = IDWriteFontFamily_GetFirstMatchingFont(family, weight, stretch, style, &font);
IDWriteFontFamily_Release(family);
if (FAILED(hr)) {
continue;
}

hr = fallback_map_characters(font, text, length, mapped_length);
if (SUCCEEDED(hr) && mapped_length > 0) {
*ret_font = font;
break;
}

IDWriteFont_Release(font);
}
}

if (!*mapped_length) {
*mapped_length = length == 0 ? 0 : 1;
hr = S_OK;
}

done:
heap_free(buff);
return hr;
Expand Down
57 changes: 50 additions & 7 deletions dlls/dwrite/layout.c
Original file line number Diff line number Diff line change
Expand Up @@ -822,20 +822,28 @@ static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout)
LIST_FOR_EACH_ENTRY(r, &layout->runs, struct layout_run, entry) {
struct regular_layout_run *run = &r->u.regular;
IDWriteFont *font;
UINT32 length;
UINT32 length, mapped_length;
FLOAT scale;

if (r->kind == LAYOUT_RUN_INLINE)
continue;

range = get_layout_range_by_pos(layout, run->descr.textPosition);

if (run->sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
IDWriteFontCollection *collection;

collection = range->collection ? range->collection : sys_collection;

if (FAILED(hr = create_matching_font(collection, range->fontfamily, range->weight, range->style,
range->stretch, &font))) {
hr = IDWriteFontFallback_MapCharacters(fallback,
(IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
run->descr.textPosition,
run->descr.stringLength,
range->collection,
range->fontfamily,
range->weight,
range->style,
range->stretch,
&mapped_length,
&font,
&scale);
if (FAILED(hr)) {
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;
Expand Down Expand Up @@ -878,6 +886,12 @@ static HRESULT layout_resolve_fonts(struct dwrite_textlayout *layout)
goto fatal;
}

if (!font) {
hr = E_FAIL;
WARN("Failed to create font face, hr %#x.\n", hr);
goto fatal;
}

hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
IDWriteFont_Release(font);
if (FAILED(hr)) {
Expand Down Expand Up @@ -1794,8 +1808,11 @@ static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, U
DWRITE_FONT_METRICS fontmetrics;
struct layout_range *range;
IDWriteFontFace *fontface;
IDWriteFontFallback *fallback;
IDWriteFont *font;
HRESULT hr;
UINT32 mapped_length;
FLOAT scale;

range = get_layout_range_by_pos(layout, pos);
hr = create_matching_font(range->collection,
Expand All @@ -1804,8 +1821,34 @@ static HRESULT layout_set_dummy_line_metrics(struct dwrite_textlayout *layout, U
range->style,
range->stretch,
&font);

if (FAILED(hr)) {
if (layout->format.fallback) {
fallback = layout->format.fallback;
IDWriteFontFallback_AddRef(fallback);
} else if (FAILED(hr = IDWriteFactory5_GetSystemFontFallback(layout->factory, &fallback))) {
WARN("Failed to get system fallback, hr %#x.\n", hr);
return hr;
}

hr = IDWriteFontFallback_MapCharacters(fallback,
(IDWriteTextAnalysisSource *)&layout->IDWriteTextAnalysisSource1_iface,
pos,
layout->len,
range->collection,
range->fontfamily,
range->weight,
range->style,
range->stretch,
&mapped_length,
&font,
&scale);
IDWriteFontFallback_Release(fallback);
}
if (FAILED(hr))
return hr;
if (font == NULL)
return S_OK;
hr = IDWriteFont_CreateFontFace(font, &fontface);
IDWriteFont_Release(font);
if (FAILED(hr))
Expand Down