Commit f27b99ec authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

dwrite: Implement DetermineMinWidth() using line breaking info.

parent 2975ae9c
......@@ -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;
......
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment