From: Nikolay Sivov Subject: [PATCH] dwrite/layout: Test resulting line width before adding inline trimming run. Message-Id: <20180921135419.7020-1-nsivov@codeweavers.com> Date: Fri, 21 Sep 2018 16:54:19 +0300 Signed-off-by: Nikolay Sivov --- This fixes out-of-bounds read in cluster array, for example when trimming is applied to single cluster layout. dlls/dwrite/layout.c | 3 +++ dlls/dwrite/tests/layout.c | 43 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c index 10d591457c..5deae455b1 100644 --- a/dlls/dwrite/layout.c +++ b/dlls/dwrite/layout.c @@ -1926,6 +1926,9 @@ static void layout_add_line(struct dwrite_textlayout *layout, UINT32 first_clust if (FAILED(hr)) return; + if (get_cluster_range_width(layout, start, i) + sign_metrics.width > layout->metrics.layoutWidth) + append_trimming_run = FALSE; + if (append_trimming_run) { struct layout_effective_inline *trimming_sign; diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index 652f6b78ac..c77a0ea51b 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -1636,6 +1636,11 @@ static const struct drawcall_entry draw_seq[] = { { DRAW_LAST_KIND } }; +static const struct drawcall_entry draw_trimmed_seq[] = { + { DRAW_GLYPHRUN, {'a',0}, {'e','n','-','u','s',0}, 1 }, + { DRAW_LAST_KIND } +}; + static const struct drawcall_entry draw_seq2[] = { { DRAW_GLYPHRUN, {'s',0}, {'r','u',0}, 1 }, { DRAW_GLYPHRUN, {'t',0}, {'r','u',0}, 1 }, @@ -2386,6 +2391,44 @@ todo_wine IDWriteTextLayout_Release(layout); + /* Single cluster layout, trigger trimming. */ + hr = IDWriteFactory_CreateTextLayout(factory, str6W, 1, format, 1000.0f, 200.0f, &layout); + ok(hr == S_OK, "Failed to create layout, hr %#x.\n", hr); + + count = 0; + memset(metrics, 0, sizeof(metrics)); + hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count); + ok(hr == S_OK, "Failed to get cluster metrics, hr %#x.\n", hr); + ok(count == 1, "Unexpected cluster count %u.\n", count); + + hr = IDWriteTextLayout_SetMaxWidth(layout, metrics[0].width / 2.0f); + ok(hr == S_OK, "Failed to set layout width, hr %#x.\n", hr); + + trimming_options.granularity = DWRITE_TRIMMING_GRANULARITY_CHARACTER; + trimming_options.delimiter = 0; + trimming_options.delimiterCount = 0; + hr = IDWriteTextLayout_SetTrimming(layout, &trimming_options, trimm); + ok(hr == S_OK, "Failed to set trimming options, hr %#x.\n", hr); + + count = 0; + memset(metrics, 0, sizeof(metrics)); + hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count); + ok(hr == S_OK, "Failed to get cluster metrics, hr %#x.\n", hr); + ok(count == 1, "Unexpected cluster count %u.\n", count); + + hr = IDWriteTextLayout_GetLineMetrics(layout, &line, 1, &count); + ok(hr == S_OK, "Failed to get line metrics, hr %#x.\n", hr); + ok(count == 1, "Unexpected line count %u.\n", count); + ok(line.length == 1, "Unexpected line length %u.\n", line.length); + ok(line.isTrimmed, "Unexpected trimming flag %x.\n", line.isTrimmed); + + flush_sequence(sequences, RENDERER_ID); + hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0f, 0.0f); + ok(hr == S_OK, "Draw() failed, hr %#x.\n", hr); + ok_sequence(sequences, RENDERER_ID, draw_trimmed_seq, "Trimmed draw test", FALSE); + + IDWriteTextLayout_Release(layout); + IDWriteInlineObject_Release(trimm); IDWriteTextFormat_Release(format); IDWriteFactory_Release(factory); -- 2.18.0