[PATCH 0/1] MR9989: dwrite/layout: Partially implement HitTestTextPosition().
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> -- https://gitlab.winehq.org/wine/wine/-/merge_requests/9989
From: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> --- dlls/dwrite/layout.c | 186 +++++++++++++++++++++++++++++++------ dlls/dwrite/tests/layout.c | 176 +++++++++++------------------------ 2 files changed, 212 insertions(+), 150 deletions(-) diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c index 63c0fd05bea..73ff74044fa 100644 --- a/dlls/dwrite/layout.c +++ b/dlls/dwrite/layout.c @@ -158,17 +158,21 @@ struct layout_effective_run struct list entry; /* Common fields */ - UINT32 start; /* relative text position, 0 means first text position of a nominal run */ + UINT32 first_cluster; /* First cluster of this run, in logical order. */ + UINT32 start_position; /* Absolute text position. */ UINT32 length; /* length in codepoints that this run covers */ IUnknown *effect; /* original reference is kept only at range level */ D2D1_POINT_2F origin; /* baseline origin or left top corner */ float align_dx; /* adjustment from text alignment */ float width; /* run width */ + float left; /* Logically left boundary, independent of reading direction. */ UINT32 line; /* 0-based line index in line metrics array */ UINT8 bidi_level; /* For inline objects level is derived from the first character */ + bool trimming; /* Run contains trimmed text */ /* Text run fields */ const struct layout_run *run; /* nominal run this one is based on */ + UINT32 start; /* Text position relative to the nominal run. */ UINT32 glyphcount; /* total glyph count in this run */ UINT16 *clustermap; /* Clustermap allocated separately, not reused from nominal map. */ bool underlined; /* Set if this run is underlined */ @@ -1510,12 +1514,23 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const UINT32 cluster_count, UINT32 line, FLOAT origin_x, struct layout_final_splitting_params *params) { BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT; - UINT32 i, start, length, last_cluster; struct layout_effective_run *run; + UINT32 start, last_cluster; if (!(run = calloc(1, sizeof(*run)))) return E_OUTOFMEMORY; + /* No need to iterate for that, use simple fact that: + <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */ + last_cluster = first_cluster + cluster_count - 1; + run->start_position = layout->clusters[first_cluster].position + layout->clusters[first_cluster].run->start_position; + run->length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position + + layout->clustermetrics[last_cluster].length; + run->first_cluster = first_cluster; + + run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count); + run->left = is_rtl ? origin_x - run->width : origin_x; + if (r->kind == LAYOUT_RUN_INLINE) { run->object = r->u.object.object; @@ -1542,13 +1557,7 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const return S_OK; } - /* No need to iterate for that, use simple fact that: - <last cluster position> = <first cluster position> + <sum of cluster lengths not including last one> */ - last_cluster = first_cluster + cluster_count - 1; - length = layout->clusters[last_cluster].position - layout->clusters[first_cluster].position + - layout->clustermetrics[last_cluster].length; - - if (!(run->clustermap = calloc(length, sizeof(*run->clustermap)))) + if (!(run->clustermap = calloc(run->length, sizeof(*run->clustermap)))) { free(run); return E_OUTOFMEMORY; @@ -1556,8 +1565,6 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const run->run = r; run->start = start = layout->clusters[first_cluster].position; - run->length = length; - run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count); run->bidi_level = r->u.regular.run.bidiLevel; /* Adjust by run width if direction differs. */ @@ -1571,12 +1578,12 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const if (r->u.regular.run.glyphCount) { /* Trim leading and trailing clusters. */ run->glyphcount = r->u.regular.run.glyphCount - r->u.regular.clustermap[start]; - if (start + length < r->u.regular.descr.stringLength) - run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + length]; + if (start + run->length < r->u.regular.descr.stringLength) + run->glyphcount -= r->u.regular.run.glyphCount - r->u.regular.clustermap[start + run->length]; } /* cluster map needs to be shifted */ - for (i = 0; i < length; i++) + for (unsigned int i = 0; i < run->length; ++i) run->clustermap[i] = r->u.regular.clustermap[start + i] - r->u.regular.clustermap[start]; run->effect = params->effect; @@ -1596,7 +1603,7 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const return E_OUTOFMEMORY; layout_get_text_run_font_metrics(layout, run, &metrics); - s->s.width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count); + s->s.width = run->width; s->s.thickness = SCALE_FONT_METRIC(metrics.strikethroughThickness, r->u.regular.run.fontEmSize, &metrics); /* Negative offset moves it above baseline as Y coordinate grows downward. */ s->s.offset = -SCALE_FONT_METRIC(metrics.strikethroughPosition, r->u.regular.run.fontEmSize, &metrics); @@ -1668,6 +1675,14 @@ static inline struct layout_effective_run *layout_get_next_effective_run(const s return LIST_ENTRY(e, struct layout_effective_run, entry); } +static inline struct layout_effective_run *layout_get_trailing_effective_run(const struct dwrite_textlayout *layout) +{ + if (list_empty(&layout->effective_runs)) + return NULL; + + return LIST_ENTRY(list_tail(&layout->effective_runs), struct layout_effective_run, entry); +} + static inline struct layout_effective_run *layout_get_next_text_run(const struct dwrite_textlayout *layout, const struct layout_effective_run *cur) { @@ -2045,7 +2060,7 @@ static HRESULT layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cl BOOL is_rtl = layout->format.readingdir == DWRITE_READING_DIRECTION_RIGHT_TO_LEFT; struct layout_final_splitting_params params, prev_params; DWRITE_INLINE_OBJECT_METRICS sign_metrics = { 0 }; - UINT32 count, start, end, pos = *textpos; + UINT32 count, length, start, end, pos = *textpos; UINT32 line = layout->metrics.lineCount; DWRITE_LINE_METRICS1 metrics = { 0 }; FLOAT descent, trailingspacewidth; @@ -2077,12 +2092,21 @@ static HRESULT layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cl } /* Line length includes every cluster. */ - for (UINT32 i = first_cluster; i < first_cluster + cluster_count; ++i) + for (unsigned int i = first_cluster; i < first_cluster + cluster_count; ++i) metrics.length += layout->clustermetrics[i].length; - /* Ignore trailing whitespaces */ - while (cluster_count && layout->clustermetrics[first_cluster + cluster_count - 1].isWhitespace) + /* Ignore trailing whitespaces, up to a newline. */ + while (cluster_count) + { + unsigned int cluster = first_cluster + cluster_count - 1; + + if (layout->clustermetrics[cluster].isNewline) + break; + if (!layout->clustermetrics[cluster].isWhitespace) + break; + --cluster_count; + } /* Does not include trailing space width */ width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count); @@ -2134,6 +2158,7 @@ static HRESULT layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cl run = layout->clusters[first_cluster].run; /* Form runs from a range of clusters; this is what will be reported with DrawGlyphRun() */ + length = 0; origin_x = is_rtl ? layout->metrics.layoutWidth : 0.0f; for (start = first_cluster, end = first_cluster; end < first_cluster + cluster_count; ++end) { @@ -2153,6 +2178,7 @@ static HRESULT layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cl prev_params = params; pos += layout->clustermetrics[end].length; + length += layout->clustermetrics[end].length; } /* Final run from what's left from cluster range */ @@ -2169,19 +2195,19 @@ static HRESULT layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cl if (!(trimming_sign = calloc(1, sizeof(*trimming_sign)))) return E_OUTOFMEMORY; + trimming_sign->start_position = layout->clusters[end].position + layout->clusters[end].run->start_position; + trimming_sign->length = metrics.length - length; trimming_sign->object = layout->format.trimmingsign; trimming_sign->width = sign_metrics.width; origin_x += is_rtl ? -get_cluster_range_width(layout, start, end) : get_cluster_range_width(layout, start, end); trimming_sign->origin.x = is_rtl ? origin_x - trimming_sign->width : origin_x; - trimming_sign->origin.y = 0.0f; /* set after line is built */ - trimming_sign->align_dx = 0.0f; trimming_sign->baseline = sign_metrics.baseline; - trimming_sign->is_sideways = false; + trimming_sign->bidi_level = layout->clusters[end].run->u.regular.run.bidiLevel; + trimming_sign->trimming = true; trimming_sign->line = line; - trimming_sign->effect = layout_get_effect_from_pos(layout, layout->clusters[end].position + - layout->clusters[end].run->start_position); + trimming_sign->effect = layout_get_effect_from_pos(layout, trimming_sign->start_position); list_add_tail(&layout->inlineobjects, &trimming_sign->draw_entry); list_add_tail(&layout->effective_runs, &trimming_sign->entry); @@ -2192,7 +2218,7 @@ static HRESULT layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cl metrics.baseline = run->baseline; descent = run->height - run->baseline; - for (UINT32 cluster = first_cluster + 1; cluster < first_cluster + cluster_count; ++cluster) + for (unsigned int cluster = first_cluster + 1; cluster < first_cluster + cluster_count; ++cluster) { run = layout->clusters[cluster].run; @@ -2205,6 +2231,7 @@ static HRESULT layout_add_line(struct dwrite_textlayout *layout, UINT32 first_cl layout->metrics.widthIncludingTrailingWhitespace); metrics.height = descent + metrics.baseline; + metrics.isTrimmed = append_trimming_run || width > layout->metrics.layoutWidth; *textpos += metrics.length; @@ -4109,12 +4136,115 @@ static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout4 *iface, return E_NOTIMPL; } +static struct layout_effective_run *layout_get_effective_run_for_position(struct dwrite_textlayout *layout, + UINT32 position) +{ + struct layout_effective_run *run; + + /* TODO: this should be indexed by text position */ + LIST_FOR_EACH_ENTRY(run, &layout->effective_runs, struct layout_effective_run, entry) + { + if (run->start_position <= position && position < run->start_position + run->length) + return run; + } + + return NULL; +} + static HRESULT WINAPI dwritetextlayout_HitTestTextPosition(IDWriteTextLayout4 *iface, - UINT32 textPosition, BOOL is_trailinghit, FLOAT *pointX, FLOAT *pointY, DWRITE_HIT_TEST_METRICS *metrics) + UINT32 position, BOOL is_trailinghit, FLOAT *point_x, FLOAT *point_y, DWRITE_HIT_TEST_METRICS *metrics) { - FIXME("%p, %u, %d, %p, %p, %p): stub\n", iface, textPosition, is_trailinghit, pointX, pointY, metrics); + struct dwrite_textlayout *layout = impl_from_IDWriteTextLayout4(iface); + struct layout_effective_run *run; + HRESULT hr; - return E_NOTIMPL; + TRACE("%p, %u, %d, %p, %p, %p.\n", iface, position, is_trailinghit, point_x, point_y, metrics); + + if (FAILED(hr = layout_compute_effective_runs(layout))) + return hr; + + position = min(position, layout->length); + + if (position == layout->length) + { + const DWRITE_LINE_METRICS1 *line = &layout->lines[layout->metrics.lineCount - 1].metrics; + UINT8 level; + + run = layout_get_trailing_effective_run(layout); + level = run->object ? run->bidi_level : run->run->u.regular.run.bidiLevel; + + metrics->textPosition = position; + metrics->length = 0; + /* Empty box following the last run */ + metrics->left = run->left + run->align_dx + run->width; + metrics->top = layout->metrics.height - line->height; + metrics->width = 0.0f; + metrics->height = line->height; + metrics->bidiLevel = level; + metrics->isText = run->trimming || !run->object; + metrics->isTrimmed = run->trimming; + + *point_x = metrics->left; + *point_y = metrics->top; + return S_OK; + } + + if (!(run = layout_get_effective_run_for_position(layout, position))) + { + FIXME("Couldn't find a run for position %u\n", position); + return E_FAIL; + } + + if (run->object) + { + metrics->textPosition = run->start_position; + metrics->length = run->length; + metrics->left = run->origin.x + run->align_dx; + metrics->top = run->origin.y - layout->lines[run->line].baseline; + metrics->height = 0.0f; + metrics->width = run->width; + metrics->bidiLevel = run->bidi_level; + metrics->isText = run->trimming; + metrics->isTrimmed = run->trimming; + } + else + { + unsigned int cluster, cursor = run->start_position; + + /* Locate cluster that contains given position. */ + for (cluster = run->first_cluster; cluster < layout->cluster_count; ++cluster) + { + if (position >= cursor && position < cursor + layout->clustermetrics[cluster].length) + break; + cursor += layout->clustermetrics[cluster].length; + } + + metrics->textPosition = position; + metrics->length = layout->clustermetrics[cluster].length; + metrics->bidiLevel = run->run->u.regular.run.bidiLevel; + + metrics->width = layout->clustermetrics[cluster].width; + metrics->left = run->left + run->align_dx; + if (metrics->bidiLevel & 1) + { + metrics->left += run->width; + metrics->left -= get_cluster_range_width(layout, run->first_cluster, cluster); + metrics->left -= metrics->width; + } + else + { + metrics->left += get_cluster_range_width(layout, run->first_cluster, cluster); + } + metrics->top = run->origin.y - layout->lines[run->line].baseline; + metrics->height = layout->lines[run->line].height; + metrics->isText = TRUE; + metrics->isTrimmed = FALSE; + } + + *point_x = !!(metrics->bidiLevel & 1) == !!is_trailinghit ? metrics->left : metrics->left + metrics->width; + *point_y = metrics->top; + + return S_OK; } static HRESULT WINAPI dwritetextlayout_HitTestTextRange(IDWriteTextLayout4 *iface, diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index 4b7099ceef9..436cc68b1b6 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -7401,10 +7401,7 @@ static void test_HitTestTextPosition(void) /* Out of bounds */ hr = IDWriteTextLayout_HitTestTextPosition(layout, 10, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 6, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 0, "Unexpected length %u.\n", metrics.length); @@ -7415,12 +7412,9 @@ if (hr == S_OK) ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 10, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 6, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 0, "Unexpected length %u.\n", metrics.length); @@ -7431,13 +7425,10 @@ if (hr == S_OK) ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + /* Text-only, simple clusters, one line. */ hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == 0.0f && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7448,12 +7439,9 @@ if (hr == S_OK) ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.width && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7464,12 +7452,9 @@ if (hr == S_OK) ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 5, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 5, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7480,12 +7465,9 @@ if (hr == S_OK) ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 5, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left + metrics.width && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 5, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7496,16 +7478,13 @@ if (hr == S_OK) ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + /* Right-to-left direction. */ hr = IDWriteTextLayout_SetReadingDirection(layout, DWRITE_READING_DIRECTION_RIGHT_TO_LEFT); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDWriteTextLayout_HitTestTextPosition(layout, 10, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 6, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 0, "Unexpected length %u.\n", metrics.length); @@ -7516,12 +7495,9 @@ if (hr == S_OK) ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 10, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 6, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 0, "Unexpected length %u.\n", metrics.length); @@ -7532,12 +7508,9 @@ if (hr == S_OK) ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7548,12 +7521,9 @@ if (hr == S_OK) ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left + metrics.width && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7564,12 +7534,9 @@ if (hr == S_OK) ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 5, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 5, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7580,12 +7547,9 @@ if (hr == S_OK) ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 5, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == layout_metrics.layoutWidth && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 5, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7596,7 +7560,7 @@ if (hr == S_OK) ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + /* Trimming */ hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -7610,53 +7574,53 @@ if (hr == S_OK) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); + todo_wine ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); ok(metrics.left != 0.0f, "Unexpected left %.8e.\n", metrics.left); ok(metrics.top == 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); + todo_wine ok(metrics.height > 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); + todo_wine ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left + metrics.width && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); + todo_wine ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); ok(metrics.left != 0.0f, "Unexpected left %.8e.\n", metrics.left); ok(metrics.top == 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); + todo_wine ok(metrics.height > 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); + todo_wine ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 5, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left + metrics.width && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); + todo_wine ok(metrics.textPosition == 1, "Unexpected text position %u.\n", metrics.textPosition); + todo_wine ok(metrics.length == 5, "Unexpected length %u.\n", metrics.length); ok(metrics.left > 0.0f, "Unexpected left %.8e.\n", metrics.left); ok(metrics.top == 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); + todo_wine ok(metrics.height > 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + /* Width can't fit a single cluster. */ hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, ARRAYSIZE(clusters), &count); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -7669,37 +7633,38 @@ if (hr == S_OK) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDWriteTextLayout_HitTestTextPosition(layout, 1, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ + todo_wine ok(posx > 0.0f && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); + todo_wine ok(metrics.textPosition == 1, "Unexpected text position %u.\n", metrics.textPosition); + todo_wine ok(metrics.length == 5, "Unexpected length %u.\n", metrics.length); + todo_wine ok(metrics.left != 0.0f, "Unexpected left %.8e.\n", metrics.left); ok(metrics.top == 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); + todo_wine ok(metrics.height > 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); + todo_wine ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); ok(metrics.left == 0.0f, "Unexpected left %.8e.\n", metrics.left); ok(metrics.top == 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); + todo_wine ok(metrics.height > 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); + todo_wine ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} hr = IDWriteTextLayout_SetReadingDirection(layout, DWRITE_READING_DIRECTION_RIGHT_TO_LEFT); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -7716,73 +7681,65 @@ if (hr == S_OK) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == 0.0f && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 2, "Unexpected length %u.\n", metrics.length); ok(metrics.left == 0.0f, "Unexpected left %.8e.\n", metrics.left); + todo_wine ok(metrics.top > 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); ok(metrics.height == 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(!metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.width && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 2, "Unexpected length %u.\n", metrics.length); ok(metrics.left == 0.0f, "Unexpected left %.8e.\n", metrics.left); + todo_wine ok(metrics.top > 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); ok(metrics.height == 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(!metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + /* Inline object, RTL */ hr = IDWriteTextLayout_SetReadingDirection(layout, DWRITE_READING_DIRECTION_RIGHT_TO_LEFT); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 2, "Unexpected length %u.\n", metrics.length); ok(metrics.left > 0.0f, "Unexpected left %.8e.\n", metrics.left); + todo_wine ok(metrics.top > 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); ok(metrics.height == 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(!metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left + metrics.width && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 2, "Unexpected length %u.\n", metrics.length); ok(metrics.left > 0.0f, "Unexpected left %.8e.\n", metrics.left); + todo_wine ok(metrics.top > 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); ok(metrics.height == 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(!metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + IDWriteTextLayout_Release(layout); /* Non-trivial clusters */ @@ -7793,10 +7750,7 @@ if (hr == S_OK) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == 100.0f && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7807,12 +7761,9 @@ if (hr == S_OK) ok(metrics.bidiLevel == 1, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 0, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 0, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7823,12 +7774,9 @@ if (hr == S_OK) ok(metrics.bidiLevel == 1, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 10, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 6, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 0, "Unexpected length %u.\n", metrics.length); @@ -7839,12 +7787,9 @@ if (hr == S_OK) ok(metrics.bidiLevel == 1, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 10, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == 0.0f, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 6, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 0, "Unexpected length %u.\n", metrics.length); @@ -7855,7 +7800,6 @@ if (hr == S_OK) ok(metrics.bidiLevel == 1, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} /* Set inline object to contain both Arabic and Latin, Arabic first */ range.startPosition = 1; @@ -7864,21 +7808,19 @@ if (hr == S_OK) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDWriteTextLayout_HitTestTextPosition(layout, 1, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left + metrics.width && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 1, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 2, "Unexpected length %u.\n", metrics.length); ok(metrics.left > 0.0f, "Unexpected left %.8e.\n", metrics.left); + todo_wine ok(metrics.top > 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); ok(metrics.height == 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(metrics.bidiLevel == 1, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(!metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_SetInlineObject(layout, NULL, range); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -7889,21 +7831,18 @@ if (hr == S_OK) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDWriteTextLayout_HitTestTextPosition(layout, 4, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 4, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 2, "Unexpected length %u.\n", metrics.length); ok(metrics.left > 0.0f, "Unexpected left %.8e.\n", metrics.left); + todo_wine ok(metrics.top > 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.width > 0.0f, "Unexpected width %.8e.\n", metrics.width); ok(metrics.height == 0.0f, "Unexpected height %.8e.\n", metrics.height); ok(metrics.bidiLevel == 2, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(!metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} IDWriteTextLayout_Release(layout); @@ -7912,10 +7851,7 @@ if (hr == S_OK) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); hr = IDWriteTextLayout_HitTestTextPosition(layout, 1, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 1, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7926,12 +7862,9 @@ if (hr == S_OK) ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + hr = IDWriteTextLayout_HitTestTextPosition(layout, 1, TRUE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.textPosition == 1, "Unexpected text position %u.\n", metrics.textPosition); ok(metrics.length == 1, "Unexpected length %u.\n", metrics.length); @@ -7942,7 +7875,7 @@ if (hr == S_OK) ok(!metrics.bidiLevel, "Unexpected bidi level %u.\n", metrics.bidiLevel); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); ok(!metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + IDWriteTextLayout_Release(layout); /* A few lines with mandatory breaks, some lines trimmed away */ @@ -7960,9 +7893,7 @@ if (hr == S_OK) ok(count == 3, "Unexpected count %u.\n", count); hr = IDWriteTextLayout_HitTestTextPosition(layout, 4, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) ok(metrics.top > 0.0f, "Unexpected top %.8e.\n", metrics.top); hr = IDWriteTextLayout_SetMaxHeight(layout, line_metrics[0].height * 1.5f); @@ -7974,20 +7905,21 @@ if (hr == S_OK) /* Everything past the first line was trimmed. It's reported in a single hit box. */ hr = IDWriteTextLayout_HitTestTextPosition(layout, 4, FALSE, &posx, &posy, &metrics); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); -if (hr == S_OK) -{ ok(posx == metrics.left && posy == metrics.top, "Unexpected position {%.8e,%.8e}.\n", posx, posy); ok(metrics.left == 0.0f, "Unexpected left %.8e.\n", metrics.left); ok(metrics.top > 0.0f, "Unexpected top %.8e.\n", metrics.top); ok(metrics.textPosition == 4, "Unexpected text position %u.\n", metrics.textPosition); + todo_wine ok(metrics.length == 7, "Unexpected length %u.\n", metrics.length); + todo_wine ok(metrics.height == 0.0f, "Unexpected height %.8e.\n", metrics.height); + todo_wine ok(metrics.width == 0.0f, "Unexpected width %.8e.\n", metrics.width); ok(metrics.isText, "Unexpected isText %d.\n", metrics.isText); + todo_wine ok(metrics.isTrimmed, "Unexpected isTrimmed %d.\n", metrics.isTrimmed); -} + IDWriteTextLayout_Release(layout); IDWriteInlineObject_Release(trimming_sign); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9989
participants (2)
-
Nikolay Sivov -
Nikolay Sivov (@nsivov)