dwrite: Implement leading and trailing text alignment modes.

This commit is contained in:
Nikolay Sivov 2015-07-06 09:05:41 +03:00 committed by Alexandre Julliard
parent de46f610fe
commit 44c135dd17
2 changed files with 173 additions and 8 deletions

View File

@ -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)

View File

@ -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);
}