Signed-off-by: Nikolay Sivov nsivov@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);