[PATCH] dwrite: Consider inline objects overhang metrics for overall layout overhang metrics

Nikolay Sivov nsivov at codeweavers.com
Sun Oct 1 23:50:58 CDT 2017


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

diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 7975651299..eda90ec784 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -3673,10 +3673,37 @@ static void layout_get_erun_bbox(struct dwrite_textlayout *layout, struct layout
     d2d_rect_offset(bbox, run->origin.x + run->align_dx, run->origin.y);
 }
 
+static void layout_get_inlineobj_bbox(struct dwrite_textlayout *layout, struct layout_effective_inline *run,
+        D2D1_RECT_F *bbox)
+{
+    DWRITE_OVERHANG_METRICS overhang_metrics = { 0 };
+    DWRITE_INLINE_OBJECT_METRICS metrics = { 0 };
+    HRESULT hr;
+
+    if (FAILED(hr = IDWriteInlineObject_GetMetrics(run->object, &metrics))) {
+        WARN("Failed to get inline object metrics, hr %#x.\n", hr);
+        memset(bbox, 0, sizeof(*bbox));
+        return;
+    }
+
+    bbox->left = run->origin.x + run->align_dx;
+    bbox->right = bbox->left + metrics.width;
+    bbox->top = run->origin.y;
+    bbox->bottom = bbox->top + metrics.height;
+
+    IDWriteInlineObject_GetOverhangMetrics(run->object, &overhang_metrics);
+
+    bbox->left -= overhang_metrics.left;
+    bbox->right += overhang_metrics.right;
+    bbox->top -= overhang_metrics.top;
+    bbox->bottom += overhang_metrics.bottom;
+}
+
 static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface,
         DWRITE_OVERHANG_METRICS *overhangs)
 {
     struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
+    struct layout_effective_inline *inline_run;
     struct layout_effective_run *run;
     D2D1_RECT_F bbox = { 0 };
     HRESULT hr;
@@ -3701,9 +3728,14 @@ static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *if
         d2d_rect_union(&bbox, &run_bbox);
     }
 
-    /* FIXME: iterate over inline objects too */
+    LIST_FOR_EACH_ENTRY(inline_run, &This->inlineobjects, struct layout_effective_inline, entry) {
+        D2D1_RECT_F object_bbox;
+
+        layout_get_inlineobj_bbox(This, inline_run, &object_bbox);
+        d2d_rect_union(&bbox, &object_bbox);
+    }
 
-    /* deltas from text content metrics */
+    /* Deltas from layout box. */
     This->overhangs.left = -bbox.left;
     This->overhangs.top = -bbox.top;
     This->overhangs.right = bbox.right - This->metrics.layoutWidth;
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index 3b0bf98125..d689771ed7 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -782,6 +782,51 @@ static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl };
 static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
 static IDWriteInlineObject testinlineobj3 = { &testinlineobjvtbl2 };
 
+struct test_inline_obj
+{
+    IDWriteInlineObject IDWriteInlineObject_iface;
+    DWRITE_INLINE_OBJECT_METRICS metrics;
+    DWRITE_OVERHANG_METRICS overhangs;
+};
+
+static inline struct test_inline_obj *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
+{
+    return CONTAINING_RECORD(iface, struct test_inline_obj, IDWriteInlineObject_iface);
+}
+
+static HRESULT WINAPI testinlineobj3_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
+{
+    struct test_inline_obj *obj = impl_from_IDWriteInlineObject(iface);
+    *metrics = obj->metrics;
+    return S_OK;
+}
+
+static HRESULT WINAPI testinlineobj3_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
+{
+    struct test_inline_obj *obj = impl_from_IDWriteInlineObject(iface);
+    *overhangs = obj->overhangs;
+    /* Return value is ignored. */
+    return E_NOTIMPL;
+}
+
+static const IDWriteInlineObjectVtbl testinlineobjvtbl3 = {
+    testinlineobj_QI,
+    testinlineobj_AddRef,
+    testinlineobj_Release,
+    testinlineobj_Draw,
+    testinlineobj3_GetMetrics,
+    testinlineobj3_GetOverhangMetrics,
+    testinlineobj_GetBreakConditions,
+};
+
+static void test_inline_obj_init(struct test_inline_obj *obj, const DWRITE_INLINE_OBJECT_METRICS *metrics,
+        const DWRITE_OVERHANG_METRICS *overhangs)
+{
+    obj->IDWriteInlineObject_iface.lpVtbl = &testinlineobjvtbl3;
+    obj->metrics = *metrics;
+    obj->overhangs = *overhangs;
+}
+
 struct test_effect
 {
     IUnknown IUnknown_iface;
@@ -5398,6 +5443,77 @@ static void test_line_spacing(void)
     IDWriteFactory_Release(factory);
 }
 
+static void test_GetOverhangMetrics(void)
+{
+    static const struct overhangs_test
+    {
+        FLOAT uniform_baseline;
+        DWRITE_INLINE_OBJECT_METRICS metrics;
+        DWRITE_OVERHANG_METRICS overhang_metrics;
+        DWRITE_OVERHANG_METRICS expected;
+    } overhangs_tests[] = {
+        { 16.0f, { 10.0f, 50.0f, 20.0f }, { 1.0f, 2.0f, 3.0f, 4.0f }, { 1.0f, 6.0f, 3.0f, 0.0f } },
+        { 15.0f, { 10.0f, 50.0f, 20.0f }, { 1.0f, 2.0f, 3.0f, 4.0f }, { 1.0f, 7.0f, 3.0f, -1.0f } },
+        { 16.0f, { 10.0f, 50.0f, 20.0f }, { -1.0f, 0.0f, -3.0f, 4.0f }, { -1.0f, 4.0f, -3.0f, 0.0f } },
+        { 15.0f, { 10.0f, 50.0f, 20.0f }, { -1.0f, 10.0f, 3.0f, -4.0f }, { -1.0f, 15.0f, 3.0f, -9.0f } },
+    };
+    static const WCHAR strW[] = {'A',0};
+    IDWriteFactory *factory;
+    IDWriteTextFormat *format;
+    IDWriteTextLayout *layout;
+    HRESULT hr;
+    UINT32 i;
+
+    factory = create_factory();
+
+    hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
+            DWRITE_FONT_STRETCH_NORMAL, 100.0f, enusW, &format);
+    ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
+
+    hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 1000.0f, 1000.0f, &layout);
+    ok(hr == S_OK, "Failed to create text layout, hr %x.\n", hr);
+
+    for (i = 0; i < sizeof(overhangs_tests)/sizeof(overhangs_tests[0]); i++) {
+        const struct overhangs_test *test = &overhangs_tests[i];
+        DWRITE_OVERHANG_METRICS overhang_metrics;
+        DWRITE_TEXT_RANGE range = { 0, 1 };
+        DWRITE_TEXT_METRICS metrics;
+        struct test_inline_obj obj;
+
+        test_inline_obj_init(&obj, &test->metrics, &test->overhang_metrics);
+
+        hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_UNIFORM, test->metrics.height * 2.0f,
+                test->uniform_baseline);
+        ok(hr == S_OK, "Failed to set line spacing, hr %#x.\n", hr);
+
+        hr = IDWriteTextLayout_SetInlineObject(layout, NULL, range);
+        ok(hr == S_OK, "Failed to reset inline object, hr %#x.\n", hr);
+
+        hr = IDWriteTextLayout_SetInlineObject(layout, &obj.IDWriteInlineObject_iface, range);
+        ok(hr == S_OK, "Failed to set inline object, hr %#x.\n", hr);
+
+        hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
+        ok(hr == S_OK, "Failed to get layout metrics, hr %#x.\n", hr);
+
+        ok(metrics.width == test->metrics.width, "%u: unexpected formatted width.\n", i);
+        ok(metrics.height == test->metrics.height * 2.0f, "%u: unexpected formatted height.\n", i);
+
+        hr = IDWriteTextLayout_SetMaxWidth(layout, metrics.width);
+        hr = IDWriteTextLayout_SetMaxHeight(layout, test->metrics.height);
+
+        hr = IDWriteTextLayout_GetOverhangMetrics(layout, &overhang_metrics);
+        ok(hr == S_OK, "Failed to get overhang metrics, hr %#x.\n", hr);
+
+        ok(!memcmp(&overhang_metrics, &test->expected, sizeof(overhang_metrics)),
+                "%u: unexpected overhang metrics (%f, %f, %f, %f).\n", i, overhang_metrics.left, overhang_metrics.top,
+                overhang_metrics.right, overhang_metrics.bottom);
+    }
+
+    IDWriteTextLayout_Release(layout);
+    IDWriteTextFormat_Release(format);
+    IDWriteFactory_Release(factory);
+}
+
 START_TEST(layout)
 {
     IDWriteFactory *factory;
@@ -5447,6 +5563,7 @@ START_TEST(layout)
     test_SetUnderline();
     test_InvalidateLayout();
     test_line_spacing();
+    test_GetOverhangMetrics();
 
     IDWriteFactory_Release(factory);
 }
-- 
2.14.2




More information about the wine-patches mailing list