[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