dwrite: Fix the way drawing effects are reported for inline objects.

This commit is contained in:
Nikolay Sivov 2015-06-15 01:15:25 +03:00 committed by Alexandre Julliard
parent 6655b0c93a
commit b7fb00e9aa
2 changed files with 321 additions and 54 deletions

View File

@ -95,7 +95,8 @@ struct layout_range_attr_value {
enum layout_range_kind { enum layout_range_kind {
LAYOUT_RANGE_REGULAR, LAYOUT_RANGE_REGULAR,
LAYOUT_RANGE_STRIKETHROUGH LAYOUT_RANGE_STRIKETHROUGH,
LAYOUT_RANGE_EFFECT
}; };
struct layout_range_header { struct layout_range_header {
@ -111,7 +112,6 @@ struct layout_range {
FLOAT fontsize; FLOAT fontsize;
DWRITE_FONT_STRETCH stretch; DWRITE_FONT_STRETCH stretch;
IDWriteInlineObject *object; IDWriteInlineObject *object;
IUnknown *effect;
BOOL underline; BOOL underline;
BOOL pair_kerning; BOOL pair_kerning;
IDWriteFontCollection *collection; IDWriteFontCollection *collection;
@ -124,6 +124,11 @@ struct layout_range_bool {
BOOL value; BOOL value;
}; };
struct layout_range_effect {
struct layout_range_header h;
IUnknown *effect;
};
enum layout_run_kind { enum layout_run_kind {
LAYOUT_RUN_REGULAR, LAYOUT_RUN_REGULAR,
LAYOUT_RUN_INLINE LAYOUT_RUN_INLINE
@ -153,7 +158,6 @@ struct layout_run {
struct inline_object_run object; struct inline_object_run object;
struct regular_layout_run regular; struct regular_layout_run regular;
} u; } u;
IUnknown *effect;
}; };
struct layout_effective_run { struct layout_effective_run {
@ -170,6 +174,7 @@ struct layout_effective_run {
struct layout_effective_inline { struct layout_effective_inline {
struct list entry; struct list entry;
IDWriteInlineObject *object; IDWriteInlineObject *object;
IUnknown *effect;
FLOAT origin_x; FLOAT origin_x;
FLOAT origin_y; FLOAT origin_y;
BOOL is_sideways; BOOL is_sideways;
@ -207,6 +212,7 @@ struct dwrite_textlayout {
FLOAT maxwidth; FLOAT maxwidth;
FLOAT maxheight; FLOAT maxheight;
struct list strike_ranges; struct list strike_ranges;
struct list effects;
struct list ranges; struct list ranges;
struct list runs; struct list runs;
/* lists ready to use by Draw() */ /* lists ready to use by Draw() */
@ -601,7 +607,6 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
r->u.object.object = range->object; r->u.object.object = range->object;
r->u.object.length = get_clipped_range_length(layout, range); r->u.object.length = get_clipped_range_length(layout, range);
r->effect = range->effect;
list_add_tail(&layout->runs, &r->entry); list_add_tail(&layout->runs, &r->entry);
continue; continue;
} }
@ -661,7 +666,6 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout)
} }
range = get_layout_range_by_pos(layout, run->descr.textPosition); range = get_layout_range_by_pos(layout, run->descr.textPosition);
r->effect = range->effect;
hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists); hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists);
if (FAILED(hr) || !exists) { if (FAILED(hr) || !exists) {
@ -844,6 +848,25 @@ static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UI
return width; return width;
} }
static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
{
struct layout_range_header *cur;
LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
DWRITE_TEXT_RANGE *r = &cur->range;
if (r->startPosition <= pos && pos < r->startPosition + r->length)
return cur;
}
return NULL;
}
static inline IUnknown *layout_get_effect_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
{
struct layout_range_header *h = get_layout_range_header_by_pos(&layout->effects, pos);
return ((struct layout_range_effect*)h)->effect;
}
/* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index, /* Effective run is built from consecutive clusters of a single nominal run, 'first_cluster' is 0 based cluster index,
'cluster_count' indicates how many clusters to add, including first one. */ 'cluster_count' indicates how many clusters to add, including first one. */
static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster, static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const struct layout_run *r, UINT32 first_cluster,
@ -867,6 +890,10 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const
different ranges which differ in reading direction). */ different ranges which differ in reading direction). */
inlineobject->is_sideways = FALSE; inlineobject->is_sideways = FALSE;
inlineobject->is_rtl = FALSE; inlineobject->is_rtl = FALSE;
/* effect assigned from start position and on is used for inline objects */
inlineobject->effect = layout_get_effect_from_pos(layout, layout->clusters[first_cluster].position);
list_add_tail(&layout->inlineobjects, &inlineobject->entry); list_add_tail(&layout->inlineobjects, &inlineobject->entry);
return S_OK; return S_OK;
} }
@ -970,19 +997,6 @@ static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_
return S_OK; return S_OK;
} }
static struct layout_range_header *get_layout_range_header_by_pos(struct list *ranges, UINT32 pos)
{
struct layout_range_header *cur;
LIST_FOR_EACH_ENTRY(cur, ranges, struct layout_range_header, entry) {
DWRITE_TEXT_RANGE *r = &cur->range;
if (r->startPosition <= pos && pos < r->startPosition + r->length)
return cur;
}
return NULL;
}
static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos) static inline BOOL layout_get_strikethrough_from_pos(struct dwrite_textlayout *layout, UINT32 pos)
{ {
struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos); struct layout_range_header *h = get_layout_range_header_by_pos(&layout->strike_ranges, pos);
@ -1090,6 +1104,7 @@ static HRESULT layout_compute_effective_runs(struct dwrite_textlayout *layout)
static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value) static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
{ {
struct layout_range_effect const *range_effect = (struct layout_range_effect*)h;
struct layout_range_bool const *range_bool = (struct layout_range_bool*)h; struct layout_range_bool const *range_bool = (struct layout_range_bool*)h;
struct layout_range const *range = (struct layout_range*)h; struct layout_range const *range = (struct layout_range*)h;
@ -1105,7 +1120,7 @@ static BOOL is_same_layout_attrvalue(struct layout_range_header const *h, enum l
case LAYOUT_RANGE_ATTR_INLINE: case LAYOUT_RANGE_ATTR_INLINE:
return range->object == value->u.object; return range->object == value->u.object;
case LAYOUT_RANGE_ATTR_EFFECT: case LAYOUT_RANGE_ATTR_EFFECT:
return range->effect == value->u.effect; return range_effect->effect == value->u.effect;
case LAYOUT_RANGE_ATTR_UNDERLINE: case LAYOUT_RANGE_ATTR_UNDERLINE:
return range->underline == value->u.underline; return range->underline == value->u.underline;
case LAYOUT_RANGE_ATTR_STRIKETHROUGH: case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
@ -1138,7 +1153,6 @@ static inline BOOL is_same_layout_attributes(struct layout_range_header const *h
left->stretch == right->stretch && left->stretch == right->stretch &&
left->fontsize == right->fontsize && left->fontsize == right->fontsize &&
left->object == right->object && left->object == right->object &&
left->effect == right->effect &&
left->underline == right->underline && left->underline == right->underline &&
left->pair_kerning == right->pair_kerning && left->pair_kerning == right->pair_kerning &&
left->collection == right->collection && left->collection == right->collection &&
@ -1151,6 +1165,12 @@ static inline BOOL is_same_layout_attributes(struct layout_range_header const *h
struct layout_range_bool const *right = (struct layout_range_bool const*)hright; struct layout_range_bool const *right = (struct layout_range_bool const*)hright;
return left->value == right->value; return left->value == right->value;
} }
case LAYOUT_RANGE_EFFECT:
{
struct layout_range_effect const *left = (struct layout_range_effect const*)hleft;
struct layout_range_effect const *right = (struct layout_range_effect const*)hright;
return left->effect == right->effect;
}
default: default:
FIXME("unknown range kind %d\n", hleft->kind); FIXME("unknown range kind %d\n", hleft->kind);
return FALSE; return FALSE;
@ -1182,7 +1202,6 @@ static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *
range->stretch = layout->format.stretch; range->stretch = layout->format.stretch;
range->fontsize = layout->format.fontsize; range->fontsize = layout->format.fontsize;
range->object = NULL; range->object = NULL;
range->effect = NULL;
range->underline = FALSE; range->underline = FALSE;
range->pair_kerning = FALSE; range->pair_kerning = FALSE;
@ -1211,6 +1230,17 @@ static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout *
h = &range->h; h = &range->h;
break; break;
} }
case LAYOUT_RANGE_EFFECT:
{
struct layout_range_effect *range;
range = heap_alloc(sizeof(*range));
if (!range) return NULL;
range->effect = NULL;
h = &range->h;
break;
}
default: default:
FIXME("unknown range kind %d\n", kind); FIXME("unknown range kind %d\n", kind);
return NULL; return NULL;
@ -1244,8 +1274,6 @@ static struct layout_range_header *alloc_layout_range_from(struct layout_range_h
/* update refcounts */ /* update refcounts */
if (range->object) if (range->object)
IDWriteInlineObject_AddRef(range->object); IDWriteInlineObject_AddRef(range->object);
if (range->effect)
IUnknown_AddRef(range->effect);
if (range->collection) if (range->collection)
IDWriteFontCollection_AddRef(range->collection); IDWriteFontCollection_AddRef(range->collection);
ret = &range->h; ret = &range->h;
@ -1260,6 +1288,17 @@ static struct layout_range_header *alloc_layout_range_from(struct layout_range_h
ret = &strike->h; ret = &strike->h;
break; break;
} }
case LAYOUT_RANGE_EFFECT:
{
struct layout_range_effect *effect = heap_alloc(sizeof(*effect));
if (!effect) return NULL;
*effect = *(struct layout_range_effect*)h;
if (effect->effect)
IUnknown_AddRef(effect->effect);
ret = &effect->h;
break;
}
default: default:
FIXME("unknown range kind %d\n", h->kind); FIXME("unknown range kind %d\n", h->kind);
return NULL; return NULL;
@ -1274,16 +1313,28 @@ static void free_layout_range(struct layout_range_header *h)
if (!h) if (!h)
return; return;
if (h->kind == LAYOUT_RANGE_REGULAR) { switch (h->kind)
{
case LAYOUT_RANGE_REGULAR:
{
struct layout_range *range = (struct layout_range*)h; struct layout_range *range = (struct layout_range*)h;
if (range->object) if (range->object)
IDWriteInlineObject_Release(range->object); IDWriteInlineObject_Release(range->object);
if (range->effect)
IUnknown_Release(range->effect);
if (range->collection) if (range->collection)
IDWriteFontCollection_Release(range->collection); IDWriteFontCollection_Release(range->collection);
heap_free(range->fontfamily); heap_free(range->fontfamily);
break;
}
case LAYOUT_RANGE_EFFECT:
{
struct layout_range_effect *effect = (struct layout_range_effect*)h;
if (effect->effect)
IUnknown_Release(effect->effect);
break;
}
default:
;
} }
heap_free(h); heap_free(h);
@ -1302,6 +1353,11 @@ static void free_layout_ranges_list(struct dwrite_textlayout *layout)
list_remove(&cur->entry); list_remove(&cur->entry);
free_layout_range(cur); free_layout_range(cur);
} }
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &layout->effects, struct layout_range_header, entry) {
list_remove(&cur->entry);
free_layout_range(cur);
}
} }
static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range) static struct layout_range_header *find_outer_range(struct list *ranges, const DWRITE_TEXT_RANGE *range)
@ -1351,6 +1407,7 @@ static inline BOOL set_layout_range_iface_attr(IUnknown **dest, IUnknown *value)
static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value) static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_range_attr_kind attr, struct layout_range_attr_value *value)
{ {
struct layout_range_effect *dest_effect = (struct layout_range_effect*)h;
struct layout_range_bool *dest_bool = (struct layout_range_bool*)h; struct layout_range_bool *dest_bool = (struct layout_range_bool*)h;
struct layout_range *dest = (struct layout_range*)h; struct layout_range *dest = (struct layout_range*)h;
@ -1377,7 +1434,7 @@ static BOOL set_layout_range_attrval(struct layout_range_header *h, enum layout_
changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object); changed = set_layout_range_iface_attr((IUnknown**)&dest->object, (IUnknown*)value->u.object);
break; break;
case LAYOUT_RANGE_ATTR_EFFECT: case LAYOUT_RANGE_ATTR_EFFECT:
changed = set_layout_range_iface_attr((IUnknown**)&dest->effect, (IUnknown*)value->u.effect); changed = set_layout_range_iface_attr((IUnknown**)&dest_effect->effect, (IUnknown*)value->u.effect);
break; break;
case LAYOUT_RANGE_ATTR_UNDERLINE: case LAYOUT_RANGE_ATTR_UNDERLINE:
changed = dest->underline != value->u.underline; changed = dest->underline != value->u.underline;
@ -1444,7 +1501,6 @@ static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layo
case LAYOUT_RANGE_ATTR_STYLE: case LAYOUT_RANGE_ATTR_STYLE:
case LAYOUT_RANGE_ATTR_STRETCH: case LAYOUT_RANGE_ATTR_STRETCH:
case LAYOUT_RANGE_ATTR_FONTSIZE: case LAYOUT_RANGE_ATTR_FONTSIZE:
case LAYOUT_RANGE_ATTR_EFFECT:
case LAYOUT_RANGE_ATTR_INLINE: case LAYOUT_RANGE_ATTR_INLINE:
case LAYOUT_RANGE_ATTR_UNDERLINE: case LAYOUT_RANGE_ATTR_UNDERLINE:
case LAYOUT_RANGE_ATTR_PAIR_KERNING: case LAYOUT_RANGE_ATTR_PAIR_KERNING:
@ -1456,6 +1512,9 @@ static HRESULT set_layout_range_attr(struct dwrite_textlayout *layout, enum layo
case LAYOUT_RANGE_ATTR_STRIKETHROUGH: case LAYOUT_RANGE_ATTR_STRIKETHROUGH:
ranges = &layout->strike_ranges; ranges = &layout->strike_ranges;
break; break;
case LAYOUT_RANGE_ATTR_EFFECT:
ranges = &layout->effects;
break;
default: default:
FIXME("unknown attr kind %d\n", attr); FIXME("unknown attr kind %d\n", attr);
return E_FAIL; return E_FAIL;
@ -2191,14 +2250,11 @@ static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *ifac
UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r) UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r)
{ {
struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface); struct dwrite_textlayout *This = impl_from_IDWriteTextLayout2(iface);
struct layout_range *range; struct layout_range_effect *range;
TRACE("(%p)->(%u %p %p)\n", This, position, effect, r); TRACE("(%p)->(%u %p %p)\n", This, position, effect, r);
if (position >= This->len) range = (struct layout_range_effect*)get_layout_range_header_by_pos(&This->effects, position);
return S_OK;
range = get_layout_range_by_pos(This, position);
*effect = range->effect; *effect = range->effect;
if (*effect) if (*effect)
IUnknown_AddRef(*effect); IUnknown_AddRef(*effect);
@ -2297,7 +2353,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
DWRITE_MEASURING_MODE_NATURAL, DWRITE_MEASURING_MODE_NATURAL,
&glyph_run, &glyph_run,
&descr, &descr,
run->run->effect); NULL);
} }
/* 2. Inline objects */ /* 2. Inline objects */
@ -2309,7 +2365,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
inlineobject->object, inlineobject->object,
inlineobject->is_sideways, inlineobject->is_sideways,
inlineobject->is_rtl, inlineobject->is_rtl,
run->run->effect); inlineobject->effect);
} }
/* TODO: 3. Underlines */ /* TODO: 3. Underlines */
@ -2321,7 +2377,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface,
s->run->origin_x, s->run->origin_x,
s->run->origin_y, s->run->origin_y,
&s->s, &s->s,
s->run->run->effect); NULL);
} }
return S_OK; return S_OK;
@ -3254,7 +3310,7 @@ static HRESULT layout_format_from_textformat(struct dwrite_textlayout *layout, I
static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout) static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *format, FLOAT maxwidth, FLOAT maxheight, struct dwrite_textlayout *layout)
{ {
struct layout_range_header *range, *strike; struct layout_range_header *range, *strike, *effect;
DWRITE_TEXT_RANGE r = { 0, ~0u }; DWRITE_TEXT_RANGE r = { 0, ~0u };
HRESULT hr; HRESULT hr;
@ -3282,6 +3338,7 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
list_init(&layout->runs); list_init(&layout->runs);
list_init(&layout->ranges); list_init(&layout->ranges);
list_init(&layout->strike_ranges); list_init(&layout->strike_ranges);
list_init(&layout->effects);
memset(&layout->format, 0, sizeof(layout->format)); memset(&layout->format, 0, sizeof(layout->format));
layout->gdicompatible = FALSE; layout->gdicompatible = FALSE;
@ -3301,15 +3358,18 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat *
range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR); range = alloc_layout_range(layout, &r, LAYOUT_RANGE_REGULAR);
strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH); strike = alloc_layout_range(layout, &r, LAYOUT_RANGE_STRIKETHROUGH);
if (!range || !strike) { effect = alloc_layout_range(layout, &r, LAYOUT_RANGE_EFFECT);
if (!range || !strike || !effect) {
free_layout_range(range); free_layout_range(range);
free_layout_range(strike); free_layout_range(strike);
free_layout_range(effect);
hr = E_OUTOFMEMORY; hr = E_OUTOFMEMORY;
goto fail; goto fail;
} }
list_add_head(&layout->ranges, &range->entry); list_add_head(&layout->ranges, &range->entry);
list_add_head(&layout->strike_ranges, &strike->entry); list_add_head(&layout->strike_ranges, &strike->entry);
list_add_head(&layout->effects, &effect->entry);
return S_OK; return S_OK;
fail: fail:

