Nikolay Sivov : dwrite: Implement DetermineMinWidth() using line breaking info.
Alexandre Julliard
julliard at wine.codeweavers.com
Tue Jan 26 10:32:51 CST 2016
Module: wine
Branch: master
Commit: f27b99ec2f4a7cade70e51a5a3e0193ff7499d4c
URL: http://source.winehq.org/git/wine.git/?a=commit;h=f27b99ec2f4a7cade70e51a5a3e0193ff7499d4c
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Tue Jan 26 15:44:48 2016 +0300
dwrite: Implement DetermineMinWidth() using line breaking info.
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/dwrite/layout.c | 51 +++++++++++++++++++++++-----------------------
dlls/dwrite/tests/layout.c | 42 +++++++++++++++++++++++++++++++++-----
2 files changed, 62 insertions(+), 31 deletions(-)
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index da08b39..0300166 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -3229,23 +3229,12 @@ static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *ifa
return max_count >= This->cluster_count ? S_OK : E_NOT_SUFFICIENT_BUFFER;
}
-/* Only to be used with DetermineMinWidth() to find the longest cluster sequence that we don't want to try
- too hard to break. */
-static inline BOOL is_terminal_cluster(struct dwrite_textlayout *layout, UINT32 index)
-{
- if (layout->clustermetrics[index].isWhitespace || layout->clustermetrics[index].isNewline ||
- (index == layout->cluster_count - 1))
- return TRUE;
- /* check next one */
- return (index < layout->cluster_count - 1) && layout->clustermetrics[index+1].isWhitespace;
-}
-
static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
{
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
+ UINT32 start;
FLOAT width;
HRESULT hr;
- UINT32 i;
TRACE("(%p)->(%p)\n", This, min_width);
@@ -3260,20 +3249,30 @@ static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *ifa
if (FAILED(hr))
return hr;
- for (i = 0; i < This->cluster_count;) {
- if (is_terminal_cluster(This, i)) {
- width = This->clustermetrics[i].width;
- i++;
- }
- else {
- width = 0.0f;
- while (!is_terminal_cluster(This, i)) {
- width += This->clustermetrics[i].width;
- i++;
- }
- /* count last one too */
- width += This->clustermetrics[i].width;
- }
+ /* Find widest word without emergency breaking between clusters, trailing whitespaces
+ preceding breaking point do not contribute to word width. */
+ for (start = 0; start < This->cluster_count;) {
+ UINT32 end = start, j, next;
+
+ /* Last cluster always could be wrapped after. */
+ while (!This->clustermetrics[end].canWrapLineAfter)
+ end++;
+ /* make is so current cluster range that we can wrap after is [start,end) */
+ end++;
+
+ next = end;
+
+ /* Ignore trailing whitespace clusters, in case of single space range will
+ be reduced to empty range, or [start,start+1). */
+ while ((end - 1) >= start && This->clustermetrics[end-1].isWhitespace)
+ end--;
+
+ /* check if cluster range exceeds last minimal width */
+ width = 0.0f;
+ for (j = start; j < end; j++)
+ width += This->clustermetrics[j].width;
+
+ start = next;
if (width > This->minwidth)
This->minwidth = width;
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index c04e73a..7d83c1a 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -2347,10 +2347,21 @@ if (hr == S_OK) {
static void test_DetermineMinWidth(void)
{
+ struct minwidth_test {
+ const WCHAR text[10]; /* text to create a layout for */
+ const WCHAR mintext[10]; /* text that represents sequence of minimal width */
+ } minwidth_tests[] = {
+ { {' ','a','b',' ',0}, {'a','b',0} },
+ { {'a','\n',' ',' ',0}, {'a',0} },
+ { {'a','\n',' ',' ','b',0}, {'b',0} },
+ { {'a','b','c','\n',' ',' ','b',0}, {'a','b','c',0} },
+ };
static const WCHAR strW[] = {'a','b','c','d',0};
+ DWRITE_CLUSTER_METRICS metrics[10];
IDWriteTextFormat *format;
IDWriteTextLayout *layout;
IDWriteFactory *factory;
+ UINT32 count, i, j;
FLOAT minwidth;
HRESULT hr;
@@ -2365,13 +2376,34 @@ static void test_DetermineMinWidth(void)
hr = IDWriteTextLayout_DetermineMinWidth(layout, NULL);
ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
+ IDWriteTextLayout_Release(layout);
- minwidth = 0.0;
- hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
- ok(hr == S_OK, "got 0x%08x\n", hr);
- ok(minwidth > 0.0, "got %.2f\n", minwidth);
+ for (i = 0; i < sizeof(minwidth_tests)/sizeof(minwidth_tests[0]); i++) {
+ FLOAT width = 0.0f;
+
+ /* measure expected width */
+ hr = IDWriteFactory_CreateTextLayout(factory, minwidth_tests[i].mintext, lstrlenW(minwidth_tests[i].mintext), format, 1000.0f, 1000.0f, &layout);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ for (j = 0; j < count; j++)
+ width += metrics[j].width;
+
+ IDWriteTextLayout_Release(layout);
+
+ hr = IDWriteFactory_CreateTextLayout(factory, minwidth_tests[i].text, lstrlenW(minwidth_tests[i].text), format, 1000.0f, 1000.0f, &layout);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ minwidth = 0.0f;
+ hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(minwidth == width, "test %u: expected width %f, got %f\n", i, width, minwidth);
+
+ IDWriteTextLayout_Release(layout);
+ }
- IDWriteTextLayout_Release(layout);
IDWriteTextFormat_Release(format);
IDWriteFactory_Release(factory);
}
More information about the wine-cvs
mailing list