dwrite/layout: Add support for character spacing attributes.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2021-02-22 21:29:38 +03:00 committed by Alexandre Julliard
parent f18acbfef3
commit 8dac512e8c
2 changed files with 81 additions and 2 deletions

View file

@ -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;

View file

@ -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);