dwrite: Return valid metrics for layout created on empty text.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2016-01-28 04:17:17 +03:00 committed by Alexandre Julliard
parent df68743187
commit fbcf15313d
2 changed files with 86 additions and 69 deletions

View File

@ -350,10 +350,9 @@ static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypog
return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface); return CONTAINING_RECORD(iface, struct dwrite_typography, IDWriteTypography_iface);
} }
static inline const char *debugstr_run(const struct regular_layout_run *run) static inline const char *debugstr_rundescr(const DWRITE_GLYPH_RUN_DESCRIPTION *descr)
{ {
return wine_dbg_sprintf("[%u,%u)", run->descr.textPosition, run->descr.textPosition + return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
run->descr.stringLength);
} }
static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout) static inline BOOL is_layout_gdi_compatible(struct dwrite_textlayout *layout)
@ -670,6 +669,57 @@ static void layout_set_cluster_metrics(struct dwrite_textlayout *layout, const s
#define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm) #define SCALE_FONT_METRIC(metric, emSize, metrics) ((FLOAT)(metric) * (emSize) / (FLOAT)(metrics)->designUnitsPerEm)
static HRESULT create_fontface_by_pos(struct dwrite_textlayout *layout, struct layout_range *range, IDWriteFontFace **fontface)
{
static DWRITE_GLYPH_RUN_DESCRIPTION descr = { 0 };
IDWriteFontFamily *family;
BOOL exists = FALSE;
IDWriteFont *font;
UINT32 index;
HRESULT hr;
*fontface = NULL;
hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
if (FAILED(hr) || !exists) {
WARN("%s: family %s not found in collection %p\n", debugstr_rundescr(&descr), debugstr_w(range->fontfamily), range->collection);
return hr;
}
hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
if (FAILED(hr))
return hr;
hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
IDWriteFontFamily_Release(family);
if (FAILED(hr)) {
WARN("%s: failed to get a matching font\n", debugstr_rundescr(&descr));
return hr;
}
hr = IDWriteFont_CreateFontFace(font, fontface);
IDWriteFont_Release(font);
return hr;
}
static void layout_get_font_metrics(struct dwrite_textlayout *layout, IDWriteFontFace *fontface, FLOAT emsize,
DWRITE_FONT_METRICS *fontmetrics)
{
if (is_layout_gdi_compatible(layout)) {
HRESULT hr = IDWriteFontFace_GetGdiCompatibleMetrics(fontface, emsize, layout->ppdip, &layout->transform, fontmetrics);
if (FAILED(hr))
WARN("failed to get compat metrics, 0x%08x\n", hr);
}
else
IDWriteFontFace_GetMetrics(fontface, fontmetrics);
}
static void layout_get_font_height(FLOAT emsize, DWRITE_FONT_METRICS *fontmetrics, FLOAT *baseline, FLOAT *height)
{
*baseline = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->lineGap, emsize, fontmetrics);
*height = SCALE_FONT_METRIC(fontmetrics->ascent + fontmetrics->descent + fontmetrics->lineGap, emsize, fontmetrics);
}
static HRESULT layout_compute_runs(struct dwrite_textlayout *layout) static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
{ {
IDWriteTextAnalyzer *analyzer; IDWriteTextAnalyzer *analyzer;
@ -737,10 +787,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL; DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
struct regular_layout_run *run = &r->u.regular; struct regular_layout_run *run = &r->u.regular;
DWRITE_FONT_METRICS fontmetrics = { 0 }; DWRITE_FONT_METRICS fontmetrics = { 0 };
IDWriteFontFamily *family; UINT32 max_count;
UINT32 index, max_count;
IDWriteFont *font;
BOOL exists = TRUE;
/* we need to do very little in case of inline objects */ /* we need to do very little in case of inline objects */
if (r->kind == LAYOUT_RUN_INLINE) { if (r->kind == LAYOUT_RUN_INLINE) {
@ -776,26 +823,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
} }
range = get_layout_range_by_pos(layout, run->descr.textPosition); range = get_layout_range_by_pos(layout, run->descr.textPosition);
hr = create_fontface_by_pos(layout, range, &run->run.fontFace);
hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
if (FAILED(hr) || !exists) {
WARN("%s: family %s not found in collection %p\n", debugstr_run(run), debugstr_w(range->fontfamily), range->collection);
continue;
}
hr = IDWriteFontCollection_GetFontFamily(range->collection, index, &family);
if (FAILED(hr))
continue;
hr = IDWriteFontFamily_GetFirstMatchingFont(family, range->weight, range->stretch, range->style, &font);
IDWriteFontFamily_Release(family);
if (FAILED(hr)) {
WARN("%s: failed to get a matching font\n", debugstr_run(run));
continue;
}
hr = IDWriteFont_CreateFontFace(font, &run->run.fontFace);
IDWriteFont_Release(font);
if (FAILED(hr)) if (FAILED(hr))
continue; continue;
@ -838,7 +866,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
if (FAILED(hr)) { if (FAILED(hr)) {
heap_free(text_props); heap_free(text_props);
heap_free(glyph_props); heap_free(glyph_props);
WARN("%s: shaping failed 0x%08x\n", debugstr_run(run), hr); WARN("%s: shaping failed 0x%08x\n", debugstr_rundescr(&run->descr), hr);
continue; continue;
} }
@ -866,7 +894,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
heap_free(text_props); heap_free(text_props);
heap_free(glyph_props); heap_free(glyph_props);
if (FAILED(hr)) if (FAILED(hr))
WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_run(run), hr); WARN("%s: failed to get glyph placement info, 0x%08x\n", debugstr_rundescr(&run->descr), hr);
run->run.glyphAdvances = run->advances; run->run.glyphAdvances = run->advances;
run->run.glyphOffsets = run->offsets; run->run.glyphOffsets = run->offsets;
@ -880,23 +908,10 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
run->run.glyphCount = run->glyphcount; run->run.glyphCount = run->glyphcount;
/* baseline derived from font metrics */ /* baseline derived from font metrics */
if (is_layout_gdi_compatible(layout)) { layout_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
hr = IDWriteFontFace_GetGdiCompatibleMetrics(run->run.fontFace, layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
run->run.fontEmSize,
layout->ppdip,
&layout->transform,
&fontmetrics);
if (FAILED(hr))
WARN("failed to get compat metrics, 0x%08x\n", hr);
}
else
IDWriteFontFace_GetMetrics(run->run.fontFace, &fontmetrics);
r->baseline = SCALE_FONT_METRIC(fontmetrics.ascent + fontmetrics.lineGap, run->run.fontEmSize, &fontmetrics);
r->height = SCALE_FONT_METRIC(fontmetrics.ascent + fontmetrics.descent + fontmetrics.lineGap, run->run.fontEmSize, &fontmetrics);
layout_set_cluster_metrics(layout, r, &cluster); layout_set_cluster_metrics(layout, r, &cluster);
continue; continue;
memerr: memerr:
@ -1702,7 +1717,32 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
textpos += layout->clustermetrics[i].length; textpos += layout->clustermetrics[i].length;
} }
layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0; /* Add dummy line when there's no text. Metrics come from first range. */
if (layout->len == 0) {
DWRITE_FONT_METRICS fontmetrics;
struct layout_range *range;
IDWriteFontFace *fontface;
range = get_layout_range_by_pos(layout, 0);
hr = create_fontface_by_pos(layout, range, &fontface);
if (FAILED(hr))
return hr;
layout_get_font_metrics(layout, fontface, range->fontsize, &fontmetrics);
layout_get_font_height(range->fontsize, &fontmetrics, &metrics.baseline, &metrics.height);
IDWriteFontFace_Release(fontface);
line = 0;
metrics.length = 0;
metrics.trailingWhitespaceLength = 0;
metrics.newlineLength = 0;
metrics.isTrimmed = FALSE;
hr = layout_set_line_metrics(layout, &metrics, &line);
if (FAILED(hr))
return hr;
}
layout->metrics.left = is_rtl ? layout->metrics.layoutWidth - layout->metrics.width : 0.0f;
layout->metrics.top = 0.0f; layout->metrics.top = 0.0f;
layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */ layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */
layout->metrics.height = 0.0f; layout->metrics.height = 0.0f;

View File

@ -3391,15 +3391,12 @@ todo_wine {
memset(metrics, 0, sizeof(metrics)); memset(metrics, 0, sizeof(metrics));
hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 1, &count); hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 1, &count);
ok(hr == S_OK, "got 0x%08x\n", hr); ok(hr == S_OK, "got 0x%08x\n", hr);
todo_wine
ok(count == 1, "got %u\n", count); ok(count == 1, "got %u\n", count);
ok(metrics[0].length == 0, "got %u\n", metrics[0].length); ok(metrics[0].length == 0, "got %u\n", metrics[0].length);
ok(metrics[0].trailingWhitespaceLength == 0, "got %u\n", metrics[0].trailingWhitespaceLength); ok(metrics[0].trailingWhitespaceLength == 0, "got %u\n", metrics[0].trailingWhitespaceLength);
ok(metrics[0].newlineLength == 0, "got %u\n", metrics[0].newlineLength); ok(metrics[0].newlineLength == 0, "got %u\n", metrics[0].newlineLength);
todo_wine {
ok(metrics[0].height > 0.0f, "got %f\n", metrics[0].height); ok(metrics[0].height > 0.0f, "got %f\n", metrics[0].height);
ok(metrics[0].baseline > 0.0f, "got %f\n", metrics[0].baseline); ok(metrics[0].baseline > 0.0f, "got %f\n", metrics[0].baseline);
}
ok(!metrics[0].isTrimmed, "got %d\n", metrics[0].isTrimmed); ok(!metrics[0].isTrimmed, "got %d\n", metrics[0].isTrimmed);
/* change font size at first position, see if metrics changed */ /* change font size at first position, see if metrics changed */
@ -3411,12 +3408,10 @@ todo_wine {
count = 0; count = 0;
hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count); hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count);
ok(hr == S_OK, "got 0x%08x\n", hr); ok(hr == S_OK, "got 0x%08x\n", hr);
todo_wine
ok(count == 1, "got %u\n", count); ok(count == 1, "got %u\n", count);
todo_wine {
ok(metrics[1].height > metrics[0].height, "got %f\n", metrics[1].height); ok(metrics[1].height > metrics[0].height, "got %f\n", metrics[1].height);
ok(metrics[1].baseline > metrics[0].baseline, "got %f\n", metrics[1].baseline); ok(metrics[1].baseline > metrics[0].baseline, "got %f\n", metrics[1].baseline);
}
/* revert font size back to format value, set different size for position 1 */ /* revert font size back to format value, set different size for position 1 */
hr = IDWriteTextLayout_SetFontSize(layout, 12.0f, range); hr = IDWriteTextLayout_SetFontSize(layout, 12.0f, range);
ok(hr == S_OK, "got 0x%08x\n", hr); ok(hr == S_OK, "got 0x%08x\n", hr);
@ -3430,7 +3425,6 @@ todo_wine {
count = 0; count = 0;
hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count); hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count);
ok(hr == S_OK, "got 0x%08x\n", hr); ok(hr == S_OK, "got 0x%08x\n", hr);
todo_wine
ok(count == 1, "got %u\n", count); ok(count == 1, "got %u\n", count);
ok(metrics[1].height == metrics[0].height, "got %f\n", metrics[1].height); ok(metrics[1].height == metrics[0].height, "got %f\n", metrics[1].height);
ok(metrics[1].baseline == metrics[0].baseline, "got %f\n", metrics[1].baseline); ok(metrics[1].baseline == metrics[0].baseline, "got %f\n", metrics[1].baseline);
@ -3508,7 +3502,6 @@ static void test_SetTextAlignment(void)
win_skip("IDWriteTextFormat1 is not supported\n"); win_skip("IDWriteTextFormat1 is not supported\n");
for (i = 0; i < sizeof(stringsW)/sizeof(stringsW[0]); i++) { for (i = 0; i < sizeof(stringsW)/sizeof(stringsW[0]); i++) {
BOOL todo = lstrlenW(stringsW[i]) == 0;
FLOAT text_width; FLOAT text_width;
hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING); hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING);
@ -3542,10 +3535,6 @@ static void test_SetTextAlignment(void)
ok(metrics.left == 0.0f, "got %.2f\n", metrics.left); ok(metrics.left == 0.0f, "got %.2f\n", metrics.left);
ok(metrics.width == text_width, "got %.2f\n", metrics.width); ok(metrics.width == text_width, "got %.2f\n", metrics.width);
ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth); ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth);
if (todo)
todo_wine
ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
else
ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount); ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
/* maxwidth is 500, trailing alignment */ /* maxwidth is 500, trailing alignment */
@ -3558,10 +3547,6 @@ static void test_SetTextAlignment(void)
ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left); ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
ok(metrics.width == text_width, "got %.2f\n", metrics.width); ok(metrics.width == text_width, "got %.2f\n", metrics.width);
ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth); ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth);
if (todo)
todo_wine
ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
else
ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount); ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
IDWriteTextLayout_Release(layout); IDWriteTextLayout_Release(layout);
@ -3578,10 +3563,6 @@ static void test_SetTextAlignment(void)
ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left); ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
ok(metrics.width == text_width, "got %.2f\n", metrics.width); ok(metrics.width == text_width, "got %.2f\n", metrics.width);
ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth); ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth);
if (todo)
todo_wine
ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
else
ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount); ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
IDWriteTextLayout_Release(layout); IDWriteTextLayout_Release(layout);
@ -3611,10 +3592,6 @@ static void test_SetTextAlignment(void)
ok(hr == S_OK, "got 0x%08x\n", hr); ok(hr == S_OK, "got 0x%08x\n", hr);
ok(metrics.left == (metrics.layoutWidth - metrics.width) / 2.0f, "got %.2f\n", metrics.left); ok(metrics.left == (metrics.layoutWidth - metrics.width) / 2.0f, "got %.2f\n", metrics.left);
ok(metrics.width == text_width, "got %.2f\n", metrics.width); ok(metrics.width == text_width, "got %.2f\n", metrics.width);
if (todo)
todo_wine
ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
else
ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount); ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
IDWriteTextLayout_Release(layout); IDWriteTextLayout_Release(layout);