dwrite: Implement DetermineMinWidth() using line breaking info.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
2975ae9cbf
commit
f27b99ec2f
|
@ -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);
|
||||
|
||||
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);
|
||||
|
||||
IDWriteTextLayout_Release(layout);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
IDWriteTextFormat_Release(format);
|
||||
IDWriteFactory_Release(factory);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue