dwrite: Initial implementation of DetermineMinWidth().
This commit is contained in:
parent
ee698506c8
commit
8303199cbe
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Text format and layout
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -121,6 +121,12 @@ struct layout_run {
|
||||||
DWRITE_GLYPH_OFFSET *offsets;
|
DWRITE_GLYPH_OFFSET *offsets;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum layout_recompute_mask {
|
||||||
|
RECOMPUTE_NOMINAL_RUNS = 1 << 0,
|
||||||
|
RECOMPUTE_MINIMAL_WIDTH = 1 << 1,
|
||||||
|
RECOMPUTE_EVERYTHING = 0xffff
|
||||||
|
};
|
||||||
|
|
||||||
struct dwrite_textlayout {
|
struct dwrite_textlayout {
|
||||||
IDWriteTextLayout2 IDWriteTextLayout2_iface;
|
IDWriteTextLayout2 IDWriteTextLayout2_iface;
|
||||||
IDWriteTextFormat1 IDWriteTextFormat1_iface;
|
IDWriteTextFormat1 IDWriteTextFormat1_iface;
|
||||||
|
@ -135,13 +141,14 @@ struct dwrite_textlayout {
|
||||||
FLOAT maxheight;
|
FLOAT maxheight;
|
||||||
struct list ranges;
|
struct list ranges;
|
||||||
struct list runs;
|
struct list runs;
|
||||||
BOOL recompute;
|
USHORT recompute;
|
||||||
|
|
||||||
DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
|
DWRITE_LINE_BREAKPOINT *nominal_breakpoints;
|
||||||
DWRITE_LINE_BREAKPOINT *actual_breakpoints;
|
DWRITE_LINE_BREAKPOINT *actual_breakpoints;
|
||||||
|
|
||||||
DWRITE_CLUSTER_METRICS *clusters;
|
DWRITE_CLUSTER_METRICS *clusters;
|
||||||
UINT32 clusters_count;
|
UINT32 clusters_count;
|
||||||
|
FLOAT minwidth;
|
||||||
|
|
||||||
/* gdi-compatible layout specifics */
|
/* gdi-compatible layout specifics */
|
||||||
BOOL gdicompatible;
|
BOOL gdicompatible;
|
||||||
|
@ -586,7 +593,7 @@ static HRESULT layout_compute(struct dwrite_textlayout *layout)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
|
|
||||||
if (!layout->recompute)
|
if (!(layout->recompute & RECOMPUTE_NOMINAL_RUNS))
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
|
||||||
/* nominal breakpoints are evaluated only once, because string never changes */
|
/* 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;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -998,7 +1005,7 @@ done:
|
||||||
if (changed) {
|
if (changed) {
|
||||||
struct list *next, *i;
|
struct list *next, *i;
|
||||||
|
|
||||||
layout->recompute = TRUE;
|
layout->recompute = RECOMPUTE_EVERYTHING;
|
||||||
i = list_head(ranges);
|
i = list_head(ranges);
|
||||||
while ((next = list_next(ranges, i))) {
|
while ((next = list_next(ranges, i))) {
|
||||||
struct layout_range *next_range = LIST_ENTRY(next, struct layout_range, entry);
|
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;
|
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)
|
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);
|
||||||
FIXME("(%p)->(%p): stub\n", This, min_width);
|
FLOAT width;
|
||||||
return E_NOTIMPL;
|
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,
|
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->len = len;
|
||||||
layout->maxwidth = maxwidth;
|
layout->maxwidth = maxwidth;
|
||||||
layout->maxheight = maxheight;
|
layout->maxheight = maxheight;
|
||||||
layout->recompute = TRUE;
|
layout->recompute = RECOMPUTE_EVERYTHING;
|
||||||
layout->nominal_breakpoints = NULL;
|
layout->nominal_breakpoints = NULL;
|
||||||
layout->actual_breakpoints = NULL;
|
layout->actual_breakpoints = NULL;
|
||||||
layout->clusters_count = 0;
|
layout->clusters_count = 0;
|
||||||
layout->clusters = NULL;
|
layout->clusters = NULL;
|
||||||
|
layout->minwidth = 0.0;
|
||||||
list_init(&layout->runs);
|
list_init(&layout->runs);
|
||||||
list_init(&layout->ranges);
|
list_init(&layout->ranges);
|
||||||
memset(&layout->format, 0, sizeof(layout->format));
|
memset(&layout->format, 0, sizeof(layout->format));
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* Text layout/format tests
|
* 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
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
@ -1297,6 +1297,36 @@ if (hr == S_OK) {
|
||||||
IDWriteFactory_Release(factory);
|
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)
|
START_TEST(layout)
|
||||||
{
|
{
|
||||||
IDWriteFactory *factory;
|
IDWriteFactory *factory;
|
||||||
|
@ -1323,6 +1353,7 @@ START_TEST(layout)
|
||||||
test_SetPairKerning();
|
test_SetPairKerning();
|
||||||
test_SetVerticalGlyphOrientation();
|
test_SetVerticalGlyphOrientation();
|
||||||
test_fallback();
|
test_fallback();
|
||||||
|
test_DetermineMinWidth();
|
||||||
|
|
||||||
IDWriteFactory_Release(factory);
|
IDWriteFactory_Release(factory);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue