From: Nikolay Sivov Subject: [1/2] dwrite: Implement ranges merging Message-Id: <53F175F7.2080009@codeweavers.com> Date: Mon, 18 Aug 2014 07:41:43 +0400 --- From 939c7f0ec9eec05ed537bd5d09f7b3b2340f7c44 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 15 Aug 2014 07:10:58 +0400 Subject: [PATCH 01/15] dwrite: Implement ranges merging --- dlls/dwrite/layout.c | 55 +++++++++++++++++++++++++++++++++++----------- dlls/dwrite/tests/layout.c | 28 +++++++++++++++++++---- 2 files changed, 66 insertions(+), 17 deletions(-) diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c index 1ed0a87..aed6652 100644 --- a/dlls/dwrite/layout.c +++ b/dlls/dwrite/layout.c @@ -155,7 +155,7 @@ static inline BOOL validate_text_range(struct dwrite_textlayout *layout, DWRITE_ return TRUE; } -static BOOL is_same_layout_range(struct layout_range const *range, enum layout_range_attr_kind attr, struct layout_range_attr_value *value) +static BOOL is_same_layout_attrvalue(struct layout_range const *range, enum layout_range_attr_kind attr, struct layout_range_attr_value *value) { switch (attr) { case LAYOUT_RANGE_ATTR_WEIGHT: @@ -177,6 +177,16 @@ static BOOL is_same_layout_range(struct layout_range const *range, enum layout_r return FALSE; } +static inline BOOL is_same_layout_attributes(struct layout_range const *left, struct layout_range const *right) +{ + return left->weight == right->weight && + left->style == right->style && + left->object == right->object && + left->effect == right->effect && + left->underline == right->underline && + left->strikethrough == right->strikethrough; +} + static inline BOOL is_same_text_range(const DWRITE_TEXT_RANGE *left, const DWRITE_TEXT_RANGE *right) { return left->startPosition == right->startPosition && left->length == right->length; @@ -325,19 +335,20 @@ static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layo { struct layout_range *outer, *right, *left, *cur; struct list *ranges = &layout->ranges; + BOOL changed = FALSE; DWRITE_TEXT_RANGE r; /* If new range is completely within existing range, split existing range in two */ if ((outer = find_outer_range(ranges, &value->range))) { /* no need to add same range */ - if (is_same_layout_range(outer, attr, value)) + if (is_same_layout_attrvalue(outer, attr, value)) return S_OK; /* for matching range bounds just replace data */ if (is_same_text_range(&outer->range, &value->range)) { - set_layout_range_attrval(outer, attr, value); - return S_OK; + changed = set_layout_range_attrval(outer, attr, value); + goto done; } /* add new range to the left */ @@ -345,11 +356,11 @@ static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layo left = alloc_layout_range_from(outer, &value->range); if (!left) return E_OUTOFMEMORY; - set_layout_range_attrval(left, attr, value); + changed = set_layout_range_attrval(left, attr, value); list_add_before(&outer->entry, &left->entry); outer->range.startPosition += value->range.length; outer->range.length -= value->range.length; - return S_OK; + goto done; } /* add new range to the right */ @@ -357,10 +368,10 @@ static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layo right = alloc_layout_range_from(outer, &value->range); if (!right) return E_OUTOFMEMORY; - set_layout_range_attrval(right, attr, value); + changed = set_layout_range_attrval(right, attr, value); list_add_after(&outer->entry, &right->entry); outer->range.length -= value->range.length; - return S_OK; + goto done; } r.startPosition = value->range.startPosition + value->range.length; @@ -392,20 +403,20 @@ static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layo Update all of them. */ left = get_layout_range_by_pos(ranges, value->range.startPosition); if (left->range.startPosition == value->range.startPosition) - set_layout_range_attrval(left, attr, value); + changed = set_layout_range_attrval(left, attr, value); else /* need to split */ { r.startPosition = value->range.startPosition; r.length = left->range.length - value->range.startPosition + left->range.startPosition; left->range.length -= r.length; cur = alloc_layout_range_from(left, &r); - set_layout_range_attrval(cur, attr, value); + changed = set_layout_range_attrval(cur, attr, value); list_add_after(&left->entry, &cur->entry); } cur = LIST_ENTRY(list_next(ranges, &left->entry), struct layout_range, entry); /* for all existing ranges covered by new one update value */ while (is_in_layout_range(&value->range, &cur->range)) { - set_layout_range_attrval(cur, attr, value); + changed = set_layout_range_attrval(cur, attr, value); cur = LIST_ENTRY(list_next(ranges, &cur->entry), struct layout_range, entry); } @@ -414,13 +425,31 @@ static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layo r.startPosition = cur->range.startPosition; r.length = value->range.startPosition + value->range.length - cur->range.startPosition; left = alloc_layout_range_from(cur, &r); - set_layout_range_attrval(left, attr, value); + changed = set_layout_range_attrval(left, attr, value); cur->range.startPosition += left->range.length; cur->range.length -= left->range.length; list_add_before(&cur->entry, &left->entry); } - /* TODO: compact adjacent ranges if needed */ +done: + if (changed) { + struct list *next, *i; + + i = list_head(ranges); + while ((next = list_next(ranges, i))) { + struct layout_range *next_range = LIST_ENTRY(next, struct layout_range, entry); + + cur = LIST_ENTRY(i, struct layout_range, entry); + if (is_same_layout_attributes(cur, next_range)) { + /* remove similar range */ + cur->range.length += next_range->range.length; + list_remove(next); + free_layout_range(next_range); + } + else + i = list_next(ranges, i); + } + } return S_OK; } diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index 336cc0b..236c34b 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -591,7 +591,7 @@ static void test_SetInlineObject(void) IDWriteInlineObject *inlineobj, *inlineobj2, *inlinetest; IDWriteTextFormat *format; IDWriteTextLayout *layout; - DWRITE_TEXT_RANGE range; + DWRITE_TEXT_RANGE range, r2; HRESULT hr; hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL, @@ -623,9 +623,11 @@ static void test_SetInlineObject(void) ok(inlinetest == NULL, "got %p\n", inlinetest); inlinetest = NULL; - hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, NULL); + r2.startPosition = r2.length = 100; + hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2); ok(hr == S_OK, "got 0x%08x\n", hr); ok(inlinetest == inlineobj, "got %p\n", inlinetest); + ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length); IDWriteInlineObject_Release(inlinetest); range.startPosition = 1; @@ -634,15 +636,19 @@ static void test_SetInlineObject(void) ok(hr == S_OK, "got 0x%08x\n", hr); inlinetest = NULL; - hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, NULL); + r2.startPosition = r2.length = 100; + hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2); ok(hr == S_OK, "got 0x%08x\n", hr); ok(inlinetest == inlineobj2, "got %p\n", inlinetest); + ok(r2.startPosition == 1 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length); IDWriteInlineObject_Release(inlinetest); inlinetest = NULL; - hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, NULL); + r2.startPosition = r2.length = 100; + hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2); ok(hr == S_OK, "got 0x%08x\n", hr); ok(inlinetest == inlineobj, "got %p\n", inlinetest); + ok(r2.startPosition == 0 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length); IDWriteInlineObject_Release(inlinetest); range.startPosition = 1; @@ -650,11 +656,25 @@ static void test_SetInlineObject(void) hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range); ok(hr == S_OK, "got 0x%08x\n", hr); + r2.startPosition = r2.length = 100; + hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(inlinetest == inlineobj, "got %p\n", inlinetest); + ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length); + IDWriteInlineObject_Release(inlinetest); + range.startPosition = 1; range.length = 2; hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range); ok(hr == S_OK, "got 0x%08x\n", hr); + r2.startPosition = r2.length = 100; + hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2); + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(inlinetest == inlineobj, "got %p\n", inlinetest); + ok(r2.startPosition == 0 && r2.length == 3, "got %d, %d\n", r2.startPosition, r2.length); + IDWriteInlineObject_Release(inlinetest); + IDWriteTextLayout_Release(layout); IDWriteTextFormat_Release(format); } -- 2.1.0.rc1