From cb0b0885510c69854e82d35144fa65cbd069a277 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 2 Feb 2017 02:11:35 +0300 Subject: [PATCH] dwrite: Added support for uniform and proportional spacing methods. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/dwrite/layout.c | 142 +++++++++++++++++++++++++++---------- dlls/dwrite/tests/layout.c | 2 - 2 files changed, 104 insertions(+), 40 deletions(-) diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c index c2094cf081b..08d3aba798b 100644 --- a/dlls/dwrite/layout.c +++ b/dlls/dwrite/layout.c @@ -1316,6 +1316,8 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_LINE_METRICS1 *metrics) { + UINT32 i = layout->metrics.lineCount; + if (!layout->line_alloc) { layout->line_alloc = 5; layout->linemetrics = heap_alloc(layout->line_alloc * sizeof(*layout->linemetrics)); @@ -1344,9 +1346,28 @@ static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_ layout->line_alloc *= 2; } - layout->linemetrics[layout->metrics.lineCount] = *metrics; - layout->lines[layout->metrics.lineCount].height = metrics->height; - layout->lines[layout->metrics.lineCount].baseline = metrics->baseline; + layout->linemetrics[i] = *metrics; + + switch (layout->format.spacing.method) + { + case DWRITE_LINE_SPACING_METHOD_UNIFORM: + if (layout->format.spacing.method == DWRITE_LINE_SPACING_METHOD_UNIFORM) { + layout->linemetrics[i].height = layout->format.spacing.height; + layout->linemetrics[i].baseline = layout->format.spacing.baseline; + } + break; + case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL: + if (layout->format.spacing.method == DWRITE_LINE_SPACING_METHOD_UNIFORM) { + layout->linemetrics[i].height = layout->format.spacing.height * metrics->height; + layout->linemetrics[i].baseline = layout->format.spacing.baseline * metrics->baseline; + } + break; + default: + /* using content values */; + } + + layout->lines[i].height = metrics->height; + layout->lines[i].baseline = metrics->baseline; layout->metrics.lineCount++; return S_OK; @@ -1604,17 +1625,19 @@ static void layout_apply_par_alignment(struct dwrite_textlayout *layout) erun = layout_get_next_erun(layout, NULL); inrun = layout_get_next_inline_run(layout, NULL); for (line = 0; line < layout->metrics.lineCount; line++) { - origin_y += layout->linemetrics[line].baseline; + FLOAT pos_y = origin_y + layout->linemetrics[line].baseline; while (erun && erun->line == line) { - erun->origin_y = origin_y; + erun->origin_y = pos_y; erun = layout_get_next_erun(layout, erun); } while (inrun && inrun->line == line) { - inrun->origin_y = origin_y - inrun->baseline; + inrun->origin_y = pos_y - inrun->baseline; inrun = layout_get_next_inline_run(layout, inrun); } + + origin_y += layout->linemetrics[line].height; } } @@ -1890,6 +1913,42 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust *textpos += metrics.length; } +static void layout_set_line_positions(struct dwrite_textlayout *layout) +{ + struct layout_effective_inline *inrun; + struct layout_effective_run *erun; + FLOAT origin_y; + UINT32 line; + + /* Now all line info is here, update effective runs positions in flow direction */ + erun = layout_get_next_erun(layout, NULL); + inrun = layout_get_next_inline_run(layout, NULL); + + for (line = 0, origin_y = 0.0f; line < layout->metrics.lineCount; line++) { + FLOAT pos_y = origin_y + layout->linemetrics[line].baseline; + + /* For all runs on this line */ + while (erun && erun->line == line) { + erun->origin_y = pos_y; + erun = layout_get_next_erun(layout, erun); + } + + /* Same for inline runs */ + while (inrun && inrun->line == line) { + inrun->origin_y = pos_y - inrun->baseline; + inrun = layout_get_next_inline_run(layout, inrun); + } + + origin_y += layout->linemetrics[line].height; + } + + layout->metrics.height = origin_y; + + /* Initial paragraph alignment is always near */ + if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR) + layout_apply_par_alignment(layout); +} + static BOOL layout_can_wrap_after(const struct dwrite_textlayout *layout, UINT32 cluster) { if (layout->format.wrapping == DWRITE_WORD_WRAPPING_CHARACTER) @@ -1902,10 +1961,10 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout) { BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT; struct layout_effective_run *erun, *first_underlined; - UINT32 i, start, line, textpos, last_breaking_point; - struct layout_effective_inline *inrun; - FLOAT width, origin_y; + UINT32 i, start, textpos, last_breaking_point; DWRITE_LINE_METRICS1 metrics; + FLOAT width; + UINT32 line; HRESULT hr; if (!(layout->recompute & RECOMPUTE_LINES)) @@ -1918,7 +1977,6 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout) return hr; layout->metrics.lineCount = 0; - line = 0; memset(&metrics, 0, sizeof(metrics)); layout->metrics.height = 0.0f; @@ -1971,7 +2029,6 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout) - there's no text, metrics come from first range in this case; - last ended with a mandatory break, metrics come from last text position. */ - line = layout->metrics.lineCount - 1; if (layout->len == 0) hr = layout_set_dummy_line_metrics(layout, 0); else if (layout->clustermetrics[layout->cluster_count - 1].isNewline) @@ -1983,20 +2040,11 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout) layout->metrics.top = 0.0f; layout->metrics.maxBidiReorderingDepth = 1; /* FIXME */ - /* Now all line info is here, update effective runs positions in flow direction */ + /* Add explicit underlined runs */ erun = layout_get_next_erun(layout, NULL); first_underlined = erun && erun->underlined ? erun : NULL; - - inrun = layout_get_next_inline_run(layout, NULL); - - origin_y = 0.0f; for (line = 0; line < layout->metrics.lineCount; line++) { - - origin_y += layout->linemetrics[line].baseline; - - /* For all runs on this line */ while (erun && erun->line == line) { - erun->origin_y = origin_y; erun = layout_get_next_erun(layout, erun); if (first_underlined && (!erun || !erun->underlined)) { @@ -2006,28 +2054,15 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout) else if (!first_underlined && erun && erun->underlined) first_underlined = erun; } - - /* Same for inline runs */ - while (inrun && inrun->line == line) { - inrun->origin_y = origin_y - inrun->baseline; - inrun = layout_get_next_inline_run(layout, inrun); - } } - /* Use last line origin y + line descent as total content height */ - line--; - layout->metrics.height = origin_y + layout->linemetrics[line].height - layout->linemetrics[line].baseline; + /* Position runs in flow direction */ + layout_set_line_positions(layout); /* Initial alignment is always leading */ if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING) layout_apply_text_alignment(layout); - /* Initial paragraph alignment is always near */ - if (layout->format.paralign != DWRITE_PARAGRAPH_ALIGNMENT_NEAR) - layout_apply_par_alignment(layout); - - layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */ - layout->recompute &= ~RECOMPUTE_LINES; return hr; } @@ -3880,8 +3915,39 @@ static HRESULT WINAPI dwritetextlayout3_SetLineSpacing(IDWriteTextLayout3 *iface if (FAILED(hr)) return hr; - if (changed) - This->recompute |= RECOMPUTE_LINES_AND_OVERHANGS; + if (changed) { + if (!(This->recompute & RECOMPUTE_LINES)) { + UINT32 line; + + switch (This->format.spacing.method) + { + case DWRITE_LINE_SPACING_METHOD_DEFAULT: + for (line = 0; line < This->metrics.lineCount; line++) { + This->linemetrics[line].height = This->lines[line].height; + This->linemetrics[line].baseline = This->lines[line].baseline; + } + break; + case DWRITE_LINE_SPACING_METHOD_UNIFORM: + for (line = 0; line < This->metrics.lineCount; line++) { + This->linemetrics[line].height = This->format.spacing.height; + This->linemetrics[line].baseline = This->format.spacing.baseline; + } + break; + case DWRITE_LINE_SPACING_METHOD_PROPORTIONAL: + for (line = 0; line < This->metrics.lineCount; line++) { + This->linemetrics[line].height = This->format.spacing.height * This->lines[line].height; + This->linemetrics[line].baseline = This->format.spacing.baseline * This->lines[line].baseline; + } + break; + default: + ; + } + + layout_set_line_positions(This); + } + + This->recompute |= RECOMPUTE_OVERHANGS; + } return S_OK; } diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index 741fc3e6046..07c2ebdb968 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -3633,11 +3633,9 @@ static void test_GetLineMetrics(void) ok(count == 2, "got %u\n", count); for (i = 0; i < count; i++) { - todo_wine { ok(metrics[i].height == 456.0f, "%u: got line height %f\n", i, metrics[i].height); ok(metrics[i].baseline == 123.0f, "%u: got line baseline %f\n", i, metrics[i].baseline); } - } IDWriteTextLayout_Release(layout);