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