dwrite: Implement leading and trailing text alignment modes.
This commit is contained in:
parent
de46f610fe
commit
44c135dd17
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue