dwrite: Implement centered text alignment.
[wine.git] / dlls / dwrite / tests / layout.c
blob07ebaf3bfd352ccacbf977c511a96dcf05c4f4e7
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_modifiers_kind {
219 DRAW_EFFECT = 0x1000
222 enum drawcall_kind {
223 DRAW_GLYPHRUN = 0,
224 DRAW_UNDERLINE = 1,
225 DRAW_STRIKETHROUGH = 2,
226 DRAW_INLINE = 3,
227 DRAW_LAST_KIND = 4,
228 DRAW_TOTAL_KINDS = 5,
229 DRAW_KINDS_MASK = 0xff
232 static const char *get_draw_kind_name(unsigned short kind)
234 static const char *kind_names[] = {
235 "GLYPH_RUN",
236 "UNDERLINE",
237 "STRIKETHROUGH",
238 "INLINE",
239 "END_OF_SEQ",
241 "GLYPH_RUN|EFFECT",
242 "UNDERLINE|EFFECT",
243 "STRIKETHROUGH|EFFECT",
244 "INLINE|EFFECT",
245 "END_OF_SEQ"
247 if ((kind & DRAW_KINDS_MASK) > DRAW_LAST_KIND)
248 return "unknown";
249 return (kind & DRAW_EFFECT) ? kind_names[(kind & DRAW_KINDS_MASK) + DRAW_TOTAL_KINDS] :
250 kind_names[kind];
253 struct drawcall_entry {
254 enum drawcall_kind kind;
255 WCHAR string[10]; /* only meaningful for DrawGlyphRun() */
258 struct drawcall_sequence
260 int count;
261 int size;
262 struct drawcall_entry *sequence;
265 struct drawtestcontext {
266 unsigned short kind;
267 BOOL todo;
268 int *failcount;
269 const char *file;
270 int line;
273 #define NUM_CALL_SEQUENCES 1
274 #define RENDERER_ID 0
275 static struct drawcall_sequence *sequences[NUM_CALL_SEQUENCES];
276 static struct drawcall_sequence *expected_seq[1];
278 static void add_call(struct drawcall_sequence **seq, int sequence_index, const struct drawcall_entry *call)
280 struct drawcall_sequence *call_seq = seq[sequence_index];
282 if (!call_seq->sequence) {
283 call_seq->size = 10;
284 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0, call_seq->size * sizeof (struct drawcall_entry));
287 if (call_seq->count == call_seq->size) {
288 call_seq->size *= 2;
289 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
290 call_seq->sequence,
291 call_seq->size * sizeof (struct drawcall_entry));
294 assert(call_seq->sequence);
295 call_seq->sequence[call_seq->count++] = *call;
298 static inline void flush_sequence(struct drawcall_sequence **seg, int sequence_index)
300 struct drawcall_sequence *call_seq = seg[sequence_index];
302 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
303 call_seq->sequence = NULL;
304 call_seq->count = call_seq->size = 0;
307 static inline void flush_sequences(struct drawcall_sequence **seq, int n)
309 int i;
310 for (i = 0; i < n; i++)
311 flush_sequence(seq, i);
314 static void init_call_sequences(struct drawcall_sequence **seq, int n)
316 int i;
318 for (i = 0; i < n; i++)
319 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct drawcall_sequence));
322 static void ok_sequence_(struct drawcall_sequence **seq, int sequence_index,
323 const struct drawcall_entry *expected, const char *context, BOOL todo,
324 const char *file, int line)
326 static const struct drawcall_entry end_of_sequence = { DRAW_LAST_KIND };
327 struct drawcall_sequence *call_seq = seq[sequence_index];
328 const struct drawcall_entry *actual, *sequence;
329 int failcount = 0;
331 add_call(seq, sequence_index, &end_of_sequence);
333 sequence = call_seq->sequence;
334 actual = sequence;
336 while (expected->kind != DRAW_LAST_KIND && actual->kind != DRAW_LAST_KIND) {
337 if (expected->kind != actual->kind) {
338 if (todo) {
339 failcount++;
340 todo_wine
341 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
342 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
344 flush_sequence(seq, sequence_index);
345 return;
347 else
348 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
349 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
351 else if ((expected->kind & DRAW_KINDS_MASK) == DRAW_GLYPHRUN) {
352 int cmp = lstrcmpW(expected->string, actual->string);
353 if (cmp != 0 && todo) {
354 failcount++;
355 todo_wine
356 ok_(file, line) (0, "%s: glyphrun string %s was expected, but got %s instead\n",
357 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
359 else
360 ok_(file, line) (cmp == 0, "%s: glyphrun string %s was expected, but got %s instead\n",
361 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
363 expected++;
364 actual++;
367 if (todo) {
368 todo_wine {
369 if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND) {
370 failcount++;
371 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
372 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
376 else if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND)
377 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
378 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
380 if (todo && !failcount) /* succeeded yet marked todo */
381 todo_wine
382 ok_(file, line)(1, "%s: marked \"todo_wine\" but succeeds\n", context);
384 flush_sequence(seq, sequence_index);
387 #define ok_sequence(seq, index, exp, contx, todo) \
388 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
390 static HRESULT WINAPI testrenderer_QI(IDWriteTextRenderer *iface, REFIID riid, void **obj)
392 if (IsEqualIID(riid, &IID_IDWriteTextRenderer) ||
393 IsEqualIID(riid, &IID_IDWritePixelSnapping) ||
394 IsEqualIID(riid, &IID_IUnknown)
396 *obj = iface;
397 return S_OK;
400 *obj = NULL;
402 /* IDWriteTextRenderer1 overrides drawing calls, ignore for now */
403 if (IsEqualIID(riid, &IID_IDWriteTextRenderer1))
404 return E_NOINTERFACE;
406 ok(0, "unexpected QI %s\n", wine_dbgstr_guid(riid));
407 return E_NOINTERFACE;
410 static ULONG WINAPI testrenderer_AddRef(IDWriteTextRenderer *iface)
412 return 2;
415 static ULONG WINAPI testrenderer_Release(IDWriteTextRenderer *iface)
417 return 1;
420 static HRESULT WINAPI testrenderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
421 void *client_drawingcontext, BOOL *disabled)
423 *disabled = TRUE;
424 return S_OK;
427 static HRESULT WINAPI testrenderer_GetCurrentTransform(IDWriteTextRenderer *iface,
428 void *client_drawingcontext, DWRITE_MATRIX *transform)
430 ok(0, "unexpected call\n");
431 return E_NOTIMPL;
434 static HRESULT WINAPI testrenderer_GetPixelsPerDip(IDWriteTextRenderer *iface,
435 void *client_drawingcontext, FLOAT *pixels_per_dip)
437 ok(0, "unexpected call\n");
438 return E_NOTIMPL;
441 static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface,
442 void* client_drawingcontext,
443 FLOAT baselineOriginX,
444 FLOAT baselineOriginY,
445 DWRITE_MEASURING_MODE mode,
446 DWRITE_GLYPH_RUN const *run,
447 DWRITE_GLYPH_RUN_DESCRIPTION const *descr,
448 IUnknown *effect)
450 struct drawcall_entry entry;
451 DWRITE_SCRIPT_ANALYSIS sa;
453 ok(descr->stringLength < sizeof(entry.string)/sizeof(WCHAR), "string is too long\n");
454 if (descr->stringLength && descr->stringLength < sizeof(entry.string)/sizeof(WCHAR)) {
455 memcpy(entry.string, descr->string, descr->stringLength*sizeof(WCHAR));
456 entry.string[descr->stringLength] = 0;
458 else
459 entry.string[0] = 0;
461 /* see what's reported for control codes runs */
462 get_script_analysis(descr->string, descr->stringLength, &sa);
463 if (sa.script == g_control_sa.script) {
464 /* glyphs are not reported at all for control code runs */
465 ok(run->glyphCount == 0, "got %u\n", run->glyphCount);
466 ok(run->glyphAdvances != NULL, "advances array %p\n", run->glyphAdvances);
467 ok(run->glyphOffsets != NULL, "offsets array %p\n", run->glyphOffsets);
468 ok(run->fontFace != NULL, "got %p\n", run->fontFace);
469 /* text positions are still valid */
470 ok(descr->string != NULL, "got string %p\n", descr->string);
471 ok(descr->stringLength > 0, "got string length %u\n", descr->stringLength);
472 ok(descr->clusterMap != NULL, "clustermap %p\n", descr->clusterMap);
475 entry.kind = DRAW_GLYPHRUN;
476 if (effect)
477 entry.kind |= DRAW_EFFECT;
478 add_call(sequences, RENDERER_ID, &entry);
479 return S_OK;
482 static HRESULT WINAPI testrenderer_DrawUnderline(IDWriteTextRenderer *iface,
483 void *client_drawingcontext,
484 FLOAT baselineOriginX,
485 FLOAT baselineOriginY,
486 DWRITE_UNDERLINE const* underline,
487 IUnknown *effect)
489 struct drawcall_entry entry;
490 entry.kind = DRAW_UNDERLINE;
491 if (effect)
492 entry.kind |= DRAW_EFFECT;
493 add_call(sequences, RENDERER_ID, &entry);
494 return S_OK;
497 static HRESULT WINAPI testrenderer_DrawStrikethrough(IDWriteTextRenderer *iface,
498 void *client_drawingcontext,
499 FLOAT baselineOriginX,
500 FLOAT baselineOriginY,
501 DWRITE_STRIKETHROUGH const* strikethrough,
502 IUnknown *effect)
504 struct drawcall_entry entry;
505 entry.kind = DRAW_STRIKETHROUGH;
506 if (effect)
507 entry.kind |= DRAW_EFFECT;
508 add_call(sequences, RENDERER_ID, &entry);
509 return S_OK;
512 static HRESULT WINAPI testrenderer_DrawInlineObject(IDWriteTextRenderer *iface,
513 void *client_drawingcontext,
514 FLOAT originX,
515 FLOAT originY,
516 IDWriteInlineObject *object,
517 BOOL is_sideways,
518 BOOL is_rtl,
519 IUnknown *effect)
521 struct drawcall_entry entry;
522 entry.kind = DRAW_INLINE;
523 if (effect)
524 entry.kind |= DRAW_EFFECT;
525 add_call(sequences, RENDERER_ID, &entry);
526 return S_OK;
529 static const IDWriteTextRendererVtbl testrenderervtbl = {
530 testrenderer_QI,
531 testrenderer_AddRef,
532 testrenderer_Release,
533 testrenderer_IsPixelSnappingDisabled,
534 testrenderer_GetCurrentTransform,
535 testrenderer_GetPixelsPerDip,
536 testrenderer_DrawGlyphRun,
537 testrenderer_DrawUnderline,
538 testrenderer_DrawStrikethrough,
539 testrenderer_DrawInlineObject
542 static IDWriteTextRenderer testrenderer = { &testrenderervtbl };
544 /* test IDWriteInlineObject */
545 static HRESULT WINAPI testinlineobj_QI(IDWriteInlineObject *iface, REFIID riid, void **obj)
547 if (IsEqualIID(riid, &IID_IDWriteInlineObject) || IsEqualIID(riid, &IID_IUnknown)) {
548 *obj = iface;
549 IDWriteInlineObject_AddRef(iface);
550 return S_OK;
553 *obj = NULL;
554 return E_NOINTERFACE;
557 static ULONG WINAPI testinlineobj_AddRef(IDWriteInlineObject *iface)
559 return 2;
562 static ULONG WINAPI testinlineobj_Release(IDWriteInlineObject *iface)
564 return 1;
567 static HRESULT WINAPI testinlineobj_Draw(IDWriteInlineObject *iface,
568 void* client_drawingontext, IDWriteTextRenderer* renderer,
569 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *drawing_effect)
571 ok(0, "unexpected call\n");
572 return E_NOTIMPL;
575 static HRESULT WINAPI testinlineobj_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
577 metrics->width = 123.0;
578 return 0x8faecafe;
581 static HRESULT WINAPI testinlineobj_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
583 ok(0, "unexpected call\n");
584 return E_NOTIMPL;
587 static HRESULT WINAPI testinlineobj_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
588 DWRITE_BREAK_CONDITION *after)
590 *before = *after = DWRITE_BREAK_CONDITION_MUST_BREAK;
591 return 0x8feacafe;
594 static HRESULT WINAPI testinlineobj2_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
595 DWRITE_BREAK_CONDITION *after)
597 *before = *after = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
598 return S_OK;
601 static IDWriteInlineObjectVtbl testinlineobjvtbl = {
602 testinlineobj_QI,
603 testinlineobj_AddRef,
604 testinlineobj_Release,
605 testinlineobj_Draw,
606 testinlineobj_GetMetrics,
607 testinlineobj_GetOverhangMetrics,
608 testinlineobj_GetBreakConditions
611 static IDWriteInlineObjectVtbl testinlineobjvtbl2 = {
612 testinlineobj_QI,
613 testinlineobj_AddRef,
614 testinlineobj_Release,
615 testinlineobj_Draw,
616 testinlineobj_GetMetrics,
617 testinlineobj_GetOverhangMetrics,
618 testinlineobj2_GetBreakConditions
621 static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl };
622 static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
623 static IDWriteInlineObject testinlineobj3 = { &testinlineobjvtbl2 };
625 static HRESULT WINAPI testeffect_QI(IUnknown *iface, REFIID riid, void **obj)
627 if (IsEqualIID(riid, &IID_IUnknown)) {
628 *obj = iface;
629 IUnknown_AddRef(iface);
630 return S_OK;
633 *obj = NULL;
634 return E_NOINTERFACE;
637 static ULONG WINAPI testeffect_AddRef(IUnknown *iface)
639 return 2;
642 static ULONG WINAPI testeffect_Release(IUnknown *iface)
644 return 1;
647 static const IUnknownVtbl testeffectvtbl = {
648 testeffect_QI,
649 testeffect_AddRef,
650 testeffect_Release
653 static IUnknown testeffect = { &testeffectvtbl };
655 static void test_CreateTextLayout(void)
657 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
658 IDWriteTextLayout2 *layout2;
659 IDWriteTextLayout *layout;
660 IDWriteTextFormat *format;
661 IDWriteFactory *factory;
662 HRESULT hr;
664 factory = create_factory();
666 hr = IDWriteFactory_CreateTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, &layout);
667 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
669 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 0.0, &layout);
670 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
672 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1.0, 0.0, &layout);
673 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
675 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 1.0, &layout);
676 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
678 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, &layout);
679 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
681 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
682 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
683 ok(hr == S_OK, "got 0x%08x\n", hr);
685 EXPECT_REF(format, 1);
686 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 1000.0, 1000.0, &layout);
687 ok(hr == S_OK, "got 0x%08x\n", hr);
688 EXPECT_REF(format, 1);
690 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
691 if (hr == S_OK) {
692 IDWriteTextLayout1 *layout1;
693 IDWriteTextFormat1 *format1;
694 IDWriteTextFormat *format;
696 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextLayout1, (void**)&layout1);
697 ok(hr == S_OK, "got 0x%08x\n", hr);
698 IDWriteTextLayout1_Release(layout1);
700 EXPECT_REF(layout2, 2);
701 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
702 ok(hr == S_OK, "got 0x%08x\n", hr);
703 EXPECT_REF(layout2, 3);
705 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat, (void**)&format);
706 ok(hr == S_OK, "got 0x%08x\n", hr);
707 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
708 ok(format != (IDWriteTextFormat*)layout2, "got %p, %p\n", format, layout2);
709 EXPECT_REF(layout2, 4);
711 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextLayout1, (void**)&layout1);
712 ok(hr == S_OK, "got 0x%08x\n", hr);
713 IDWriteTextLayout1_Release(layout1);
715 IDWriteTextFormat1_Release(format1);
716 IDWriteTextFormat_Release(format);
718 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
719 ok(hr == S_OK, "got 0x%08x\n", hr);
720 EXPECT_REF(layout2, 3);
722 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format);
723 ok(hr == S_OK, "got 0x%08x\n", hr);
724 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
725 EXPECT_REF(layout2, 4);
727 IDWriteTextFormat1_Release(format1);
728 IDWriteTextFormat_Release(format);
729 IDWriteTextLayout2_Release(layout2);
731 else
732 win_skip("IDWriteTextLayout2 is not supported.\n");
734 IDWriteTextLayout_Release(layout);
735 IDWriteTextFormat_Release(format);
736 IDWriteFactory_Release(factory);
739 static void test_CreateGdiCompatibleTextLayout(void)
741 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
742 IDWriteTextLayout *layout;
743 IDWriteTextFormat *format;
744 IDWriteFactory *factory;
745 FLOAT dimension;
746 HRESULT hr;
748 factory = create_factory();
750 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
751 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
753 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
754 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
756 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 0.0, NULL, FALSE, &layout);
757 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
759 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 1.0, NULL, FALSE, &layout);
760 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
762 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, 1.0, NULL, FALSE, &layout);
763 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
765 /* create with text format */
766 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
767 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
768 ok(hr == S_OK, "got 0x%08x\n", hr);
769 EXPECT_REF(format, 1);
771 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
772 ok(hr == S_OK, "got 0x%08x\n", hr);
773 EXPECT_REF(format, 1);
774 EXPECT_REF(layout, 1);
776 IDWriteTextLayout_AddRef(layout);
777 EXPECT_REF(format, 1);
778 EXPECT_REF(layout, 2);
779 IDWriteTextLayout_Release(layout);
780 IDWriteTextLayout_Release(layout);
782 /* zero length string is okay */
783 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
784 ok(hr == S_OK, "got 0x%08x\n", hr);
786 dimension = IDWriteTextLayout_GetMaxWidth(layout);
787 ok(dimension == 100.0, "got %f\n", dimension);
789 dimension = IDWriteTextLayout_GetMaxHeight(layout);
790 ok(dimension == 100.0, "got %f\n", dimension);
792 IDWriteTextLayout_Release(layout);
793 IDWriteTextFormat_Release(format);
794 IDWriteFactory_Release(factory);
797 static void test_CreateTextFormat(void)
799 IDWriteFontCollection *collection, *syscoll;
800 DWRITE_PARAGRAPH_ALIGNMENT paralign;
801 DWRITE_READING_DIRECTION readdir;
802 DWRITE_WORD_WRAPPING wrapping;
803 DWRITE_TEXT_ALIGNMENT align;
804 DWRITE_FLOW_DIRECTION flow;
805 DWRITE_LINE_SPACING_METHOD method;
806 DWRITE_TRIMMING trimming;
807 IDWriteTextFormat *format;
808 FLOAT spacing, baseline;
809 IDWriteInlineObject *trimmingsign;
810 IDWriteFactory *factory;
811 HRESULT hr;
813 factory = create_factory();
815 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
816 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
817 ok(hr == S_OK, "got 0x%08x\n", hr);
819 if (0) /* crashes on native */
820 hr = IDWriteTextFormat_GetFontCollection(format, NULL);
822 collection = NULL;
823 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
824 ok(hr == S_OK, "got 0x%08x\n", hr);
825 ok(collection != NULL, "got %p\n", collection);
827 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
828 ok(hr == S_OK, "got 0x%08x\n", hr);
829 ok(collection == syscoll, "got %p, was %p\n", syscoll, collection);
830 IDWriteFontCollection_Release(syscoll);
831 IDWriteFontCollection_Release(collection);
833 /* default format properties */
834 align = IDWriteTextFormat_GetTextAlignment(format);
835 ok(align == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", align);
837 paralign = IDWriteTextFormat_GetParagraphAlignment(format);
838 ok(paralign == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", paralign);
840 wrapping = IDWriteTextFormat_GetWordWrapping(format);
841 ok(wrapping == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", wrapping);
843 readdir = IDWriteTextFormat_GetReadingDirection(format);
844 ok(readdir == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", readdir);
846 flow = IDWriteTextFormat_GetFlowDirection(format);
847 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
849 hr = IDWriteTextFormat_GetLineSpacing(format, &method, &spacing, &baseline);
850 ok(hr == S_OK, "got 0x%08x\n", hr);
851 ok(spacing == 0.0, "got %f\n", spacing);
852 ok(baseline == 0.0, "got %f\n", baseline);
853 ok(method == DWRITE_LINE_SPACING_METHOD_DEFAULT, "got %d\n", method);
855 trimming.granularity = DWRITE_TRIMMING_GRANULARITY_WORD;
856 trimming.delimiter = 10;
857 trimming.delimiterCount = 10;
858 trimmingsign = (void*)0xdeadbeef;
859 hr = IDWriteTextFormat_GetTrimming(format, &trimming, &trimmingsign);
860 ok(hr == S_OK, "got 0x%08x\n", hr);
861 ok(trimming.granularity == DWRITE_TRIMMING_GRANULARITY_NONE, "got %d\n", trimming.granularity);
862 ok(trimming.delimiter == 0, "got %d\n", trimming.delimiter);
863 ok(trimming.delimiterCount == 0, "got %d\n", trimming.delimiterCount);
864 ok(trimmingsign == NULL, "got %p\n", trimmingsign);
866 /* setters */
867 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING);
868 ok(hr == S_OK, "got 0x%08x\n", hr);
870 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_JUSTIFIED+1);
871 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
873 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
874 ok(hr == S_OK, "got 0x%08x\n", hr);
876 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_CENTER+1);
877 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
879 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_WRAP);
880 ok(hr == S_OK, "got 0x%08x\n", hr);
882 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_CHARACTER+1);
883 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
885 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
886 ok(hr == S_OK, "got 0x%08x\n", hr);
888 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
889 ok(hr == S_OK, "got 0x%08x\n", hr);
891 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0, 0.0);
892 ok(hr == S_OK, "got 0x%08x\n", hr);
894 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0, -10.0);
895 ok(hr == S_OK, "got 0x%08x\n", hr);
897 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, -10.0, 0.0);
898 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
900 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_UNIFORM+1, 0.0, 0.0);
901 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
903 hr = IDWriteTextFormat_SetTrimming(format, &trimming, NULL);
904 ok(hr == S_OK, "got 0x%08x\n", hr);
906 IDWriteTextFormat_Release(format);
907 IDWriteFactory_Release(factory);
910 static void test_GetLocaleName(void)
912 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
913 static const WCHAR ruW[] = {'r','u',0};
914 IDWriteTextLayout *layout;
915 IDWriteTextFormat *format, *format2;
916 IDWriteFactory *factory;
917 WCHAR buff[10];
918 UINT32 len;
919 HRESULT hr;
921 factory = create_factory();
923 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
924 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
925 ok(hr == S_OK, "got 0x%08x\n", hr);
927 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
928 ok(hr == S_OK, "got 0x%08x\n", hr);
930 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format2);
931 ok(hr == S_OK, "got 0x%08x\n", hr);
933 len = IDWriteTextFormat_GetLocaleNameLength(format2);
934 ok(len == 2, "got %u\n", len);
935 len = IDWriteTextFormat_GetLocaleNameLength(format);
936 ok(len == 2, "got %u\n", len);
937 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len);
938 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
939 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len+1);
940 ok(hr == S_OK, "got 0x%08x\n", hr);
941 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
942 hr = IDWriteTextFormat_GetLocaleName(format, buff, len);
943 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
944 hr = IDWriteTextFormat_GetLocaleName(format, buff, len+1);
945 ok(hr == S_OK, "got 0x%08x\n", hr);
946 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
948 IDWriteTextLayout_Release(layout);
949 IDWriteTextFormat_Release(format);
950 IDWriteTextFormat_Release(format2);
951 IDWriteFactory_Release(factory);
954 static const struct drawcall_entry drawellipsis_seq[] = {
955 { DRAW_GLYPHRUN, {0x2026, 0} },
956 { DRAW_LAST_KIND }
959 static void test_CreateEllipsisTrimmingSign(void)
961 DWRITE_BREAK_CONDITION before, after;
962 IDWriteTextFormat *format;
963 IDWriteInlineObject *sign;
964 IDWriteFactory *factory;
965 IUnknown *unk;
966 HRESULT hr;
968 factory = create_factory();
970 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
971 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
972 ok(hr == S_OK, "got 0x%08x\n", hr);
974 EXPECT_REF(format, 1);
975 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
976 ok(hr == S_OK, "got 0x%08x\n", hr);
977 EXPECT_REF(format, 1);
979 hr = IDWriteInlineObject_QueryInterface(sign, &IID_IDWriteTextLayout, (void**)&unk);
980 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
982 if (0) /* crashes on native */
983 hr = IDWriteInlineObject_GetBreakConditions(sign, NULL, NULL);
985 before = after = DWRITE_BREAK_CONDITION_CAN_BREAK;
986 hr = IDWriteInlineObject_GetBreakConditions(sign, &before, &after);
987 ok(hr == S_OK, "got 0x%08x\n", hr);
988 ok(before == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", before);
989 ok(after == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", after);
991 /* Draw tests */
992 flush_sequence(sequences, RENDERER_ID);
993 hr = IDWriteInlineObject_Draw(sign, NULL, &testrenderer, 0.0, 0.0, FALSE, FALSE, NULL);
994 ok(hr == S_OK, "got 0x%08x\n", hr);
995 ok_sequence(sequences, RENDERER_ID, drawellipsis_seq, "ellipsis sign draw test", FALSE);
996 IDWriteInlineObject_Release(sign);
998 /* non-orthogonal flow/reading combination */
999 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
1000 ok(hr == S_OK, "got 0x%08x\n", hr);
1002 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT);
1003 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* vista, win7 */, "got 0x%08x\n", hr);
1004 if (hr == S_OK) {
1005 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
1006 ok(hr == DWRITE_E_FLOWDIRECTIONCONFLICTS, "got 0x%08x\n", hr);
1009 IDWriteTextFormat_Release(format);
1010 IDWriteFactory_Release(factory);
1013 static void test_fontweight(void)
1015 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1016 static const WCHAR ruW[] = {'r','u',0};
1017 IDWriteTextFormat *format, *fmt2;
1018 IDWriteTextLayout *layout;
1019 DWRITE_FONT_WEIGHT weight;
1020 DWRITE_TEXT_RANGE range;
1021 IDWriteFactory *factory;
1022 FLOAT size;
1023 HRESULT hr;
1025 factory = create_factory();
1027 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1028 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1029 ok(hr == S_OK, "got 0x%08x\n", hr);
1031 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1032 ok(hr == S_OK, "got 0x%08x\n", hr);
1034 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&fmt2);
1035 ok(hr == S_OK, "got 0x%08x\n", hr);
1037 weight = IDWriteTextFormat_GetFontWeight(fmt2);
1038 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
1040 range.startPosition = range.length = 0;
1041 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1042 ok(hr == S_OK, "got 0x%08x\n", hr);
1043 ok(range.startPosition == 0 && range.length == ~0u, "got %u, %u\n", range.startPosition, range.length);
1045 range.startPosition = 0;
1046 range.length = 6;
1047 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_NORMAL, range);
1048 ok(hr == S_OK, "got 0x%08x\n", hr);
1050 range.startPosition = range.length = 0;
1051 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1052 ok(hr == S_OK, "got 0x%08x\n", hr);
1053 ok(range.startPosition == 0 && range.length == 6, "got %u, %u\n", range.startPosition, range.length);
1055 /* IDWriteTextFormat methods output doesn't reflect layout changes */
1056 weight = IDWriteTextFormat_GetFontWeight(fmt2);
1057 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
1059 range.length = 0;
1060 weight = DWRITE_FONT_WEIGHT_BOLD;
1061 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1062 ok(hr == S_OK, "got 0x%08x\n", hr);
1063 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
1064 ok(range.length == 6, "got %d\n", range.length);
1066 size = IDWriteTextLayout_GetMaxWidth(layout);
1067 ok(size == 100.0, "got %.2f\n", size);
1069 hr = IDWriteTextLayout_SetMaxWidth(layout, 0.0);
1070 ok(hr == S_OK, "got 0x%08x\n", hr);
1072 size = IDWriteTextLayout_GetMaxWidth(layout);
1073 ok(size == 0.0, "got %.2f\n", size);
1075 hr = IDWriteTextLayout_SetMaxWidth(layout, -1.0);
1076 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1078 size = IDWriteTextLayout_GetMaxWidth(layout);
1079 ok(size == 0.0, "got %.2f\n", size);
1081 hr = IDWriteTextLayout_SetMaxWidth(layout, 100.0);
1082 ok(hr == S_OK, "got 0x%08x\n", hr);
1084 size = IDWriteTextLayout_GetMaxWidth(layout);
1085 ok(size == 100.0, "got %.2f\n", size);
1087 size = IDWriteTextLayout_GetMaxHeight(layout);
1088 ok(size == 100.0, "got %.2f\n", size);
1090 hr = IDWriteTextLayout_SetMaxHeight(layout, 0.0);
1091 ok(hr == S_OK, "got 0x%08x\n", hr);
1093 size = IDWriteTextLayout_GetMaxHeight(layout);
1094 ok(size == 0.0, "got %.2f\n", size);
1096 hr = IDWriteTextLayout_SetMaxHeight(layout, -1.0);
1097 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1099 size = IDWriteTextLayout_GetMaxHeight(layout);
1100 ok(size == 0.0, "got %.2f\n", size);
1102 hr = IDWriteTextLayout_SetMaxHeight(layout, 100.0);
1103 ok(hr == S_OK, "got 0x%08x\n", hr);
1105 size = IDWriteTextLayout_GetMaxHeight(layout);
1106 ok(size == 100.0, "got %.2f\n", size);
1108 IDWriteTextLayout_Release(layout);
1109 IDWriteTextFormat_Release(fmt2);
1110 IDWriteTextFormat_Release(format);
1111 IDWriteFactory_Release(factory);
1114 static void test_SetInlineObject(void)
1116 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1117 static const WCHAR ruW[] = {'r','u',0};
1119 IDWriteInlineObject *inlineobj, *inlineobj2, *inlinetest;
1120 IDWriteTextFormat *format;
1121 IDWriteTextLayout *layout;
1122 DWRITE_TEXT_RANGE range, r2;
1123 IDWriteFactory *factory;
1124 HRESULT hr;
1126 factory = create_factory();
1128 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1129 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1130 ok(hr == S_OK, "got 0x%08x\n", hr);
1132 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1133 ok(hr == S_OK, "got 0x%08x\n", hr);
1135 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1136 ok(hr == S_OK, "got 0x%08x\n", hr);
1138 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj2);
1139 ok(hr == S_OK, "got 0x%08x\n", hr);
1141 EXPECT_REF(inlineobj, 1);
1142 EXPECT_REF(inlineobj2, 1);
1144 inlinetest = (void*)0x1;
1145 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, NULL);
1146 ok(hr == S_OK, "got 0x%08x\n", hr);
1147 ok(inlinetest == NULL, "got %p\n", inlinetest);
1149 range.startPosition = 0;
1150 range.length = 2;
1151 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1152 ok(hr == S_OK, "got 0x%08x\n", hr);
1154 EXPECT_REF(inlineobj, 2);
1156 inlinetest = (void*)0x1;
1157 hr = IDWriteTextLayout_GetInlineObject(layout, 2, &inlinetest, NULL);
1158 ok(hr == S_OK, "got 0x%08x\n", hr);
1159 ok(inlinetest == NULL, "got %p\n", inlinetest);
1161 inlinetest = NULL;
1162 r2.startPosition = r2.length = 100;
1163 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1164 ok(hr == S_OK, "got 0x%08x\n", hr);
1165 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1166 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1167 IDWriteInlineObject_Release(inlinetest);
1169 EXPECT_REF(inlineobj, 2);
1171 /* get from somewhere inside a range */
1172 inlinetest = NULL;
1173 r2.startPosition = r2.length = 100;
1174 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1175 ok(hr == S_OK, "got 0x%08x\n", hr);
1176 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1177 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1178 IDWriteInlineObject_Release(inlinetest);
1180 EXPECT_REF(inlineobj, 2);
1182 range.startPosition = 1;
1183 range.length = 1;
1184 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj2, range);
1185 ok(hr == S_OK, "got 0x%08x\n", hr);
1187 inlinetest = NULL;
1188 r2.startPosition = r2.length = 100;
1189 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1190 ok(hr == S_OK, "got 0x%08x\n", hr);
1191 ok(inlinetest == inlineobj2, "got %p\n", inlinetest);
1192 ok(r2.startPosition == 1 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1193 IDWriteInlineObject_Release(inlinetest);
1195 EXPECT_REF(inlineobj, 2);
1196 EXPECT_REF(inlineobj2, 2);
1198 inlinetest = NULL;
1199 r2.startPosition = r2.length = 100;
1200 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1201 ok(hr == S_OK, "got 0x%08x\n", hr);
1202 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1203 ok(r2.startPosition == 0 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1204 IDWriteInlineObject_Release(inlinetest);
1206 EXPECT_REF(inlineobj, 2);
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 r2.startPosition = r2.length = 100;
1214 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1215 ok(hr == S_OK, "got 0x%08x\n", hr);
1216 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1217 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1218 IDWriteInlineObject_Release(inlinetest);
1220 EXPECT_REF(inlineobj, 2);
1222 range.startPosition = 1;
1223 range.length = 2;
1224 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1225 ok(hr == S_OK, "got 0x%08x\n", hr);
1227 EXPECT_REF(inlineobj, 2);
1229 r2.startPosition = r2.length = 100;
1230 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1231 ok(hr == S_OK, "got 0x%08x\n", hr);
1232 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1233 ok(r2.startPosition == 0 && r2.length == 3, "got %d, %d\n", r2.startPosition, r2.length);
1234 IDWriteInlineObject_Release(inlinetest);
1236 EXPECT_REF(inlineobj, 2);
1237 EXPECT_REF(inlineobj2, 1);
1239 IDWriteTextLayout_Release(layout);
1241 EXPECT_REF(inlineobj, 1);
1243 IDWriteInlineObject_Release(inlineobj);
1244 IDWriteInlineObject_Release(inlineobj2);
1245 IDWriteTextFormat_Release(format);
1246 IDWriteFactory_Release(factory);
1249 /* drawing calls sequence doesn't depend on run order, instead all runs are
1250 drawn first, inline objects next and then underline/strikes */
1251 static const struct drawcall_entry draw_seq[] = {
1252 { DRAW_GLYPHRUN, {'s',0} },
1253 { DRAW_GLYPHRUN, {'r','i',0} },
1254 { DRAW_GLYPHRUN|DRAW_EFFECT, {'n',0} },
1255 { DRAW_GLYPHRUN, {'g',0} },
1256 { DRAW_INLINE },
1257 { DRAW_UNDERLINE },
1258 { DRAW_STRIKETHROUGH },
1259 { DRAW_LAST_KIND }
1262 static const struct drawcall_entry draw_seq2[] = {
1263 { DRAW_GLYPHRUN, {'s',0} },
1264 { DRAW_GLYPHRUN, {'t',0} },
1265 { DRAW_GLYPHRUN, {'r',0} },
1266 { DRAW_GLYPHRUN, {'i',0} },
1267 { DRAW_GLYPHRUN, {'n',0} },
1268 { DRAW_GLYPHRUN, {'g',0} },
1269 { DRAW_LAST_KIND }
1272 static const struct drawcall_entry draw_seq3[] = {
1273 { DRAW_GLYPHRUN },
1274 { DRAW_GLYPHRUN, {'a','b',0} },
1275 { DRAW_LAST_KIND }
1278 static const struct drawcall_entry draw_seq4[] = {
1279 { DRAW_GLYPHRUN, {'s','t','r',0} },
1280 { DRAW_GLYPHRUN, {'i','n','g',0} },
1281 { DRAW_STRIKETHROUGH },
1282 { DRAW_LAST_KIND }
1285 static const struct drawcall_entry draw_seq5[] = {
1286 { DRAW_GLYPHRUN, {'s','t',0} },
1287 { DRAW_GLYPHRUN, {'r','i',0} },
1288 { DRAW_GLYPHRUN, {'n','g',0} },
1289 { DRAW_STRIKETHROUGH },
1290 { DRAW_LAST_KIND }
1293 static const struct drawcall_entry empty_seq[] = {
1294 { DRAW_LAST_KIND }
1297 static const struct drawcall_entry draw_single_run_seq[] = {
1298 { DRAW_GLYPHRUN, {'s','t','r','i','n','g',0} },
1299 { DRAW_LAST_KIND }
1302 static void test_Draw(void)
1304 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1305 static const WCHAR str2W[] = {0x202a,0x202c,'a','b',0};
1306 static const WCHAR ruW[] = {'r','u',0};
1307 IDWriteInlineObject *inlineobj;
1308 IDWriteTextFormat *format;
1309 IDWriteTextLayout *layout;
1310 DWRITE_TEXT_RANGE range;
1311 IDWriteFactory *factory;
1312 DWRITE_MATRIX m;
1313 HRESULT hr;
1315 factory = create_factory();
1317 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1318 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1319 ok(hr == S_OK, "got 0x%08x\n", hr);
1321 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 100.0, 100.0, &layout);
1322 ok(hr == S_OK, "got 0x%08x\n", hr);
1324 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1325 ok(hr == S_OK, "got 0x%08x\n", hr);
1327 range.startPosition = 5;
1328 range.length = 1;
1329 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1330 ok(hr == S_OK, "got 0x%08x\n", hr);
1332 range.startPosition = 1;
1333 range.length = 1;
1334 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1335 ok(hr == S_OK, "got 0x%08x\n", hr);
1337 range.startPosition = 4;
1338 range.length = 1;
1339 hr = IDWriteTextLayout_SetDrawingEffect(layout, (IUnknown*)inlineobj, range);
1340 ok(hr == S_OK, "got 0x%08x\n", hr);
1342 range.startPosition = 0;
1343 range.length = 1;
1344 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
1345 ok(hr == S_OK, "got 0x%08x\n", hr);
1347 flush_sequence(sequences, RENDERER_ID);
1348 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1349 ok(hr == S_OK, "got 0x%08x\n", hr);
1350 ok_sequence(sequences, RENDERER_ID, draw_seq, "draw test", TRUE);
1351 IDWriteTextLayout_Release(layout);
1353 /* with reduced width DrawGlyphRun() is called for every line */
1354 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 5.0, 100.0, &layout);
1355 ok(hr == S_OK, "got 0x%08x\n", hr);
1356 flush_sequence(sequences, RENDERER_ID);
1357 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1358 ok(hr == S_OK, "got 0x%08x\n", hr);
1359 ok_sequence(sequences, RENDERER_ID, draw_seq2, "draw test 2", TRUE);
1360 IDWriteTextLayout_Release(layout);
1362 /* string with control characters */
1363 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 100.0, &layout);
1364 ok(hr == S_OK, "got 0x%08x\n", hr);
1365 flush_sequence(sequences, RENDERER_ID);
1366 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1367 ok(hr == S_OK, "got 0x%08x\n", hr);
1368 ok_sequence(sequences, RENDERER_ID, draw_seq3, "draw test 3", TRUE);
1369 IDWriteTextLayout_Release(layout);
1371 /* strikethrough splits ranges from renderer point of view, but doesn't break
1372 shaping */
1373 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1374 ok(hr == S_OK, "got 0x%08x\n", hr);
1375 flush_sequence(sequences, RENDERER_ID);
1377 range.startPosition = 0;
1378 range.length = 3;
1379 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1380 ok(hr == S_OK, "got 0x%08x\n", hr);
1382 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1383 ok(hr == S_OK, "got 0x%08x\n", hr);
1384 ok_sequence(sequences, RENDERER_ID, draw_seq4, "draw test 4", FALSE);
1385 IDWriteTextLayout_Release(layout);
1387 /* strikethrough somewhere in the middle */
1388 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1389 ok(hr == S_OK, "got 0x%08x\n", hr);
1390 flush_sequence(sequences, RENDERER_ID);
1392 range.startPosition = 2;
1393 range.length = 2;
1394 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1395 ok(hr == S_OK, "got 0x%08x\n", hr);
1397 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1398 ok(hr == S_OK, "got 0x%08x\n", hr);
1399 ok_sequence(sequences, RENDERER_ID, draw_seq5, "draw test 5", FALSE);
1400 IDWriteTextLayout_Release(layout);
1402 /* empty string */
1403 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 500.0, 100.0, &layout);
1404 ok(hr == S_OK, "got 0x%08x\n", hr);
1406 flush_sequence(sequences, RENDERER_ID);
1407 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1408 ok(hr == S_OK, "got 0x%08x\n", hr);
1409 ok_sequence(sequences, RENDERER_ID, empty_seq, "draw test 6", FALSE);
1410 IDWriteTextLayout_Release(layout);
1412 /* different parameter combinations with gdi-compatible layout */
1413 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, TRUE, &layout);
1414 ok(hr == S_OK, "got 0x%08x\n", hr);
1415 flush_sequence(sequences, RENDERER_ID);
1416 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1417 ok(hr == S_OK, "got 0x%08x\n", hr);
1418 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 7", FALSE);
1419 IDWriteTextLayout_Release(layout);
1421 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1422 ok(hr == S_OK, "got 0x%08x\n", hr);
1423 flush_sequence(sequences, RENDERER_ID);
1424 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1425 ok(hr == S_OK, "got 0x%08x\n", hr);
1426 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 8", FALSE);
1427 IDWriteTextLayout_Release(layout);
1429 m.m11 = m.m22 = 2.0;
1430 m.m12 = m.m21 = m.dx = m.dy = 0.0;
1431 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, &m, TRUE, &layout);
1432 ok(hr == S_OK, "got 0x%08x\n", hr);
1433 flush_sequence(sequences, RENDERER_ID);
1434 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1435 ok(hr == S_OK, "got 0x%08x\n", hr);
1436 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 9", FALSE);
1437 IDWriteTextLayout_Release(layout);
1439 m.m11 = m.m22 = 2.0;
1440 m.m12 = m.m21 = m.dx = m.dy = 0.0;
1441 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, &m, FALSE, &layout);
1442 ok(hr == S_OK, "got 0x%08x\n", hr);
1443 flush_sequence(sequences, RENDERER_ID);
1444 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1445 ok(hr == S_OK, "got 0x%08x\n", hr);
1446 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 10", FALSE);
1447 IDWriteTextLayout_Release(layout);
1449 IDWriteTextFormat_Release(format);
1450 IDWriteFactory_Release(factory);
1453 static void test_typography(void)
1455 DWRITE_FONT_FEATURE feature;
1456 IDWriteTypography *typography;
1457 IDWriteFactory *factory;
1458 UINT32 count;
1459 HRESULT hr;
1461 factory = create_factory();
1463 hr = IDWriteFactory_CreateTypography(factory, &typography);
1464 ok(hr == S_OK, "got 0x%08x\n", hr);
1466 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1467 feature.parameter = 1;
1468 hr = IDWriteTypography_AddFontFeature(typography, feature);
1469 ok(hr == S_OK, "got 0x%08x\n", hr);
1471 count = IDWriteTypography_GetFontFeatureCount(typography);
1472 ok(count == 1, "got %u\n", count);
1474 /* duplicated features work just fine */
1475 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1476 feature.parameter = 0;
1477 hr = IDWriteTypography_AddFontFeature(typography, feature);
1478 ok(hr == S_OK, "got 0x%08x\n", hr);
1480 count = IDWriteTypography_GetFontFeatureCount(typography);
1481 ok(count == 2, "got %u\n", count);
1483 memset(&feature, 0, sizeof(feature));
1484 hr = IDWriteTypography_GetFontFeature(typography, 0, &feature);
1485 ok(hr == S_OK, "got 0x%08x\n", hr);
1486 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1487 ok(feature.parameter == 1, "got %u\n", feature.parameter);
1489 memset(&feature, 0, sizeof(feature));
1490 hr = IDWriteTypography_GetFontFeature(typography, 1, &feature);
1491 ok(hr == S_OK, "got 0x%08x\n", hr);
1492 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1493 ok(feature.parameter == 0, "got %u\n", feature.parameter);
1495 hr = IDWriteTypography_GetFontFeature(typography, 2, &feature);
1496 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1498 IDWriteTypography_Release(typography);
1499 IDWriteFactory_Release(factory);
1502 static void test_GetClusterMetrics(void)
1504 static const WCHAR str3W[] = {0x2066,')',')',0x661,'(',0x627,')',0};
1505 static const WCHAR str2W[] = {0x202a,0x202c,'a',0};
1506 static const WCHAR strW[] = {'a','b','c','d',0};
1507 static const WCHAR str4W[] = {'a',' ',0};
1508 DWRITE_INLINE_OBJECT_METRICS inline_metrics;
1509 DWRITE_CLUSTER_METRICS metrics[4];
1510 IDWriteTextLayout1 *layout1;
1511 IDWriteInlineObject *trimm;
1512 IDWriteTextFormat *format;
1513 IDWriteTextLayout *layout;
1514 DWRITE_TEXT_RANGE range;
1515 IDWriteFactory *factory;
1516 UINT32 count, i;
1517 HRESULT hr;
1519 factory = create_factory();
1521 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1522 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1523 ok(hr == S_OK, "got 0x%08x\n", hr);
1525 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 7, format, 1000.0, 1000.0, &layout);
1526 ok(hr == S_OK, "got 0x%08x\n", hr);
1527 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1528 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1529 ok(count == 7, "got %u\n", count);
1530 IDWriteTextLayout_Release(layout);
1532 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1533 ok(hr == S_OK, "got 0x%08x\n", hr);
1535 count = 0;
1536 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1537 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1538 ok(count == 4, "got %u\n", count);
1540 /* check every cluster width */
1541 count = 0;
1542 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
1543 ok(hr == S_OK, "got 0x%08x\n", hr);
1544 ok(count == 4, "got %u\n", count);
1545 for (i = 0; i < count; i++) {
1546 ok(metrics[i].width > 0.0, "%u: got width %.2f\n", i, metrics[i].width);
1547 ok(metrics[i].length == 1, "%u: got length %u\n", i, metrics[i].length);
1550 /* apply spacing and check widths again */
1551 if (IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1) == S_OK) {
1552 DWRITE_CLUSTER_METRICS metrics2[4];
1553 FLOAT leading, trailing, min_advance;
1554 DWRITE_TEXT_RANGE r;
1556 leading = trailing = min_advance = 2.0;
1557 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 500, &leading, &trailing,
1558 &min_advance, &r);
1559 ok(hr == S_OK, "got 0x%08x\n", hr);
1560 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
1561 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
1562 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
1564 leading = trailing = min_advance = 2.0;
1565 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 0, &leading, &trailing,
1566 &min_advance, NULL);
1567 ok(hr == S_OK, "got 0x%08x\n", hr);
1568 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
1569 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
1571 r.startPosition = 0;
1572 r.length = 4;
1573 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 10.0, 15.0, 0.0, r);
1574 ok(hr == S_OK, "got 0x%08x\n", hr);
1576 count = 0;
1577 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics2, sizeof(metrics2)/sizeof(metrics2[0]), &count);
1578 ok(hr == S_OK, "got 0x%08x\n", hr);
1579 ok(count == 4, "got %u\n", count);
1580 for (i = 0; i < count; i++) {
1581 todo_wine
1582 ok(metrics2[i].width > metrics[i].width, "%u: got width %.2f, was %.2f\n", i, metrics2[i].width,
1583 metrics[i].width);
1584 ok(metrics2[i].length == 1, "%u: got length %u\n", i, metrics2[i].length);
1587 /* back to defaults */
1588 r.startPosition = 0;
1589 r.length = 4;
1590 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, 0.0, r);
1591 ok(hr == S_OK, "got 0x%08x\n", hr);
1593 /* negative advance limit */
1594 r.startPosition = 0;
1595 r.length = 4;
1596 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, -10.0, r);
1597 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1599 IDWriteTextLayout1_Release(layout1);
1601 else
1602 win_skip("IDWriteTextLayout1 is not supported, cluster spacing test skipped.\n");
1604 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &trimm);
1605 ok(hr == S_OK, "got 0x%08x\n", hr);
1607 range.startPosition = 0;
1608 range.length = 2;
1609 hr = IDWriteTextLayout_SetInlineObject(layout, trimm, range);
1610 ok(hr == S_OK, "got 0x%08x\n", hr);
1612 /* inline object takes a separate cluster, replaced codepoints number doesn't matter */
1613 count = 0;
1614 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1615 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1616 ok(count == 3, "got %u\n", count);
1618 count = 0;
1619 memset(&metrics, 0, sizeof(metrics));
1620 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
1621 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1622 ok(count == 3, "got %u\n", count);
1623 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
1625 hr = IDWriteInlineObject_GetMetrics(trimm, &inline_metrics);
1626 ok(hr == S_OK, "got 0x%08x\n", hr);
1627 todo_wine
1628 ok(inline_metrics.width > 0.0 && inline_metrics.width == metrics[0].width, "got %.2f, expected %.2f\n",
1629 inline_metrics.width, metrics[0].width);
1631 IDWriteTextLayout_Release(layout);
1633 /* text with non-visual control codes */
1634 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 3, format, 1000.0, 1000.0, &layout);
1635 ok(hr == S_OK, "got 0x%08x\n", hr);
1637 /* bidi control codes take a separate cluster */
1638 count = 0;
1639 memset(metrics, 0, sizeof(metrics));
1640 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1641 ok(hr == S_OK, "got 0x%08x\n", hr);
1642 ok(count == 3, "got %u\n", count);
1644 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1645 ok(metrics[0].length == 1, "got %d\n", metrics[0].length);
1646 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
1647 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1648 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1649 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1650 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1652 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
1653 ok(metrics[1].length == 1, "got %d\n", metrics[1].length);
1654 ok(metrics[1].canWrapLineAfter == 0, "got %d\n", metrics[1].canWrapLineAfter);
1655 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
1656 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
1657 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
1658 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
1660 ok(metrics[2].width > 0.0, "got %.2f\n", metrics[2].width);
1661 ok(metrics[2].length == 1, "got %d\n", metrics[2].length);
1662 ok(metrics[2].canWrapLineAfter == 1, "got %d\n", metrics[2].canWrapLineAfter);
1663 ok(metrics[2].isWhitespace == 0, "got %d\n", metrics[2].isWhitespace);
1664 ok(metrics[2].isNewline == 0, "got %d\n", metrics[2].isNewline);
1665 ok(metrics[2].isSoftHyphen == 0, "got %d\n", metrics[2].isSoftHyphen);
1666 ok(metrics[2].isRightToLeft == 0, "got %d\n", metrics[2].isRightToLeft);
1668 IDWriteTextLayout_Release(layout);
1670 /* single inline object that fails to report its metrics */
1671 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1672 ok(hr == S_OK, "got 0x%08x\n", hr);
1674 range.startPosition = 0;
1675 range.length = 4;
1676 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj, range);
1677 ok(hr == S_OK, "got 0x%08x\n", hr);
1679 count = 0;
1680 memset(metrics, 0, sizeof(metrics));
1681 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1682 ok(hr == S_OK, "got 0x%08x\n", hr);
1683 ok(count == 1, "got %u\n", count);
1685 /* object sets a width to 123.0, but returns failure from GetMetrics() */
1686 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1687 ok(metrics[0].length == 4, "got %d\n", metrics[0].length);
1688 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
1689 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1690 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1691 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1692 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1694 /* now set two inline object for [0,1] and [2,3], both fail to report break conditions */
1695 range.startPosition = 2;
1696 range.length = 2;
1697 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj2, range);
1698 ok(hr == S_OK, "got 0x%08x\n", hr);
1700 count = 0;
1701 memset(metrics, 0, sizeof(metrics));
1702 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1703 ok(hr == S_OK, "got 0x%08x\n", hr);
1704 ok(count == 2, "got %u\n", count);
1706 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1707 ok(metrics[0].length == 2, "got %d\n", metrics[0].length);
1708 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
1709 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1710 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1711 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1712 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1714 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
1715 ok(metrics[1].length == 2, "got %d\n", metrics[1].length);
1716 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
1717 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
1718 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
1719 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
1720 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
1722 IDWriteTextLayout_Release(layout);
1724 /* zero length string */
1725 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 1000.0, 1000.0, &layout);
1726 ok(hr == S_OK, "got 0x%08x\n", hr);
1728 count = 1;
1729 memset(metrics, 0, sizeof(metrics));
1730 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1731 ok(hr == S_OK, "got 0x%08x\n", hr);
1732 ok(count == 0, "got %u\n", count);
1733 IDWriteTextLayout_Release(layout);
1735 /* whitespace */
1736 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 2, format, 1000.0, 1000.0, &layout);
1737 ok(hr == S_OK, "got 0x%08x\n", hr);
1739 count = 0;
1740 memset(metrics, 0, sizeof(metrics));
1741 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 2, &count);
1742 ok(hr == S_OK, "got 0x%08x\n", hr);
1743 ok(count == 2, "got %u\n", count);
1744 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1745 ok(metrics[1].isWhitespace == 1, "got %d\n", metrics[1].isWhitespace);
1746 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
1747 IDWriteTextLayout_Release(layout);
1749 /* layout is fully covered by inline object with after condition DWRITE_BREAK_CONDITION_MAY_NOT_BREAK */
1750 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 2, format, 1000.0, 1000.0, &layout);
1751 ok(hr == S_OK, "got 0x%08x\n", hr);
1753 range.startPosition = 0;
1754 range.length = ~0u;
1755 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj3, range);
1756 ok(hr == S_OK, "got 0x%08x\n", hr);
1758 count = 0;
1759 memset(metrics, 0, sizeof(metrics));
1760 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 2, &count);
1761 ok(hr == S_OK, "got 0x%08x\n", hr);
1762 ok(count == 1, "got %u\n", count);
1763 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
1765 IDWriteTextLayout_Release(layout);
1767 IDWriteInlineObject_Release(trimm);
1768 IDWriteTextFormat_Release(format);
1769 IDWriteFactory_Release(factory);
1772 static void test_SetLocaleName(void)
1774 static const WCHAR strW[] = {'a','b','c','d',0};
1775 WCHAR buffW[LOCALE_NAME_MAX_LENGTH+sizeof(strW)/sizeof(WCHAR)];
1776 IDWriteTextFormat *format;
1777 IDWriteTextLayout *layout;
1778 DWRITE_TEXT_RANGE range;
1779 IDWriteFactory *factory;
1780 HRESULT hr;
1782 factory = create_factory();
1784 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1785 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1786 ok(hr == S_OK, "got 0x%08x\n", hr);
1788 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1789 ok(hr == S_OK, "got 0x%08x\n", hr);
1791 range.startPosition = 0;
1792 range.length = 1;
1793 hr = IDWriteTextLayout_SetLocaleName(layout, enusW, range);
1794 ok(hr == S_OK, "got 0x%08x\n", hr);
1796 hr = IDWriteTextLayout_SetLocaleName(layout, NULL, range);
1797 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1799 /* invalid locale name is allowed */
1800 hr = IDWriteTextLayout_SetLocaleName(layout, strW, range);
1801 ok(hr == S_OK, "got 0x%08x\n", hr);
1803 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 0, NULL);
1804 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1806 if (0) /* crashes on native */
1807 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 1, NULL);
1809 buffW[0] = 0;
1810 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), NULL);
1811 ok(hr == S_OK, "got 0x%08x\n", hr);
1812 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
1814 /* get with a shorter buffer */
1815 buffW[0] = 0xa;
1816 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, 1, NULL);
1817 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1818 ok(buffW[0] == 0, "got %x\n", buffW[0]);
1820 /* name is too long */
1821 lstrcpyW(buffW, strW);
1822 while (lstrlenW(buffW) <= LOCALE_NAME_MAX_LENGTH)
1823 lstrcatW(buffW, strW);
1825 range.startPosition = 0;
1826 range.length = 1;
1827 hr = IDWriteTextLayout_SetLocaleName(layout, buffW, range);
1828 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1830 buffW[0] = 0;
1831 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), NULL);
1832 ok(hr == S_OK, "got 0x%08x\n", hr);
1833 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
1835 IDWriteTextLayout_Release(layout);
1836 IDWriteTextFormat_Release(format);
1837 IDWriteFactory_Release(factory);
1840 static void test_SetPairKerning(void)
1842 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
1843 DWRITE_CLUSTER_METRICS clusters[4];
1844 IDWriteTextLayout1 *layout1;
1845 IDWriteTextFormat *format;
1846 IDWriteTextLayout *layout;
1847 DWRITE_TEXT_RANGE range;
1848 IDWriteFactory *factory;
1849 BOOL kerning;
1850 UINT32 count;
1851 HRESULT hr;
1853 factory = create_factory();
1855 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1856 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1857 ok(hr == S_OK, "got 0x%08x\n", hr);
1859 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1860 ok(hr == S_OK, "got 0x%08x\n", hr);
1861 IDWriteTextFormat_Release(format);
1863 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1);
1864 IDWriteTextLayout_Release(layout);
1866 if (hr != S_OK) {
1867 win_skip("SetPairKerning() is not supported.\n");
1868 IDWriteFactory_Release(factory);
1869 return;
1872 if (0) { /* crashes on native */
1873 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, NULL);
1874 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, &range);
1877 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, NULL);
1878 ok(hr == S_OK, "got 0x%08x\n", hr);
1880 range.startPosition = 0;
1881 range.length = 0;
1882 kerning = TRUE;
1883 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
1884 ok(hr == S_OK, "got 0x%08x\n", hr);
1885 ok(!kerning, "got %d\n", kerning);
1886 ok(range.length == ~0u, "got %u\n", range.length);
1888 count = 0;
1889 hr = IDWriteTextLayout1_GetClusterMetrics(layout1, clusters, 4, &count);
1890 ok(hr == S_OK, "got 0x%08x\n", hr);
1891 todo_wine
1892 ok(count == 3, "got %u\n", count);
1893 if (count == 3) {
1894 ok(clusters[0].length == 1, "got %u\n", clusters[0].length);
1895 ok(clusters[1].length == 2, "got %u\n", clusters[1].length);
1896 ok(clusters[2].length == 1, "got %u\n", clusters[2].length);
1898 /* pair kerning flag participates in itemization - combining characters
1899 breaks */
1900 range.startPosition = 0;
1901 range.length = 2;
1902 hr = IDWriteTextLayout1_SetPairKerning(layout1, 2, range);
1903 ok(hr == S_OK, "got 0x%08x\n", hr);
1905 kerning = FALSE;
1906 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
1907 ok(hr == S_OK, "got 0x%08x\n", hr);
1908 ok(kerning == TRUE, "got %d\n", kerning);
1910 count = 0;
1911 hr = IDWriteTextLayout1_GetClusterMetrics(layout1, clusters, 4, &count);
1912 ok(hr == S_OK, "got 0x%08x\n", hr);
1913 ok(count == 4, "got %u\n", count);
1914 ok(clusters[0].length == 1, "got %u\n", clusters[0].length);
1915 ok(clusters[1].length == 1, "got %u\n", clusters[1].length);
1916 ok(clusters[2].length == 1, "got %u\n", clusters[2].length);
1917 ok(clusters[3].length == 1, "got %u\n", clusters[3].length);
1919 IDWriteTextLayout1_Release(layout1);
1920 IDWriteFactory_Release(factory);
1923 static void test_SetVerticalGlyphOrientation(void)
1925 static const WCHAR strW[] = {'a','b','c','d',0};
1926 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation;
1927 IDWriteTextLayout2 *layout2;
1928 IDWriteTextFormat *format;
1929 IDWriteTextLayout *layout;
1930 IDWriteFactory *factory;
1931 HRESULT hr;
1933 factory = create_factory();
1935 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1936 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1937 ok(hr == S_OK, "got 0x%08x\n", hr);
1939 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1940 ok(hr == S_OK, "got 0x%08x\n", hr);
1941 IDWriteTextFormat_Release(format);
1943 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
1944 IDWriteTextLayout_Release(layout);
1946 if (hr != S_OK) {
1947 win_skip("SetVerticalGlyphOrientation() is not supported.\n");
1948 IDWriteFactory_Release(factory);
1949 return;
1952 orientation = IDWriteTextLayout2_GetVerticalGlyphOrientation(layout2);
1953 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT, "got %d\n", orientation);
1955 hr = IDWriteTextLayout2_SetVerticalGlyphOrientation(layout2, DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED+1);
1956 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1958 IDWriteTextLayout2_Release(layout2);
1959 IDWriteFactory_Release(factory);
1962 static void test_fallback(void)
1964 static const WCHAR strW[] = {'a','b','c','d',0};
1965 IDWriteFontFallback *fallback, *fallback2;
1966 IDWriteTextLayout2 *layout2;
1967 IDWriteTextFormat1 *format1;
1968 IDWriteTextFormat *format;
1969 IDWriteTextLayout *layout;
1970 IDWriteFactory2 *factory2;
1971 IDWriteFactory *factory;
1972 HRESULT hr;
1974 factory = create_factory();
1976 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1977 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1978 ok(hr == S_OK, "got 0x%08x\n", hr);
1980 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1981 ok(hr == S_OK, "got 0x%08x\n", hr);
1982 IDWriteTextFormat_Release(format);
1984 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
1985 IDWriteTextLayout_Release(layout);
1987 if (hr != S_OK) {
1988 win_skip("GetFontFallback() is not supported.\n");
1989 IDWriteFactory_Release(factory);
1990 return;
1993 if (0) /* crashes on native */
1994 hr = IDWriteTextLayout2_GetFontFallback(layout2, NULL);
1996 fallback = (void*)0xdeadbeef;
1997 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback);
1998 ok(hr == S_OK, "got 0x%08x\n", hr);
1999 ok(fallback == NULL, "got %p\n", fallback);
2001 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
2002 ok(hr == S_OK, "got 0x%08x\n", hr);
2004 fallback = (void*)0xdeadbeef;
2005 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback);
2006 ok(hr == S_OK, "got 0x%08x\n", hr);
2007 ok(fallback == NULL, "got %p\n", fallback);
2009 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
2010 ok(hr == S_OK, "got 0x%08x\n", hr);
2012 fallback = NULL;
2013 hr = IDWriteFactory2_GetSystemFontFallback(factory2, &fallback);
2014 todo_wine
2015 ok(hr == S_OK, "got 0x%08x\n", hr);
2016 if (hr == S_OK) {
2017 ok(fallback != NULL, "got %p\n", fallback);
2019 hr = IDWriteTextFormat1_SetFontFallback(format1, fallback);
2020 ok(hr == S_OK, "got 0x%08x\n", hr);
2022 fallback2 = (void*)0xdeadbeef;
2023 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback2);
2024 ok(hr == S_OK, "got 0x%08x\n", hr);
2025 ok(fallback2 == fallback, "got %p\n", fallback2);
2027 hr = IDWriteTextLayout2_SetFontFallback(layout2, NULL);
2028 ok(hr == S_OK, "got 0x%08x\n", hr);
2030 fallback2 = (void*)0xdeadbeef;
2031 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback2);
2032 ok(hr == S_OK, "got 0x%08x\n", hr);
2033 ok(fallback2 == NULL, "got %p\n", fallback2);
2035 IDWriteFontFallback_Release(fallback);
2037 IDWriteTextFormat1_Release(format1);
2038 IDWriteTextLayout2_Release(layout2);
2039 IDWriteFactory_Release(factory);
2042 static void test_DetermineMinWidth(void)
2044 static const WCHAR strW[] = {'a','b','c','d',0};
2045 IDWriteTextFormat *format;
2046 IDWriteTextLayout *layout;
2047 IDWriteFactory *factory;
2048 FLOAT minwidth;
2049 HRESULT hr;
2051 factory = create_factory();
2053 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2054 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2055 ok(hr == S_OK, "got 0x%08x\n", hr);
2057 hr = IDWriteFactory_CreateTextLayout(factory, strW, lstrlenW(strW), format, 1000.0, 1000.0, &layout);
2058 ok(hr == S_OK, "got 0x%08x\n", hr);
2060 hr = IDWriteTextLayout_DetermineMinWidth(layout, NULL);
2061 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2063 minwidth = 0.0;
2064 hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
2065 ok(hr == S_OK, "got 0x%08x\n", hr);
2066 ok(minwidth > 0.0, "got %.2f\n", minwidth);
2068 IDWriteTextLayout_Release(layout);
2069 IDWriteTextFormat_Release(format);
2070 IDWriteFactory_Release(factory);
2073 static void test_SetFontSize(void)
2075 static const WCHAR strW[] = {'a','b','c','d',0};
2076 IDWriteTextFormat *format;
2077 IDWriteTextLayout *layout;
2078 IDWriteFactory *factory;
2079 DWRITE_TEXT_RANGE r;
2080 FLOAT size;
2081 HRESULT hr;
2083 factory = create_factory();
2085 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2086 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2087 ok(hr == S_OK, "got 0x%08x\n", hr);
2089 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2090 ok(hr == S_OK, "got 0x%08x\n", hr);
2092 /* negative/zero size */
2093 r.startPosition = 1;
2094 r.length = 1;
2095 hr = IDWriteTextLayout_SetFontSize(layout, -15.0, r);
2096 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2098 hr = IDWriteTextLayout_SetFontSize(layout, 0.0, r);
2099 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2101 r.startPosition = 1;
2102 r.length = 0;
2103 size = 0.0;
2104 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
2105 ok(hr == S_OK, "got 0x%08x\n", hr);
2106 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2107 ok(size == 10.0, "got %.2f\n", size);
2109 r.startPosition = 1;
2110 r.length = 1;
2111 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
2112 ok(hr == S_OK, "got 0x%08x\n", hr);
2114 /* zero length range */
2115 r.startPosition = 1;
2116 r.length = 0;
2117 hr = IDWriteTextLayout_SetFontSize(layout, 123.0, r);
2118 ok(hr == S_OK, "got 0x%08x\n", hr);
2120 size = 0.0;
2121 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
2122 ok(hr == S_OK, "got 0x%08x\n", hr);
2123 ok(size == 15.0, "got %.2f\n", size);
2125 r.startPosition = 0;
2126 r.length = 4;
2127 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
2128 ok(hr == S_OK, "got 0x%08x\n", hr);
2130 size = 0.0;
2131 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
2132 ok(hr == S_OK, "got 0x%08x\n", hr);
2133 ok(size == 15.0, "got %.2f\n", size);
2135 size = 0.0;
2136 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
2137 ok(hr == S_OK, "got 0x%08x\n", hr);
2138 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2139 ok(size == 15.0, "got %.2f\n", size);
2141 size = 15.0;
2142 r.startPosition = r.length = 0;
2143 hr = IDWriteTextLayout_GetFontSize(layout, 20, &size, &r);
2144 ok(hr == S_OK, "got 0x%08x\n", hr);
2145 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2146 ok(size == 10.0, "got %.2f\n", size);
2148 r.startPosition = 100;
2149 r.length = 4;
2150 hr = IDWriteTextLayout_SetFontSize(layout, 25.0, r);
2151 ok(hr == S_OK, "got 0x%08x\n", hr);
2153 size = 15.0;
2154 r.startPosition = r.length = 0;
2155 hr = IDWriteTextLayout_GetFontSize(layout, 100, &size, &r);
2156 ok(hr == S_OK, "got 0x%08x\n", hr);
2157 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2158 ok(size == 25.0, "got %.2f\n", size);
2160 IDWriteTextLayout_Release(layout);
2161 IDWriteTextFormat_Release(format);
2162 IDWriteFactory_Release(factory);
2165 static void test_SetFontFamilyName(void)
2167 static const WCHAR taHomaW[] = {'T','a','H','o','m','a',0};
2168 static const WCHAR arialW[] = {'A','r','i','a','l',0};
2169 static const WCHAR strW[] = {'a','b','c','d',0};
2170 IDWriteTextFormat *format;
2171 IDWriteTextLayout *layout;
2172 IDWriteFactory *factory;
2173 DWRITE_TEXT_RANGE r;
2174 WCHAR nameW[50];
2175 HRESULT hr;
2177 factory = create_factory();
2179 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2180 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2181 ok(hr == S_OK, "got 0x%08x\n", hr);
2183 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2184 ok(hr == S_OK, "got 0x%08x\n", hr);
2186 /* NULL name */
2187 r.startPosition = 1;
2188 r.length = 1;
2189 hr = IDWriteTextLayout_SetFontFamilyName(layout, NULL, r);
2190 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2192 r.startPosition = 1;
2193 r.length = 0;
2194 nameW[0] = 0;
2195 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2196 ok(hr == S_OK, "got 0x%08x\n", hr);
2197 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2199 /* set name only different in casing */
2200 r.startPosition = 1;
2201 r.length = 1;
2202 hr = IDWriteTextLayout_SetFontFamilyName(layout, taHomaW, r);
2203 ok(hr == S_OK, "got 0x%08x\n", hr);
2205 /* zero length range */
2206 r.startPosition = 1;
2207 r.length = 0;
2208 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
2209 ok(hr == S_OK, "got 0x%08x\n", hr);
2211 r.startPosition = 0;
2212 r.length = 0;
2213 nameW[0] = 0;
2214 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2215 ok(hr == S_OK, "got 0x%08x\n", hr);
2216 ok(!lstrcmpW(nameW, taHomaW), "got %s\n", wine_dbgstr_w(nameW));
2217 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2219 r.startPosition = 1;
2220 r.length = 1;
2221 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
2222 ok(hr == S_OK, "got 0x%08x\n", hr);
2224 r.startPosition = 1;
2225 r.length = 0;
2226 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2227 ok(hr == S_OK, "got 0x%08x\n", hr);
2228 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2230 r.startPosition = 0;
2231 r.length = 4;
2232 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
2233 ok(hr == S_OK, "got 0x%08x\n", hr);
2235 nameW[0] = 0;
2236 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2237 ok(hr == S_OK, "got 0x%08x\n", hr);
2238 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2239 ok(!lstrcmpW(nameW, arialW), "got name %s\n", wine_dbgstr_w(nameW));
2241 IDWriteTextLayout_Release(layout);
2242 IDWriteTextFormat_Release(format);
2243 IDWriteFactory_Release(factory);
2246 static void test_SetFontStyle(void)
2248 static const WCHAR strW[] = {'a','b','c','d',0};
2249 IDWriteTextFormat *format;
2250 IDWriteTextLayout *layout;
2251 IDWriteFactory *factory;
2252 DWRITE_FONT_STYLE style;
2253 DWRITE_TEXT_RANGE r;
2254 HRESULT hr;
2256 factory = create_factory();
2258 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2259 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2260 ok(hr == S_OK, "got 0x%08x\n", hr);
2262 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2263 ok(hr == S_OK, "got 0x%08x\n", hr);
2265 /* invalid style value */
2266 r.startPosition = 1;
2267 r.length = 1;
2268 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC+1, r);
2269 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2271 r.startPosition = 1;
2272 r.length = 0;
2273 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
2274 ok(hr == S_OK, "got 0x%08x\n", hr);
2275 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2276 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
2278 r.startPosition = 1;
2279 r.length = 1;
2280 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC, r);
2281 ok(hr == S_OK, "got 0x%08x\n", hr);
2283 /* zero length range */
2284 r.startPosition = 1;
2285 r.length = 0;
2286 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_NORMAL, r);
2287 ok(hr == S_OK, "got 0x%08x\n", hr);
2289 style = DWRITE_FONT_STYLE_NORMAL;
2290 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
2291 ok(hr == S_OK, "got 0x%08x\n", hr);
2292 ok(style == DWRITE_FONT_STYLE_ITALIC, "got %d\n", style);
2294 r.startPosition = 0;
2295 r.length = 4;
2296 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
2297 ok(hr == S_OK, "got 0x%08x\n", hr);
2299 style = DWRITE_FONT_STYLE_ITALIC;
2300 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
2301 ok(hr == S_OK, "got 0x%08x\n", hr);
2302 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2304 style = DWRITE_FONT_STYLE_ITALIC;
2305 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
2306 ok(hr == S_OK, "got 0x%08x\n", hr);
2307 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2308 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2310 style = DWRITE_FONT_STYLE_ITALIC;
2311 r.startPosition = r.length = 0;
2312 hr = IDWriteTextLayout_GetFontStyle(layout, 20, &style, &r);
2313 ok(hr == S_OK, "got 0x%08x\n", hr);
2314 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2315 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
2317 r.startPosition = 100;
2318 r.length = 4;
2319 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
2320 ok(hr == S_OK, "got 0x%08x\n", hr);
2322 style = DWRITE_FONT_STYLE_NORMAL;
2323 r.startPosition = r.length = 0;
2324 hr = IDWriteTextLayout_GetFontStyle(layout, 100, &style, &r);
2325 ok(hr == S_OK, "got 0x%08x\n", hr);
2326 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2327 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2329 IDWriteTextLayout_Release(layout);
2330 IDWriteTextFormat_Release(format);
2331 IDWriteFactory_Release(factory);
2334 static void test_SetFontStretch(void)
2336 static const WCHAR strW[] = {'a','b','c','d',0};
2337 DWRITE_FONT_STRETCH stretch;
2338 IDWriteTextFormat *format;
2339 IDWriteTextLayout *layout;
2340 IDWriteFactory *factory;
2341 DWRITE_TEXT_RANGE r;
2342 HRESULT hr;
2344 factory = create_factory();
2346 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2347 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2348 ok(hr == S_OK, "got 0x%08x\n", hr);
2350 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2351 ok(hr == S_OK, "got 0x%08x\n", hr);
2353 /* invalid stretch value */
2354 r.startPosition = 1;
2355 r.length = 1;
2356 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_ULTRA_EXPANDED+1, r);
2357 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2359 r.startPosition = 1;
2360 r.length = 0;
2361 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2362 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
2363 ok(hr == S_OK, "got 0x%08x\n", hr);
2364 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2365 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
2367 r.startPosition = 1;
2368 r.length = 1;
2369 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_CONDENSED, r);
2370 ok(hr == S_OK, "got 0x%08x\n", hr);
2372 /* zero length range */
2373 r.startPosition = 1;
2374 r.length = 0;
2375 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_NORMAL, r);
2376 ok(hr == S_OK, "got 0x%08x\n", hr);
2378 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2379 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
2380 ok(hr == S_OK, "got 0x%08x\n", hr);
2381 ok(stretch == DWRITE_FONT_STRETCH_CONDENSED, "got %d\n", stretch);
2383 r.startPosition = 0;
2384 r.length = 4;
2385 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
2386 ok(hr == S_OK, "got 0x%08x\n", hr);
2388 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2389 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
2390 ok(hr == S_OK, "got 0x%08x\n", hr);
2391 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
2393 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2394 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
2395 ok(hr == S_OK, "got 0x%08x\n", hr);
2396 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2397 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
2399 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2400 r.startPosition = r.length = 0;
2401 hr = IDWriteTextLayout_GetFontStretch(layout, 20, &stretch, &r);
2402 ok(hr == S_OK, "got 0x%08x\n", hr);
2403 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2404 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
2406 r.startPosition = 100;
2407 r.length = 4;
2408 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
2409 ok(hr == S_OK, "got 0x%08x\n", hr);
2411 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2412 r.startPosition = r.length = 0;
2413 hr = IDWriteTextLayout_GetFontStretch(layout, 100, &stretch, &r);
2414 ok(hr == S_OK, "got 0x%08x\n", hr);
2415 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2416 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
2418 /* trying to set undefined value */
2419 r.startPosition = 0;
2420 r.length = 2;
2421 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_UNDEFINED, r);
2422 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2424 IDWriteTextLayout_Release(layout);
2425 IDWriteTextFormat_Release(format);
2426 IDWriteFactory_Release(factory);
2429 static void test_SetStrikethrough(void)
2431 static const WCHAR strW[] = {'a','b','c','d',0};
2432 IDWriteTextFormat *format;
2433 IDWriteTextLayout *layout;
2434 IDWriteFactory *factory;
2435 DWRITE_TEXT_RANGE r;
2436 BOOL value;
2437 HRESULT hr;
2439 factory = create_factory();
2441 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2442 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2443 ok(hr == S_OK, "got 0x%08x\n", hr);
2445 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2446 ok(hr == S_OK, "got 0x%08x\n", hr);
2448 r.startPosition = 1;
2449 r.length = 0;
2450 value = TRUE;
2451 hr = IDWriteTextLayout_GetStrikethrough(layout, 0, &value, &r);
2452 ok(hr == S_OK, "got 0x%08x\n", hr);
2453 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2454 ok(value == FALSE, "got %d\n", value);
2456 r.startPosition = 1;
2457 r.length = 1;
2458 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, r);
2459 ok(hr == S_OK, "got 0x%08x\n", hr);
2461 value = FALSE;
2462 hr = IDWriteTextLayout_GetStrikethrough(layout, 1, &value, &r);
2463 ok(hr == S_OK, "got 0x%08x\n", hr);
2464 ok(value == TRUE, "got %d\n", value);
2465 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2467 value = TRUE;
2468 r.startPosition = r.length = 0;
2469 hr = IDWriteTextLayout_GetStrikethrough(layout, 20, &value, &r);
2470 ok(hr == S_OK, "got 0x%08x\n", hr);
2471 ok(r.startPosition == 2 && r.length == ~0u-2, "got %u, %u\n", r.startPosition, r.length);
2472 ok(value == FALSE, "got %d\n", value);
2474 r.startPosition = 100;
2475 r.length = 4;
2476 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, r);
2477 ok(hr == S_OK, "got 0x%08x\n", hr);
2479 value = FALSE;
2480 r.startPosition = r.length = 0;
2481 hr = IDWriteTextLayout_GetStrikethrough(layout, 100, &value, &r);
2482 ok(hr == S_OK, "got 0x%08x\n", hr);
2483 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2484 ok(value == TRUE, "got %d\n", value);
2486 IDWriteTextLayout_Release(layout);
2487 IDWriteTextFormat_Release(format);
2488 IDWriteFactory_Release(factory);
2491 static void test_GetMetrics(void)
2493 static const WCHAR str2W[] = {0x2066,')',')',0x661,'(',0x627,')',0};
2494 static const WCHAR strW[] = {'a','b','c','d',0};
2495 static const WCHAR str3W[] = {'a',0};
2496 DWRITE_CLUSTER_METRICS clusters[4];
2497 DWRITE_TEXT_METRICS metrics;
2498 IDWriteTextFormat *format;
2499 IDWriteTextLayout *layout;
2500 IDWriteFactory *factory;
2501 UINT32 count, i;
2502 FLOAT width;
2503 HRESULT hr;
2505 factory = create_factory();
2507 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2508 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2509 ok(hr == S_OK, "got 0x%08x\n", hr);
2511 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2512 ok(hr == S_OK, "got 0x%08x\n", hr);
2514 count = 0;
2515 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count);
2516 ok(hr == S_OK, "got 0x%08x\n", hr);
2517 ok(count == 4, "got %u\n", count);
2518 for (i = 0, width = 0.0; i < count; i++)
2519 width += clusters[i].width;
2521 memset(&metrics, 0xcc, sizeof(metrics));
2522 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
2523 ok(hr == S_OK, "got 0x%08x\n", hr);
2524 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
2525 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
2526 ok(metrics.width == width, "got %.2f, expected %.2f\n", metrics.width, width);
2527 ok(metrics.widthIncludingTrailingWhitespace == width, "got %.2f, expected %.2f\n",
2528 metrics.widthIncludingTrailingWhitespace, width);
2529 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
2530 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
2531 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
2532 ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
2533 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
2535 IDWriteTextLayout_Release(layout);
2537 /* a string with more complex bidi sequence */
2538 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 7, format, 500.0, 1000.0, &layout);
2539 ok(hr == S_OK, "got 0x%08x\n", hr);
2541 memset(&metrics, 0xcc, sizeof(metrics));
2542 metrics.maxBidiReorderingDepth = 0;
2543 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
2544 ok(hr == S_OK, "got 0x%08x\n", hr);
2545 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
2546 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
2547 ok(metrics.width > 0.0, "got %.2f\n", metrics.width);
2548 ok(metrics.widthIncludingTrailingWhitespace > 0.0, "got %.2f\n", metrics.widthIncludingTrailingWhitespace);
2549 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
2550 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
2551 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
2552 todo_wine
2553 ok(metrics.maxBidiReorderingDepth > 1, "got %u\n", metrics.maxBidiReorderingDepth);
2554 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
2556 IDWriteTextLayout_Release(layout);
2558 /* single cluster layout */
2559 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 1, format, 500.0, 1000.0, &layout);
2560 ok(hr == S_OK, "got 0x%08x\n", hr);
2562 count = 0;
2563 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
2564 ok(hr == S_OK, "got 0x%08x\n", hr);
2565 ok(count == 1, "got %u\n", count);
2567 memset(&metrics, 0xcc, sizeof(metrics));
2568 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
2569 ok(hr == S_OK, "got 0x%08x\n", hr);
2570 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
2571 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
2572 ok(metrics.width == clusters[0].width, "got %.2f, expected %.2f\n", metrics.width, clusters[0].width);
2573 ok(metrics.widthIncludingTrailingWhitespace == clusters[0].width, "got %.2f\n", metrics.widthIncludingTrailingWhitespace);
2574 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
2575 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
2576 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
2577 ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
2578 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
2579 IDWriteTextLayout_Release(layout);
2581 IDWriteTextFormat_Release(format);
2582 IDWriteFactory_Release(factory);
2585 static void test_SetFlowDirection(void)
2587 static const WCHAR strW[] = {'a','b','c','d',0};
2588 DWRITE_READING_DIRECTION reading;
2589 DWRITE_FLOW_DIRECTION flow;
2590 IDWriteTextFormat *format;
2591 IDWriteTextLayout *layout;
2592 IDWriteFactory *factory;
2593 HRESULT hr;
2595 factory = create_factory();
2597 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2598 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2599 ok(hr == S_OK, "got 0x%08x\n", hr);
2601 flow = IDWriteTextFormat_GetFlowDirection(format);
2602 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
2604 reading = IDWriteTextFormat_GetReadingDirection(format);
2605 ok(reading == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", reading);
2607 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2608 ok(hr == S_OK, "got 0x%08x\n", hr);
2609 IDWriteTextLayout_Release(layout);
2611 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT);
2612 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* vista,win7 */, "got 0x%08x\n", hr);
2613 if (hr == S_OK) {
2614 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2615 ok(hr == S_OK, "got 0x%08x\n", hr);
2616 IDWriteTextLayout_Release(layout);
2618 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_TOP_TO_BOTTOM);
2619 ok(hr == S_OK, "got 0x%08x\n", hr);
2621 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
2622 ok(hr == S_OK, "got 0x%08x\n", hr);
2624 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2625 ok(hr == S_OK, "got 0x%08x\n", hr);
2626 IDWriteTextLayout_Release(layout);
2628 else
2629 win_skip("DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT is not supported\n");
2631 IDWriteTextFormat_Release(format);
2632 IDWriteFactory_Release(factory);
2635 static const struct drawcall_entry draweffect_seq[] = {
2636 { DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0x0300,0} },
2637 { DRAW_GLYPHRUN, {'d',0} },
2638 { DRAW_LAST_KIND }
2641 static const struct drawcall_entry draweffect2_seq[] = {
2642 { DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0} },
2643 { DRAW_GLYPHRUN, {'c','d',0} },
2644 { DRAW_LAST_KIND }
2647 static const struct drawcall_entry draweffect3_seq[] = {
2648 { DRAW_INLINE|DRAW_EFFECT },
2649 { DRAW_LAST_KIND }
2652 static const struct drawcall_entry draweffect4_seq[] = {
2653 { DRAW_INLINE },
2654 { DRAW_LAST_KIND }
2657 static void test_SetDrawingEffect(void)
2659 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
2660 static const WCHAR str2W[] = {'a','e','c','d',0};
2661 IDWriteInlineObject *sign;
2662 IDWriteTextFormat *format;
2663 IDWriteTextLayout *layout;
2664 IDWriteFactory *factory;
2665 DWRITE_TEXT_RANGE r;
2666 IUnknown *unk;
2667 HRESULT hr;
2669 factory = create_factory();
2671 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2672 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2673 ok(hr == S_OK, "got 0x%08x\n", hr);
2675 /* string with combining mark */
2676 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2677 ok(hr == S_OK, "got 0x%08x\n", hr);
2679 /* set effect past the end of text */
2680 r.startPosition = 100;
2681 r.length = 10;
2682 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2683 ok(hr == S_OK, "got 0x%08x\n", hr);
2685 r.startPosition = r.length = 0;
2686 hr = IDWriteTextLayout_GetDrawingEffect(layout, 101, &unk, &r);
2687 ok(hr == S_OK, "got 0x%08x\n", hr);
2688 ok(r.startPosition == 100 && r.length == 10, "got %u, %u\n", r.startPosition, r.length);
2690 r.startPosition = r.length = 0;
2691 unk = (void*)0xdeadbeef;
2692 hr = IDWriteTextLayout_GetDrawingEffect(layout, 1000, &unk, &r);
2693 ok(hr == S_OK, "got 0x%08x\n", hr);
2694 ok(r.startPosition == 110 && r.length == ~0u-110, "got %u, %u\n", r.startPosition, r.length);
2695 ok(unk == NULL, "got %p\n", unk);
2697 /* effect is applied to clusters, not individual text positions */
2698 r.startPosition = 0;
2699 r.length = 2;
2700 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2701 ok(hr == S_OK, "got 0x%08x\n", hr);
2703 flush_sequence(sequences, RENDERER_ID);
2704 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
2705 ok(hr == S_OK, "got 0x%08x\n", hr);
2706 ok_sequence(sequences, RENDERER_ID, draweffect_seq, "effect draw test", TRUE);
2707 IDWriteTextLayout_Release(layout);
2709 /* simple string */
2710 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 1000.0, &layout);
2711 ok(hr == S_OK, "got 0x%08x\n", hr);
2713 r.startPosition = 0;
2714 r.length = 2;
2715 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2716 ok(hr == S_OK, "got 0x%08x\n", hr);
2718 flush_sequence(sequences, RENDERER_ID);
2719 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
2720 ok(hr == S_OK, "got 0x%08x\n", hr);
2721 ok_sequence(sequences, RENDERER_ID, draweffect2_seq, "effect draw test 2", TRUE);
2722 IDWriteTextLayout_Release(layout);
2724 /* Inline object - effect set for same range */
2725 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
2726 ok(hr == S_OK, "got 0x%08x\n", hr);
2728 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 1000.0, &layout);
2729 ok(hr == S_OK, "got 0x%08x\n", hr);
2731 r.startPosition = 0;
2732 r.length = 4;
2733 hr = IDWriteTextLayout_SetInlineObject(layout, sign, r);
2734 ok(hr == S_OK, "got 0x%08x\n", hr);
2736 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2737 ok(hr == S_OK, "got 0x%08x\n", hr);
2739 flush_sequence(sequences, RENDERER_ID);
2740 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
2741 ok(hr == S_OK, "got 0x%08x\n", hr);
2742 ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 3", FALSE);
2744 /* now set effect somewhere inside a range replaced by inline object */
2745 hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
2746 ok(hr == S_OK, "got 0x%08x\n", hr);
2748 r.startPosition = 1;
2749 r.length = 1;
2750 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2751 ok(hr == S_OK, "got 0x%08x\n", hr);
2753 /* no effect is reported in this case */
2754 flush_sequence(sequences, RENDERER_ID);
2755 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
2756 ok(hr == S_OK, "got 0x%08x\n", hr);
2757 ok_sequence(sequences, RENDERER_ID, draweffect4_seq, "effect draw test 4", FALSE);
2759 r.startPosition = 0;
2760 r.length = 4;
2761 hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
2762 ok(hr == S_OK, "got 0x%08x\n", hr);
2764 r.startPosition = 0;
2765 r.length = 1;
2766 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2767 ok(hr == S_OK, "got 0x%08x\n", hr);
2769 /* first range position is all that matters for inline ranges */
2770 flush_sequence(sequences, RENDERER_ID);
2771 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
2772 ok(hr == S_OK, "got 0x%08x\n", hr);
2773 ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 5", FALSE);
2775 IDWriteTextLayout_Release(layout);
2777 IDWriteInlineObject_Release(sign);
2778 IDWriteTextFormat_Release(format);
2779 IDWriteFactory_Release(factory);
2782 static IDWriteFontFace *get_fontface_from_format(IDWriteTextFormat *format)
2784 IDWriteFontCollection *collection;
2785 IDWriteFontFamily *family;
2786 IDWriteFontFace *fontface;
2787 IDWriteFont *font;
2788 WCHAR nameW[255];
2789 UINT32 index;
2790 BOOL exists;
2791 HRESULT hr;
2793 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
2794 ok(hr == S_OK, "got 0x%08x\n", hr);
2796 hr = IDWriteTextFormat_GetFontFamilyName(format, nameW, sizeof(nameW)/sizeof(WCHAR));
2797 ok(hr == S_OK, "got 0x%08x\n", hr);
2799 hr = IDWriteFontCollection_FindFamilyName(collection, nameW, &index, &exists);
2800 ok(hr == S_OK, "got 0x%08x\n", hr);
2802 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
2803 ok(hr == S_OK, "got 0x%08x\n", hr);
2804 IDWriteFontCollection_Release(collection);
2806 hr = IDWriteFontFamily_GetFirstMatchingFont(family,
2807 IDWriteTextFormat_GetFontWeight(format),
2808 IDWriteTextFormat_GetFontStretch(format),
2809 IDWriteTextFormat_GetFontStyle(format),
2810 &font);
2811 ok(hr == S_OK, "got 0x%08x\n", hr);
2813 hr = IDWriteFont_CreateFontFace(font, &fontface);
2814 ok(hr == S_OK, "got 0x%08x\n", hr);
2816 IDWriteFont_Release(font);
2817 IDWriteFontFamily_Release(family);
2819 return fontface;
2822 static void test_GetLineMetrics(void)
2824 static const WCHAR strW[] = {'a','b','c','d',' ',0};
2825 static const WCHAR str2W[] = {'a','b','\r','c','d',0};
2826 DWRITE_FONT_METRICS fontmetrics;
2827 DWRITE_LINE_METRICS metrics[2];
2828 IDWriteTextFormat *format;
2829 IDWriteTextLayout *layout;
2830 IDWriteFontFace *fontface;
2831 IDWriteFactory *factory;
2832 UINT32 count;
2833 HRESULT hr;
2835 factory = create_factory();
2837 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2838 DWRITE_FONT_STRETCH_NORMAL, 2048.0, enusW, &format);
2839 ok(hr == S_OK, "got 0x%08x\n", hr);
2841 hr = IDWriteFactory_CreateTextLayout(factory, strW, 5, format, 30000.0, 1000.0, &layout);
2842 ok(hr == S_OK, "got 0x%08x\n", hr);
2844 count = 0;
2845 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 0, &count);
2846 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2847 ok(count == 1, "got count %u\n", count);
2849 memset(metrics, 0, sizeof(metrics));
2850 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 1, &count);
2851 ok(hr == S_OK, "got 0x%08x\n", hr);
2852 ok(metrics[0].length == 5, "got %u\n", metrics[0].length);
2853 ok(metrics[0].trailingWhitespaceLength == 1, "got %u\n", metrics[0].trailingWhitespaceLength);
2855 ok(metrics[0].newlineLength == 0, "got %u\n", metrics[0].newlineLength);
2856 ok(metrics[0].isTrimmed == FALSE, "got %d\n", metrics[0].isTrimmed);
2858 /* Tahoma doesn't provide BASE table, so baseline is calculated from font metrics */
2859 fontface = get_fontface_from_format(format);
2860 ok(fontface != NULL, "got %p\n", fontface);
2861 IDWriteFontFace_GetMetrics(fontface, &fontmetrics);
2863 ok(metrics[0].baseline == fontmetrics.ascent, "got %.2f, expected %d\n", metrics[0].baseline,
2864 fontmetrics.ascent);
2865 ok(metrics[0].height == fontmetrics.ascent + fontmetrics.descent, "got %.2f, expected %d\n",
2866 metrics[0].height, fontmetrics.ascent + fontmetrics.descent);
2867 IDWriteTextLayout_Release(layout);
2869 /* force 2 lines */
2870 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 5, format, 10000.0, 1000.0, &layout);
2871 ok(hr == S_OK, "got 0x%08x\n", hr);
2873 memset(metrics, 0, sizeof(metrics));
2874 count = 2;
2875 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 2, &count);
2876 ok(hr == S_OK, "got 0x%08x\n", hr);
2877 todo_wine {
2878 ok(count == 2, "got %u\n", count);
2879 /* baseline is relative to a line, and is not accumulated */
2880 ok(metrics[0].baseline == metrics[1].baseline, "got %.2f, %.2f\n", metrics[0].baseline,
2881 metrics[1].baseline);
2883 IDWriteTextLayout_Release(layout);
2885 IDWriteFontFace_Release(fontface);
2886 IDWriteTextFormat_Release(format);
2887 IDWriteFactory_Release(factory);
2890 static void test_SetTextAlignment(void)
2892 static const WCHAR str2W[] = {'a','a','a','a','a',0};
2893 static const WCHAR strW[] = {'a',0};
2894 DWRITE_CLUSTER_METRICS clusters[1];
2895 DWRITE_TEXT_METRICS metrics;
2896 IDWriteTextFormat1 *format1;
2897 IDWriteTextFormat *format;
2898 IDWriteTextLayout *layout;
2899 IDWriteFactory *factory;
2900 DWRITE_TEXT_ALIGNMENT v;
2901 UINT32 count;
2902 HRESULT hr;
2904 factory = create_factory();
2906 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2907 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
2908 ok(hr == S_OK, "got 0x%08x\n", hr);
2910 v = IDWriteTextFormat_GetTextAlignment(format);
2911 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
2913 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
2914 ok(hr == S_OK, "got 0x%08x\n", hr);
2916 v = IDWriteTextLayout_GetTextAlignment(layout);
2917 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
2919 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
2920 ok(hr == S_OK, "got 0x%08x\n", hr);
2922 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
2923 ok(hr == S_OK, "got 0x%08x\n", hr);
2925 v = IDWriteTextFormat_GetTextAlignment(format);
2926 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
2928 v = IDWriteTextLayout_GetTextAlignment(layout);
2929 ok(v == DWRITE_TEXT_ALIGNMENT_TRAILING, "got %d\n", v);
2931 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
2932 if (hr == S_OK) {
2933 hr = IDWriteTextFormat1_SetTextAlignment(format1, DWRITE_TEXT_ALIGNMENT_CENTER);
2934 ok(hr == S_OK, "got 0x%08x\n", hr);
2936 v = IDWriteTextFormat_GetTextAlignment(format);
2937 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
2939 v = IDWriteTextLayout_GetTextAlignment(layout);
2940 ok(v == DWRITE_TEXT_ALIGNMENT_CENTER, "got %d\n", v);
2942 v = IDWriteTextFormat1_GetTextAlignment(format1);
2943 ok(v == DWRITE_TEXT_ALIGNMENT_CENTER, "got %d\n", v);
2945 IDWriteTextFormat1_Release(format1);
2947 else
2948 win_skip("IDWriteTextFormat1 is not supported\n");
2950 count = 0;
2951 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
2952 ok(hr == S_OK, "got 0x%08x\n", hr);
2953 ok(count == 1, "got %u\n", count);
2955 /* maxwidth is 500, leading alignment */
2956 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_LEADING);
2957 ok(hr == S_OK, "got 0x%08x\n", hr);
2959 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
2960 ok(hr == S_OK, "got 0x%08x\n", hr);
2962 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
2963 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
2964 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
2965 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
2967 /* maxwidth is 500, trailing alignment */
2968 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
2969 ok(hr == S_OK, "got 0x%08x\n", hr);
2971 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
2972 ok(hr == S_OK, "got 0x%08x\n", hr);
2974 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
2975 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
2976 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
2977 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
2978 IDWriteTextLayout_Release(layout);
2980 /* initially created with trailing alignment */
2981 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_TRAILING);
2982 ok(hr == S_OK, "got 0x%08x\n", hr);
2984 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
2985 ok(hr == S_OK, "got 0x%08x\n", hr);
2987 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
2988 ok(hr == S_OK, "got 0x%08x\n", hr);
2990 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
2991 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
2992 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
2993 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
2994 IDWriteTextLayout_Release(layout);
2996 /* max width less than total run width, trailing alignment */
2997 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_NO_WRAP);
2998 ok(hr == S_OK, "got 0x%08x\n", hr);
3000 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 5, format, 2*clusters[0].width, 100.0, &layout);
3001 ok(hr == S_OK, "got 0x%08x\n", hr);
3002 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3003 ok(hr == S_OK, "got 0x%08x\n", hr);
3004 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
3005 todo_wine
3006 ok(metrics.width == 5*clusters[0].width, "got %.2f\n", metrics.width);
3007 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3008 IDWriteTextLayout_Release(layout);
3010 /* maxwidth is 500, centered */
3011 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_CENTER);
3012 ok(hr == S_OK, "got 0x%08x\n", hr);
3014 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 5, format, 500.0, 100.0, &layout);
3015 ok(hr == S_OK, "got 0x%08x\n", hr);
3017 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3018 ok(hr == S_OK, "got 0x%08x\n", hr);
3019 ok(metrics.left == (metrics.layoutWidth - metrics.width) / 2.0, "got %.2f\n", metrics.left);
3020 ok(metrics.width == 5*clusters[0].width, "got %.2f\n", metrics.width);
3021 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3023 IDWriteTextLayout_Release(layout);
3025 IDWriteTextFormat_Release(format);
3026 IDWriteFactory_Release(factory);
3029 static void test_SetParagraphAlignment(void)
3031 static const WCHAR strW[] = {'a',0};
3032 DWRITE_TEXT_METRICS metrics;
3033 IDWriteTextFormat *format;
3034 IDWriteTextLayout *layout;
3035 IDWriteFactory *factory;
3036 DWRITE_PARAGRAPH_ALIGNMENT v;
3037 DWRITE_LINE_METRICS lines[1];
3038 UINT32 count;
3039 HRESULT hr;
3041 factory = create_factory();
3043 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3044 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3045 ok(hr == S_OK, "got 0x%08x\n", hr);
3047 v = IDWriteTextFormat_GetParagraphAlignment(format);
3048 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
3050 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3051 ok(hr == S_OK, "got 0x%08x\n", hr);
3053 v = IDWriteTextLayout_GetParagraphAlignment(layout);
3054 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
3056 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
3057 ok(hr == S_OK, "got 0x%08x\n", hr);
3059 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
3060 ok(hr == S_OK, "got 0x%08x\n", hr);
3062 v = IDWriteTextFormat_GetParagraphAlignment(format);
3063 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
3065 v = IDWriteTextLayout_GetParagraphAlignment(layout);
3066 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_FAR, "got %d\n", v);
3068 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
3069 ok(hr == S_OK, "got 0x%08x\n", hr);
3071 v = IDWriteTextLayout_GetParagraphAlignment(layout);
3072 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_CENTER, "got %d\n", v);
3074 count = 0;
3075 hr = IDWriteTextLayout_GetLineMetrics(layout, lines, 1, &count);
3076 ok(hr == S_OK, "got 0x%08x\n", hr);
3077 ok(count == 1, "got %u\n", count);
3079 /* maxheight is 100, near alignment */
3080 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
3081 ok(hr == S_OK, "got 0x%08x\n", hr);
3083 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3084 ok(hr == S_OK, "got 0x%08x\n", hr);
3086 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3087 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3088 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
3089 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3091 /* maxwidth is 100, far alignment */
3092 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
3093 ok(hr == S_OK, "got 0x%08x\n", hr);
3095 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3096 ok(hr == S_OK, "got 0x%08x\n", hr);
3098 ok(metrics.top == metrics.layoutHeight - metrics.height, "got %.2f\n", metrics.top);
3099 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3100 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
3101 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3102 IDWriteTextLayout_Release(layout);
3104 /* initially created with centered alignment */
3105 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
3106 ok(hr == S_OK, "got 0x%08x\n", hr);
3108 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3109 ok(hr == S_OK, "got 0x%08x\n", hr);
3111 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3112 ok(hr == S_OK, "got 0x%08x\n", hr);
3114 ok(metrics.top == (metrics.layoutHeight - lines[0].height) / 2, "got %.2f\n", metrics.top);
3115 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3116 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3117 IDWriteTextLayout_Release(layout);
3119 IDWriteTextFormat_Release(format);
3120 IDWriteFactory_Release(factory);
3123 START_TEST(layout)
3125 static const WCHAR ctrlstrW[] = {0x202a,0};
3126 IDWriteFactory *factory;
3128 if (!(factory = create_factory())) {
3129 win_skip("failed to create factory\n");
3130 return;
3133 /* actual script ids are not fixed */
3134 get_script_analysis(ctrlstrW, 1, &g_control_sa);
3136 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
3137 init_call_sequences(expected_seq, 1);
3139 test_CreateTextLayout();
3140 test_CreateGdiCompatibleTextLayout();
3141 test_CreateTextFormat();
3142 test_GetLocaleName();
3143 test_CreateEllipsisTrimmingSign();
3144 test_fontweight();
3145 test_SetInlineObject();
3146 test_Draw();
3147 test_typography();
3148 test_GetClusterMetrics();
3149 test_SetLocaleName();
3150 test_SetPairKerning();
3151 test_SetVerticalGlyphOrientation();
3152 test_fallback();
3153 test_DetermineMinWidth();
3154 test_SetFontSize();
3155 test_SetFontFamilyName();
3156 test_SetFontStyle();
3157 test_SetFontStretch();
3158 test_SetStrikethrough();
3159 test_GetMetrics();
3160 test_SetFlowDirection();
3161 test_SetDrawingEffect();
3162 test_GetLineMetrics();
3163 test_SetTextAlignment();
3164 test_SetParagraphAlignment();
3166 IDWriteFactory_Release(factory);