dwrite: Initial implementation of DetermineMinWidth().

This commit is contained in:
Nikolay Sivov 2015-03-30 10:15:48 +03:00 committed by Alexandre Julliard
parent ee698506c8
commit 8303199cbe
2 changed files with 97 additions and 9 deletions

View File

@ -1,7 +1,7 @@
/*
* Text format and layout
*
* Copyright 2012, 2014 Nikolay Sivov for CodeWeavers
* Copyright 2012, 2014-2015 Nikolay Sivov for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -121,6 +121,12 @@ struct layout_run {
DWRITE_GLYPH_OFFSET *offsets;
};
enum layout_recompute_mask {
RECOMPUTE_NOMINAL_RUNS = 1 << 0,
RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
RECOMPUTE_EVERYTHING = 0xffff
};
struct dwrite_textlayout {
IDWriteTextLayout2 IDWriteTextLayout2_iface;
IDWriteTextFormat1 IDWriteTextFormat1_iface;
@ -135,13 +141,14 @@ struct dwrite_textlayout {
FLOAT maxheight;
struct list ranges;
struct list runs;
BOOL recompute;
USHORT recompute;
DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
DWRITE_LINE_BREAKPOINT *actual_breakpoints;
DWRITE_CLUSTER_METRICS *clusters;
UINT32 clusters_count;
FLOAT minwidth;
/* gdi-compatible layout specifics */
BOOL gdicompatible;
@ -586,7 +593,7 @@ static HRESULT layout_compute(struct dwrite_textlayout *layout)
{
HRESULT hr;
if (!layout->recompute)
if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
return S_OK;
/* nominal breakpoints are evaluated only once, because string never changes */
@ -618,7 +625,7 @@ static HRESULT layout_compute(struct dwrite_textlayout *layout)
}
}
layout->recompute = FALSE;
layout->recompute &= ~RECOMPUTE_NOMINAL_RUNS;
return hr;
}
@ -998,7 +1005,7 @@ done:
if (changed) {
struct list *next, *i;
layout->recompute = TRUE;
layout->recompute = RECOMPUTE_EVERYTHING;
i = list_head(ranges);
while ((next = list_next(ranges, i))) {
struct layout_range *next_range = LIST_ENTRY(next, struct layout_range, entry);
@ -1743,11 +1750,60 @@ static HRESULT WINAPI dwritetextlayout_GetClusterMetrics(IDWriteTextLayout2 *ifa
return max_count >= This->clusters_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->clusters[index].isWhitespace || layout->clusters[index].isNewline ||
(index == layout->clusters_count - 1))
return TRUE;
/* check next one */
return (index < layout->clusters_count - 1) && layout->clusters[index+1].isWhitespace;
}
static HRESULT WINAPI dwritetextlayout_DetermineMinWidth(IDWriteTextLayout2 *iface, FLOAT* min_width)
{
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
FIXME("(%p)->(%p): stub\n", This, min_width);
return E_NOTIMPL;
FLOAT width;
HRESULT hr;
UINT32 i;
TRACE("(%p)->(%p)\n", This, min_width);
if (!min_width)
return E_INVALIDARG;
if (!(This->recompute & RECOMPUTE_MINIMAL_WIDTH))
goto width_done;
*min_width = 0.0;
hr = layout_compute(This);
if (FAILED(hr))
return hr;
for (i = 0; i < This->clusters_count;) {
if (is_terminal_cluster(This, i)) {
width = This->clusters[i].width;
i++;
}
else {
width = 0.0;
while (!is_terminal_cluster(This, i)) {
width += This->clusters[i].width;
i++;
}
/* count last one too */
width += This->clusters[i].width;
}
if (width > This->minwidth)
This->minwidth = width;
}
This->recompute &= ~RECOMPUTE_MINIMAL_WIDTH;
width_done:
*min_width = This->minwidth;
return S_OK;
}
static HRESULT WINAPI dwritetextlayout_HitTestPoint(IDWriteTextLayout2 *iface,
@ -2579,11 +2635,12 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
layout->len = len;
layout->maxwidth = maxwidth;
layout->maxheight = maxheight;
layout->recompute = TRUE;
layout->recompute = RECOMPUTE_EVERYTHING;
layout->nominal_breakpoints = NULL;
layout->actual_breakpoints = NULL;
layout->clusters_count = 0;
layout->clusters = NULL;
layout->minwidth = 0.0;
list_init(&layout->runs);
list_init(&layout->ranges);
memset(&layout->format, 0, sizeof(layout->format));

View File

@ -1,7 +1,7 @@
/*
* Text layout/format tests
*
* Copyright 2012, 2014 Nikolay Sivov for CodeWeavers
* Copyright 2012, 2014-2015 Nikolay Sivov for CodeWeavers
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@ -1297,6 +1297,36 @@ if (hr == S_OK) {
IDWriteFactory_Release(factory);
}
static void test_DetermineMinWidth(void)
{
static const WCHAR strW[] = {'a','b','c','d',0};
IDWriteTextFormat *format;
IDWriteTextLayout *layout;
IDWriteFactory *factory;
FLOAT minwidth;
HRESULT hr;
factory = create_factory();
hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IDWriteFactory_CreateTextLayout(factory, strW, lstrlenW(strW), format, 1000.0, 1000.0, &layout);
ok(hr == S_OK, "got 0x%08x\n", hr);
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);
IDWriteTextFormat_Release(format);
}
START_TEST(layout)
{
IDWriteFactory *factory;
@ -1323,6 +1353,7 @@ START_TEST(layout)
test_SetPairKerning();
test_SetVerticalGlyphOrientation();
test_fallback();
test_DetermineMinWidth();
IDWriteFactory_Release(factory);
}