Nikolay Sivov : dwrite: Implement ranges merging.
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Aug 18 16:08:48 CDT 2014
Module: wine
Branch: master
Commit: baedef728c325125f8617508a256a94a3cabc767
URL: http://source.winehq.org/git/wine.git/?a=commit;h=baedef728c325125f8617508a256a94a3cabc767
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Fri Aug 15 07:10:58 2014 +0400
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);
}
More information about the wine-cvs
mailing list