[PATCH 4/4] dwrite/layout: Add support for character spacing attributes.

Nikolay Sivov nsivov at codeweavers.com
Mon Feb 22 12:29:38 CST 2021


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/dwrite/layout.c       | 79 ++++++++++++++++++++++++++++++++++++++
 dlls/dwrite/tests/layout.c |  4 +-
 2 files changed, 81 insertions(+), 2 deletions(-)

diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 3e5c0379609..38be4eeb2da 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -1144,6 +1144,82 @@ static HRESULT layout_shape_get_glyphs(struct dwrite_textlayout *layout, struct
     return hr;
 }
 
+static struct layout_range_spacing *layout_get_next_spacing_range(struct dwrite_textlayout *layout,
+        struct layout_range_spacing *cur)
+{
+    return (struct layout_range_spacing *)LIST_ENTRY(list_next(&layout->spacing, &cur->h.entry),
+            struct layout_range_header, entry);
+}
+
+static HRESULT layout_shape_apply_character_spacing(struct dwrite_textlayout *layout, struct shaping_context *context)
+{
+    struct regular_layout_run *run = context->run;
+    struct layout_range_spacing *first = NULL, *last = NULL, *cur;
+    unsigned int i, length, pos, start, end, g0, glyph_count;
+    struct layout_range_header *h;
+    UINT16 *clustermap;
+
+    LIST_FOR_EACH_ENTRY(h, &layout->spacing, struct layout_range_header, entry)
+    {
+        if ((h->range.startPosition >= run->descr.textPosition &&
+                h->range.startPosition <= run->descr.textPosition + run->descr.stringLength) ||
+            (run->descr.textPosition >= h->range.startPosition &&
+                run->descr.textPosition <= h->range.startPosition + h->range.length))
+        {
+            if (!first) first = last = (struct layout_range_spacing *)h;
+        }
+        else if (last) break;
+    }
+    if (!first) return S_OK;
+
+    if (!(clustermap = heap_calloc(run->descr.stringLength, sizeof(*clustermap)))) return E_OUTOFMEMORY;
+
+    pos = run->descr.textPosition;
+
+    for (cur = first;; cur = layout_get_next_spacing_range(layout, cur))
+    {
+        float leading, trailing;
+
+        /* The range current spacing settings apply to. */
+        start = max(pos, cur->h.range.startPosition);
+        pos = end = min(pos + run->descr.stringLength, cur->h.range.startPosition + cur->h.range.length);
+
+        /* Back to run-relative index. */
+        start -= run->descr.textPosition;
+        end -= run->descr.textPosition;
+
+        length = end - start;
+
+        g0 = run->descr.clusterMap[start];
+
+        for (i = 0; i < length; ++i)
+            clustermap[i] = run->descr.clusterMap[start + i] - run->descr.clusterMap[start];
+
+        glyph_count = (end < run->descr.stringLength ? run->descr.clusterMap[end] + 1 : run->glyphcount) - g0;
+
+        /* There is no direction argument for spacing interface, we have to swap arguments here to get desired output. */
+        if (run->run.bidiLevel & 1)
+        {
+            leading = cur->trailing;
+            trailing = cur->leading;
+        }
+        else
+        {
+            leading = cur->leading;
+            trailing = cur->trailing;
+        }
+        IDWriteTextAnalyzer2_ApplyCharacterSpacing(context->analyzer, leading, trailing, cur->min_advance,
+                length, glyph_count, clustermap, &run->advances[g0], &run->offsets[g0], &context->glyph_props[g0],
+                &run->advances[g0], &run->offsets[g0]);
+
+        if (cur == last) break;
+    }
+
+    heap_free(clustermap);
+
+    return S_OK;
+}
+
 static HRESULT layout_shape_get_positions(struct dwrite_textlayout *layout, struct shaping_context *context)
 {
     struct regular_layout_run *run = context->run;
@@ -1176,6 +1252,9 @@ static HRESULT layout_shape_get_positions(struct dwrite_textlayout *layout, stru
         WARN("%s: failed to get glyph placement info, hr %#x.\n", debugstr_rundescr(&run->descr), hr);
     }
 
+    if (SUCCEEDED(hr))
+        hr = layout_shape_apply_character_spacing(layout, context);
+
     run->run.glyphAdvances = run->advances;
     run->run.glyphOffsets = run->offsets;
 
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index adc9503ffd9..43e62a39956 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -2121,8 +2121,8 @@ static void test_GetClusterMetrics(void)
         hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics2, ARRAY_SIZE(metrics2), &count);
         ok(hr == S_OK, "got 0x%08x\n", hr);
         ok(count == 4, "got %u\n", count);
-        for (i = 0; i < count; i++) {
-todo_wine
+        for (i = 0; i < count; ++i)
+        {
             ok(metrics2[i].width > metrics[i].width, "%u: got width %.2f, was %.2f\n", i, metrics2[i].width,
                 metrics[i].width);
             ok(metrics2[i].length == 1, "%u: got length %u\n", i, metrics2[i].length);
-- 
2.30.0




More information about the wine-devel mailing list