From b7fb00e9aa7b17c4fe9f90ac137b50a245528704 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Mon, 15 Jun 2015 01:15:25 +0300 Subject: [PATCH] dwrite: Fix the way drawing effects are reported for inline objects. --- dlls/dwrite/layout.c | 136 +++++++++++++++------ dlls/dwrite/tests/layout.c | 239 ++++++++++++++++++++++++++++++++++--- 2 files changed, 321 insertions(+), 54 deletions(-) diff --git a/dlls/dwrite/layout.c b/dlls/dwrite/layout.c index 74cdc46be00..4b91f6e09ee 100644 --- a/dlls/dwrite/layout.c +++ b/dlls/dwrite/layout.c @@ -95,7 +95,8 @@ struct layout_range_attr_value { enum layout_range_kind { LAYOUT_RANGE_REGULAR, - LAYOUT_RANGE_STRIKETHROUGH + LAYOUT_RANGE_STRIKETHROUGH, + LAYOUT_RANGE_EFFECT }; struct layout_range_header { @@ -111,7 +112,6 @@ struct layout_range { FLOAT fontsize; DWRITE_FONT_STRETCH stretch; IDWriteInlineObject *object; - IUnknown *effect; BOOL underline; BOOL pair_kerning; IDWriteFontCollection *collection; @@ -124,6 +124,11 @@ struct layout_range_bool { BOOL value; }; +struct layout_range_effect { + struct layout_range_header h; + IUnknown *effect; +}; + enum layout_run_kind { LAYOUT_RUN_REGULAR, LAYOUT_RUN_INLINE @@ -153,7 +158,6 @@ struct layout_run { struct inline_object_run object; struct regular_layout_run regular; } u; - IUnknown *effect; }; struct layout_effective_run { @@ -170,6 +174,7 @@ struct layout_effective_run { struct layout_effective_inline { struct list entry; IDWriteInlineObject *object; + IUnknown *effect; FLOAT origin_x; FLOAT origin_y; BOOL is_sideways; @@ -207,6 +212,7 @@ struct dwrite_textlayout { FLOAT maxwidth; FLOAT maxheight; struct list strike_ranges; + struct list effects; struct list ranges; struct list runs; /* 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.length = get_clipped_range_length(layout, range); - r->effect = range->effect; list_add_tail(&layout->runs, &r->entry); continue; } @@ -661,7 +666,6 @@ static HRESULT layout_compute_runs(struct dwrite_textlayout *layout) } range = get_layout_range_by_pos(layout, run->descr.textPosition); - r->effect = range->effect; hr = IDWriteFontCollection_FindFamilyName(range->collection, range->fontfamily, &index, &exists); if (FAILED(hr) || !exists) { @@ -844,6 +848,25 @@ static inline FLOAT get_cluster_range_width(struct dwrite_textlayout *layout, UI 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, '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, @@ -867,6 +890,10 @@ static HRESULT layout_add_effective_run(struct dwrite_textlayout *layout, const different ranges which differ in reading direction). */ inlineobject->is_sideways = 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); return S_OK; } @@ -970,19 +997,6 @@ static HRESULT layout_set_line_metrics(struct dwrite_textlayout *layout, DWRITE_ 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) { 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) { + 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 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: return range->object == value->u.object; case LAYOUT_RANGE_ATTR_EFFECT: - return range->effect == value->u.effect; + return range_effect->effect == value->u.effect; case LAYOUT_RANGE_ATTR_UNDERLINE: return range->underline == value->u.underline; 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->fontsize == right->fontsize && left->object == right->object && - left->effect == right->effect && left->underline == right->underline && left->pair_kerning == right->pair_kerning && 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; 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: FIXME("unknown range kind %d\n", hleft->kind); return FALSE; @@ -1182,7 +1202,6 @@ static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout * range->stretch = layout->format.stretch; range->fontsize = layout->format.fontsize; range->object = NULL; - range->effect = NULL; range->underline = FALSE; range->pair_kerning = FALSE; @@ -1211,6 +1230,17 @@ static struct layout_range_header *alloc_layout_range(struct dwrite_textlayout * h = &range->h; 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: FIXME("unknown range kind %d\n", kind); return NULL; @@ -1244,8 +1274,6 @@ static struct layout_range_header *alloc_layout_range_from(struct layout_range_h /* update refcounts */ if (range->object) IDWriteInlineObject_AddRef(range->object); - if (range->effect) - IUnknown_AddRef(range->effect); if (range->collection) IDWriteFontCollection_AddRef(range->collection); ret = &range->h; @@ -1260,6 +1288,17 @@ static struct layout_range_header *alloc_layout_range_from(struct layout_range_h ret = &strike->h; 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: FIXME("unknown range kind %d\n", h->kind); return NULL; @@ -1274,16 +1313,28 @@ static void free_layout_range(struct layout_range_header *h) if (!h) return; - if (h->kind == LAYOUT_RANGE_REGULAR) { + switch (h->kind) + { + case LAYOUT_RANGE_REGULAR: + { struct layout_range *range = (struct layout_range*)h; if (range->object) IDWriteInlineObject_Release(range->object); - if (range->effect) - IUnknown_Release(range->effect); if (range->collection) IDWriteFontCollection_Release(range->collection); 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); @@ -1302,6 +1353,11 @@ static void free_layout_ranges_list(struct dwrite_textlayout *layout) list_remove(&cur->entry); 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) @@ -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) { + 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 *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); break; 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; case LAYOUT_RANGE_ATTR_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_STRETCH: case LAYOUT_RANGE_ATTR_FONTSIZE: - case LAYOUT_RANGE_ATTR_EFFECT: case LAYOUT_RANGE_ATTR_INLINE: case LAYOUT_RANGE_ATTR_UNDERLINE: 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: ranges = &layout->strike_ranges; break; + case LAYOUT_RANGE_ATTR_EFFECT: + ranges = &layout->effects; + break; default: FIXME("unknown attr kind %d\n", attr); return E_FAIL; @@ -2191,14 +2250,11 @@ static HRESULT WINAPI dwritetextlayout_GetDrawingEffect(IDWriteTextLayout2 *ifac UINT32 position, IUnknown **effect, DWRITE_TEXT_RANGE *r) { 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); - if (position >= This->len) - return S_OK; - - range = get_layout_range_by_pos(This, position); + range = (struct layout_range_effect*)get_layout_range_header_by_pos(&This->effects, position); *effect = range->effect; if (*effect) IUnknown_AddRef(*effect); @@ -2297,7 +2353,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface, DWRITE_MEASURING_MODE_NATURAL, &glyph_run, &descr, - run->run->effect); + NULL); } /* 2. Inline objects */ @@ -2309,7 +2365,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface, inlineobject->object, inlineobject->is_sideways, inlineobject->is_rtl, - run->run->effect); + inlineobject->effect); } /* TODO: 3. Underlines */ @@ -2321,7 +2377,7 @@ static HRESULT WINAPI dwritetextlayout_Draw(IDWriteTextLayout2 *iface, s->run->origin_x, s->run->origin_y, &s->s, - s->run->run->effect); + NULL); } 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) { - struct layout_range_header *range, *strike; + struct layout_range_header *range, *strike, *effect; DWRITE_TEXT_RANGE r = { 0, ~0u }; HRESULT hr; @@ -3282,6 +3338,7 @@ static HRESULT init_textlayout(const WCHAR *str, UINT32 len, IDWriteTextFormat * list_init(&layout->runs); list_init(&layout->ranges); list_init(&layout->strike_ranges); + list_init(&layout->effects); memset(&layout->format, 0, sizeof(layout->format)); 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); 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(strike); + free_layout_range(effect); hr = E_OUTOFMEMORY; goto fail; } list_add_head(&layout->ranges, &range->entry); list_add_head(&layout->strike_ranges, &strike->entry); + list_add_head(&layout->effects, &effect->entry); return S_OK; fail: diff --git a/dlls/dwrite/tests/layout.c b/dlls/dwrite/tests/layout.c index d03d14a84e8..86f4f636630 100644 --- a/dlls/dwrite/tests/layout.c +++ b/dlls/dwrite/tests/layout.c @@ -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); } -enum drawcall_kind { - DRAW_GLYPHRUN = 0, - DRAW_UNDERLINE, - DRAW_STRIKETHROUGH, - DRAW_INLINE, - DRAW_LAST_KIND +enum drawcall_modifiers_kind { + DRAW_EFFECT = 0x1000 }; -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" }; - return kind > DRAW_LAST_KIND ? "unknown" : kind_names[kind]; + static const char *kind_names[] = { + "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 { @@ -242,7 +263,7 @@ struct drawcall_sequence }; struct drawtestcontext { - enum drawcall_kind kind; + unsigned short kind; BOOL todo; int *failcount; 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", 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); if (cmp != 0 && todo) { failcount++; @@ -424,7 +445,7 @@ static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface, DWRITE_MEASURING_MODE mode, DWRITE_GLYPH_RUN const *run, DWRITE_GLYPH_RUN_DESCRIPTION const *descr, - IUnknown *drawing_effect) + IUnknown *effect) { struct drawcall_entry entry; DWRITE_SCRIPT_ANALYSIS sa; @@ -452,6 +473,8 @@ static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface, } entry.kind = DRAW_GLYPHRUN; + if (effect) + entry.kind |= DRAW_EFFECT; add_call(sequences, RENDERER_ID, &entry); return S_OK; } @@ -461,10 +484,12 @@ static HRESULT WINAPI testrenderer_DrawUnderline(IDWriteTextRenderer *iface, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_UNDERLINE const* underline, - IUnknown *drawing_effect) + IUnknown *effect) { struct drawcall_entry entry; entry.kind = DRAW_UNDERLINE; + if (effect) + entry.kind |= DRAW_EFFECT; add_call(sequences, RENDERER_ID, &entry); return S_OK; } @@ -474,10 +499,12 @@ static HRESULT WINAPI testrenderer_DrawStrikethrough(IDWriteTextRenderer *iface, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_STRIKETHROUGH const* strikethrough, - IUnknown *drawing_effect) + IUnknown *effect) { struct drawcall_entry entry; entry.kind = DRAW_STRIKETHROUGH; + if (effect) + entry.kind |= DRAW_EFFECT; add_call(sequences, RENDERER_ID, &entry); return S_OK; } @@ -489,10 +516,12 @@ static HRESULT WINAPI testrenderer_DrawInlineObject(IDWriteTextRenderer *iface, IDWriteInlineObject *object, BOOL is_sideways, BOOL is_rtl, - IUnknown *drawing_effect) + IUnknown *effect) { struct drawcall_entry entry; entry.kind = DRAW_INLINE; + if (effect) + entry.kind |= DRAW_EFFECT; add_call(sequences, RENDERER_ID, &entry); return S_OK; } @@ -575,6 +604,36 @@ static IDWriteInlineObjectVtbl testinlineobjvtbl = { static IDWriteInlineObject testinlineobj = { &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 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[] = { { DRAW_GLYPHRUN, {'s',0} }, { DRAW_GLYPHRUN, {'r','i',0} }, - { DRAW_GLYPHRUN, {'n',0} }, + { DRAW_GLYPHRUN|DRAW_EFFECT, {'n',0} }, { DRAW_GLYPHRUN, {'g',0} }, { DRAW_INLINE }, { DRAW_UNDERLINE }, @@ -2438,6 +2497,153 @@ static void test_SetFlowDirection(void) 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) { static const WCHAR ctrlstrW[] = {0x202a,0}; @@ -2476,6 +2682,7 @@ START_TEST(layout) test_SetStrikethrough(); test_GetMetrics(); test_SetFlowDirection(); + test_SetDrawingEffect(); IDWriteFactory_Release(factory); }