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;
|
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)
|
static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
|
||||||
{
|
{
|
||||||
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
|
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
|
||||||
|
UINT32 start;
|
||||||
FLOAT width;
|
FLOAT width;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
UINT32 i;
|
|
||||||
|
|
||||||
TRACE("(%p)->(%p)\n", This, min_width);
|
TRACE("(%p)->(%p)\n", This, min_width);
|
||||||
|
|
||||||
|
@ -3260,20 +3249,30 @@ static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *ifa
|
||||||
if (FAILED(hr))
|
if (FAILED(hr))
|
||||||
return hr;
|
return hr;
|
||||||
|
|
||||||
for (i = 0; i < This->cluster_count;) {
|
/* Find widest word without emergency breaking between clusters, trailing whitespaces
|
||||||
if (is_terminal_cluster(This, i)) {
|
preceding breaking point do not contribute to word width. */
|
||||||
width = This->clustermetrics[i].width;
|
for (start = 0; start < This->cluster_count;) {
|
||||||
i++;
|
UINT32 end = start, j, next;
|
||||||
}
|
|
||||||
else {
|
/* 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;
|
width = 0.0f;
|
||||||
while (!is_terminal_cluster(This, i)) {
|
for (j = start; j < end; j++)
|
||||||
width += This->clustermetrics[i].width;
|
width += This->clustermetrics[j].width;
|
||||||
i++;
|
|
||||||
}
|
start = next;
|
||||||
/* count last one too */
|
|
||||||
width += This->clustermetrics[i].width;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (width > This->minwidth)
|
if (width > This->minwidth)
|
||||||
This->minwidth = width;
|
This->minwidth = width;
|
||||||
|
|
|
@ -2347,10 +2347,21 @@ if (hr == S_OK) {
|
||||||
|
|
||||||
static void test_DetermineMinWidth(void)
|
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};
|
static const WCHAR strW[] = {'a','b','c','d',0};
|
||||||
|
DWRITE_CLUSTER_METRICS metrics[10];
|
||||||
IDWriteTextFormat *format;
|
IDWriteTextFormat *format;
|
||||||
IDWriteTextLayout *layout;
|
IDWriteTextLayout *layout;
|
||||||
IDWriteFactory *factory;
|
IDWriteFactory *factory;
|
||||||
|
UINT32 count, i, j;
|
||||||
FLOAT minwidth;
|
FLOAT minwidth;
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
|
@ -2365,13 +2376,34 @@ static void test_DetermineMinWidth(void)
|
||||||
|
|
||||||
hr = IDWriteTextLayout_DetermineMinWidth(layout, NULL);
|
hr = IDWriteTextLayout_DetermineMinWidth(layout, NULL);
|
||||||
ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
|
ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
|
||||||
|
IDWriteTextLayout_Release(layout);
|
||||||
|
|
||||||
minwidth = 0.0;
|
for (i = 0; i < sizeof(minwidth_tests)/sizeof(minwidth_tests[0]); i++) {
|
||||||
hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
|
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);
|
ok(hr == S_OK, "got 0x%08x\n", hr);
|
||||||
ok(minwidth > 0.0, "got %.2f\n", minwidth);
|
|
||||||
|
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);
|
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);
|
IDWriteTextFormat_Release(format);
|
||||||
IDWriteFactory_Release(factory);
|
IDWriteFactory_Release(factory);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue