dwrite: Consider inline objects overhang metrics for overall layout overhang metrics.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
850b67f28f
commit
3fbc00b593
|
@ -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);
|
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,
|
static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *iface,
|
||||||
DWRITE_OVERHANG_METRICS *overhangs)
|
DWRITE_OVERHANG_METRICS *overhangs)
|
||||||
{
|
{
|
||||||
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
|
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout3(iface);
|
||||||
|
struct layout_effective_inline *inline_run;
|
||||||
struct layout_effective_run *run;
|
struct layout_effective_run *run;
|
||||||
D2D1_RECT_F bbox = { 0 };
|
D2D1_RECT_F bbox = { 0 };
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
@ -3701,9 +3728,14 @@ static HRESULT WINAPI dwritetextlayout_GetOverhangMetrics(IDWriteTextLayout3 *if
|
||||||
d2d_rect_union(&bbox, &run_bbox);
|
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;
|
||||||
|
|
||||||
/* deltas from text content metrics */
|
layout_get_inlineobj_bbox(This, inline_run, &object_bbox);
|
||||||
|
d2d_rect_union(&bbox, &object_bbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deltas from layout box. */
|
||||||
This->overhangs.left = -bbox.left;
|
This->overhangs.left = -bbox.left;
|
||||||
This->overhangs.top = -bbox.top;
|
This->overhangs.top = -bbox.top;
|
||||||
This->overhangs.right = bbox.right - This->metrics.layoutWidth;
|
This->overhangs.right = bbox.right - This->metrics.layoutWidth;
|
||||||
|
|
|
@ -782,6 +782,51 @@ static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl };
|
||||||
static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
|
static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
|
||||||
static IDWriteInlineObject testinlineobj3 = { &testinlineobjvtbl2 };
|
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
|
struct test_effect
|
||||||
{
|
{
|
||||||
IUnknown IUnknown_iface;
|
IUnknown IUnknown_iface;
|
||||||
|
@ -5398,6 +5443,77 @@ static void test_line_spacing(void)
|
||||||
IDWriteFactory_Release(factory);
|
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)
|
START_TEST(layout)
|
||||||
{
|
{
|
||||||
IDWriteFactory *factory;
|
IDWriteFactory *factory;
|
||||||
|
@ -5447,6 +5563,7 @@ START_TEST(layout)
|
||||||
test_SetUnderline();
|
test_SetUnderline();
|
||||||
test_InvalidateLayout();
|
test_InvalidateLayout();
|
||||||
test_line_spacing();
|
test_line_spacing();
|
||||||
|
test_GetOverhangMetrics();
|
||||||
|
|
||||||
IDWriteFactory_Release(factory);
|
IDWriteFactory_Release(factory);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue