Nikolay Sivov : dwrite: Consider inline objects overhang metrics for overall layout overhang metrics.
Alexandre Julliard
julliard at winehq.org
Mon Oct 2 15:46:22 CDT 2017
Module: wine
Branch: master
Commit: 3fbc00b593b242902d027147563cf88eb1f23fa8
URL: http://source.winehq.org/git/wine.git/?a=commit;h=3fbc00b593b242902d027147563cf88eb1f23fa8
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Mon Oct 2 07:50:58 2017 +0300
dwrite: Consider inline objects overhang metrics for overall layout overhang metrics.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
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 7975651..eda90ec 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 3b0bf98..d689771 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);
}
More information about the wine-cvs
mailing list