View File

@ -215,18 +215,39 @@ static void _expect_ref(IUnknown* obj, ULONG ref, int line)
ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1); ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
} }
enum drawcall_kind { enum drawcall_modifiers_kind {
DRAW_GLYPHRUN = 0, DRAW_EFFECT = 0x1000
DRAW_UNDERLINE,
DRAW_STRIKETHROUGH,
DRAW_INLINE,
DRAW_LAST_KIND
}; };
static const char *get_draw_kind_name(enum drawcall_kind kind) enum drawcall_kind {
DRAW_GLYPHRUN = 0,
DRAW_UNDERLINE = 1,
DRAW_STRIKETHROUGH = 2,
DRAW_INLINE = 3,
DRAW_LAST_KIND = 4,
DRAW_TOTAL_KINDS = 5,
DRAW_KINDS_MASK = 0xff
};
static const char *get_draw_kind_name(unsigned short kind)
{ {
static const char *kind_names[] = { "GLYPH_RUN", "UNDERLINE", "STRIKETHROUGH", "INLINE", "END_OF_SEQ" }; static const char *kind_names[] = {
return kind > DRAW_LAST_KIND ? "unknown" : kind_names[kind]; "GLYPH_RUN",
"UNDERLINE",
"STRIKETHROUGH",
"INLINE",
"END_OF_SEQ",
"GLYPH_RUN|EFFECT",
"UNDERLINE|EFFECT",
"STRIKETHROUGH|EFFECT",
"INLINE|EFFECT",
"END_OF_SEQ"
};
if ((kind & DRAW_KINDS_MASK) > DRAW_LAST_KIND)
return "unknown";
return (kind & DRAW_EFFECT) ? kind_names[(kind & DRAW_KINDS_MASK) + DRAW_TOTAL_KINDS] :
kind_names[kind];
} }
struct drawcall_entry { struct drawcall_entry {
@ -242,7 +263,7 @@ struct drawcall_sequence
}; };
struct drawtestcontext { struct drawtestcontext {
enum drawcall_kind kind; unsigned short kind;
BOOL todo; BOOL todo;
int *failcount; int *failcount;
const char *file; const char *file;
@ -327,7 +348,7 @@ static void ok_sequence_(struct drawcall_sequence **seq, int sequence_index,
ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n", ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind)); context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
} }
else if (expected->kind == DRAW_GLYPHRUN) { else if ((expected->kind & DRAW_KINDS_MASK) == DRAW_GLYPHRUN) {
int cmp = lstrcmpW(expected->string, actual->string); int cmp = lstrcmpW(expected->string, actual->string);
if (cmp != 0 && todo) { if (cmp != 0 && todo) {
failcount++; failcount++;
@ -424,7 +445,7 @@ static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface,
DWRITE_MEASURING_MODE mode, DWRITE_MEASURING_MODE mode,
DWRITE_GLYPH_RUN const *run, DWRITE_GLYPH_RUN const *run,
DWRITE_GLYPH_RUN_DESCRIPTION const *descr, DWRITE_GLYPH_RUN_DESCRIPTION const *descr,
IUnknown *drawing_effect) IUnknown *effect)
{ {
struct drawcall_entry entry; struct drawcall_entry entry;
DWRITE_SCRIPT_ANALYSIS sa; DWRITE_SCRIPT_ANALYSIS sa;
@ -452,6 +473,8 @@ static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface,
} }
entry.kind = DRAW_GLYPHRUN; entry.kind = DRAW_GLYPHRUN;
if (effect)
entry.kind |= DRAW_EFFECT;
add_call(sequences, RENDERER_ID, &entry); add_call(sequences, RENDERER_ID, &entry);
return S_OK; return S_OK;
} }
@ -461,10 +484,12 @@ static HRESULT WINAPI testrenderer_DrawUnderline(IDWriteTextRenderer *iface,
FLOAT baselineOriginX, FLOAT baselineOriginX,
FLOAT baselineOriginY, FLOAT baselineOriginY,
DWRITE_UNDERLINE const* underline, DWRITE_UNDERLINE const* underline,
IUnknown *drawing_effect) IUnknown *effect)
{ {
struct drawcall_entry entry; struct drawcall_entry entry;
entry.kind = DRAW_UNDERLINE; entry.kind = DRAW_UNDERLINE;
if (effect)
entry.kind |= DRAW_EFFECT;
add_call(sequences, RENDERER_ID, &entry); add_call(sequences, RENDERER_ID, &entry);
return S_OK; return S_OK;
} }
@ -474,10 +499,12 @@ static HRESULT WINAPI testrenderer_DrawStrikethrough(IDWriteTextRenderer *iface,
FLOAT baselineOriginX, FLOAT baselineOriginX,
FLOAT baselineOriginY, FLOAT baselineOriginY,
DWRITE_STRIKETHROUGH const* strikethrough, DWRITE_STRIKETHROUGH const* strikethrough,
IUnknown *drawing_effect) IUnknown *effect)
{ {
struct drawcall_entry entry; struct drawcall_entry entry;
entry.kind = DRAW_STRIKETHROUGH; entry.kind = DRAW_STRIKETHROUGH;
if (effect)
entry.kind |= DRAW_EFFECT;
add_call(sequences, RENDERER_ID, &entry); add_call(sequences, RENDERER_ID, &entry);
return S_OK; return S_OK;
} }
@ -489,10 +516,12 @@ static HRESULT WINAPI testrenderer_DrawInlineObject(IDWriteTextRenderer *iface,
IDWriteInlineObject *object, IDWriteInlineObject *object,
BOOL is_sideways, BOOL is_sideways,
BOOL is_rtl, BOOL is_rtl,
IUnknown *drawing_effect) IUnknown *effect)
{ {
struct drawcall_entry entry; struct drawcall_entry entry;
entry.kind = DRAW_INLINE; entry.kind = DRAW_INLINE;
if (effect)
entry.kind |= DRAW_EFFECT;
add_call(sequences, RENDERER_ID, &entry); add_call(sequences, RENDERER_ID, &entry);
return S_OK; return S_OK;
} }
@ -575,6 +604,36 @@ static IDWriteInlineObjectVtbl testinlineobjvtbl = {
static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl }; static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl };
static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl }; static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
static HRESULT WINAPI testeffect_QI(IUnknown *iface, REFIID riid, void **obj)
{
if (IsEqualIID(riid, &IID_IUnknown)) {
*obj = iface;
IUnknown_AddRef(iface);
return S_OK;
}
*obj = NULL;
return E_NOINTERFACE;
}
static ULONG WINAPI testeffect_AddRef(IUnknown *iface)
{
return 2;
}
static ULONG WINAPI testeffect_Release(IUnknown *iface)
{
return 1;
}
static const IUnknownVtbl testeffectvtbl = {
testeffect_QI,
testeffect_AddRef,
testeffect_Release
};
static IUnknown testeffect = { &testeffectvtbl };
static void test_CreateTextLayout(void) static void test_CreateTextLayout(void)
{ {
static const WCHAR strW[] = {'s','t','r','i','n','g',0}; static const WCHAR strW[] = {'s','t','r','i','n','g',0};
@ -1156,7 +1215,7 @@ static void test_SetInlineObject(void)
static const struct drawcall_entry draw_seq[] = { static const struct drawcall_entry draw_seq[] = {
{ DRAW_GLYPHRUN, {'s',0} }, { DRAW_GLYPHRUN, {'s',0} },
{ DRAW_GLYPHRUN, {'r','i',0} }, { DRAW_GLYPHRUN, {'r','i',0} },
{ DRAW_GLYPHRUN, {'n',0} }, { DRAW_GLYPHRUN|DRAW_EFFECT, {'n',0} },
{ DRAW_GLYPHRUN, {'g',0} }, { DRAW_GLYPHRUN, {'g',0} },
{ DRAW_INLINE }, { DRAW_INLINE },
{ DRAW_UNDERLINE }, { DRAW_UNDERLINE },
@ -2438,6 +2497,153 @@ static void test_SetFlowDirection(void)
IDWriteFactory_Release(factory); IDWriteFactory_Release(factory);
} }
static const struct drawcall_entry draweffect_seq[] = {
{ DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0x0300,0} },
{ DRAW_GLYPHRUN, {'d',0} },
{ DRAW_LAST_KIND }
};
static const struct drawcall_entry draweffect2_seq[] = {
{ DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0} },
{ DRAW_GLYPHRUN, {'c','d',0} },
{ DRAW_LAST_KIND }
};
static const struct drawcall_entry draweffect3_seq[] = {
{ DRAW_INLINE|DRAW_EFFECT },
{ DRAW_LAST_KIND }
};
static const struct drawcall_entry draweffect4_seq[] = {
{ DRAW_INLINE },
{ DRAW_LAST_KIND }
};
static void test_SetDrawingEffect(void)
{
static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
static const WCHAR str2W[] = {'a','e','c','d',0};
IDWriteInlineObject *sign;
IDWriteTextFormat *format;
IDWriteTextLayout *layout;
IDWriteFactory *factory;
DWRITE_TEXT_RANGE r;
IUnknown *unk;
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);
/* string with combining mark */
hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
ok(hr == S_OK, "got 0x%08x\n", hr);
/* set effect past the end of text */
r.startPosition = 100;
r.length = 10;
hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
ok(hr == S_OK, "got 0x%08x\n", hr);
r.startPosition = r.length = 0;
hr = IDWriteTextLayout_GetDrawingEffect(layout, 101, &unk, &r);
ok(hr == S_OK, "got 0x%08x\n", hr);
ok(r.startPosition == 100 && r.length == 10, "got %u, %u\n", r.startPosition, r.length);
r.startPosition = r.length = 0;
unk = (void*)0xdeadbeef;
hr = IDWriteTextLayout_GetDrawingEffect(layout, 1000, &unk, &r);
ok(hr == S_OK, "got 0x%08x\n", hr);
ok(r.startPosition == 110 && r.length == ~0u-110, "got %u, %u\n", r.startPosition, r.length);
ok(unk == NULL, "got %p\n", unk);
/* effect is applied to clusters, not individual text positions */
r.startPosition = 0;
r.length = 2;
hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
ok(hr == S_OK, "got 0x%08x\n", hr);
flush_sequence(sequences, RENDERER_ID);
hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
ok(hr == S_OK, "got 0x%08x\n", hr);
ok_sequence(sequences, RENDERER_ID, draweffect_seq, "effect draw test", TRUE);
IDWriteTextLayout_Release(layout);
/* simple string */
hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 1000.0, &layout);
ok(hr == S_OK, "got 0x%08x\n", hr);
r.startPosition = 0;
r.length = 2;
hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
ok(hr == S_OK, "got 0x%08x\n", hr);
flush_sequence(sequences, RENDERER_ID);
hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
ok(hr == S_OK, "got 0x%08x\n", hr);
ok_sequence(sequences, RENDERER_ID, draweffect2_seq, "effect draw test 2", TRUE);
IDWriteTextLayout_Release(layout);
/* Inline object - effect set for same range */
hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 1000.0, &layout);
ok(hr == S_OK, "got 0x%08x\n", hr);
r.startPosition = 0;
r.length = 4;
hr = IDWriteTextLayout_SetInlineObject(layout, sign, r);
ok(hr == S_OK, "got 0x%08x\n", hr);
hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
ok(hr == S_OK, "got 0x%08x\n", hr);
flush_sequence(sequences, RENDERER_ID);
hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
ok(hr == S_OK, "got 0x%08x\n", hr);
ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 3", FALSE);
/* now set effect somewhere inside a range replaced by inline object */
hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
ok(hr == S_OK, "got 0x%08x\n", hr);
r.startPosition = 1;
r.length = 1;
hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
ok(hr == S_OK, "got 0x%08x\n", hr);
/* no effect is reported in this case */
flush_sequence(sequences, RENDERER_ID);
hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
ok(hr == S_OK, "got 0x%08x\n", hr);
ok_sequence(sequences, RENDERER_ID, draweffect4_seq, "effect draw test 4", FALSE);
r.startPosition = 0;
r.length = 4;
hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
ok(hr == S_OK, "got 0x%08x\n", hr);
r.startPosition = 0;
r.length = 1;
hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
ok(hr == S_OK, "got 0x%08x\n", hr);
/* first range position is all that matters for inline ranges */
flush_sequence(sequences, RENDERER_ID);
hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
ok(hr == S_OK, "got 0x%08x\n", hr);
ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 5", FALSE);
IDWriteTextLayout_Release(layout);
IDWriteInlineObject_Release(sign);
IDWriteTextFormat_Release(format);
IDWriteFactory_Release(factory);
}
START_TEST(layout) START_TEST(layout)
{ {
static const WCHAR ctrlstrW[] = {0x202a,0}; static const WCHAR ctrlstrW[] = {0x202a,0};
@ -2476,6 +2682,7 @@ START_TEST(layout)
test_SetStrikethrough(); test_SetStrikethrough();
test_GetMetrics(); test_GetMetrics();
test_SetFlowDirection(); test_SetFlowDirection();
test_SetDrawingEffect();
IDWriteFactory_Release(factory); IDWriteFactory_Release(factory);
} }