[PATCH 3/5] dwrite: Implement leading and trailing text alignment modes
Nikolay Sivov
nsivov at codeweavers.com
Mon Jul 6 01:05:41 CDT 2015
---
-------------- next part --------------
From dc9c58e8b2c11a752ce435a54d76c981cfce90fa Mon Sep 17 00:00:00 2001
From: Nikolay Sivov <nsivov at codeweavers.com>
Date: Mon, 6 Jul 2015 08:41:46 +0300
Subject: [PATCH 3/5] dwrite: Implement leading and trailing text alignment
modes
---
dlls/dwrite/layout.c | 127 ++++++++++++++++++++++++++++++++++++++++++---
dlls/dwrite/tests/layout.c | 54 ++++++++++++++++++-
2 files changed, 173 insertions(+), 8 deletions(-)
diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c
index 13a9ce0..18462b0 100644
--- a/dlls/dwrite/layout.c
+++ b/dlls/dwrite/layout.c
@@ -180,6 +180,8 @@ struct layout_effective_run {
UINT32 glyphcount; /* total glyph count in this run */
FLOAT origin_x; /* baseline X position */
FLOAT origin_y; /* baseline Y position */
+ FLOAT align_dx; /* adjustment from text alignment */
+ FLOAT width; /* run width */
UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
UINT32 line;
};
@@ -190,6 +192,8 @@ struct layout_effective_inline {
IUnknown *effect;
FLOAT origin_x;
FLOAT origin_y;
+ FLOAT align_dx;
+ FLOAT width;
BOOL is_sideways;
BOOL is_rtl;
UINT32 line;
@@ -328,10 +332,12 @@ static inline const char *debugstr_run(const struct regular_layout_run *run)
run->descr.stringLength);
}
-static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment)
+static inline HRESULT format_set_textalignment(struct dwrite_textformat_data *format, DWRITE_TEXT_ALIGNMENT alignment,
+ BOOL *changed)
{
if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
return E_INVALIDARG;
+ if (changed) *changed = format->textalignment != alignment;
format->textalignment = alignment;
return S_OK;
}
@@ -934,6 +940,8 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
inlineobject->object = r->u.object.object;
inlineobject->origin_x = origin_x;
inlineobject->origin_y = 0.0; /* FIXME */
+ inlineobject->align_dx = 0.0;
+ inlineobject->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
/* It's not clear how these two are set, possibly directionality
is derived from surrounding text (replaced text could have
different ranges which differ in reading direction). */
@@ -969,6 +977,8 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
run->length = length;
run->origin_x = origin_x;
run->origin_y = 0.0; /* set after line is built */
+ run->align_dx = 0.0;
+ run->width = get_cluster_range_width(layout, first_cluster, first_cluster + cluster_count);
run->line = line;
if (r->u.regular.run.glyphCount) {
@@ -1083,6 +1093,95 @@ static inline struct layout_effective_inline *layout_get_next_inline_run(struct
return LIST_ENTRY(e, struct layout_effective_inline, entry);
}
+static FLOAT layout_get_line_width(struct dwrite_textlayout *layout,
+ struct layout_effective_run *erun, struct layout_effective_inline *inrun, UINT32 line)
+{
+ FLOAT width = 0.0;
+
+ while (erun && erun->line == line) {
+ width += erun->width;
+ erun = layout_get_next_erun(layout, erun);
+ if (!erun)
+ break;
+ }
+
+ while (inrun && inrun->line == line) {
+ width += inrun->width;
+ inrun = layout_get_next_inline_run(layout, inrun);
+ if (!inrun)
+ break;
+ }
+
+ return width;
+}
+
+static void layout_apply_leading_alignment(struct dwrite_textlayout *layout)
+{
+ struct layout_effective_inline *inrun;
+ struct layout_effective_run *erun;
+
+ erun = layout_get_next_erun(layout, NULL);
+ inrun = layout_get_next_inline_run(layout, NULL);
+
+ while (erun) {
+ erun->align_dx = 0.0;
+ erun = layout_get_next_erun(layout, erun);
+ }
+
+ while (inrun) {
+ inrun->align_dx = 0.0;
+ inrun = layout_get_next_inline_run(layout, inrun);
+ }
+
+ layout->metrics.left = 0;
+}
+
+static void layout_apply_trailing_alignment(struct dwrite_textlayout *layout)
+{
+ struct layout_effective_inline *inrun;
+ struct layout_effective_run *erun;
+ UINT32 line;
+
+ erun = layout_get_next_erun(layout, NULL);
+ inrun = layout_get_next_inline_run(layout, NULL);
+
+ for (line = 0; line < layout->metrics.lineCount; line++) {
+ FLOAT width = layout_get_line_width(layout, erun, inrun, line);
+ FLOAT shift = layout->metrics.layoutWidth - width;
+
+ while (erun && erun->line == line) {
+ erun->align_dx = shift;
+ erun = layout_get_next_erun(layout, erun);
+ }
+
+ while (inrun && inrun->line == line) {
+ erun->align_dx = shift;
+ inrun = layout_get_next_inline_run(layout, inrun);
+ }
+ }
+
+ layout->metrics.left = layout->metrics.layoutWidth - layout->metrics.width;
+}
+
+static void layout_apply_text_alignment(struct dwrite_textlayout *layout)
+{
+ switch (layout->format.textalignment)
+ {
+ case DWRITE_TEXT_ALIGNMENT_LEADING:
+ layout_apply_leading_alignment(layout);
+ break;
+ case DWRITE_TEXT_ALIGNMENT_TRAILING:
+ layout_apply_trailing_alignment(layout);
+ break;
+ case DWRITE_TEXT_ALIGNMENT_JUSTIFIED:
+ case DWRITE_TEXT_ALIGNMENT_CENTER:
+ FIXME("alignment %d not implemented\n", layout->format.textalignment);
+ break;
+ default:
+ ;
+ }
+}
+
static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
{
struct layout_effective_inline *inrun;
@@ -1251,6 +1350,10 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
layout->metrics.height += layout->lines[line].height;
}
+ /* initial alignment is always leading */
+ if (layout->format.textalignment != DWRITE_TEXT_ALIGNMENT_LEADING)
+ layout_apply_text_alignment(layout);
+
layout->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
@@ -2555,7 +2658,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
/* return value is ignored */
IDWriteTextRenderer_DrawGlyphRun(renderer,
context,
- run->origin_x + origin_x,
+ run->origin_x + run->align_dx + origin_x,
run->origin_y + origin_y,
DWRITE_MEASURING_MODE_NATURAL,
&glyph_run,
@@ -2567,8 +2670,8 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
IDWriteTextRenderer_DrawInlineObject(renderer,
context,
- inlineobject->origin_x,
- inlineobject->origin_y,
+ inlineobject->origin_x + inlineobject->align_dx + origin_x,
+ inlineobject->origin_y + origin_y,
inlineobject->object,
inlineobject->is_sideways,
inlineobject->is_rtl,
@@ -2978,8 +3081,20 @@ static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
{
struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
+ BOOL changed;
+ HRESULT hr;
+
TRACE("(%p)->(%d)\n", This, alignment);
- return format_set_textalignment(&This->format, alignment);
+
+ hr = format_set_textalignment(&This->format, alignment, &changed);
+ if (FAILED(hr))
+ return hr;
+
+ /* if layout is not ready there's nothing to align */
+ if (changed && !(This->recompute & RECOMPUTE_EFFECTIVE_RUNS))
+ layout_apply_text_alignment(This);
+
+ return S_OK;
}
static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
@@ -3853,7 +3968,7 @@ static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *ifac
{
struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
TRACE("(%p)->(%d)\n", This, alignment);
- return format_set_textalignment(&This->format, alignment);
+ return format_set_textalignment(&This->format, alignment, NULL);
}
static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c
index 57d3a34..8e8651a 100644
--- a/dlls/dwrite/tests/layout.c
+++ b/dlls/dwrite/tests/layout.c
@@ -2865,12 +2865,15 @@ todo_wine {
static void test_SetTextAlignment(void)
{
- static const WCHAR strW[] = {'a','b','c','d',0};
+ static const WCHAR strW[] = {'a',0};
+ DWRITE_CLUSTER_METRICS clusters[1];
+ DWRITE_TEXT_METRICS metrics;
IDWriteTextFormat1 *format1;
IDWriteTextFormat *format;
IDWriteTextLayout *layout;
IDWriteFactory *factory;
DWRITE_TEXT_ALIGNMENT v;
+ UINT32 count;
HRESULT hr;
factory = create_factory();
@@ -2882,7 +2885,7 @@ static void test_SetTextAlignment(void)
v = IDWriteTextFormat_GetTextAlignment(format);
ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
- hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 300.0, 100.0, &layout);
+ hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
ok(hr == S_OK, "got 0x%08x\n", hr);
v = IDWriteTextLayout_GetTextAlignment(layout);
@@ -2891,6 +2894,9 @@ static void test_SetTextAlignment(void)
hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
ok(hr == S_OK, "got 0x%08x\n", hr);
+ hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
v = IDWriteTextFormat_GetTextAlignment(format);
ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
@@ -2916,8 +2922,52 @@ static void test_SetTextAlignment(void)
else
win_skip("IDWriteTextFormat1 is not supported\n");
+ count = 0;
+ hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ ok(count == 1, "got %u\n", count);
+
+ /* maxwidth is 500, leading alignment */
+ hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_LEADING);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
+ ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
+ ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
+ ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
+
+ /* maxwidth is 500, trailing alignment */
+ hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
+ ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
+ ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
+ ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
+ IDWriteTextLayout_Release(layout);
+
+ /* initially created with trailing alignment */
+ hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_TRAILING);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+ hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
+ ok(hr == S_OK, "got 0x%08x\n", hr);
+
+ ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
+ ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
+ ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
+ ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
IDWriteTextLayout_Release(layout);
+
IDWriteTextFormat_Release(format);
IDWriteFactory_Release(factory);
}
--
2.1.4
More information about the wine-patches
mailing list