Nikolay Sivov : dwrite: Initial implementation of DetermineMinWidth().
Alexandre Julliard
julliard at wine.codeweavers.com
Mon Mar 30 10:12:58 CDT 2015
Module: wine
Branch: master
Commit: 8303199cbe4e0e2a645fe45161fb36922753bc68
URL: http://source.winehq.org/git/wine.git/?a=commit;h=8303199cbe4e0e2a645fe45161fb36922753bc68
Author: Nikolay Sivov <nsivov at codeweavers.com>
Date: Mon Mar 30 10:15:48 2015 +0300
dwrite: Initial implementation of DetermineMinWidth().
---
dlls/dwrite/layout.c | 73 +++++++++++++++++++++++++++++++++++++++++-----
dlls/dwrite/tests/layout.c | 33 ++++++++++++++++++++-
2 files changed, 97 insertions(+), 9 deletions(-)
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 054aae7..28889a7 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -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));
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index bbfc7bc..f36c01e 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -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);
}
More information about the wine-cvs
mailing list