Commit 44c135dd authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

dwrite: Implement leading and trailing text alignment modes.

parent de46f610
...@@ -180,6 +180,8 @@ struct layout_effective_run { ...@@ -180,6 +180,8 @@ struct layout_effective_run {
UINT32 glyphcount; /* total glyph count in this run */ UINT32 glyphcount; /* total glyph count in this run */
FLOAT origin_x; /* baseline X position */ FLOAT origin_x; /* baseline X position */
FLOAT origin_y; /* baseline Y 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 */ UINT16 *clustermap; /* effective clustermap, allocated separately, is not reused from nominal map */
UINT32 line; UINT32 line;
}; };
...@@ -190,6 +192,8 @@ struct layout_effective_inline { ...@@ -190,6 +192,8 @@ struct layout_effective_inline {
IUnknown *effect; IUnknown *effect;
FLOAT origin_x; FLOAT origin_x;
FLOAT origin_y; FLOAT origin_y;
FLOAT align_dx;
FLOAT width;
BOOL is_sideways; BOOL is_sideways;
BOOL is_rtl; BOOL is_rtl;
UINT32 line; UINT32 line;
...@@ -328,10 +332,12 @@ static inline const char *debugstr_run(const struct regular_layout_run *run) ...@@ -328,10 +332,12 @@ static inline const char *debugstr_run(const struct regular_layout_run *run)
run->descr.stringLength); 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) if ((UINT32)alignment > DWRITE_TEXT_ALIGNMENT_JUSTIFIED)
return E_INVALIDARG; return E_INVALIDARG;
if (changed) *changed = format->textalignment != alignment;
format->textalignment = alignment; format->textalignment = alignment;
return S_OK; return S_OK;
} }
...@@ -934,6 +940,8 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const ...@@ -934,6 +940,8 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
inlineobject->object = r->u.object.object; inlineobject->object = r->u.object.object;
inlineobject->origin_x = origin_x; inlineobject->origin_x = origin_x;
inlineobject->origin_y = 0.0; /* FIXME */ 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 /* It's not clear how these two are set, possibly directionality
is derived from surrounding text (replaced text could have is derived from surrounding text (replaced text could have
different ranges which differ in reading direction). */ different ranges which differ in reading direction). */
...@@ -969,6 +977,8 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const ...@@ -969,6 +977,8 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
run->length = length; run->length = length;
run->origin_x = origin_x; run->origin_x = origin_x;
run->origin_y = 0.0; /* set after line is built */ 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; run->line = line;
if (r->u.regular.run.glyphCount) { if (r->u.regular.run.glyphCount) {
...@@ -1083,6 +1093,95 @@ static inline struct layout_effective_inline *layout_get_next_inline_run(struct ...@@ -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); 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) static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
{ {
struct layout_effective_inline *inrun; struct layout_effective_inline *inrun;
...@@ -1251,6 +1350,10 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout) ...@@ -1251,6 +1350,10 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
layout->metrics.height += layout->lines[line].height; 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->metrics.heightIncludingTrailingWhitespace = layout->metrics.height; /* FIXME: not true for vertical text */
layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS; layout->recompute &= ~RECOMPUTE_EFFECTIVE_RUNS;
...@@ -2555,7 +2658,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface, ...@@ -2555,7 +2658,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
/* return value is ignored */ /* return value is ignored */
IDWriteTextRenderer_DrawGlyphRun(renderer, IDWriteTextRenderer_DrawGlyphRun(renderer,
context, context,
run->origin_x + origin_x, run->origin_x + run->align_dx + origin_x,
run->origin_y + origin_y, run->origin_y + origin_y,
DWRITE_MEASURING_MODE_NATURAL, DWRITE_MEASURING_MODE_NATURAL,
&glyph_run, &glyph_run,
...@@ -2567,8 +2670,8 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface, ...@@ -2567,8 +2670,8 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) { LIST_FOR_EACH_ENTRY(inlineobject, &This->inlineobjects, struct layout_effective_inline, entry) {
IDWriteTextRenderer_DrawInlineObject(renderer, IDWriteTextRenderer_DrawInlineObject(renderer,
context, context,
inlineobject->origin_x, inlineobject->origin_x + inlineobject->align_dx + origin_x,
inlineobject->origin_y, inlineobject->origin_y + origin_y,
inlineobject->object, inlineobject->object,
inlineobject->is_sideways, inlineobject->is_sideways,
inlineobject->is_rtl, inlineobject->is_rtl,
...@@ -2978,8 +3081,20 @@ static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface) ...@@ -2978,8 +3081,20 @@ static ULONG WINAPI dwritetextformat1_layout_Release(IDWriteTextFormat1 *iface)
static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment) static HRESULT WINAPI dwritetextformat1_layout_SetTextAlignment(IDWriteTextFormat1 *iface, DWRITE_TEXT_ALIGNMENT alignment)
{ {
struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface); struct dwrite_textlayout *This = impl_layout_form_IDWriteTextFormat1(iface);
BOOL changed;
HRESULT hr;
TRACE("(%p)->(%d)\n", This, alignment); 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) static HRESULT WINAPI dwritetextformat1_layout_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
...@@ -3853,7 +3968,7 @@ static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *ifac ...@@ -3853,7 +3968,7 @@ static HRESULT WINAPI dwritetextformat_SetTextAlignment(IDWriteTextFormat1 *ifac
{ {
struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface); struct dwrite_textformat *This = impl_from_IDWriteTextFormat1(iface);
TRACE("(%p)->(%d)\n", This, alignment); 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) static HRESULT WINAPI dwritetextformat_SetParagraphAlignment(IDWriteTextFormat1 *iface, DWRITE_PARAGRAPH_ALIGNMENT alignment)
......
...@@ -2865,12 +2865,15 @@ todo_wine { ...@@ -2865,12 +2865,15 @@ todo_wine {
static void test_SetTextAlignment(void) 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; IDWriteTextFormat1 *format1;
IDWriteTextFormat *format; IDWriteTextFormat *format;
IDWriteTextLayout *layout; IDWriteTextLayout *layout;
IDWriteFactory *factory; IDWriteFactory *factory;
DWRITE_TEXT_ALIGNMENT v; DWRITE_TEXT_ALIGNMENT v;
UINT32 count;
HRESULT hr; HRESULT hr;
factory = create_factory(); factory = create_factory();
...@@ -2882,7 +2885,7 @@ static void test_SetTextAlignment(void) ...@@ -2882,7 +2885,7 @@ static void test_SetTextAlignment(void)
v = IDWriteTextFormat_GetTextAlignment(format); v = IDWriteTextFormat_GetTextAlignment(format);
ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v); 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); ok(hr == S_OK, "got 0x%08x\n", hr);
v = IDWriteTextLayout_GetTextAlignment(layout); v = IDWriteTextLayout_GetTextAlignment(layout);
...@@ -2891,6 +2894,9 @@ static void test_SetTextAlignment(void) ...@@ -2891,6 +2894,9 @@ static void test_SetTextAlignment(void)
hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING); hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
ok(hr == S_OK, "got 0x%08x\n", hr); 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); v = IDWriteTextFormat_GetTextAlignment(format);
ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v); ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
...@@ -2916,8 +2922,52 @@ static void test_SetTextAlignment(void) ...@@ -2916,8 +2922,52 @@ static void test_SetTextAlignment(void)
else else
win_skip("IDWriteTextFormat1 is not supported\n"); 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); IDWriteTextLayout_Release(layout);
IDWriteTextFormat_Release(format); IDWriteTextFormat_Release(format);
IDWriteFactory_Release(factory); IDWriteFactory_Release(factory);
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment