dwrite/tests: Some tests for setting per-range layout properties.
[wine.git] / dlls / dwrite / tests / layout.c
blobd3cb29aafbd04fe00a497be758131517cea6d6b5
1 /*
2 * Text layout/format tests
4 * Copyright 2012, 2014-2015 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <assert.h>
25 #include "windows.h"
26 #include "dwrite.h"
27 #include "dwrite_2.h"
29 #include "wine/test.h"
31 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
32 static const WCHAR enusW[] = {'e','n','-','u','s',0};
34 static DWRITE_SCRIPT_ANALYSIS g_sa;
35 static DWRITE_SCRIPT_ANALYSIS g_control_sa;
37 /* test IDWriteTextAnalysisSink */
38 static HRESULT WINAPI analysissink_QueryInterface(IDWriteTextAnalysisSink *iface, REFIID riid, void **obj)
40 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown))
42 *obj = iface;
43 return S_OK;
46 *obj = NULL;
47 return E_NOINTERFACE;
50 static ULONG WINAPI analysissink_AddRef(IDWriteTextAnalysisSink *iface)
52 return 2;
55 static ULONG WINAPI analysissink_Release(IDWriteTextAnalysisSink *iface)
57 return 1;
60 static HRESULT WINAPI analysissink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
61 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
63 g_sa = *sa;
64 return S_OK;
67 static HRESULT WINAPI analysissink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
68 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
70 ok(0, "unexpected call\n");
71 return E_NOTIMPL;
74 static HRESULT WINAPI analysissink_SetBidiLevel(IDWriteTextAnalysisSink *iface,
75 UINT32 position, UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
77 ok(0, "unexpected\n");
78 return E_NOTIMPL;
81 static HRESULT WINAPI analysissink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
82 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
84 ok(0, "unexpected\n");
85 return E_NOTIMPL;
88 static IDWriteTextAnalysisSinkVtbl analysissinkvtbl = {
89 analysissink_QueryInterface,
90 analysissink_AddRef,
91 analysissink_Release,
92 analysissink_SetScriptAnalysis,
93 analysissink_SetLineBreakpoints,
94 analysissink_SetBidiLevel,
95 analysissink_SetNumberSubstitution
98 static IDWriteTextAnalysisSink analysissink = { &analysissinkvtbl };
100 /* test IDWriteTextAnalysisSource */
101 static HRESULT WINAPI analysissource_QueryInterface(IDWriteTextAnalysisSource *iface,
102 REFIID riid, void **obj)
104 ok(0, "QueryInterface not expected\n");
105 return E_NOTIMPL;
108 static ULONG WINAPI analysissource_AddRef(IDWriteTextAnalysisSource *iface)
110 ok(0, "AddRef not expected\n");
111 return 2;
114 static ULONG WINAPI analysissource_Release(IDWriteTextAnalysisSource *iface)
116 ok(0, "Release not expected\n");
117 return 1;
120 static const WCHAR *g_source;
122 static HRESULT WINAPI analysissource_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
123 UINT32 position, WCHAR const** text, UINT32* text_len)
125 if (position >= lstrlenW(g_source))
127 *text = NULL;
128 *text_len = 0;
130 else
132 *text = &g_source[position];
133 *text_len = lstrlenW(g_source) - position;
136 return S_OK;
139 static HRESULT WINAPI analysissource_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
140 UINT32 position, WCHAR const** text, UINT32* text_len)
142 ok(0, "unexpected\n");
143 return E_NOTIMPL;
146 static DWRITE_READING_DIRECTION WINAPI analysissource_GetParagraphReadingDirection(
147 IDWriteTextAnalysisSource *iface)
149 ok(0, "unexpected\n");
150 return DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
153 static HRESULT WINAPI analysissource_GetLocaleName(IDWriteTextAnalysisSource *iface,
154 UINT32 position, UINT32* text_len, WCHAR const** locale)
156 *locale = NULL;
157 *text_len = 0;
158 return S_OK;
161 static HRESULT WINAPI analysissource_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
162 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
164 ok(0, "unexpected\n");
165 return E_NOTIMPL;
168 static IDWriteTextAnalysisSourceVtbl analysissourcevtbl = {
169 analysissource_QueryInterface,
170 analysissource_AddRef,
171 analysissource_Release,
172 analysissource_GetTextAtPosition,
173 analysissource_GetTextBeforePosition,
174 analysissource_GetParagraphReadingDirection,
175 analysissource_GetLocaleName,
176 analysissource_GetNumberSubstitution
179 static IDWriteTextAnalysisSource analysissource = { &analysissourcevtbl };
181 static IDWriteFactory *create_factory(void)
183 IDWriteFactory *factory;
184 HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory);
185 ok(hr == S_OK, "got 0x%08x\n", hr);
186 return factory;
189 /* obvious limitation is that only last script data is returned, so this
190 helper is suitable for single script strings only */
191 static void get_script_analysis(const WCHAR *str, UINT32 len, DWRITE_SCRIPT_ANALYSIS *sa)
193 IDWriteTextAnalyzer *analyzer;
194 IDWriteFactory *factory;
195 HRESULT hr;
197 g_source = str;
199 factory = create_factory();
200 hr = IDWriteFactory_CreateTextAnalyzer(factory, &analyzer);
201 ok(hr == S_OK, "got 0x%08x\n", hr);
203 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &analysissource, 0, len, &analysissink);
204 ok(hr == S_OK, "got 0x%08x\n", hr);
206 *sa = g_sa;
207 IDWriteFactory_Release(factory);
210 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
211 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
213 ULONG rc = IUnknown_AddRef(obj);
214 IUnknown_Release(obj);
215 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
218 enum drawcall_kind {
219 DRAW_GLYPHRUN = 0,
220 DRAW_UNDERLINE,
221 DRAW_STRIKETHROUGH,
222 DRAW_INLINE,
223 DRAW_LAST_KIND
226 static const char *get_draw_kind_name(enum drawcall_kind kind)
228 static const char *kind_names[] = { "GLYPH_RUN", "UNDERLINE", "STRIKETHROUGH", "INLINE", "END_OF_SEQ" };
229 return kind > DRAW_LAST_KIND ? "unknown" : kind_names[kind];
232 struct drawcall_entry {
233 enum drawcall_kind kind;
234 WCHAR string[10]; /* only meaningful for DrawGlyphRun() */
237 struct drawcall_sequence
239 int count;
240 int size;
241 struct drawcall_entry *sequence;
244 struct drawtestcontext {
245 enum drawcall_kind kind;
246 BOOL todo;
247 int *failcount;
248 const char *file;
249 int line;
252 #define NUM_CALL_SEQUENCES 1
253 #define RENDERER_ID 0
254 static struct drawcall_sequence *sequences[NUM_CALL_SEQUENCES];
255 static struct drawcall_sequence *expected_seq[1];
257 static void add_call(struct drawcall_sequence **seq, int sequence_index, const struct drawcall_entry *call)
259 struct drawcall_sequence *call_seq = seq[sequence_index];
261 if (!call_seq->sequence) {
262 call_seq->size = 10;
263 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0, call_seq->size * sizeof (struct drawcall_entry));
266 if (call_seq->count == call_seq->size) {
267 call_seq->size *= 2;
268 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
269 call_seq->sequence,
270 call_seq->size * sizeof (struct drawcall_entry));
273 assert(call_seq->sequence);
274 call_seq->sequence[call_seq->count++] = *call;
277 static inline void flush_sequence(struct drawcall_sequence **seg, int sequence_index)
279 struct drawcall_sequence *call_seq = seg[sequence_index];
281 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
282 call_seq->sequence = NULL;
283 call_seq->count = call_seq->size = 0;
286 static inline void flush_sequences(struct drawcall_sequence **seq, int n)
288 int i;
289 for (i = 0; i < n; i++)
290 flush_sequence(seq, i);
293 static void init_call_sequences(struct drawcall_sequence **seq, int n)
295 int i;
297 for (i = 0; i < n; i++)
298 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct drawcall_sequence));
301 static void ok_sequence_(struct drawcall_sequence **seq, int sequence_index,
302 const struct drawcall_entry *expected, const char *context, BOOL todo,
303 const char *file, int line)
305 static const struct drawcall_entry end_of_sequence = { DRAW_LAST_KIND };
306 struct drawcall_sequence *call_seq = seq[sequence_index];
307 const struct drawcall_entry *actual, *sequence;
308 int failcount = 0;
310 add_call(seq, sequence_index, &end_of_sequence);
312 sequence = call_seq->sequence;
313 actual = sequence;
315 while (expected->kind != DRAW_LAST_KIND && actual->kind != DRAW_LAST_KIND) {
316 if (expected->kind != actual->kind) {
317 if (todo) {
318 failcount++;
319 todo_wine
320 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
321 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
323 flush_sequence(seq, sequence_index);
324 return;
326 else
327 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
328 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
330 else if (expected->kind == DRAW_GLYPHRUN) {
331 int cmp = lstrcmpW(expected->string, actual->string);
332 if (cmp != 0 && todo) {
333 failcount++;
334 todo_wine
335 ok_(file, line) (0, "%s: glyphrun string %s was expected, but got %s instead\n",
336 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
338 else
339 ok_(file, line) (cmp == 0, "%s: glyphrun string %s was expected, but got %s instead\n",
340 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
342 expected++;
343 actual++;
346 if (todo) {
347 todo_wine {
348 if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND) {
349 failcount++;
350 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
351 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
355 else if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND)
356 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
357 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
359 if (todo && !failcount) /* succeeded yet marked todo */
360 todo_wine
361 ok_(file, line)(1, "%s: marked \"todo_wine\" but succeeds\n", context);
363 flush_sequence(seq, sequence_index);
366 #define ok_sequence(seq, index, exp, contx, todo) \
367 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
369 static HRESULT WINAPI testrenderer_QI(IDWriteTextRenderer *iface, REFIID riid, void **obj)
371 if (IsEqualIID(riid, &IID_IDWriteTextRenderer) ||
372 IsEqualIID(riid, &IID_IDWritePixelSnapping) ||
373 IsEqualIID(riid, &IID_IUnknown)
375 *obj = iface;
376 return S_OK;
379 *obj = NULL;
381 /* IDWriteTextRenderer1 overrides drawing calls, ignore for now */
382 if (IsEqualIID(riid, &IID_IDWriteTextRenderer1))
383 return E_NOINTERFACE;
385 ok(0, "unexpected QI %s\n", wine_dbgstr_guid(riid));
386 return E_NOINTERFACE;
389 static ULONG WINAPI testrenderer_AddRef(IDWriteTextRenderer *iface)
391 return 2;
394 static ULONG WINAPI testrenderer_Release(IDWriteTextRenderer *iface)
396 return 1;
399 static HRESULT WINAPI testrenderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
400 void *client_drawingcontext, BOOL *disabled)
402 *disabled = TRUE;
403 return S_OK;
406 static HRESULT WINAPI testrenderer_GetCurrentTransform(IDWriteTextRenderer *iface,
407 void *client_drawingcontext, DWRITE_MATRIX *transform)
409 transform->m11 = 1.0;
410 transform->m12 = 0.0;
411 transform->m21 = 0.0;
412 transform->m22 = 1.0;
413 transform->dx = 0.0;
414 transform->dy = 0.0;
415 return S_OK;
418 static HRESULT WINAPI testrenderer_GetPixelsPerDip(IDWriteTextRenderer *iface,
419 void *client_drawingcontext, FLOAT *pixels_per_dip)
421 *pixels_per_dip = 1.0;
422 return S_OK;
425 static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface,
426 void* client_drawingcontext,
427 FLOAT baselineOriginX,
428 FLOAT baselineOriginY,
429 DWRITE_MEASURING_MODE mode,
430 DWRITE_GLYPH_RUN const *run,
431 DWRITE_GLYPH_RUN_DESCRIPTION const *descr,
432 IUnknown *drawing_effect)
434 struct drawcall_entry entry;
435 DWRITE_SCRIPT_ANALYSIS sa;
437 ok(descr->stringLength < sizeof(entry.string)/sizeof(WCHAR), "string is too long\n");
438 if (descr->stringLength && descr->stringLength < sizeof(entry.string)/sizeof(WCHAR)) {
439 memcpy(entry.string, descr->string, descr->stringLength*sizeof(WCHAR));
440 entry.string[descr->stringLength] = 0;
442 else
443 entry.string[0] = 0;
445 /* see what's reported for control codes runs */
446 get_script_analysis(descr->string, descr->stringLength, &sa);
447 if (sa.script == g_control_sa.script) {
448 /* glyphs are not reported at all for control code runs */
449 ok(run->glyphCount == 0, "got %u\n", run->glyphCount);
450 ok(run->glyphAdvances != NULL, "advances array %p\n", run->glyphAdvances);
451 ok(run->glyphOffsets != NULL, "offsets array %p\n", run->glyphOffsets);
452 ok(run->fontFace != NULL, "got %p\n", run->fontFace);
453 /* text positions are still valid */
454 ok(descr->string != NULL, "got string %p\n", descr->string);
455 ok(descr->stringLength > 0, "got string length %u\n", descr->stringLength);
456 ok(descr->clusterMap != NULL, "clustermap %p\n", descr->clusterMap);
459 entry.kind = DRAW_GLYPHRUN;
460 add_call(sequences, RENDERER_ID, &entry);
461 return S_OK;
464 static HRESULT WINAPI testrenderer_DrawUnderline(IDWriteTextRenderer *iface,
465 void *client_drawingcontext,
466 FLOAT baselineOriginX,
467 FLOAT baselineOriginY,
468 DWRITE_UNDERLINE const* underline,
469 IUnknown *drawing_effect)
471 struct drawcall_entry entry;
472 entry.kind = DRAW_UNDERLINE;
473 add_call(sequences, RENDERER_ID, &entry);
474 return S_OK;
477 static HRESULT WINAPI testrenderer_DrawStrikethrough(IDWriteTextRenderer *iface,
478 void *client_drawingcontext,
479 FLOAT baselineOriginX,
480 FLOAT baselineOriginY,
481 DWRITE_STRIKETHROUGH const* strikethrough,
482 IUnknown *drawing_effect)
484 struct drawcall_entry entry;
485 entry.kind = DRAW_STRIKETHROUGH;
486 add_call(sequences, RENDERER_ID, &entry);
487 return S_OK;
490 static HRESULT WINAPI testrenderer_DrawInlineObject(IDWriteTextRenderer *iface,
491 void *client_drawingcontext,
492 FLOAT originX,
493 FLOAT originY,
494 IDWriteInlineObject *object,
495 BOOL is_sideways,
496 BOOL is_rtl,
497 IUnknown *drawing_effect)
499 struct drawcall_entry entry;
500 entry.kind = DRAW_INLINE;
501 add_call(sequences, RENDERER_ID, &entry);
502 return S_OK;
505 static const IDWriteTextRendererVtbl testrenderervtbl = {
506 testrenderer_QI,
507 testrenderer_AddRef,
508 testrenderer_Release,
509 testrenderer_IsPixelSnappingDisabled,
510 testrenderer_GetCurrentTransform,
511 testrenderer_GetPixelsPerDip,
512 testrenderer_DrawGlyphRun,
513 testrenderer_DrawUnderline,
514 testrenderer_DrawStrikethrough,
515 testrenderer_DrawInlineObject
518 static IDWriteTextRenderer testrenderer = { &testrenderervtbl };
520 /* test IDWriteInlineObject */
521 static HRESULT WINAPI testinlineobj_QI(IDWriteInlineObject *iface, REFIID riid, void **obj)
523 if (IsEqualIID(riid, &IID_IDWriteInlineObject) || IsEqualIID(riid, &IID_IUnknown)) {
524 *obj = iface;
525 IDWriteInlineObject_AddRef(iface);
526 return S_OK;
529 *obj = NULL;
530 return E_NOINTERFACE;
533 static ULONG WINAPI testinlineobj_AddRef(IDWriteInlineObject *iface)
535 return 2;
538 static ULONG WINAPI testinlineobj_Release(IDWriteInlineObject *iface)
540 return 1;
543 static HRESULT WINAPI testinlineobj_Draw(IDWriteInlineObject *iface,
544 void* client_drawingontext, IDWriteTextRenderer* renderer,
545 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *drawing_effect)
547 ok(0, "unexpected call\n");
548 return E_NOTIMPL;
551 static HRESULT WINAPI testinlineobj_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
553 metrics->width = 123.0;
554 return 0x8faecafe;
557 static HRESULT WINAPI testinlineobj_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
559 ok(0, "unexpected call\n");
560 return E_NOTIMPL;
563 static HRESULT WINAPI testinlineobj_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
564 DWRITE_BREAK_CONDITION *after)
566 *before = *after = DWRITE_BREAK_CONDITION_MUST_BREAK;
567 return 0x8feacafe;
570 static IDWriteInlineObjectVtbl testinlineobjvtbl = {
571 testinlineobj_QI,
572 testinlineobj_AddRef,
573 testinlineobj_Release,
574 testinlineobj_Draw,
575 testinlineobj_GetMetrics,
576 testinlineobj_GetOverhangMetrics,
577 testinlineobj_GetBreakConditions
580 static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl };
581 static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
583 static void test_CreateTextLayout(void)
585 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
586 IDWriteTextLayout2 *layout2;
587 IDWriteTextLayout *layout;
588 IDWriteTextFormat *format;
589 IDWriteFactory *factory;
590 HRESULT hr;
592 factory = create_factory();
594 hr = IDWriteFactory_CreateTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, &layout);
595 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
597 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 0.0, &layout);
598 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
600 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1.0, 0.0, &layout);
601 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
603 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 1.0, &layout);
604 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
606 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, &layout);
607 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
609 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
610 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
611 ok(hr == S_OK, "got 0x%08x\n", hr);
613 EXPECT_REF(format, 1);
614 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 1000.0, 1000.0, &layout);
615 ok(hr == S_OK, "got 0x%08x\n", hr);
616 EXPECT_REF(format, 1);
618 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
619 if (hr == S_OK) {
620 IDWriteTextLayout1 *layout1;
621 IDWriteTextFormat1 *format1;
622 IDWriteTextFormat *format;
624 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextLayout1, (void**)&layout1);
625 ok(hr == S_OK, "got 0x%08x\n", hr);
626 IDWriteTextLayout1_Release(layout1);
628 EXPECT_REF(layout2, 2);
629 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
630 ok(hr == S_OK, "got 0x%08x\n", hr);
631 EXPECT_REF(layout2, 3);
633 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat, (void**)&format);
634 ok(hr == S_OK, "got 0x%08x\n", hr);
635 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
636 ok(format != (IDWriteTextFormat*)layout2, "got %p, %p\n", format, layout2);
637 EXPECT_REF(layout2, 4);
639 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextLayout1, (void**)&layout1);
640 ok(hr == S_OK, "got 0x%08x\n", hr);
641 IDWriteTextLayout1_Release(layout1);
643 IDWriteTextFormat1_Release(format1);
644 IDWriteTextFormat_Release(format);
646 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
647 ok(hr == S_OK, "got 0x%08x\n", hr);
648 EXPECT_REF(layout2, 3);
650 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format);
651 ok(hr == S_OK, "got 0x%08x\n", hr);
652 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
653 EXPECT_REF(layout2, 4);
655 IDWriteTextFormat1_Release(format1);
656 IDWriteTextFormat_Release(format);
657 IDWriteTextLayout2_Release(layout2);
659 else
660 win_skip("IDWriteTextLayout2 is not supported.\n");
662 IDWriteTextLayout_Release(layout);
663 IDWriteTextFormat_Release(format);
664 IDWriteFactory_Release(factory);
667 static void test_CreateGdiCompatibleTextLayout(void)
669 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
670 IDWriteTextLayout *layout;
671 IDWriteTextFormat *format;
672 IDWriteFactory *factory;
673 FLOAT dimension;
674 HRESULT hr;
676 factory = create_factory();
678 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
679 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
681 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
682 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
684 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 0.0, NULL, FALSE, &layout);
685 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
687 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 1.0, NULL, FALSE, &layout);
688 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
690 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, 1.0, NULL, FALSE, &layout);
691 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
693 /* create with text format */
694 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
695 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
696 ok(hr == S_OK, "got 0x%08x\n", hr);
697 EXPECT_REF(format, 1);
699 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
700 ok(hr == S_OK, "got 0x%08x\n", hr);
701 EXPECT_REF(format, 1);
702 EXPECT_REF(layout, 1);
704 IDWriteTextLayout_AddRef(layout);
705 EXPECT_REF(format, 1);
706 EXPECT_REF(layout, 2);
707 IDWriteTextLayout_Release(layout);
708 IDWriteTextLayout_Release(layout);
710 /* zero length string is okay */
711 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
712 ok(hr == S_OK, "got 0x%08x\n", hr);
714 dimension = IDWriteTextLayout_GetMaxWidth(layout);
715 ok(dimension == 100.0, "got %f\n", dimension);
717 dimension = IDWriteTextLayout_GetMaxHeight(layout);
718 ok(dimension == 100.0, "got %f\n", dimension);
720 IDWriteTextLayout_Release(layout);
721 IDWriteTextFormat_Release(format);
722 IDWriteFactory_Release(factory);
725 static void test_CreateTextFormat(void)
727 IDWriteFontCollection *collection, *syscoll;
728 DWRITE_PARAGRAPH_ALIGNMENT paralign;
729 DWRITE_READING_DIRECTION readdir;
730 DWRITE_WORD_WRAPPING wrapping;
731 DWRITE_TEXT_ALIGNMENT align;
732 DWRITE_FLOW_DIRECTION flow;
733 DWRITE_LINE_SPACING_METHOD method;
734 DWRITE_TRIMMING trimming;
735 IDWriteTextFormat *format;
736 FLOAT spacing, baseline;
737 IDWriteInlineObject *trimmingsign;
738 IDWriteFactory *factory;
739 HRESULT hr;
741 factory = create_factory();
743 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
744 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
745 ok(hr == S_OK, "got 0x%08x\n", hr);
747 if (0) /* crashes on native */
748 hr = IDWriteTextFormat_GetFontCollection(format, NULL);
750 collection = NULL;
751 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
752 ok(hr == S_OK, "got 0x%08x\n", hr);
753 ok(collection != NULL, "got %p\n", collection);
755 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
756 ok(hr == S_OK, "got 0x%08x\n", hr);
757 ok(collection == syscoll, "got %p, was %p\n", syscoll, collection);
758 IDWriteFontCollection_Release(syscoll);
759 IDWriteFontCollection_Release(collection);
761 /* default format properties */
762 align = IDWriteTextFormat_GetTextAlignment(format);
763 ok(align == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", align);
765 paralign = IDWriteTextFormat_GetParagraphAlignment(format);
766 ok(paralign == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", paralign);
768 wrapping = IDWriteTextFormat_GetWordWrapping(format);
769 ok(wrapping == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", wrapping);
771 readdir = IDWriteTextFormat_GetReadingDirection(format);
772 ok(readdir == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", readdir);
774 flow = IDWriteTextFormat_GetFlowDirection(format);
775 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
777 hr = IDWriteTextFormat_GetLineSpacing(format, &method, &spacing, &baseline);
778 ok(hr == S_OK, "got 0x%08x\n", hr);
779 ok(spacing == 0.0, "got %f\n", spacing);
780 ok(baseline == 0.0, "got %f\n", baseline);
781 ok(method == DWRITE_LINE_SPACING_METHOD_DEFAULT, "got %d\n", method);
783 trimming.granularity = DWRITE_TRIMMING_GRANULARITY_WORD;
784 trimming.delimiter = 10;
785 trimming.delimiterCount = 10;
786 trimmingsign = (void*)0xdeadbeef;
787 hr = IDWriteTextFormat_GetTrimming(format, &trimming, &trimmingsign);
788 ok(hr == S_OK, "got 0x%08x\n", hr);
789 ok(trimming.granularity == DWRITE_TRIMMING_GRANULARITY_NONE, "got %d\n", trimming.granularity);
790 ok(trimming.delimiter == 0, "got %d\n", trimming.delimiter);
791 ok(trimming.delimiterCount == 0, "got %d\n", trimming.delimiterCount);
792 ok(trimmingsign == NULL, "got %p\n", trimmingsign);
794 /* setters */
795 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING);
796 ok(hr == S_OK, "got 0x%08x\n", hr);
798 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
799 ok(hr == S_OK, "got 0x%08x\n", hr);
801 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_WRAP);
802 ok(hr == S_OK, "got 0x%08x\n", hr);
804 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
805 ok(hr == S_OK, "got 0x%08x\n", hr);
807 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
808 ok(hr == S_OK, "got 0x%08x\n", hr);
810 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0, 0.0);
811 ok(hr == S_OK, "got 0x%08x\n", hr);
813 hr = IDWriteTextFormat_SetTrimming(format, &trimming, NULL);
814 ok(hr == S_OK, "got 0x%08x\n", hr);
816 IDWriteTextFormat_Release(format);
817 IDWriteFactory_Release(factory);
820 static void test_GetLocaleName(void)
822 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
823 static const WCHAR ruW[] = {'r','u',0};
824 IDWriteTextLayout *layout;
825 IDWriteTextFormat *format, *format2;
826 IDWriteFactory *factory;
827 WCHAR buff[10];
828 UINT32 len;
829 HRESULT hr;
831 factory = create_factory();
833 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
834 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
835 ok(hr == S_OK, "got 0x%08x\n", hr);
837 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
838 ok(hr == S_OK, "got 0x%08x\n", hr);
840 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format2);
841 ok(hr == S_OK, "got 0x%08x\n", hr);
843 len = IDWriteTextFormat_GetLocaleNameLength(format2);
844 ok(len == 2, "got %u\n", len);
845 len = IDWriteTextFormat_GetLocaleNameLength(format);
846 ok(len == 2, "got %u\n", len);
847 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len);
848 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
849 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len+1);
850 ok(hr == S_OK, "got 0x%08x\n", hr);
851 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
852 hr = IDWriteTextFormat_GetLocaleName(format, buff, len);
853 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
854 hr = IDWriteTextFormat_GetLocaleName(format, buff, len+1);
855 ok(hr == S_OK, "got 0x%08x\n", hr);
856 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
858 IDWriteTextLayout_Release(layout);
859 IDWriteTextFormat_Release(format);
860 IDWriteTextFormat_Release(format2);
861 IDWriteFactory_Release(factory);
864 static void test_CreateEllipsisTrimmingSign(void)
866 DWRITE_BREAK_CONDITION before, after;
867 IDWriteTextFormat *format;
868 IDWriteInlineObject *sign;
869 IDWriteFactory *factory;
870 HRESULT hr;
872 factory = create_factory();
874 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
875 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
876 ok(hr == S_OK, "got 0x%08x\n", hr);
878 EXPECT_REF(format, 1);
879 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
880 ok(hr == S_OK, "got 0x%08x\n", hr);
881 EXPECT_REF(format, 1);
883 if (0) /* crashes on native */
884 hr = IDWriteInlineObject_GetBreakConditions(sign, NULL, NULL);
886 before = after = DWRITE_BREAK_CONDITION_CAN_BREAK;
887 hr = IDWriteInlineObject_GetBreakConditions(sign, &before, &after);
888 ok(hr == S_OK, "got 0x%08x\n", hr);
889 ok(before == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", before);
890 ok(after == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", after);
892 IDWriteInlineObject_Release(sign);
893 IDWriteTextFormat_Release(format);
894 IDWriteFactory_Release(factory);
897 static void test_fontweight(void)
899 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
900 static const WCHAR ruW[] = {'r','u',0};
901 IDWriteTextFormat *format, *fmt2;
902 IDWriteTextLayout *layout;
903 DWRITE_FONT_WEIGHT weight;
904 DWRITE_TEXT_RANGE range;
905 IDWriteFactory *factory;
906 FLOAT size;
907 HRESULT hr;
909 factory = create_factory();
911 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
912 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
913 ok(hr == S_OK, "got 0x%08x\n", hr);
915 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
916 ok(hr == S_OK, "got 0x%08x\n", hr);
918 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&fmt2);
919 ok(hr == S_OK, "got 0x%08x\n", hr);
921 weight = IDWriteTextFormat_GetFontWeight(fmt2);
922 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
924 range.startPosition = range.length = 0;
925 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
926 ok(hr == S_OK, "got 0x%08x\n", hr);
927 todo_wine
928 ok(range.startPosition == 0 && range.length == ~0u, "got %u, %u\n", range.startPosition, range.length);
930 range.startPosition = 0;
931 range.length = 6;
932 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_NORMAL, range);
933 ok(hr == S_OK, "got 0x%08x\n", hr);
935 range.startPosition = range.length = 0;
936 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
937 ok(hr == S_OK, "got 0x%08x\n", hr);
938 ok(range.startPosition == 0 && range.length == 6, "got %u, %u\n", range.startPosition, range.length);
940 /* IDWriteTextFormat methods output doesn't reflect layout changes */
941 weight = IDWriteTextFormat_GetFontWeight(fmt2);
942 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
944 range.length = 0;
945 weight = DWRITE_FONT_WEIGHT_BOLD;
946 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
947 ok(hr == S_OK, "got 0x%08x\n", hr);
948 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
949 ok(range.length == 6, "got %d\n", range.length);
951 size = IDWriteTextLayout_GetMaxWidth(layout);
952 ok(size == 100.0, "got %.2f\n", size);
954 hr = IDWriteTextLayout_SetMaxWidth(layout, 0.0);
955 ok(hr == S_OK, "got 0x%08x\n", hr);
957 size = IDWriteTextLayout_GetMaxWidth(layout);
958 ok(size == 0.0, "got %.2f\n", size);
960 hr = IDWriteTextLayout_SetMaxWidth(layout, -1.0);
961 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
963 size = IDWriteTextLayout_GetMaxWidth(layout);
964 ok(size == 0.0, "got %.2f\n", size);
966 hr = IDWriteTextLayout_SetMaxWidth(layout, 100.0);
967 ok(hr == S_OK, "got 0x%08x\n", hr);
969 size = IDWriteTextLayout_GetMaxWidth(layout);
970 ok(size == 100.0, "got %.2f\n", size);
972 size = IDWriteTextLayout_GetMaxHeight(layout);
973 ok(size == 100.0, "got %.2f\n", size);
975 hr = IDWriteTextLayout_SetMaxHeight(layout, 0.0);
976 ok(hr == S_OK, "got 0x%08x\n", hr);
978 size = IDWriteTextLayout_GetMaxHeight(layout);
979 ok(size == 0.0, "got %.2f\n", size);
981 hr = IDWriteTextLayout_SetMaxHeight(layout, -1.0);
982 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
984 size = IDWriteTextLayout_GetMaxHeight(layout);
985 ok(size == 0.0, "got %.2f\n", size);
987 hr = IDWriteTextLayout_SetMaxHeight(layout, 100.0);
988 ok(hr == S_OK, "got 0x%08x\n", hr);
990 size = IDWriteTextLayout_GetMaxHeight(layout);
991 ok(size == 100.0, "got %.2f\n", size);
993 IDWriteTextLayout_Release(layout);
994 IDWriteTextFormat_Release(fmt2);
995 IDWriteTextFormat_Release(format);
996 IDWriteFactory_Release(factory);
999 static void test_SetInlineObject(void)
1001 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1002 static const WCHAR ruW[] = {'r','u',0};
1004 IDWriteInlineObject *inlineobj, *inlineobj2, *inlinetest;
1005 IDWriteTextFormat *format;
1006 IDWriteTextLayout *layout;
1007 DWRITE_TEXT_RANGE range, r2;
1008 IDWriteFactory *factory;
1009 HRESULT hr;
1011 factory = create_factory();
1013 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1014 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1015 ok(hr == S_OK, "got 0x%08x\n", hr);
1017 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1018 ok(hr == S_OK, "got 0x%08x\n", hr);
1020 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1021 ok(hr == S_OK, "got 0x%08x\n", hr);
1023 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj2);
1024 ok(hr == S_OK, "got 0x%08x\n", hr);
1026 EXPECT_REF(inlineobj, 1);
1027 EXPECT_REF(inlineobj2, 1);
1029 inlinetest = (void*)0x1;
1030 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, NULL);
1031 ok(hr == S_OK, "got 0x%08x\n", hr);
1032 ok(inlinetest == NULL, "got %p\n", inlinetest);
1034 range.startPosition = 0;
1035 range.length = 2;
1036 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1037 ok(hr == S_OK, "got 0x%08x\n", hr);
1039 EXPECT_REF(inlineobj, 2);
1041 inlinetest = (void*)0x1;
1042 hr = IDWriteTextLayout_GetInlineObject(layout, 2, &inlinetest, NULL);
1043 ok(hr == S_OK, "got 0x%08x\n", hr);
1044 ok(inlinetest == NULL, "got %p\n", inlinetest);
1046 inlinetest = NULL;
1047 r2.startPosition = r2.length = 100;
1048 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1049 ok(hr == S_OK, "got 0x%08x\n", hr);
1050 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1051 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1052 IDWriteInlineObject_Release(inlinetest);
1054 EXPECT_REF(inlineobj, 2);
1056 /* get from somewhere inside a range */
1057 inlinetest = NULL;
1058 r2.startPosition = r2.length = 100;
1059 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1060 ok(hr == S_OK, "got 0x%08x\n", hr);
1061 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1062 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1063 IDWriteInlineObject_Release(inlinetest);
1065 EXPECT_REF(inlineobj, 2);
1067 range.startPosition = 1;
1068 range.length = 1;
1069 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj2, range);
1070 ok(hr == S_OK, "got 0x%08x\n", hr);
1072 inlinetest = NULL;
1073 r2.startPosition = r2.length = 100;
1074 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1075 ok(hr == S_OK, "got 0x%08x\n", hr);
1076 ok(inlinetest == inlineobj2, "got %p\n", inlinetest);
1077 ok(r2.startPosition == 1 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1078 IDWriteInlineObject_Release(inlinetest);
1080 EXPECT_REF(inlineobj, 2);
1081 EXPECT_REF(inlineobj2, 2);
1083 inlinetest = NULL;
1084 r2.startPosition = r2.length = 100;
1085 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1086 ok(hr == S_OK, "got 0x%08x\n", hr);
1087 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1088 ok(r2.startPosition == 0 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1089 IDWriteInlineObject_Release(inlinetest);
1091 EXPECT_REF(inlineobj, 2);
1093 range.startPosition = 1;
1094 range.length = 1;
1095 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1096 ok(hr == S_OK, "got 0x%08x\n", hr);
1098 r2.startPosition = r2.length = 100;
1099 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1100 ok(hr == S_OK, "got 0x%08x\n", hr);
1101 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1102 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1103 IDWriteInlineObject_Release(inlinetest);
1105 EXPECT_REF(inlineobj, 2);
1107 range.startPosition = 1;
1108 range.length = 2;
1109 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1110 ok(hr == S_OK, "got 0x%08x\n", hr);
1112 EXPECT_REF(inlineobj, 2);
1114 r2.startPosition = r2.length = 100;
1115 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1116 ok(hr == S_OK, "got 0x%08x\n", hr);
1117 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1118 ok(r2.startPosition == 0 && r2.length == 3, "got %d, %d\n", r2.startPosition, r2.length);
1119 IDWriteInlineObject_Release(inlinetest);
1121 EXPECT_REF(inlineobj, 2);
1122 EXPECT_REF(inlineobj2, 1);
1124 IDWriteTextLayout_Release(layout);
1126 EXPECT_REF(inlineobj, 1);
1128 IDWriteInlineObject_Release(inlineobj);
1129 IDWriteInlineObject_Release(inlineobj2);
1130 IDWriteTextFormat_Release(format);
1131 IDWriteFactory_Release(factory);
1134 /* drawing calls sequence doesn't depend on run order, instead all runs are
1135 drawn first, inline objects next and then underline/strikes */
1136 static const struct drawcall_entry draw_seq[] = {
1137 { DRAW_GLYPHRUN, {'s',0} },
1138 { DRAW_GLYPHRUN, {'r','i',0} },
1139 { DRAW_GLYPHRUN, {'n',0} },
1140 { DRAW_GLYPHRUN, {'g',0} },
1141 { DRAW_INLINE },
1142 { DRAW_UNDERLINE },
1143 { DRAW_STRIKETHROUGH },
1144 { DRAW_LAST_KIND }
1147 static const struct drawcall_entry draw_seq2[] = {
1148 { DRAW_GLYPHRUN, {'s',0} },
1149 { DRAW_GLYPHRUN, {'t',0} },
1150 { DRAW_GLYPHRUN, {'r',0} },
1151 { DRAW_GLYPHRUN, {'i',0} },
1152 { DRAW_GLYPHRUN, {'n',0} },
1153 { DRAW_GLYPHRUN, {'g',0} },
1154 { DRAW_LAST_KIND }
1157 static const struct drawcall_entry draw_seq3[] = {
1158 { DRAW_GLYPHRUN },
1159 { DRAW_GLYPHRUN, {'a','b',0} },
1160 { DRAW_LAST_KIND }
1163 static const struct drawcall_entry draw_seq4[] = {
1164 { DRAW_GLYPHRUN, {'s','t','r',0} },
1165 { DRAW_GLYPHRUN, {'i','n','g',0} },
1166 { DRAW_STRIKETHROUGH },
1167 { DRAW_LAST_KIND }
1170 static const struct drawcall_entry draw_seq5[] = {
1171 { DRAW_GLYPHRUN, {'s','t',0} },
1172 { DRAW_GLYPHRUN, {'r','i',0} },
1173 { DRAW_GLYPHRUN, {'n','g',0} },
1174 { DRAW_STRIKETHROUGH },
1175 { DRAW_LAST_KIND }
1178 static void test_Draw(void)
1180 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1181 static const WCHAR str2W[] = {0x202a,0x202c,'a','b',0};
1182 static const WCHAR ruW[] = {'r','u',0};
1184 IDWriteInlineObject *inlineobj;
1185 IDWriteTextFormat *format;
1186 IDWriteTextLayout *layout;
1187 DWRITE_TEXT_RANGE range;
1188 IDWriteFactory *factory;
1189 HRESULT hr;
1191 factory = create_factory();
1193 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1194 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1195 ok(hr == S_OK, "got 0x%08x\n", hr);
1197 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 100.0, 100.0, &layout);
1198 ok(hr == S_OK, "got 0x%08x\n", hr);
1200 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1201 ok(hr == S_OK, "got 0x%08x\n", hr);
1203 range.startPosition = 5;
1204 range.length = 1;
1205 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1206 ok(hr == S_OK, "got 0x%08x\n", hr);
1208 range.startPosition = 1;
1209 range.length = 1;
1210 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1211 ok(hr == S_OK, "got 0x%08x\n", hr);
1213 range.startPosition = 4;
1214 range.length = 1;
1215 hr = IDWriteTextLayout_SetDrawingEffect(layout, (IUnknown*)inlineobj, range);
1216 ok(hr == S_OK, "got 0x%08x\n", hr);
1218 range.startPosition = 0;
1219 range.length = 1;
1220 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
1221 ok(hr == S_OK, "got 0x%08x\n", hr);
1223 flush_sequence(sequences, RENDERER_ID);
1224 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1225 ok(hr == S_OK, "got 0x%08x\n", hr);
1226 ok_sequence(sequences, RENDERER_ID, draw_seq, "draw test", TRUE);
1227 IDWriteTextLayout_Release(layout);
1229 /* with reduced width DrawGlyphRun() is called for every line */
1230 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 5.0, 100.0, &layout);
1231 ok(hr == S_OK, "got 0x%08x\n", hr);
1232 flush_sequence(sequences, RENDERER_ID);
1233 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1234 ok(hr == S_OK, "got 0x%08x\n", hr);
1235 ok_sequence(sequences, RENDERER_ID, draw_seq2, "draw test 2", TRUE);
1236 IDWriteTextLayout_Release(layout);
1238 /* string with control characters */
1239 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 100.0, &layout);
1240 ok(hr == S_OK, "got 0x%08x\n", hr);
1241 flush_sequence(sequences, RENDERER_ID);
1242 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1243 ok(hr == S_OK, "got 0x%08x\n", hr);
1244 ok_sequence(sequences, RENDERER_ID, draw_seq3, "draw test 3", TRUE);
1245 IDWriteTextLayout_Release(layout);
1247 /* strikethrough splits ranges from renderer point of view, but doesn't break
1248 shaping */
1249 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1250 ok(hr == S_OK, "got 0x%08x\n", hr);
1251 flush_sequence(sequences, RENDERER_ID);
1253 range.startPosition = 0;
1254 range.length = 3;
1255 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1256 ok(hr == S_OK, "got 0x%08x\n", hr);
1258 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1259 ok(hr == S_OK, "got 0x%08x\n", hr);
1260 ok_sequence(sequences, RENDERER_ID, draw_seq4, "draw test 4", FALSE);
1261 IDWriteTextLayout_Release(layout);
1263 /* strikethrough somewhere in the middle */
1264 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1265 ok(hr == S_OK, "got 0x%08x\n", hr);
1266 flush_sequence(sequences, RENDERER_ID);
1268 range.startPosition = 2;
1269 range.length = 2;
1270 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1271 ok(hr == S_OK, "got 0x%08x\n", hr);
1273 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1274 ok(hr == S_OK, "got 0x%08x\n", hr);
1275 ok_sequence(sequences, RENDERER_ID, draw_seq5, "draw test 5", FALSE);
1276 IDWriteTextLayout_Release(layout);
1278 IDWriteTextFormat_Release(format);
1279 IDWriteFactory_Release(factory);
1282 static void test_typography(void)
1284 DWRITE_FONT_FEATURE feature;
1285 IDWriteTypography *typography;
1286 IDWriteFactory *factory;
1287 UINT32 count;
1288 HRESULT hr;
1290 factory = create_factory();
1292 hr = IDWriteFactory_CreateTypography(factory, &typography);
1293 ok(hr == S_OK, "got 0x%08x\n", hr);
1295 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1296 feature.parameter = 1;
1297 hr = IDWriteTypography_AddFontFeature(typography, feature);
1298 ok(hr == S_OK, "got 0x%08x\n", hr);
1300 count = IDWriteTypography_GetFontFeatureCount(typography);
1301 ok(count == 1, "got %u\n", count);
1303 /* duplicated features work just fine */
1304 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1305 feature.parameter = 0;
1306 hr = IDWriteTypography_AddFontFeature(typography, feature);
1307 ok(hr == S_OK, "got 0x%08x\n", hr);
1309 count = IDWriteTypography_GetFontFeatureCount(typography);
1310 ok(count == 2, "got %u\n", count);
1312 memset(&feature, 0, sizeof(feature));
1313 hr = IDWriteTypography_GetFontFeature(typography, 0, &feature);
1314 ok(hr == S_OK, "got 0x%08x\n", hr);
1315 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1316 ok(feature.parameter == 1, "got %u\n", feature.parameter);
1318 memset(&feature, 0, sizeof(feature));
1319 hr = IDWriteTypography_GetFontFeature(typography, 1, &feature);
1320 ok(hr == S_OK, "got 0x%08x\n", hr);
1321 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1322 ok(feature.parameter == 0, "got %u\n", feature.parameter);
1324 hr = IDWriteTypography_GetFontFeature(typography, 2, &feature);
1325 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1327 IDWriteTypography_Release(typography);
1328 IDWriteFactory_Release(factory);
1331 static void test_GetClusterMetrics(void)
1333 static const WCHAR str2W[] = {0x202a,0x202c,'a',0};
1334 static const WCHAR strW[] = {'a','b','c','d',0};
1335 DWRITE_INLINE_OBJECT_METRICS inline_metrics;
1336 DWRITE_CLUSTER_METRICS metrics[4];
1337 IDWriteTextLayout1 *layout1;
1338 IDWriteInlineObject *trimm;
1339 IDWriteTextFormat *format;
1340 IDWriteTextLayout *layout;
1341 DWRITE_TEXT_RANGE range;
1342 IDWriteFactory *factory;
1343 UINT32 count, i;
1344 HRESULT hr;
1346 factory = create_factory();
1348 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1349 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1350 ok(hr == S_OK, "got 0x%08x\n", hr);
1352 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1353 ok(hr == S_OK, "got 0x%08x\n", hr);
1355 count = 0;
1356 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1357 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1358 ok(count == 4, "got %u\n", count);
1360 /* check every cluster width */
1361 count = 0;
1362 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
1363 ok(hr == S_OK, "got 0x%08x\n", hr);
1364 ok(count == 4, "got %u\n", count);
1365 for (i = 0; i < count; i++) {
1366 ok(metrics[i].width > 0.0, "%u: got width %.2f\n", i, metrics[i].width);
1367 ok(metrics[i].length == 1, "%u: got length %u\n", i, metrics[i].length);
1370 /* apply spacing and check widths again */
1371 if (IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1) == S_OK) {
1372 DWRITE_CLUSTER_METRICS metrics2[4];
1373 FLOAT leading, trailing, min_advance;
1374 DWRITE_TEXT_RANGE r;
1376 leading = trailing = min_advance = 2.0;
1377 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 0, &leading, &trailing,
1378 &min_advance, NULL);
1379 todo_wine {
1380 ok(hr == S_OK, "got 0x%08x\n", hr);
1381 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
1382 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
1384 r.startPosition = 0;
1385 r.length = 4;
1386 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 10.0, 15.0, 0.0, r);
1387 todo_wine
1388 ok(hr == S_OK, "got 0x%08x\n", hr);
1390 count = 0;
1391 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics2, sizeof(metrics2)/sizeof(metrics2[0]), &count);
1392 ok(hr == S_OK, "got 0x%08x\n", hr);
1393 ok(count == 4, "got %u\n", count);
1394 for (i = 0; i < count; i++) {
1395 todo_wine
1396 ok(metrics2[i].width > metrics[i].width, "%u: got width %.2f, was %.2f\n", i, metrics2[i].width,
1397 metrics[i].width);
1398 ok(metrics2[i].length == 1, "%u: got length %u\n", i, metrics2[i].length);
1401 /* back to defaults */
1402 r.startPosition = 0;
1403 r.length = 4;
1404 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, 0.0, r);
1405 todo_wine
1406 ok(hr == S_OK, "got 0x%08x\n", hr);
1408 IDWriteTextLayout1_Release(layout1);
1410 else
1411 win_skip("IDWriteTextLayout1 is not supported, cluster spacing test skipped.\n");
1413 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &trimm);
1414 ok(hr == S_OK, "got 0x%08x\n", hr);
1416 range.startPosition = 0;
1417 range.length = 2;
1418 hr = IDWriteTextLayout_SetInlineObject(layout, trimm, range);
1419 ok(hr == S_OK, "got 0x%08x\n", hr);
1421 /* inline object takes a separate cluster, replaced codepoints number doesn't matter */
1422 count = 0;
1423 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1424 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1425 ok(count == 3, "got %u\n", count);
1427 count = 0;
1428 memset(&metrics, 0, sizeof(metrics));
1429 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
1430 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1431 ok(count == 3, "got %u\n", count);
1432 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
1434 hr = IDWriteInlineObject_GetMetrics(trimm, &inline_metrics);
1435 ok(hr == S_OK, "got 0x%08x\n", hr);
1436 todo_wine
1437 ok(inline_metrics.width > 0.0 && inline_metrics.width == metrics[0].width, "got %.2f, expected %.2f\n",
1438 inline_metrics.width, metrics[0].width);
1440 IDWriteTextLayout_Release(layout);
1442 /* text with non-visual control codes */
1443 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 3, format, 1000.0, 1000.0, &layout);
1444 ok(hr == S_OK, "got 0x%08x\n", hr);
1446 /* bidi control codes take a separate cluster */
1447 count = 0;
1448 memset(metrics, 0, sizeof(metrics));
1449 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1450 ok(hr == S_OK, "got 0x%08x\n", hr);
1451 ok(count == 3, "got %u\n", count);
1453 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1454 ok(metrics[0].length == 1, "got %d\n", metrics[0].length);
1455 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
1456 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1457 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1458 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1459 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1461 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
1462 ok(metrics[1].length == 1, "got %d\n", metrics[1].length);
1463 ok(metrics[1].canWrapLineAfter == 0, "got %d\n", metrics[1].canWrapLineAfter);
1464 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
1465 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
1466 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
1467 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
1469 ok(metrics[2].width > 0.0, "got %.2f\n", metrics[2].width);
1470 ok(metrics[2].length == 1, "got %d\n", metrics[2].length);
1471 todo_wine
1472 ok(metrics[2].canWrapLineAfter == 1, "got %d\n", metrics[2].canWrapLineAfter);
1473 ok(metrics[2].isWhitespace == 0, "got %d\n", metrics[2].isWhitespace);
1474 ok(metrics[2].isNewline == 0, "got %d\n", metrics[2].isNewline);
1475 ok(metrics[2].isSoftHyphen == 0, "got %d\n", metrics[2].isSoftHyphen);
1476 ok(metrics[2].isRightToLeft == 0, "got %d\n", metrics[2].isRightToLeft);
1478 IDWriteTextLayout_Release(layout);
1480 /* single inline object that fails to report its metrics */
1481 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1482 ok(hr == S_OK, "got 0x%08x\n", hr);
1484 range.startPosition = 0;
1485 range.length = 4;
1486 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj, range);
1487 ok(hr == S_OK, "got 0x%08x\n", hr);
1489 count = 0;
1490 memset(metrics, 0, sizeof(metrics));
1491 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1492 ok(hr == S_OK, "got 0x%08x\n", hr);
1493 ok(count == 1, "got %u\n", count);
1495 /* object sets a width to 123.0, but returns failure from GetMetrics() */
1496 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1497 ok(metrics[0].length == 4, "got %d\n", metrics[0].length);
1498 todo_wine
1499 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
1500 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1501 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1502 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1503 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1505 /* now set two inline object for [0,1] and [2,3], both fail to report break conditions */
1506 range.startPosition = 2;
1507 range.length = 2;
1508 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj2, range);
1509 ok(hr == S_OK, "got 0x%08x\n", hr);
1511 count = 0;
1512 memset(metrics, 0, sizeof(metrics));
1513 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1514 ok(hr == S_OK, "got 0x%08x\n", hr);
1515 ok(count == 2, "got %u\n", count);
1517 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1518 ok(metrics[0].length == 2, "got %d\n", metrics[0].length);
1519 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
1520 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1521 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1522 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1523 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1525 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
1526 ok(metrics[1].length == 2, "got %d\n", metrics[1].length);
1527 todo_wine
1528 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
1529 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
1530 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
1531 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
1532 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
1534 IDWriteTextLayout_Release(layout);
1536 IDWriteInlineObject_Release(trimm);
1537 IDWriteTextFormat_Release(format);
1538 IDWriteFactory_Release(factory);
1541 static void test_SetLocaleName(void)
1543 static const WCHAR strW[] = {'a','b','c','d',0};
1544 WCHAR buffW[LOCALE_NAME_MAX_LENGTH+sizeof(strW)/sizeof(WCHAR)];
1545 IDWriteTextFormat *format;
1546 IDWriteTextLayout *layout;
1547 DWRITE_TEXT_RANGE range;
1548 IDWriteFactory *factory;
1549 HRESULT hr;
1551 factory = create_factory();
1553 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1554 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1555 ok(hr == S_OK, "got 0x%08x\n", hr);
1557 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1558 ok(hr == S_OK, "got 0x%08x\n", hr);
1560 range.startPosition = 0;
1561 range.length = 1;
1562 hr = IDWriteTextLayout_SetLocaleName(layout, enusW, range);
1563 ok(hr == S_OK, "got 0x%08x\n", hr);
1565 hr = IDWriteTextLayout_SetLocaleName(layout, NULL, range);
1566 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1568 /* invalid locale name is allowed */
1569 hr = IDWriteTextLayout_SetLocaleName(layout, strW, range);
1570 ok(hr == S_OK, "got 0x%08x\n", hr);
1572 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 0, NULL);
1573 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1575 if (0) /* crashes on native */
1576 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 1, NULL);
1578 buffW[0] = 0;
1579 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), NULL);
1580 ok(hr == S_OK, "got 0x%08x\n", hr);
1581 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
1583 /* get with a shorter buffer */
1584 buffW[0] = 0xa;
1585 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, 1, NULL);
1586 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1587 ok(buffW[0] == 0, "got %x\n", buffW[0]);
1589 /* name is too long */
1590 lstrcpyW(buffW, strW);
1591 while (lstrlenW(buffW) <= LOCALE_NAME_MAX_LENGTH)
1592 lstrcatW(buffW, strW);
1594 range.startPosition = 0;
1595 range.length = 1;
1596 hr = IDWriteTextLayout_SetLocaleName(layout, buffW, range);
1597 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1599 buffW[0] = 0;
1600 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), NULL);
1601 ok(hr == S_OK, "got 0x%08x\n", hr);
1602 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
1604 IDWriteTextLayout_Release(layout);
1605 IDWriteTextFormat_Release(format);
1606 IDWriteFactory_Release(factory);
1609 static void test_SetPairKerning(void)
1611 static const WCHAR strW[] = {'a','b','c','d',0};
1612 IDWriteTextLayout1 *layout1;
1613 IDWriteTextFormat *format;
1614 IDWriteTextLayout *layout;
1615 DWRITE_TEXT_RANGE range;
1616 IDWriteFactory *factory;
1617 BOOL kerning;
1618 HRESULT hr;
1620 factory = create_factory();
1622 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1623 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1624 ok(hr == S_OK, "got 0x%08x\n", hr);
1626 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1627 ok(hr == S_OK, "got 0x%08x\n", hr);
1628 IDWriteTextFormat_Release(format);
1630 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1);
1631 IDWriteTextLayout_Release(layout);
1633 if (hr != S_OK) {
1634 win_skip("SetPairKerning() is not supported.\n");
1635 IDWriteFactory_Release(factory);
1636 return;
1639 if (0) { /* crashes on native */
1640 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, NULL);
1641 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, &range);
1644 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, NULL);
1645 ok(hr == S_OK, "got 0x%08x\n", hr);
1647 range.startPosition = 0;
1648 range.length = 0;
1649 kerning = TRUE;
1650 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
1651 ok(hr == S_OK, "got 0x%08x\n", hr);
1652 ok(!kerning, "got %d\n", kerning);
1654 range.startPosition = 0;
1655 range.length = 1;
1656 hr = IDWriteTextLayout1_SetPairKerning(layout1, 2, range);
1657 ok(hr == S_OK, "got 0x%08x\n", hr);
1659 kerning = FALSE;
1660 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
1661 ok(hr == S_OK, "got 0x%08x\n", hr);
1662 ok(kerning == TRUE, "got %d\n", kerning);
1664 IDWriteTextLayout1_Release(layout1);
1665 IDWriteFactory_Release(factory);
1668 static void test_SetVerticalGlyphOrientation(void)
1670 static const WCHAR strW[] = {'a','b','c','d',0};
1671 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation;
1672 IDWriteTextLayout2 *layout2;
1673 IDWriteTextFormat *format;
1674 IDWriteTextLayout *layout;
1675 IDWriteFactory *factory;
1676 HRESULT hr;
1678 factory = create_factory();
1680 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1681 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1682 ok(hr == S_OK, "got 0x%08x\n", hr);
1684 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1685 ok(hr == S_OK, "got 0x%08x\n", hr);
1686 IDWriteTextFormat_Release(format);
1688 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
1689 IDWriteTextLayout_Release(layout);
1691 if (hr != S_OK) {
1692 win_skip("SetVerticalGlyphOrientation() is not supported.\n");
1693 IDWriteFactory_Release(factory);
1694 return;
1697 orientation = IDWriteTextLayout2_GetVerticalGlyphOrientation(layout2);
1698 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT, "got %d\n", orientation);
1700 hr = IDWriteTextLayout2_SetVerticalGlyphOrientation(layout2, DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED+1);
1701 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1703 IDWriteTextLayout2_Release(layout2);
1704 IDWriteFactory_Release(factory);
1707 static void test_fallback(void)
1709 static const WCHAR strW[] = {'a','b','c','d',0};
1710 IDWriteFontFallback *fallback, *fallback2;
1711 IDWriteTextLayout2 *layout2;
1712 IDWriteTextFormat1 *format1;
1713 IDWriteTextFormat *format;
1714 IDWriteTextLayout *layout;
1715 IDWriteFactory2 *factory2;
1716 IDWriteFactory *factory;
1717 HRESULT hr;
1719 factory = create_factory();
1721 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1722 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1723 ok(hr == S_OK, "got 0x%08x\n", hr);
1725 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1726 ok(hr == S_OK, "got 0x%08x\n", hr);
1727 IDWriteTextFormat_Release(format);
1729 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
1730 IDWriteTextLayout_Release(layout);
1732 if (hr != S_OK) {
1733 win_skip("GetFontFallback() is not supported.\n");
1734 IDWriteFactory_Release(factory);
1735 return;
1738 if (0) /* crashes on native */
1739 hr = IDWriteTextLayout2_GetFontFallback(layout2, NULL);
1741 fallback = (void*)0xdeadbeef;
1742 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback);
1743 ok(hr == S_OK, "got 0x%08x\n", hr);
1744 ok(fallback == NULL, "got %p\n", fallback);
1746 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
1747 ok(hr == S_OK, "got 0x%08x\n", hr);
1749 fallback = (void*)0xdeadbeef;
1750 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback);
1751 ok(hr == S_OK, "got 0x%08x\n", hr);
1752 ok(fallback == NULL, "got %p\n", fallback);
1754 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
1755 ok(hr == S_OK, "got 0x%08x\n", hr);
1757 fallback = NULL;
1758 hr = IDWriteFactory2_GetSystemFontFallback(factory2, &fallback);
1759 todo_wine
1760 ok(hr == S_OK, "got 0x%08x\n", hr);
1761 if (hr == S_OK) {
1762 ok(fallback != NULL, "got %p\n", fallback);
1764 hr = IDWriteTextFormat1_SetFontFallback(format1, fallback);
1765 ok(hr == S_OK, "got 0x%08x\n", hr);
1767 fallback2 = (void*)0xdeadbeef;
1768 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback2);
1769 ok(hr == S_OK, "got 0x%08x\n", hr);
1770 ok(fallback2 == fallback, "got %p\n", fallback2);
1772 hr = IDWriteTextLayout2_SetFontFallback(layout2, NULL);
1773 ok(hr == S_OK, "got 0x%08x\n", hr);
1775 fallback2 = (void*)0xdeadbeef;
1776 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback2);
1777 ok(hr == S_OK, "got 0x%08x\n", hr);
1778 ok(fallback2 == NULL, "got %p\n", fallback2);
1780 IDWriteFontFallback_Release(fallback);
1782 IDWriteTextFormat1_Release(format1);
1783 IDWriteTextLayout2_Release(layout2);
1784 IDWriteFactory_Release(factory);
1787 static void test_DetermineMinWidth(void)
1789 static const WCHAR strW[] = {'a','b','c','d',0};
1790 IDWriteTextFormat *format;
1791 IDWriteTextLayout *layout;
1792 IDWriteFactory *factory;
1793 FLOAT minwidth;
1794 HRESULT hr;
1796 factory = create_factory();
1798 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1799 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1800 ok(hr == S_OK, "got 0x%08x\n", hr);
1802 hr = IDWriteFactory_CreateTextLayout(factory, strW, lstrlenW(strW), format, 1000.0, 1000.0, &layout);
1803 ok(hr == S_OK, "got 0x%08x\n", hr);
1805 hr = IDWriteTextLayout_DetermineMinWidth(layout, NULL);
1806 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1808 minwidth = 0.0;
1809 hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
1810 ok(hr == S_OK, "got 0x%08x\n", hr);
1811 ok(minwidth > 0.0, "got %.2f\n", minwidth);
1813 IDWriteTextLayout_Release(layout);
1814 IDWriteTextFormat_Release(format);
1817 static void test_SetFontSize(void)
1819 static const WCHAR strW[] = {'a','b','c','d',0};
1820 IDWriteTextFormat *format;
1821 IDWriteTextLayout *layout;
1822 IDWriteFactory *factory;
1823 DWRITE_TEXT_RANGE r;
1824 FLOAT size;
1825 HRESULT hr;
1827 factory = create_factory();
1829 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1830 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1831 ok(hr == S_OK, "got 0x%08x\n", hr);
1833 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1834 ok(hr == S_OK, "got 0x%08x\n", hr);
1836 r.startPosition = 1;
1837 r.length = 0;
1838 size = 0.0;
1839 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
1840 ok(hr == S_OK, "got 0x%08x\n", hr);
1841 todo_wine
1842 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
1843 ok(size == 10.0, "got %.2f\n", size);
1845 r.startPosition = 1;
1846 r.length = 1;
1847 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
1848 ok(hr == S_OK, "got 0x%08x\n", hr);
1850 size = 0.0;
1851 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
1852 ok(hr == S_OK, "got 0x%08x\n", hr);
1853 ok(size == 15.0, "got %.2f\n", size);
1855 r.startPosition = 0;
1856 r.length = 4;
1857 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
1858 ok(hr == S_OK, "got 0x%08x\n", hr);
1860 size = 0.0;
1861 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
1862 ok(hr == S_OK, "got 0x%08x\n", hr);
1863 ok(size == 15.0, "got %.2f\n", size);
1865 size = 0.0;
1866 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
1867 ok(hr == S_OK, "got 0x%08x\n", hr);
1868 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
1869 ok(size == 15.0, "got %.2f\n", size);
1871 size = 15.0;
1872 r.startPosition = r.length = 0;
1873 hr = IDWriteTextLayout_GetFontSize(layout, 20, &size, &r);
1874 ok(hr == S_OK, "got 0x%08x\n", hr);
1875 todo_wine {
1876 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
1877 ok(size == 10.0, "got %.2f\n", size);
1879 r.startPosition = 100;
1880 r.length = 4;
1881 hr = IDWriteTextLayout_SetFontSize(layout, 25.0, r);
1882 ok(hr == S_OK, "got 0x%08x\n", hr);
1884 size = 15.0;
1885 r.startPosition = r.length = 0;
1886 hr = IDWriteTextLayout_GetFontSize(layout, 100, &size, &r);
1887 ok(hr == S_OK, "got 0x%08x\n", hr);
1888 todo_wine {
1889 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
1890 ok(size == 25.0, "got %.2f\n", size);
1892 IDWriteTextLayout_Release(layout);
1893 IDWriteTextFormat_Release(format);
1896 static void test_SetFontFamilyName(void)
1898 static const WCHAR arialW[] = {'A','r','i','a','l',0};
1899 static const WCHAR strW[] = {'a','b','c','d',0};
1900 IDWriteTextFormat *format;
1901 IDWriteTextLayout *layout;
1902 IDWriteFactory *factory;
1903 DWRITE_TEXT_RANGE r;
1904 WCHAR nameW[50];
1905 HRESULT hr;
1907 factory = create_factory();
1909 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1910 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1911 ok(hr == S_OK, "got 0x%08x\n", hr);
1913 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1914 ok(hr == S_OK, "got 0x%08x\n", hr);
1916 r.startPosition = 1;
1917 r.length = 0;
1918 nameW[0] = 0;
1919 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
1920 ok(hr == S_OK, "got 0x%08x\n", hr);
1921 todo_wine
1922 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
1924 r.startPosition = 1;
1925 r.length = 1;
1926 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
1927 ok(hr == S_OK, "got 0x%08x\n", hr);
1929 r.startPosition = 1;
1930 r.length = 0;
1931 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
1932 ok(hr == S_OK, "got 0x%08x\n", hr);
1933 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
1935 r.startPosition = 0;
1936 r.length = 4;
1937 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
1938 ok(hr == S_OK, "got 0x%08x\n", hr);
1940 nameW[0] = 0;
1941 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
1942 ok(hr == S_OK, "got 0x%08x\n", hr);
1943 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
1944 ok(!lstrcmpW(nameW, arialW), "got name %s\n", wine_dbgstr_w(nameW));
1946 IDWriteTextLayout_Release(layout);
1947 IDWriteTextFormat_Release(format);
1950 static void test_SetFontStyle(void)
1952 static const WCHAR strW[] = {'a','b','c','d',0};
1953 IDWriteTextFormat *format;
1954 IDWriteTextLayout *layout;
1955 IDWriteFactory *factory;
1956 DWRITE_FONT_STYLE style;
1957 DWRITE_TEXT_RANGE r;
1958 HRESULT hr;
1960 factory = create_factory();
1962 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1963 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1964 ok(hr == S_OK, "got 0x%08x\n", hr);
1966 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1967 ok(hr == S_OK, "got 0x%08x\n", hr);
1969 r.startPosition = 1;
1970 r.length = 0;
1971 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
1972 ok(hr == S_OK, "got 0x%08x\n", hr);
1973 todo_wine
1974 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
1975 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
1977 r.startPosition = 1;
1978 r.length = 1;
1979 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC, r);
1980 ok(hr == S_OK, "got 0x%08x\n", hr);
1982 style = DWRITE_FONT_STYLE_NORMAL;
1983 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
1984 ok(hr == S_OK, "got 0x%08x\n", hr);
1985 ok(style == DWRITE_FONT_STYLE_ITALIC, "got %d\n", style);
1987 r.startPosition = 0;
1988 r.length = 4;
1989 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
1990 ok(hr == S_OK, "got 0x%08x\n", hr);
1992 style = DWRITE_FONT_STYLE_ITALIC;
1993 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
1994 ok(hr == S_OK, "got 0x%08x\n", hr);
1995 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
1997 style = DWRITE_FONT_STYLE_ITALIC;
1998 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
1999 ok(hr == S_OK, "got 0x%08x\n", hr);
2000 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2001 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2003 style = DWRITE_FONT_STYLE_ITALIC;
2004 r.startPosition = r.length = 0;
2005 hr = IDWriteTextLayout_GetFontStyle(layout, 20, &style, &r);
2006 ok(hr == S_OK, "got 0x%08x\n", hr);
2007 todo_wine {
2008 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2009 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
2011 r.startPosition = 100;
2012 r.length = 4;
2013 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
2014 ok(hr == S_OK, "got 0x%08x\n", hr);
2016 style = DWRITE_FONT_STYLE_NORMAL;
2017 r.startPosition = r.length = 0;
2018 hr = IDWriteTextLayout_GetFontStyle(layout, 100, &style, &r);
2019 ok(hr == S_OK, "got 0x%08x\n", hr);
2020 todo_wine {
2021 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2022 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2024 IDWriteTextLayout_Release(layout);
2025 IDWriteTextFormat_Release(format);
2028 START_TEST(layout)
2030 static const WCHAR ctrlstrW[] = {0x202a,0};
2031 IDWriteFactory *factory;
2033 if (!(factory = create_factory())) {
2034 win_skip("failed to create factory\n");
2035 return;
2038 /* actual script ids are not fixed */
2039 get_script_analysis(ctrlstrW, 1, &g_control_sa);
2041 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
2042 init_call_sequences(expected_seq, 1);
2044 test_CreateTextLayout();
2045 test_CreateGdiCompatibleTextLayout();
2046 test_CreateTextFormat();
2047 test_GetLocaleName();
2048 test_CreateEllipsisTrimmingSign();
2049 test_fontweight();
2050 test_SetInlineObject();
2051 test_Draw();
2052 test_typography();
2053 test_GetClusterMetrics();
2054 test_SetLocaleName();
2055 test_SetPairKerning();
2056 test_SetVerticalGlyphOrientation();
2057 test_fallback();
2058 test_DetermineMinWidth();
2059 test_SetFontSize();
2060 test_SetFontFamilyName();
2061 test_SetFontStyle();
2063 IDWriteFactory_Release(factory);