[PATCH 3/5] dwrite: Return valid metrics for layout created on empty text

Nikolay Sivov nsivov at codeweavers.com
Wed Jan 27 19:17:17 CST 2016


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/layout.c       | 130 +++++++++++++++++++++++++++++----------------
 dlls/dwrite/tests/layout.c |  25 +--------
 2 files changed, 86 insertions(+), 69 deletions(-)

diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 620d389..c8ea84b 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -350,10 +350,9 @@ static inline struct dwrite_typography *impl_from_IDWriteTypography(IDWriteTypog
     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 +
-        run->descr.stringLength);
+    return wine_dbg_sprintf("[%u,%u)", descr->textPosition, descr->textPosition + descr->stringLength);
 }
 
 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)
 
+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)
 {
     IDWriteTextAnalyzer *analyzer;
@@ -737,10 +787,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
         DWRITE_SHAPING_TEXT_PROPERTIES *text_props = NULL;
         struct regular_layout_run *run = &r->u.regular;
         DWRITE_FONT_METRICS fontmetrics = { 0 };
-        IDWriteFontFamily *family;
-        UINT32 index, max_count;
-        IDWriteFont *font;
-        BOOL exists = TRUE;
+        UINT32 max_count;
 
         /* we need to do very little in case of inline objects */
         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);
-
-        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);
+        hr = create_fontface_by_pos(layout, range, &run->run.fontFace);
         if (FAILED(hr))
             continue;
 
@@ -838,7 +866,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
         if (FAILED(hr)) {
             heap_free(text_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;
         }
 
@@ -866,7 +894,7 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
         heap_free(text_props);
         heap_free(glyph_props);
         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.glyphOffsets = run->offsets;
@@ -880,23 +908,10 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
             run->run.glyphCount = run->glyphcount;
 
         /* baseline derived from font metrics */
-        if (is_layout_gdi_compatible(layout)) {
-            hr = IDWriteFontFace_GetGdiCompatibleMetrics(run->run.fontFace,
-                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_get_font_metrics(layout, run->run.fontFace, run->run.fontEmSize, &fontmetrics);
+        layout_get_font_height(run->run.fontEmSize, &fontmetrics, &r->baseline, &r->height);
 
         layout_set_cluster_metrics(layout, r, &cluster);
-
         continue;
 
     memerr:
@@ -1702,7 +1717,32 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
         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.maxBidiReorderingDepth = 1; /* FIXME */
     layout->metrics.height = 0.0f;
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index 24cf770..a7423f8 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -3391,15 +3391,12 @@ todo_wine {
     memset(metrics, 0, sizeof(metrics));
     hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 1, &count);
     ok(hr == S_OK, "got 0x%08x\n", hr);
-todo_wine
     ok(count == 1, "got %u\n", count);
     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].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].baseline > 0.0f, "got %f\n", metrics[0].baseline);
-}
     ok(!metrics[0].isTrimmed, "got %d\n", metrics[0].isTrimmed);
 
     /* change font size at first position, see if metrics changed */
@@ -3411,12 +3408,10 @@ todo_wine {
     count = 0;
     hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count);
     ok(hr == S_OK, "got 0x%08x\n", hr);
-todo_wine
     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].baseline > metrics[0].baseline, "got %f\n", metrics[1].baseline);
-}
+
     /* revert font size back to format value, set different size for position 1 */
     hr = IDWriteTextLayout_SetFontSize(layout, 12.0f, range);
     ok(hr == S_OK, "got 0x%08x\n", hr);
@@ -3430,7 +3425,6 @@ todo_wine {
     count = 0;
     hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count);
     ok(hr == S_OK, "got 0x%08x\n", hr);
-todo_wine
     ok(count == 1, "got %u\n", count);
     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);
@@ -3508,7 +3502,6 @@ static void test_SetTextAlignment(void)
         win_skip("IDWriteTextFormat1 is not supported\n");
 
     for (i = 0; i < sizeof(stringsW)/sizeof(stringsW[0]); i++) {
-        BOOL todo = lstrlenW(stringsW[i]) == 0;
         FLOAT text_width;
 
         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.width == text_width, "got %.2f\n", metrics.width);
         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);
 
         /* 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.width == text_width, "got %.2f\n", metrics.width);
         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);
         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.width == text_width, "got %.2f\n", metrics.width);
         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);
         IDWriteTextLayout_Release(layout);
 
@@ -3611,10 +3592,6 @@ static void test_SetTextAlignment(void)
         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.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);
 
         IDWriteTextLayout_Release(layout);
-- 
2.7.0.rc3




More information about the wine-patches mailing list