dwrite/tests: Some tests for SetUnderline().
[wine.git] / dlls / dwrite / tests / layout.c
blobf1534bf196c7025ddfc8cc2768bd9999eaba9157
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>
24 #include <math.h>
25 #include <limits.h>
27 #include "windows.h"
28 #include "dwrite.h"
29 #include "dwrite_2.h"
31 #include "wine/test.h"
33 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
34 static const WCHAR enusW[] = {'e','n','-','u','s',0};
36 static DWRITE_SCRIPT_ANALYSIS g_sa;
37 static DWRITE_SCRIPT_ANALYSIS g_control_sa;
39 /* test IDWriteTextAnalysisSink */
40 static HRESULT WINAPI analysissink_QueryInterface(IDWriteTextAnalysisSink *iface, REFIID riid, void **obj)
42 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown))
44 *obj = iface;
45 return S_OK;
48 *obj = NULL;
49 return E_NOINTERFACE;
52 static ULONG WINAPI analysissink_AddRef(IDWriteTextAnalysisSink *iface)
54 return 2;
57 static ULONG WINAPI analysissink_Release(IDWriteTextAnalysisSink *iface)
59 return 1;
62 static HRESULT WINAPI analysissink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
63 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
65 g_sa = *sa;
66 return S_OK;
69 static HRESULT WINAPI analysissink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
70 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
72 ok(0, "unexpected call\n");
73 return E_NOTIMPL;
76 static HRESULT WINAPI analysissink_SetBidiLevel(IDWriteTextAnalysisSink *iface,
77 UINT32 position, UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
79 ok(0, "unexpected\n");
80 return E_NOTIMPL;
83 static HRESULT WINAPI analysissink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
84 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
86 ok(0, "unexpected\n");
87 return E_NOTIMPL;
90 static IDWriteTextAnalysisSinkVtbl analysissinkvtbl = {
91 analysissink_QueryInterface,
92 analysissink_AddRef,
93 analysissink_Release,
94 analysissink_SetScriptAnalysis,
95 analysissink_SetLineBreakpoints,
96 analysissink_SetBidiLevel,
97 analysissink_SetNumberSubstitution
100 static IDWriteTextAnalysisSink analysissink = { &analysissinkvtbl };
102 /* test IDWriteTextAnalysisSource */
103 static HRESULT WINAPI analysissource_QueryInterface(IDWriteTextAnalysisSource *iface,
104 REFIID riid, void **obj)
106 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) || IsEqualIID(riid, &IID_IUnknown)) {
107 *obj = iface;
108 IDWriteTextAnalysisSource_AddRef(iface);
109 return S_OK;
111 return E_NOINTERFACE;
114 static ULONG WINAPI analysissource_AddRef(IDWriteTextAnalysisSource *iface)
116 return 2;
119 static ULONG WINAPI analysissource_Release(IDWriteTextAnalysisSource *iface)
121 return 1;
124 static const WCHAR *g_source;
126 static HRESULT WINAPI analysissource_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
127 UINT32 position, WCHAR const** text, UINT32* text_len)
129 if (position >= lstrlenW(g_source))
131 *text = NULL;
132 *text_len = 0;
134 else
136 *text = &g_source[position];
137 *text_len = lstrlenW(g_source) - position;
140 return S_OK;
143 static HRESULT WINAPI analysissource_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
144 UINT32 position, WCHAR const** text, UINT32* text_len)
146 ok(0, "unexpected\n");
147 return E_NOTIMPL;
150 static DWRITE_READING_DIRECTION WINAPI analysissource_GetParagraphReadingDirection(
151 IDWriteTextAnalysisSource *iface)
153 ok(0, "unexpected\n");
154 return DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
157 static HRESULT WINAPI analysissource_GetLocaleName(IDWriteTextAnalysisSource *iface,
158 UINT32 position, UINT32* text_len, WCHAR const** locale)
160 *locale = NULL;
161 *text_len = 0;
162 return S_OK;
165 static HRESULT WINAPI analysissource_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
166 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
168 ok(0, "unexpected\n");
169 return E_NOTIMPL;
172 static IDWriteTextAnalysisSourceVtbl analysissourcevtbl = {
173 analysissource_QueryInterface,
174 analysissource_AddRef,
175 analysissource_Release,
176 analysissource_GetTextAtPosition,
177 analysissource_GetTextBeforePosition,
178 analysissource_GetParagraphReadingDirection,
179 analysissource_GetLocaleName,
180 analysissource_GetNumberSubstitution
183 static IDWriteTextAnalysisSource analysissource = { &analysissourcevtbl };
185 static IDWriteFactory *create_factory(void)
187 IDWriteFactory *factory;
188 HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory);
189 ok(hr == S_OK, "got 0x%08x\n", hr);
190 return factory;
193 /* obvious limitation is that only last script data is returned, so this
194 helper is suitable for single script strings only */
195 static void get_script_analysis(const WCHAR *str, UINT32 len, DWRITE_SCRIPT_ANALYSIS *sa)
197 IDWriteTextAnalyzer *analyzer;
198 IDWriteFactory *factory;
199 HRESULT hr;
201 g_source = str;
203 factory = create_factory();
204 hr = IDWriteFactory_CreateTextAnalyzer(factory, &analyzer);
205 ok(hr == S_OK, "got 0x%08x\n", hr);
207 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &analysissource, 0, len, &analysissink);
208 ok(hr == S_OK, "got 0x%08x\n", hr);
210 *sa = g_sa;
211 IDWriteFactory_Release(factory);
214 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
215 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
217 ULONG rc = IUnknown_AddRef(obj);
218 IUnknown_Release(obj);
219 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
222 enum drawcall_modifiers_kind {
223 DRAW_EFFECT = 0x1000
226 enum drawcall_kind {
227 DRAW_GLYPHRUN = 0,
228 DRAW_UNDERLINE = 1,
229 DRAW_STRIKETHROUGH = 2,
230 DRAW_INLINE = 3,
231 DRAW_LAST_KIND = 4,
232 DRAW_TOTAL_KINDS = 5,
233 DRAW_KINDS_MASK = 0xff
236 static const char *get_draw_kind_name(unsigned short kind)
238 static const char *kind_names[] = {
239 "GLYPH_RUN",
240 "UNDERLINE",
241 "STRIKETHROUGH",
242 "INLINE",
243 "END_OF_SEQ",
245 "GLYPH_RUN|EFFECT",
246 "UNDERLINE|EFFECT",
247 "STRIKETHROUGH|EFFECT",
248 "INLINE|EFFECT",
249 "END_OF_SEQ"
251 if ((kind & DRAW_KINDS_MASK) > DRAW_LAST_KIND)
252 return "unknown";
253 return (kind & DRAW_EFFECT) ? kind_names[(kind & DRAW_KINDS_MASK) + DRAW_TOTAL_KINDS] :
254 kind_names[kind];
257 struct drawcall_entry {
258 enum drawcall_kind kind;
259 WCHAR string[10]; /* only meaningful for DrawGlyphRun() */
262 struct drawcall_sequence
264 int count;
265 int size;
266 struct drawcall_entry *sequence;
269 struct drawtestcontext {
270 unsigned short kind;
271 BOOL todo;
272 int *failcount;
273 const char *file;
274 int line;
277 #define NUM_CALL_SEQUENCES 1
278 #define RENDERER_ID 0
279 static struct drawcall_sequence *sequences[NUM_CALL_SEQUENCES];
280 static struct drawcall_sequence *expected_seq[1];
282 static void add_call(struct drawcall_sequence **seq, int sequence_index, const struct drawcall_entry *call)
284 struct drawcall_sequence *call_seq = seq[sequence_index];
286 if (!call_seq->sequence) {
287 call_seq->size = 10;
288 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0, call_seq->size * sizeof (struct drawcall_entry));
291 if (call_seq->count == call_seq->size) {
292 call_seq->size *= 2;
293 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
294 call_seq->sequence,
295 call_seq->size * sizeof (struct drawcall_entry));
298 assert(call_seq->sequence);
299 call_seq->sequence[call_seq->count++] = *call;
302 static inline void flush_sequence(struct drawcall_sequence **seg, int sequence_index)
304 struct drawcall_sequence *call_seq = seg[sequence_index];
306 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
307 call_seq->sequence = NULL;
308 call_seq->count = call_seq->size = 0;
311 static inline void flush_sequences(struct drawcall_sequence **seq, int n)
313 int i;
314 for (i = 0; i < n; i++)
315 flush_sequence(seq, i);
318 static void init_call_sequences(struct drawcall_sequence **seq, int n)
320 int i;
322 for (i = 0; i < n; i++)
323 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct drawcall_sequence));
326 static void ok_sequence_(struct drawcall_sequence **seq, int sequence_index,
327 const struct drawcall_entry *expected, const char *context, BOOL todo,
328 const char *file, int line)
330 static const struct drawcall_entry end_of_sequence = { DRAW_LAST_KIND };
331 struct drawcall_sequence *call_seq = seq[sequence_index];
332 const struct drawcall_entry *actual, *sequence;
333 int failcount = 0;
335 add_call(seq, sequence_index, &end_of_sequence);
337 sequence = call_seq->sequence;
338 actual = sequence;
340 while (expected->kind != DRAW_LAST_KIND && actual->kind != DRAW_LAST_KIND) {
341 if (expected->kind != actual->kind) {
342 if (todo) {
343 failcount++;
344 todo_wine
345 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
346 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
348 flush_sequence(seq, sequence_index);
349 return;
351 else
352 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
353 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
355 else if ((expected->kind & DRAW_KINDS_MASK) == DRAW_GLYPHRUN) {
356 int cmp = lstrcmpW(expected->string, actual->string);
357 if (cmp != 0 && todo) {
358 failcount++;
359 todo_wine
360 ok_(file, line) (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 else
364 ok_(file, line) (cmp == 0, "%s: glyphrun string %s was expected, but got %s instead\n",
365 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
367 expected++;
368 actual++;
371 if (todo) {
372 todo_wine {
373 if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND) {
374 failcount++;
375 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
376 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
380 else if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND)
381 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
382 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
384 if (todo && !failcount) /* succeeded yet marked todo */
385 todo_wine
386 ok_(file, line)(1, "%s: marked \"todo_wine\" but succeeds\n", context);
388 flush_sequence(seq, sequence_index);
391 #define ok_sequence(seq, index, exp, contx, todo) \
392 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
394 static HRESULT WINAPI testrenderer_QI(IDWriteTextRenderer *iface, REFIID riid, void **obj)
396 if (IsEqualIID(riid, &IID_IDWriteTextRenderer) ||
397 IsEqualIID(riid, &IID_IDWritePixelSnapping) ||
398 IsEqualIID(riid, &IID_IUnknown)
400 *obj = iface;
401 return S_OK;
404 *obj = NULL;
406 /* IDWriteTextRenderer1 overrides drawing calls, ignore for now */
407 if (IsEqualIID(riid, &IID_IDWriteTextRenderer1))
408 return E_NOINTERFACE;
410 ok(0, "unexpected QI %s\n", wine_dbgstr_guid(riid));
411 return E_NOINTERFACE;
414 static ULONG WINAPI testrenderer_AddRef(IDWriteTextRenderer *iface)
416 return 2;
419 static ULONG WINAPI testrenderer_Release(IDWriteTextRenderer *iface)
421 return 1;
424 struct renderer_context {
425 BOOL gdicompat;
426 BOOL use_gdi_natural;
427 BOOL snapping_disabled;
428 DWRITE_MATRIX m;
429 FLOAT ppdip;
430 FLOAT originX;
431 FLOAT originY;
434 static HRESULT WINAPI testrenderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
435 void *context, BOOL *disabled)
437 struct renderer_context *ctxt = (struct renderer_context*)context;
438 if (ctxt)
439 *disabled = ctxt->snapping_disabled;
440 else
441 *disabled = TRUE;
442 return S_OK;
445 static HRESULT WINAPI testrenderer_GetCurrentTransform(IDWriteTextRenderer *iface,
446 void *context, DWRITE_MATRIX *m)
448 struct renderer_context *ctxt = (struct renderer_context*)context;
449 ok(!ctxt->snapping_disabled, "expected enabled snapping\n");
450 *m = ctxt->m;
451 return S_OK;
454 static HRESULT WINAPI testrenderer_GetPixelsPerDip(IDWriteTextRenderer *iface,
455 void *context, FLOAT *pixels_per_dip)
457 struct renderer_context *ctxt = (struct renderer_context*)context;
458 *pixels_per_dip = ctxt->ppdip;
459 return S_OK;
462 #define TEST_MEASURING_MODE(ctxt, mode) test_measuring_mode(ctxt, mode, __LINE__)
463 static void test_measuring_mode(const struct renderer_context *ctxt, DWRITE_MEASURING_MODE mode, int line)
465 if (ctxt->gdicompat) {
466 if (ctxt->use_gdi_natural)
467 ok_(__FILE__, line)(mode == DWRITE_MEASURING_MODE_GDI_NATURAL, "got %d\n", mode);
468 else
469 ok_(__FILE__, line)(mode == DWRITE_MEASURING_MODE_GDI_CLASSIC, "got %d\n", mode);
471 else
472 ok_(__FILE__, line)(mode == DWRITE_MEASURING_MODE_NATURAL, "got %d\n", mode);
475 static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface,
476 void *context,
477 FLOAT baselineOriginX,
478 FLOAT baselineOriginY,
479 DWRITE_MEASURING_MODE mode,
480 DWRITE_GLYPH_RUN const *run,
481 DWRITE_GLYPH_RUN_DESCRIPTION const *descr,
482 IUnknown *effect)
484 struct renderer_context *ctxt = (struct renderer_context*)context;
485 struct drawcall_entry entry;
486 DWRITE_SCRIPT_ANALYSIS sa;
488 if (ctxt) {
489 TEST_MEASURING_MODE(ctxt, mode);
490 ctxt->originX = baselineOriginX;
491 ctxt->originY = baselineOriginY;
494 ok(descr->stringLength < sizeof(entry.string)/sizeof(WCHAR), "string is too long\n");
495 if (descr->stringLength && descr->stringLength < sizeof(entry.string)/sizeof(WCHAR)) {
496 memcpy(entry.string, descr->string, descr->stringLength*sizeof(WCHAR));
497 entry.string[descr->stringLength] = 0;
499 else
500 entry.string[0] = 0;
502 /* see what's reported for control codes runs */
503 get_script_analysis(descr->string, descr->stringLength, &sa);
504 if (sa.script == g_control_sa.script) {
505 /* glyphs are not reported at all for control code runs */
506 ok(run->glyphCount == 0, "got %u\n", run->glyphCount);
507 ok(run->glyphAdvances != NULL, "advances array %p\n", run->glyphAdvances);
508 ok(run->glyphOffsets != NULL, "offsets array %p\n", run->glyphOffsets);
509 ok(run->fontFace != NULL, "got %p\n", run->fontFace);
510 /* text positions are still valid */
511 ok(descr->string != NULL, "got string %p\n", descr->string);
512 ok(descr->stringLength > 0, "got string length %u\n", descr->stringLength);
513 ok(descr->clusterMap != NULL, "clustermap %p\n", descr->clusterMap);
516 entry.kind = DRAW_GLYPHRUN;
517 if (effect)
518 entry.kind |= DRAW_EFFECT;
519 add_call(sequences, RENDERER_ID, &entry);
520 return S_OK;
523 static HRESULT WINAPI testrenderer_DrawUnderline(IDWriteTextRenderer *iface,
524 void *context,
525 FLOAT baselineOriginX,
526 FLOAT baselineOriginY,
527 DWRITE_UNDERLINE const* underline,
528 IUnknown *effect)
530 struct renderer_context *ctxt = (struct renderer_context*)context;
531 struct drawcall_entry entry;
533 if (ctxt)
534 TEST_MEASURING_MODE(ctxt, underline->measuringMode);
536 entry.kind = DRAW_UNDERLINE;
537 if (effect)
538 entry.kind |= DRAW_EFFECT;
539 add_call(sequences, RENDERER_ID, &entry);
540 return S_OK;
543 static HRESULT WINAPI testrenderer_DrawStrikethrough(IDWriteTextRenderer *iface,
544 void *context,
545 FLOAT baselineOriginX,
546 FLOAT baselineOriginY,
547 DWRITE_STRIKETHROUGH const* strikethrough,
548 IUnknown *effect)
550 struct renderer_context *ctxt = (struct renderer_context*)context;
551 struct drawcall_entry entry;
553 if (ctxt)
554 TEST_MEASURING_MODE(ctxt, strikethrough->measuringMode);
556 entry.kind = DRAW_STRIKETHROUGH;
557 if (effect)
558 entry.kind |= DRAW_EFFECT;
559 add_call(sequences, RENDERER_ID, &entry);
560 return S_OK;
563 static HRESULT WINAPI testrenderer_DrawInlineObject(IDWriteTextRenderer *iface,
564 void *context,
565 FLOAT originX,
566 FLOAT originY,
567 IDWriteInlineObject *object,
568 BOOL is_sideways,
569 BOOL is_rtl,
570 IUnknown *effect)
572 struct drawcall_entry entry;
573 entry.kind = DRAW_INLINE;
574 if (effect)
575 entry.kind |= DRAW_EFFECT;
576 add_call(sequences, RENDERER_ID, &entry);
577 return S_OK;
580 static const IDWriteTextRendererVtbl testrenderervtbl = {
581 testrenderer_QI,
582 testrenderer_AddRef,
583 testrenderer_Release,
584 testrenderer_IsPixelSnappingDisabled,
585 testrenderer_GetCurrentTransform,
586 testrenderer_GetPixelsPerDip,
587 testrenderer_DrawGlyphRun,
588 testrenderer_DrawUnderline,
589 testrenderer_DrawStrikethrough,
590 testrenderer_DrawInlineObject
593 static IDWriteTextRenderer testrenderer = { &testrenderervtbl };
595 /* test IDWriteInlineObject */
596 static HRESULT WINAPI testinlineobj_QI(IDWriteInlineObject *iface, REFIID riid, void **obj)
598 if (IsEqualIID(riid, &IID_IDWriteInlineObject) || IsEqualIID(riid, &IID_IUnknown)) {
599 *obj = iface;
600 IDWriteInlineObject_AddRef(iface);
601 return S_OK;
604 *obj = NULL;
605 return E_NOINTERFACE;
608 static ULONG WINAPI testinlineobj_AddRef(IDWriteInlineObject *iface)
610 return 2;
613 static ULONG WINAPI testinlineobj_Release(IDWriteInlineObject *iface)
615 return 1;
618 static HRESULT WINAPI testinlineobj_Draw(IDWriteInlineObject *iface,
619 void* client_drawingontext, IDWriteTextRenderer* renderer,
620 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *drawing_effect)
622 ok(0, "unexpected call\n");
623 return E_NOTIMPL;
626 static HRESULT WINAPI testinlineobj_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
628 metrics->width = 123.0;
629 return 0x8faecafe;
632 static HRESULT WINAPI testinlineobj_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
634 ok(0, "unexpected call\n");
635 return E_NOTIMPL;
638 static HRESULT WINAPI testinlineobj_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
639 DWRITE_BREAK_CONDITION *after)
641 *before = *after = DWRITE_BREAK_CONDITION_MUST_BREAK;
642 return 0x8feacafe;
645 static HRESULT WINAPI testinlineobj2_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
646 DWRITE_BREAK_CONDITION *after)
648 *before = *after = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
649 return S_OK;
652 static IDWriteInlineObjectVtbl testinlineobjvtbl = {
653 testinlineobj_QI,
654 testinlineobj_AddRef,
655 testinlineobj_Release,
656 testinlineobj_Draw,
657 testinlineobj_GetMetrics,
658 testinlineobj_GetOverhangMetrics,
659 testinlineobj_GetBreakConditions
662 static IDWriteInlineObjectVtbl testinlineobjvtbl2 = {
663 testinlineobj_QI,
664 testinlineobj_AddRef,
665 testinlineobj_Release,
666 testinlineobj_Draw,
667 testinlineobj_GetMetrics,
668 testinlineobj_GetOverhangMetrics,
669 testinlineobj2_GetBreakConditions
672 static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl };
673 static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
674 static IDWriteInlineObject testinlineobj3 = { &testinlineobjvtbl2 };
676 static HRESULT WINAPI testeffect_QI(IUnknown *iface, REFIID riid, void **obj)
678 if (IsEqualIID(riid, &IID_IUnknown)) {
679 *obj = iface;
680 IUnknown_AddRef(iface);
681 return S_OK;
684 *obj = NULL;
685 return E_NOINTERFACE;
688 static ULONG WINAPI testeffect_AddRef(IUnknown *iface)
690 return 2;
693 static ULONG WINAPI testeffect_Release(IUnknown *iface)
695 return 1;
698 static const IUnknownVtbl testeffectvtbl = {
699 testeffect_QI,
700 testeffect_AddRef,
701 testeffect_Release
704 static IUnknown testeffect = { &testeffectvtbl };
706 static void test_CreateTextLayout(void)
708 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
709 IDWriteTextLayout2 *layout2;
710 IDWriteTextLayout *layout;
711 IDWriteTextFormat *format;
712 IDWriteFactory *factory;
713 HRESULT hr;
715 factory = create_factory();
717 hr = IDWriteFactory_CreateTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, &layout);
718 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
720 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 0.0, &layout);
721 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
723 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1.0, 0.0, &layout);
724 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
726 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 1.0, &layout);
727 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
729 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, &layout);
730 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
732 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
733 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
734 ok(hr == S_OK, "got 0x%08x\n", hr);
736 EXPECT_REF(format, 1);
737 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 1000.0, 1000.0, &layout);
738 ok(hr == S_OK, "got 0x%08x\n", hr);
739 EXPECT_REF(format, 1);
741 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
742 if (hr == S_OK) {
743 IDWriteTextLayout1 *layout1;
744 IDWriteTextFormat1 *format1;
745 IDWriteTextFormat *format;
747 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextLayout1, (void**)&layout1);
748 ok(hr == S_OK, "got 0x%08x\n", hr);
749 IDWriteTextLayout1_Release(layout1);
751 EXPECT_REF(layout2, 2);
752 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
753 ok(hr == S_OK, "got 0x%08x\n", hr);
754 EXPECT_REF(layout2, 3);
756 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat, (void**)&format);
757 ok(hr == S_OK, "got 0x%08x\n", hr);
758 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
759 ok(format != (IDWriteTextFormat*)layout2, "got %p, %p\n", format, layout2);
760 EXPECT_REF(layout2, 4);
762 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextLayout1, (void**)&layout1);
763 ok(hr == S_OK, "got 0x%08x\n", hr);
764 IDWriteTextLayout1_Release(layout1);
766 IDWriteTextFormat1_Release(format1);
767 IDWriteTextFormat_Release(format);
769 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
770 ok(hr == S_OK, "got 0x%08x\n", hr);
771 EXPECT_REF(layout2, 3);
773 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format);
774 ok(hr == S_OK, "got 0x%08x\n", hr);
775 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
776 EXPECT_REF(layout2, 4);
778 IDWriteTextFormat1_Release(format1);
779 IDWriteTextFormat_Release(format);
780 IDWriteTextLayout2_Release(layout2);
782 else
783 win_skip("IDWriteTextLayout2 is not supported.\n");
785 IDWriteTextLayout_Release(layout);
786 IDWriteTextFormat_Release(format);
787 IDWriteFactory_Release(factory);
790 static DWRITE_MATRIX layoutcreate_transforms[] = {
791 { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
792 { 1.0, 0.0, 0.0, 1.0, 0.3, 0.2 },
793 { 1.0, 0.0, 0.0, 1.0,-0.3,-0.2 },
795 { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
796 { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
797 { 1.0, 2.0, 0.5, 1.0, 0.0, 0.0 },
800 static void test_CreateGdiCompatibleTextLayout(void)
802 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
803 IDWriteTextLayout *layout;
804 IDWriteTextFormat *format;
805 IDWriteFactory *factory;
806 FLOAT dimension;
807 HRESULT hr;
808 int i;
810 factory = create_factory();
812 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
813 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
815 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
816 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
818 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 0.0, NULL, FALSE, &layout);
819 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
821 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 1.0, NULL, FALSE, &layout);
822 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
824 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, 1.0, NULL, FALSE, &layout);
825 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
827 /* create with text format */
828 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
829 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
830 ok(hr == S_OK, "got 0x%08x\n", hr);
831 EXPECT_REF(format, 1);
833 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
834 ok(hr == S_OK, "got 0x%08x\n", hr);
835 EXPECT_REF(format, 1);
836 EXPECT_REF(layout, 1);
838 IDWriteTextLayout_AddRef(layout);
839 EXPECT_REF(format, 1);
840 EXPECT_REF(layout, 2);
841 IDWriteTextLayout_Release(layout);
842 IDWriteTextLayout_Release(layout);
844 /* zero length string is okay */
845 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
846 ok(hr == S_OK, "got 0x%08x\n", hr);
848 dimension = IDWriteTextLayout_GetMaxWidth(layout);
849 ok(dimension == 100.0, "got %f\n", dimension);
851 dimension = IDWriteTextLayout_GetMaxHeight(layout);
852 ok(dimension == 100.0, "got %f\n", dimension);
854 IDWriteTextLayout_Release(layout);
856 /* negative, zero ppdip */
857 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 1, format, 100.0, 100.0, -1.0, NULL, FALSE, &layout);
858 ok(hr == S_OK, "got 0x%08x\n", hr);
859 IDWriteTextLayout_Release(layout);
861 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 1, format, 100.0, 100.0, 0.0, NULL, FALSE, &layout);
862 ok(hr == S_OK, "got 0x%08x\n", hr);
863 IDWriteTextLayout_Release(layout);
865 /* transforms */
866 for (i = 0; i < sizeof(layoutcreate_transforms)/sizeof(layoutcreate_transforms[0]); i++) {
867 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 1, format, 100.0, 100.0, 1.0,
868 &layoutcreate_transforms[i], FALSE, &layout);
869 ok(hr == S_OK, "got 0x%08x\n", hr);
870 IDWriteTextLayout_Release(layout);
873 IDWriteTextFormat_Release(format);
874 IDWriteFactory_Release(factory);
877 static void test_CreateTextFormat(void)
879 IDWriteFontCollection *collection, *syscoll;
880 DWRITE_PARAGRAPH_ALIGNMENT paralign;
881 DWRITE_READING_DIRECTION readdir;
882 DWRITE_WORD_WRAPPING wrapping;
883 DWRITE_TEXT_ALIGNMENT align;
884 DWRITE_FLOW_DIRECTION flow;
885 DWRITE_LINE_SPACING_METHOD method;
886 DWRITE_TRIMMING trimming;
887 IDWriteTextFormat *format;
888 FLOAT spacing, baseline;
889 IDWriteInlineObject *trimmingsign;
890 IDWriteFactory *factory;
891 HRESULT hr;
893 factory = create_factory();
895 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
896 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
897 ok(hr == S_OK, "got 0x%08x\n", hr);
899 if (0) /* crashes on native */
900 hr = IDWriteTextFormat_GetFontCollection(format, NULL);
902 collection = NULL;
903 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
904 ok(hr == S_OK, "got 0x%08x\n", hr);
905 ok(collection != NULL, "got %p\n", collection);
907 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
908 ok(hr == S_OK, "got 0x%08x\n", hr);
909 ok(collection == syscoll, "got %p, was %p\n", syscoll, collection);
910 IDWriteFontCollection_Release(syscoll);
911 IDWriteFontCollection_Release(collection);
913 /* default format properties */
914 align = IDWriteTextFormat_GetTextAlignment(format);
915 ok(align == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", align);
917 paralign = IDWriteTextFormat_GetParagraphAlignment(format);
918 ok(paralign == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", paralign);
920 wrapping = IDWriteTextFormat_GetWordWrapping(format);
921 ok(wrapping == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", wrapping);
923 readdir = IDWriteTextFormat_GetReadingDirection(format);
924 ok(readdir == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", readdir);
926 flow = IDWriteTextFormat_GetFlowDirection(format);
927 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
929 hr = IDWriteTextFormat_GetLineSpacing(format, &method, &spacing, &baseline);
930 ok(hr == S_OK, "got 0x%08x\n", hr);
931 ok(spacing == 0.0, "got %f\n", spacing);
932 ok(baseline == 0.0, "got %f\n", baseline);
933 ok(method == DWRITE_LINE_SPACING_METHOD_DEFAULT, "got %d\n", method);
935 trimming.granularity = DWRITE_TRIMMING_GRANULARITY_WORD;
936 trimming.delimiter = 10;
937 trimming.delimiterCount = 10;
938 trimmingsign = (void*)0xdeadbeef;
939 hr = IDWriteTextFormat_GetTrimming(format, &trimming, &trimmingsign);
940 ok(hr == S_OK, "got 0x%08x\n", hr);
941 ok(trimming.granularity == DWRITE_TRIMMING_GRANULARITY_NONE, "got %d\n", trimming.granularity);
942 ok(trimming.delimiter == 0, "got %d\n", trimming.delimiter);
943 ok(trimming.delimiterCount == 0, "got %d\n", trimming.delimiterCount);
944 ok(trimmingsign == NULL, "got %p\n", trimmingsign);
946 /* setters */
947 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING);
948 ok(hr == S_OK, "got 0x%08x\n", hr);
950 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_JUSTIFIED+1);
951 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
953 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
954 ok(hr == S_OK, "got 0x%08x\n", hr);
956 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_CENTER+1);
957 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
959 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_WRAP);
960 ok(hr == S_OK, "got 0x%08x\n", hr);
962 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_CHARACTER+1);
963 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
965 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
966 ok(hr == S_OK, "got 0x%08x\n", hr);
968 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
969 ok(hr == S_OK, "got 0x%08x\n", hr);
971 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0, 0.0);
972 ok(hr == S_OK, "got 0x%08x\n", hr);
974 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0, -10.0);
975 ok(hr == S_OK, "got 0x%08x\n", hr);
977 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, -10.0, 0.0);
978 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
980 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_PROPORTIONAL+1, 0.0, 0.0);
981 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
983 hr = IDWriteTextFormat_SetTrimming(format, &trimming, NULL);
984 ok(hr == S_OK, "got 0x%08x\n", hr);
986 IDWriteTextFormat_Release(format);
987 IDWriteFactory_Release(factory);
990 static void test_GetLocaleName(void)
992 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
993 static const WCHAR ruW[] = {'r','u',0};
994 IDWriteTextLayout *layout;
995 IDWriteTextFormat *format, *format2;
996 IDWriteFactory *factory;
997 WCHAR buff[10];
998 UINT32 len;
999 HRESULT hr;
1001 factory = create_factory();
1003 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1004 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1005 ok(hr == S_OK, "got 0x%08x\n", hr);
1007 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1008 ok(hr == S_OK, "got 0x%08x\n", hr);
1010 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format2);
1011 ok(hr == S_OK, "got 0x%08x\n", hr);
1013 len = IDWriteTextFormat_GetLocaleNameLength(format2);
1014 ok(len == 2, "got %u\n", len);
1015 len = IDWriteTextFormat_GetLocaleNameLength(format);
1016 ok(len == 2, "got %u\n", len);
1017 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len);
1018 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1019 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len+1);
1020 ok(hr == S_OK, "got 0x%08x\n", hr);
1021 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
1022 hr = IDWriteTextFormat_GetLocaleName(format, buff, len);
1023 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1024 hr = IDWriteTextFormat_GetLocaleName(format, buff, len+1);
1025 ok(hr == S_OK, "got 0x%08x\n", hr);
1026 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
1028 IDWriteTextLayout_Release(layout);
1029 IDWriteTextFormat_Release(format);
1030 IDWriteTextFormat_Release(format2);
1031 IDWriteFactory_Release(factory);
1034 static const struct drawcall_entry drawellipsis_seq[] = {
1035 { DRAW_GLYPHRUN, {0x2026, 0} },
1036 { DRAW_LAST_KIND }
1039 static void test_CreateEllipsisTrimmingSign(void)
1041 DWRITE_INLINE_OBJECT_METRICS metrics;
1042 DWRITE_BREAK_CONDITION before, after;
1043 IDWriteTextFormat *format;
1044 IDWriteInlineObject *sign;
1045 IDWriteFactory *factory;
1046 IUnknown *unk;
1047 HRESULT hr;
1049 factory = create_factory();
1051 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1052 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1053 ok(hr == S_OK, "got 0x%08x\n", hr);
1055 EXPECT_REF(format, 1);
1056 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
1057 ok(hr == S_OK, "got 0x%08x\n", hr);
1058 EXPECT_REF(format, 1);
1060 hr = IDWriteInlineObject_QueryInterface(sign, &IID_IDWriteTextLayout, (void**)&unk);
1061 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1063 if (0) {/* crashes on native */
1064 hr = IDWriteInlineObject_GetBreakConditions(sign, NULL, NULL);
1065 hr = IDWriteInlineObject_GetMetrics(sign, NULL);
1067 metrics.width = 0.0;
1068 metrics.height = 123.0;
1069 metrics.baseline = 123.0;
1070 metrics.supportsSideways = TRUE;
1071 hr = IDWriteInlineObject_GetMetrics(sign, &metrics);
1072 ok(hr == S_OK, "got 0x%08x\n", hr);
1073 todo_wine
1074 ok(metrics.width > 0.0, "got %.2f\n", metrics.width);
1075 ok(metrics.height == 0.0, "got %.2f\n", metrics.height);
1076 ok(metrics.baseline == 0.0, "got %.2f\n", metrics.baseline);
1077 ok(!metrics.supportsSideways, "got %d\n", metrics.supportsSideways);
1079 before = after = DWRITE_BREAK_CONDITION_CAN_BREAK;
1080 hr = IDWriteInlineObject_GetBreakConditions(sign, &before, &after);
1081 ok(hr == S_OK, "got 0x%08x\n", hr);
1082 ok(before == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", before);
1083 ok(after == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", after);
1085 /* Draw tests */
1086 flush_sequence(sequences, RENDERER_ID);
1087 hr = IDWriteInlineObject_Draw(sign, NULL, &testrenderer, 0.0, 0.0, FALSE, FALSE, NULL);
1088 ok(hr == S_OK, "got 0x%08x\n", hr);
1089 ok_sequence(sequences, RENDERER_ID, drawellipsis_seq, "ellipsis sign draw test", FALSE);
1090 IDWriteInlineObject_Release(sign);
1092 /* non-orthogonal flow/reading combination */
1093 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
1094 ok(hr == S_OK, "got 0x%08x\n", hr);
1096 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT);
1097 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* vista, win7 */, "got 0x%08x\n", hr);
1098 if (hr == S_OK) {
1099 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
1100 ok(hr == DWRITE_E_FLOWDIRECTIONCONFLICTS, "got 0x%08x\n", hr);
1103 IDWriteTextFormat_Release(format);
1104 IDWriteFactory_Release(factory);
1107 static void test_fontweight(void)
1109 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1110 static const WCHAR ruW[] = {'r','u',0};
1111 IDWriteTextFormat *format, *fmt2;
1112 IDWriteTextLayout *layout;
1113 DWRITE_FONT_WEIGHT weight;
1114 DWRITE_TEXT_RANGE range;
1115 IDWriteFactory *factory;
1116 FLOAT size;
1117 HRESULT hr;
1119 factory = create_factory();
1121 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1122 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1123 ok(hr == S_OK, "got 0x%08x\n", hr);
1125 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1126 ok(hr == S_OK, "got 0x%08x\n", hr);
1128 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&fmt2);
1129 ok(hr == S_OK, "got 0x%08x\n", hr);
1131 weight = IDWriteTextFormat_GetFontWeight(fmt2);
1132 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
1134 range.startPosition = range.length = 0;
1135 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1136 ok(hr == S_OK, "got 0x%08x\n", hr);
1137 ok(range.startPosition == 0 && range.length == ~0u, "got %u, %u\n", range.startPosition, range.length);
1139 range.startPosition = 0;
1140 range.length = 6;
1141 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_NORMAL, range);
1142 ok(hr == S_OK, "got 0x%08x\n", hr);
1144 range.startPosition = range.length = 0;
1145 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1146 ok(hr == S_OK, "got 0x%08x\n", hr);
1147 ok(range.startPosition == 0 && range.length == 6, "got %u, %u\n", range.startPosition, range.length);
1149 /* IDWriteTextFormat methods output doesn't reflect layout changes */
1150 weight = IDWriteTextFormat_GetFontWeight(fmt2);
1151 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
1153 range.length = 0;
1154 weight = DWRITE_FONT_WEIGHT_BOLD;
1155 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1156 ok(hr == S_OK, "got 0x%08x\n", hr);
1157 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
1158 ok(range.length == 6, "got %d\n", range.length);
1160 size = IDWriteTextLayout_GetMaxWidth(layout);
1161 ok(size == 100.0, "got %.2f\n", size);
1163 hr = IDWriteTextLayout_SetMaxWidth(layout, 0.0);
1164 ok(hr == S_OK, "got 0x%08x\n", hr);
1166 size = IDWriteTextLayout_GetMaxWidth(layout);
1167 ok(size == 0.0, "got %.2f\n", size);
1169 hr = IDWriteTextLayout_SetMaxWidth(layout, -1.0);
1170 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1172 size = IDWriteTextLayout_GetMaxWidth(layout);
1173 ok(size == 0.0, "got %.2f\n", size);
1175 hr = IDWriteTextLayout_SetMaxWidth(layout, 100.0);
1176 ok(hr == S_OK, "got 0x%08x\n", hr);
1178 size = IDWriteTextLayout_GetMaxWidth(layout);
1179 ok(size == 100.0, "got %.2f\n", size);
1181 size = IDWriteTextLayout_GetMaxHeight(layout);
1182 ok(size == 100.0, "got %.2f\n", size);
1184 hr = IDWriteTextLayout_SetMaxHeight(layout, 0.0);
1185 ok(hr == S_OK, "got 0x%08x\n", hr);
1187 size = IDWriteTextLayout_GetMaxHeight(layout);
1188 ok(size == 0.0, "got %.2f\n", size);
1190 hr = IDWriteTextLayout_SetMaxHeight(layout, -1.0);
1191 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1193 size = IDWriteTextLayout_GetMaxHeight(layout);
1194 ok(size == 0.0, "got %.2f\n", size);
1196 hr = IDWriteTextLayout_SetMaxHeight(layout, 100.0);
1197 ok(hr == S_OK, "got 0x%08x\n", hr);
1199 size = IDWriteTextLayout_GetMaxHeight(layout);
1200 ok(size == 100.0, "got %.2f\n", size);
1202 IDWriteTextLayout_Release(layout);
1203 IDWriteTextFormat_Release(fmt2);
1204 IDWriteTextFormat_Release(format);
1205 IDWriteFactory_Release(factory);
1208 static void test_SetInlineObject(void)
1210 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1211 static const WCHAR ruW[] = {'r','u',0};
1213 IDWriteInlineObject *inlineobj, *inlineobj2, *inlinetest;
1214 IDWriteTextFormat *format;
1215 IDWriteTextLayout *layout;
1216 DWRITE_TEXT_RANGE range, r2;
1217 IDWriteFactory *factory;
1218 HRESULT hr;
1220 factory = create_factory();
1222 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1223 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1224 ok(hr == S_OK, "got 0x%08x\n", hr);
1226 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1227 ok(hr == S_OK, "got 0x%08x\n", hr);
1229 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1230 ok(hr == S_OK, "got 0x%08x\n", hr);
1232 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj2);
1233 ok(hr == S_OK, "got 0x%08x\n", hr);
1235 EXPECT_REF(inlineobj, 1);
1236 EXPECT_REF(inlineobj2, 1);
1238 inlinetest = (void*)0x1;
1239 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, NULL);
1240 ok(hr == S_OK, "got 0x%08x\n", hr);
1241 ok(inlinetest == NULL, "got %p\n", inlinetest);
1243 range.startPosition = 0;
1244 range.length = 2;
1245 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1246 ok(hr == S_OK, "got 0x%08x\n", hr);
1248 EXPECT_REF(inlineobj, 2);
1250 inlinetest = (void*)0x1;
1251 hr = IDWriteTextLayout_GetInlineObject(layout, 2, &inlinetest, NULL);
1252 ok(hr == S_OK, "got 0x%08x\n", hr);
1253 ok(inlinetest == NULL, "got %p\n", inlinetest);
1255 inlinetest = NULL;
1256 r2.startPosition = r2.length = 100;
1257 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1258 ok(hr == S_OK, "got 0x%08x\n", hr);
1259 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1260 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1261 IDWriteInlineObject_Release(inlinetest);
1263 EXPECT_REF(inlineobj, 2);
1265 /* get from somewhere inside a range */
1266 inlinetest = NULL;
1267 r2.startPosition = r2.length = 100;
1268 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1269 ok(hr == S_OK, "got 0x%08x\n", hr);
1270 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1271 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1272 IDWriteInlineObject_Release(inlinetest);
1274 EXPECT_REF(inlineobj, 2);
1276 range.startPosition = 1;
1277 range.length = 1;
1278 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj2, range);
1279 ok(hr == S_OK, "got 0x%08x\n", hr);
1281 inlinetest = NULL;
1282 r2.startPosition = r2.length = 100;
1283 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1284 ok(hr == S_OK, "got 0x%08x\n", hr);
1285 ok(inlinetest == inlineobj2, "got %p\n", inlinetest);
1286 ok(r2.startPosition == 1 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1287 IDWriteInlineObject_Release(inlinetest);
1289 EXPECT_REF(inlineobj, 2);
1290 EXPECT_REF(inlineobj2, 2);
1292 inlinetest = NULL;
1293 r2.startPosition = r2.length = 100;
1294 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1295 ok(hr == S_OK, "got 0x%08x\n", hr);
1296 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1297 ok(r2.startPosition == 0 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1298 IDWriteInlineObject_Release(inlinetest);
1300 EXPECT_REF(inlineobj, 2);
1302 range.startPosition = 1;
1303 range.length = 1;
1304 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1305 ok(hr == S_OK, "got 0x%08x\n", hr);
1307 r2.startPosition = r2.length = 100;
1308 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1309 ok(hr == S_OK, "got 0x%08x\n", hr);
1310 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1311 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1312 IDWriteInlineObject_Release(inlinetest);
1314 EXPECT_REF(inlineobj, 2);
1316 range.startPosition = 1;
1317 range.length = 2;
1318 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1319 ok(hr == S_OK, "got 0x%08x\n", hr);
1321 EXPECT_REF(inlineobj, 2);
1323 r2.startPosition = r2.length = 100;
1324 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1325 ok(hr == S_OK, "got 0x%08x\n", hr);
1326 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1327 ok(r2.startPosition == 0 && r2.length == 3, "got %d, %d\n", r2.startPosition, r2.length);
1328 IDWriteInlineObject_Release(inlinetest);
1330 EXPECT_REF(inlineobj, 2);
1331 EXPECT_REF(inlineobj2, 1);
1333 IDWriteTextLayout_Release(layout);
1335 EXPECT_REF(inlineobj, 1);
1337 IDWriteInlineObject_Release(inlineobj);
1338 IDWriteInlineObject_Release(inlineobj2);
1339 IDWriteTextFormat_Release(format);
1340 IDWriteFactory_Release(factory);
1343 /* drawing calls sequence doesn't depend on run order, instead all runs are
1344 drawn first, inline objects next and then underline/strikes */
1345 static const struct drawcall_entry draw_seq[] = {
1346 { DRAW_GLYPHRUN, {'s',0} },
1347 { DRAW_GLYPHRUN, {'r','i',0} },
1348 { DRAW_GLYPHRUN|DRAW_EFFECT, {'n',0} },
1349 { DRAW_GLYPHRUN, {'g',0} },
1350 { DRAW_INLINE },
1351 { DRAW_UNDERLINE },
1352 { DRAW_STRIKETHROUGH },
1353 { DRAW_LAST_KIND }
1356 static const struct drawcall_entry draw_seq2[] = {
1357 { DRAW_GLYPHRUN, {'s',0} },
1358 { DRAW_GLYPHRUN, {'t',0} },
1359 { DRAW_GLYPHRUN, {'r',0} },
1360 { DRAW_GLYPHRUN, {'i',0} },
1361 { DRAW_GLYPHRUN, {'n',0} },
1362 { DRAW_GLYPHRUN, {'g',0} },
1363 { DRAW_LAST_KIND }
1366 static const struct drawcall_entry draw_seq3[] = {
1367 { DRAW_GLYPHRUN },
1368 { DRAW_GLYPHRUN, {'a','b',0} },
1369 { DRAW_LAST_KIND }
1372 static const struct drawcall_entry draw_seq4[] = {
1373 { DRAW_GLYPHRUN, {'s','t','r',0} },
1374 { DRAW_GLYPHRUN, {'i','n','g',0} },
1375 { DRAW_STRIKETHROUGH },
1376 { DRAW_LAST_KIND }
1379 static const struct drawcall_entry draw_seq5[] = {
1380 { DRAW_GLYPHRUN, {'s','t',0} },
1381 { DRAW_GLYPHRUN, {'r','i',0} },
1382 { DRAW_GLYPHRUN, {'n','g',0} },
1383 { DRAW_STRIKETHROUGH },
1384 { DRAW_LAST_KIND }
1387 static const struct drawcall_entry empty_seq[] = {
1388 { DRAW_LAST_KIND }
1391 static const struct drawcall_entry draw_single_run_seq[] = {
1392 { DRAW_GLYPHRUN, {'s','t','r','i','n','g',0} },
1393 { DRAW_LAST_KIND }
1396 static void test_Draw(void)
1398 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1399 static const WCHAR str2W[] = {0x202a,0x202c,'a','b',0};
1400 static const WCHAR ruW[] = {'r','u',0};
1401 IDWriteInlineObject *inlineobj;
1402 struct renderer_context ctxt;
1403 IDWriteTextFormat *format;
1404 IDWriteTextLayout *layout;
1405 DWRITE_TEXT_RANGE range;
1406 IDWriteFactory *factory;
1407 DWRITE_TEXT_METRICS tm;
1408 DWRITE_MATRIX m;
1409 HRESULT hr;
1411 factory = create_factory();
1413 ctxt.gdicompat = FALSE;
1414 ctxt.use_gdi_natural = FALSE;
1415 ctxt.snapping_disabled = TRUE;
1417 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1418 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1419 ok(hr == S_OK, "got 0x%08x\n", hr);
1421 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 100.0, 100.0, &layout);
1422 ok(hr == S_OK, "got 0x%08x\n", hr);
1424 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1425 ok(hr == S_OK, "got 0x%08x\n", hr);
1427 range.startPosition = 5;
1428 range.length = 1;
1429 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1430 ok(hr == S_OK, "got 0x%08x\n", hr);
1432 range.startPosition = 1;
1433 range.length = 1;
1434 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1435 ok(hr == S_OK, "got 0x%08x\n", hr);
1437 range.startPosition = 4;
1438 range.length = 1;
1439 hr = IDWriteTextLayout_SetDrawingEffect(layout, (IUnknown*)inlineobj, range);
1440 ok(hr == S_OK, "got 0x%08x\n", hr);
1442 range.startPosition = 0;
1443 range.length = 1;
1444 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
1445 ok(hr == S_OK, "got 0x%08x\n", hr);
1447 flush_sequence(sequences, RENDERER_ID);
1448 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1449 ok(hr == S_OK, "got 0x%08x\n", hr);
1450 ok_sequence(sequences, RENDERER_ID, draw_seq, "draw test", TRUE);
1451 IDWriteTextLayout_Release(layout);
1453 /* with reduced width DrawGlyphRun() is called for every line */
1454 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 5.0, 100.0, &layout);
1455 ok(hr == S_OK, "got 0x%08x\n", hr);
1456 flush_sequence(sequences, RENDERER_ID);
1457 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1458 ok(hr == S_OK, "got 0x%08x\n", hr);
1459 ok_sequence(sequences, RENDERER_ID, draw_seq2, "draw test 2", TRUE);
1460 IDWriteTextLayout_Release(layout);
1462 /* string with control characters */
1463 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 100.0, &layout);
1464 ok(hr == S_OK, "got 0x%08x\n", hr);
1465 flush_sequence(sequences, RENDERER_ID);
1466 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1467 ok(hr == S_OK, "got 0x%08x\n", hr);
1468 ok_sequence(sequences, RENDERER_ID, draw_seq3, "draw test 3", TRUE);
1469 IDWriteTextLayout_Release(layout);
1471 /* strikethrough splits ranges from renderer point of view, but doesn't break
1472 shaping */
1473 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1474 ok(hr == S_OK, "got 0x%08x\n", hr);
1475 flush_sequence(sequences, RENDERER_ID);
1477 range.startPosition = 0;
1478 range.length = 3;
1479 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1480 ok(hr == S_OK, "got 0x%08x\n", hr);
1482 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1483 ok(hr == S_OK, "got 0x%08x\n", hr);
1484 ok_sequence(sequences, RENDERER_ID, draw_seq4, "draw test 4", FALSE);
1485 IDWriteTextLayout_Release(layout);
1487 /* strikethrough somewhere in the middle */
1488 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1489 ok(hr == S_OK, "got 0x%08x\n", hr);
1490 flush_sequence(sequences, RENDERER_ID);
1492 range.startPosition = 2;
1493 range.length = 2;
1494 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1495 ok(hr == S_OK, "got 0x%08x\n", hr);
1497 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1498 ok(hr == S_OK, "got 0x%08x\n", hr);
1499 ok_sequence(sequences, RENDERER_ID, draw_seq5, "draw test 5", FALSE);
1500 IDWriteTextLayout_Release(layout);
1502 /* empty string */
1503 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 500.0, 100.0, &layout);
1504 ok(hr == S_OK, "got 0x%08x\n", hr);
1506 flush_sequence(sequences, RENDERER_ID);
1507 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1508 ok(hr == S_OK, "got 0x%08x\n", hr);
1509 ok_sequence(sequences, RENDERER_ID, empty_seq, "draw test 6", FALSE);
1510 IDWriteTextLayout_Release(layout);
1512 ctxt.gdicompat = TRUE;
1513 ctxt.use_gdi_natural = TRUE;
1515 /* different parameter combinations with gdi-compatible layout */
1516 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, TRUE, &layout);
1517 ok(hr == S_OK, "got 0x%08x\n", hr);
1518 flush_sequence(sequences, RENDERER_ID);
1519 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1520 ok(hr == S_OK, "got 0x%08x\n", hr);
1521 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 7", FALSE);
1523 /* text alignment keeps pixel-aligned origin */
1524 hr = IDWriteTextLayout_GetMetrics(layout, &tm);
1525 ok(hr == S_OK, "got 0x%08x\n", hr);
1526 ok(tm.width == floorf(tm.width), "got %f\n", tm.width);
1528 hr = IDWriteTextLayout_SetMaxWidth(layout, tm.width + 3.0);
1529 ok(hr == S_OK, "got 0x%08x\n", hr);
1530 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_CENTER);
1531 ok(hr == S_OK, "got 0x%08x\n", hr);
1533 ctxt.originX = ctxt.originY = 0.0;
1534 flush_sequence(sequences, RENDERER_ID);
1535 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1536 ok(hr == S_OK, "got 0x%08x\n", hr);
1537 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 7", FALSE);
1538 ok(ctxt.originX != 0.0 && ctxt.originX == floorf(ctxt.originX), "got %f\n", ctxt.originX);
1540 IDWriteTextLayout_Release(layout);
1542 ctxt.gdicompat = TRUE;
1543 ctxt.use_gdi_natural = FALSE;
1545 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1546 ok(hr == S_OK, "got 0x%08x\n", hr);
1547 flush_sequence(sequences, RENDERER_ID);
1548 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1549 ok(hr == S_OK, "got 0x%08x\n", hr);
1550 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 8", FALSE);
1551 IDWriteTextLayout_Release(layout);
1553 ctxt.gdicompat = TRUE;
1554 ctxt.use_gdi_natural = TRUE;
1556 m.m11 = m.m22 = 2.0;
1557 m.m12 = m.m21 = m.dx = m.dy = 0.0;
1558 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, &m, TRUE, &layout);
1559 ok(hr == S_OK, "got 0x%08x\n", hr);
1560 flush_sequence(sequences, RENDERER_ID);
1561 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1562 ok(hr == S_OK, "got 0x%08x\n", hr);
1563 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 9", FALSE);
1564 IDWriteTextLayout_Release(layout);
1566 ctxt.gdicompat = TRUE;
1567 ctxt.use_gdi_natural = FALSE;
1569 m.m11 = m.m22 = 2.0;
1570 m.m12 = m.m21 = m.dx = m.dy = 0.0;
1571 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, &m, FALSE, &layout);
1572 ok(hr == S_OK, "got 0x%08x\n", hr);
1573 flush_sequence(sequences, RENDERER_ID);
1574 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1575 ok(hr == S_OK, "got 0x%08x\n", hr);
1576 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 10", FALSE);
1577 IDWriteTextLayout_Release(layout);
1579 IDWriteInlineObject_Release(inlineobj);
1580 IDWriteTextFormat_Release(format);
1581 IDWriteFactory_Release(factory);
1584 static void test_typography(void)
1586 DWRITE_FONT_FEATURE feature;
1587 IDWriteTypography *typography;
1588 IDWriteFactory *factory;
1589 UINT32 count;
1590 HRESULT hr;
1592 factory = create_factory();
1594 hr = IDWriteFactory_CreateTypography(factory, &typography);
1595 ok(hr == S_OK, "got 0x%08x\n", hr);
1597 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1598 feature.parameter = 1;
1599 hr = IDWriteTypography_AddFontFeature(typography, feature);
1600 ok(hr == S_OK, "got 0x%08x\n", hr);
1602 count = IDWriteTypography_GetFontFeatureCount(typography);
1603 ok(count == 1, "got %u\n", count);
1605 /* duplicated features work just fine */
1606 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1607 feature.parameter = 0;
1608 hr = IDWriteTypography_AddFontFeature(typography, feature);
1609 ok(hr == S_OK, "got 0x%08x\n", hr);
1611 count = IDWriteTypography_GetFontFeatureCount(typography);
1612 ok(count == 2, "got %u\n", count);
1614 memset(&feature, 0xcc, sizeof(feature));
1615 hr = IDWriteTypography_GetFontFeature(typography, 0, &feature);
1616 ok(hr == S_OK, "got 0x%08x\n", hr);
1617 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1618 ok(feature.parameter == 1, "got %u\n", feature.parameter);
1620 memset(&feature, 0xcc, sizeof(feature));
1621 hr = IDWriteTypography_GetFontFeature(typography, 1, &feature);
1622 ok(hr == S_OK, "got 0x%08x\n", hr);
1623 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1624 ok(feature.parameter == 0, "got %u\n", feature.parameter);
1626 hr = IDWriteTypography_GetFontFeature(typography, 2, &feature);
1627 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1629 /* duplicated with same parameter value */
1630 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1631 feature.parameter = 0;
1632 hr = IDWriteTypography_AddFontFeature(typography, feature);
1633 ok(hr == S_OK, "got 0x%08x\n", hr);
1635 count = IDWriteTypography_GetFontFeatureCount(typography);
1636 ok(count == 3, "got %u\n", count);
1638 memset(&feature, 0xcc, sizeof(feature));
1639 hr = IDWriteTypography_GetFontFeature(typography, 2, &feature);
1640 ok(hr == S_OK, "got 0x%08x\n", hr);
1641 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1642 ok(feature.parameter == 0, "got %u\n", feature.parameter);
1644 IDWriteTypography_Release(typography);
1645 IDWriteFactory_Release(factory);
1648 static void test_GetClusterMetrics(void)
1650 static const WCHAR str5W[] = {'a','\r','b','\n','c','\n','\r','d','\r','\n','e',0xb,'f',0xc,
1651 'g',0x0085,'h',0x2028,'i',0x2029,0};
1652 static const WCHAR str3W[] = {0x2066,')',')',0x661,'(',0x627,')',0};
1653 static const WCHAR str2W[] = {0x202a,0x202c,'a',0};
1654 static const WCHAR strW[] = {'a','b','c','d',0};
1655 static const WCHAR str4W[] = {'a',' ',0};
1656 DWRITE_INLINE_OBJECT_METRICS inline_metrics;
1657 DWRITE_CLUSTER_METRICS metrics[20];
1658 IDWriteTextLayout1 *layout1;
1659 IDWriteInlineObject *trimm;
1660 IDWriteTextFormat *format;
1661 IDWriteTextLayout *layout;
1662 DWRITE_TEXT_RANGE range;
1663 IDWriteFactory *factory;
1664 UINT32 count, i;
1665 HRESULT hr;
1667 factory = create_factory();
1669 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1670 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1671 ok(hr == S_OK, "got 0x%08x\n", hr);
1673 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 7, format, 1000.0, 1000.0, &layout);
1674 ok(hr == S_OK, "got 0x%08x\n", hr);
1675 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1676 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1677 ok(count == 7, "got %u\n", count);
1678 IDWriteTextLayout_Release(layout);
1680 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1681 ok(hr == S_OK, "got 0x%08x\n", hr);
1683 count = 0;
1684 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1685 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1686 ok(count == 4, "got %u\n", count);
1688 /* check every cluster width */
1689 count = 0;
1690 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
1691 ok(hr == S_OK, "got 0x%08x\n", hr);
1692 ok(count == 4, "got %u\n", count);
1693 for (i = 0; i < count; i++) {
1694 ok(metrics[i].width > 0.0, "%u: got width %.2f\n", i, metrics[i].width);
1695 ok(metrics[i].length == 1, "%u: got length %u\n", i, metrics[i].length);
1698 /* apply spacing and check widths again */
1699 if (IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1) == S_OK) {
1700 DWRITE_CLUSTER_METRICS metrics2[4];
1701 FLOAT leading, trailing, min_advance;
1702 DWRITE_TEXT_RANGE r;
1704 leading = trailing = min_advance = 2.0;
1705 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 500, &leading, &trailing,
1706 &min_advance, &r);
1707 ok(hr == S_OK, "got 0x%08x\n", hr);
1708 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
1709 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
1710 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
1712 leading = trailing = min_advance = 2.0;
1713 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 0, &leading, &trailing,
1714 &min_advance, NULL);
1715 ok(hr == S_OK, "got 0x%08x\n", hr);
1716 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
1717 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
1719 r.startPosition = 0;
1720 r.length = 4;
1721 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 10.0, 15.0, 0.0, r);
1722 ok(hr == S_OK, "got 0x%08x\n", hr);
1724 count = 0;
1725 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics2, sizeof(metrics2)/sizeof(metrics2[0]), &count);
1726 ok(hr == S_OK, "got 0x%08x\n", hr);
1727 ok(count == 4, "got %u\n", count);
1728 for (i = 0; i < count; i++) {
1729 todo_wine
1730 ok(metrics2[i].width > metrics[i].width, "%u: got width %.2f, was %.2f\n", i, metrics2[i].width,
1731 metrics[i].width);
1732 ok(metrics2[i].length == 1, "%u: got length %u\n", i, metrics2[i].length);
1735 /* back to defaults */
1736 r.startPosition = 0;
1737 r.length = 4;
1738 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, 0.0, r);
1739 ok(hr == S_OK, "got 0x%08x\n", hr);
1741 /* negative advance limit */
1742 r.startPosition = 0;
1743 r.length = 4;
1744 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, -10.0, r);
1745 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1747 IDWriteTextLayout1_Release(layout1);
1749 else
1750 win_skip("IDWriteTextLayout1 is not supported, cluster spacing test skipped.\n");
1752 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &trimm);
1753 ok(hr == S_OK, "got 0x%08x\n", hr);
1755 range.startPosition = 0;
1756 range.length = 2;
1757 hr = IDWriteTextLayout_SetInlineObject(layout, trimm, range);
1758 ok(hr == S_OK, "got 0x%08x\n", hr);
1760 /* inline object takes a separate cluster, replaced codepoints number doesn't matter */
1761 count = 0;
1762 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1763 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1764 ok(count == 3, "got %u\n", count);
1766 count = 0;
1767 memset(&metrics, 0, sizeof(metrics));
1768 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
1769 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1770 ok(count == 3, "got %u\n", count);
1771 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
1773 hr = IDWriteInlineObject_GetMetrics(trimm, &inline_metrics);
1774 ok(hr == S_OK, "got 0x%08x\n", hr);
1775 todo_wine
1776 ok(inline_metrics.width > 0.0 && inline_metrics.width == metrics[0].width, "got %.2f, expected %.2f\n",
1777 inline_metrics.width, metrics[0].width);
1779 IDWriteTextLayout_Release(layout);
1781 /* text with non-visual control codes */
1782 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 3, format, 1000.0, 1000.0, &layout);
1783 ok(hr == S_OK, "got 0x%08x\n", hr);
1785 /* bidi control codes take a separate cluster */
1786 count = 0;
1787 memset(metrics, 0, sizeof(metrics));
1788 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1789 ok(hr == S_OK, "got 0x%08x\n", hr);
1790 ok(count == 3, "got %u\n", count);
1792 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1793 ok(metrics[0].length == 1, "got %d\n", metrics[0].length);
1794 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
1795 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1796 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1797 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1798 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1800 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
1801 ok(metrics[1].length == 1, "got %d\n", metrics[1].length);
1802 ok(metrics[1].canWrapLineAfter == 0, "got %d\n", metrics[1].canWrapLineAfter);
1803 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
1804 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
1805 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
1806 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
1808 ok(metrics[2].width > 0.0, "got %.2f\n", metrics[2].width);
1809 ok(metrics[2].length == 1, "got %d\n", metrics[2].length);
1810 ok(metrics[2].canWrapLineAfter == 1, "got %d\n", metrics[2].canWrapLineAfter);
1811 ok(metrics[2].isWhitespace == 0, "got %d\n", metrics[2].isWhitespace);
1812 ok(metrics[2].isNewline == 0, "got %d\n", metrics[2].isNewline);
1813 ok(metrics[2].isSoftHyphen == 0, "got %d\n", metrics[2].isSoftHyphen);
1814 ok(metrics[2].isRightToLeft == 0, "got %d\n", metrics[2].isRightToLeft);
1816 IDWriteTextLayout_Release(layout);
1818 /* single inline object that fails to report its metrics */
1819 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1820 ok(hr == S_OK, "got 0x%08x\n", hr);
1822 range.startPosition = 0;
1823 range.length = 4;
1824 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj, range);
1825 ok(hr == S_OK, "got 0x%08x\n", hr);
1827 count = 0;
1828 memset(metrics, 0, sizeof(metrics));
1829 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1830 ok(hr == S_OK, "got 0x%08x\n", hr);
1831 ok(count == 1, "got %u\n", count);
1833 /* object sets a width to 123.0, but returns failure from GetMetrics() */
1834 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1835 ok(metrics[0].length == 4, "got %d\n", metrics[0].length);
1836 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
1837 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1838 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1839 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1840 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1842 /* now set two inline object for [0,1] and [2,3], both fail to report break conditions */
1843 range.startPosition = 2;
1844 range.length = 2;
1845 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj2, range);
1846 ok(hr == S_OK, "got 0x%08x\n", hr);
1848 count = 0;
1849 memset(metrics, 0, sizeof(metrics));
1850 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1851 ok(hr == S_OK, "got 0x%08x\n", hr);
1852 ok(count == 2, "got %u\n", count);
1854 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1855 ok(metrics[0].length == 2, "got %d\n", metrics[0].length);
1856 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
1857 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1858 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1859 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1860 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1862 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
1863 ok(metrics[1].length == 2, "got %d\n", metrics[1].length);
1864 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
1865 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
1866 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
1867 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
1868 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
1870 IDWriteTextLayout_Release(layout);
1872 /* zero length string */
1873 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 1000.0, 1000.0, &layout);
1874 ok(hr == S_OK, "got 0x%08x\n", hr);
1876 count = 1;
1877 memset(metrics, 0, sizeof(metrics));
1878 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1879 ok(hr == S_OK, "got 0x%08x\n", hr);
1880 ok(count == 0, "got %u\n", count);
1881 IDWriteTextLayout_Release(layout);
1883 /* whitespace */
1884 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 2, format, 1000.0, 1000.0, &layout);
1885 ok(hr == S_OK, "got 0x%08x\n", hr);
1887 count = 0;
1888 memset(metrics, 0, sizeof(metrics));
1889 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 2, &count);
1890 ok(hr == S_OK, "got 0x%08x\n", hr);
1891 ok(count == 2, "got %u\n", count);
1892 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1893 ok(metrics[1].isWhitespace == 1, "got %d\n", metrics[1].isWhitespace);
1894 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
1895 IDWriteTextLayout_Release(layout);
1897 /* layout is fully covered by inline object with after condition DWRITE_BREAK_CONDITION_MAY_NOT_BREAK */
1898 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 2, format, 1000.0, 1000.0, &layout);
1899 ok(hr == S_OK, "got 0x%08x\n", hr);
1901 range.startPosition = 0;
1902 range.length = ~0u;
1903 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj3, range);
1904 ok(hr == S_OK, "got 0x%08x\n", hr);
1906 count = 0;
1907 memset(metrics, 0, sizeof(metrics));
1908 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 2, &count);
1909 ok(hr == S_OK, "got 0x%08x\n", hr);
1910 ok(count == 1, "got %u\n", count);
1911 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
1913 IDWriteTextLayout_Release(layout);
1915 /* compare natural cluster width with gdi layout */
1916 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 1, format, 100.0, 100.0, &layout);
1917 ok(hr == S_OK, "got 0x%08x\n", hr);
1919 count = 0;
1920 memset(metrics, 0, sizeof(metrics));
1921 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
1922 ok(hr == S_OK, "got 0x%08x\n", hr);
1923 ok(count == 1, "got %u\n", count);
1924 ok(metrics[0].width != floorf(metrics[0].width), "got %f\n", metrics[0].width);
1926 IDWriteTextLayout_Release(layout);
1928 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, str4W, 1, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1929 ok(hr == S_OK, "got 0x%08x\n", hr);
1931 count = 0;
1932 memset(metrics, 0, sizeof(metrics));
1933 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
1934 ok(hr == S_OK, "got 0x%08x\n", hr);
1935 ok(count == 1, "got %u\n", count);
1936 ok(metrics[0].width == floorf(metrics[0].width), "got %f\n", metrics[0].width);
1938 IDWriteTextLayout_Release(layout);
1940 /* isNewline tests */
1941 hr = IDWriteFactory_CreateTextLayout(factory, str5W, 20, format, 100.0, 200.0, &layout);
1942 ok(hr == S_OK, "got 0x%08x\n", hr);
1944 count = 0;
1945 memset(metrics, 0, sizeof(metrics));
1946 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 20, &count);
1947 ok(hr == S_OK, "got 0x%08x\n", hr);
1948 ok(count == 20, "got %u\n", count);
1950 todo_wine {
1951 ok(metrics[1].isNewline == 1, "got %d\n", metrics[1].isNewline);
1952 ok(metrics[3].isNewline == 1, "got %d\n", metrics[3].isNewline);
1953 ok(metrics[5].isNewline == 1, "got %d\n", metrics[5].isNewline);
1954 ok(metrics[6].isNewline == 1, "got %d\n", metrics[6].isNewline);
1955 ok(metrics[9].isNewline == 1, "got %d\n", metrics[9].isNewline);
1956 ok(metrics[11].isNewline == 1, "got %d\n", metrics[11].isNewline);
1957 ok(metrics[13].isNewline == 1, "got %d\n", metrics[13].isNewline);
1958 ok(metrics[15].isNewline == 1, "got %d\n", metrics[15].isNewline);
1959 ok(metrics[17].isNewline == 1, "got %d\n", metrics[17].isNewline);
1960 ok(metrics[19].isNewline == 1, "got %d\n", metrics[19].isNewline);
1962 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1963 ok(metrics[2].isNewline == 0, "got %d\n", metrics[2].isNewline);
1964 ok(metrics[4].isNewline == 0, "got %d\n", metrics[4].isNewline);
1965 ok(metrics[7].isNewline == 0, "got %d\n", metrics[7].isNewline);
1966 ok(metrics[8].isNewline == 0, "got %d\n", metrics[8].isNewline);
1967 ok(metrics[10].isNewline == 0, "got %d\n", metrics[10].isNewline);
1968 ok(metrics[12].isNewline == 0, "got %d\n", metrics[12].isNewline);
1969 ok(metrics[14].isNewline == 0, "got %d\n", metrics[14].isNewline);
1970 ok(metrics[16].isNewline == 0, "got %d\n", metrics[16].isNewline);
1971 ok(metrics[18].isNewline == 0, "got %d\n", metrics[18].isNewline);
1973 for (i = 0; i < count; i++)
1974 ok(metrics[i].length == 1, "%d: got %d\n", i, metrics[i].length);
1976 IDWriteTextLayout_Release(layout);
1978 IDWriteInlineObject_Release(trimm);
1979 IDWriteTextFormat_Release(format);
1980 IDWriteFactory_Release(factory);
1983 static void test_SetLocaleName(void)
1985 static const WCHAR eNuSW[] = {'e','N','-','u','S',0};
1986 static const WCHAR strW[] = {'a','b','c','d',0};
1987 WCHAR buffW[LOCALE_NAME_MAX_LENGTH+sizeof(strW)/sizeof(WCHAR)];
1988 IDWriteTextFormat *format;
1989 IDWriteTextLayout *layout;
1990 DWRITE_TEXT_RANGE range;
1991 IDWriteFactory *factory;
1992 HRESULT hr;
1994 factory = create_factory();
1996 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1997 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1998 ok(hr == S_OK, "got 0x%08x\n", hr);
2000 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2001 ok(hr == S_OK, "got 0x%08x\n", hr);
2003 range.startPosition = 0;
2004 range.length = 1;
2005 hr = IDWriteTextLayout_SetLocaleName(layout, enusW, range);
2006 ok(hr == S_OK, "got 0x%08x\n", hr);
2008 hr = IDWriteTextLayout_SetLocaleName(layout, NULL, range);
2009 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2011 /* invalid locale name is allowed */
2012 hr = IDWriteTextLayout_SetLocaleName(layout, strW, range);
2013 ok(hr == S_OK, "got 0x%08x\n", hr);
2015 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 0, NULL);
2016 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2018 if (0) /* crashes on native */
2019 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 1, NULL);
2021 buffW[0] = 0;
2022 range.length = 0;
2023 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), &range);
2024 ok(hr == S_OK, "got 0x%08x\n", hr);
2025 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
2026 ok(range.startPosition == 0 && range.length == 1, "got %u,%u\n", range.startPosition, range.length);
2028 /* get with a shorter buffer */
2029 buffW[0] = 0xa;
2030 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, 1, NULL);
2031 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2032 ok(buffW[0] == 0, "got %x\n", buffW[0]);
2034 /* name is too long */
2035 lstrcpyW(buffW, strW);
2036 while (lstrlenW(buffW) <= LOCALE_NAME_MAX_LENGTH)
2037 lstrcatW(buffW, strW);
2039 range.startPosition = 0;
2040 range.length = 1;
2041 hr = IDWriteTextLayout_SetLocaleName(layout, buffW, range);
2042 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2044 buffW[0] = 0;
2045 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), NULL);
2046 ok(hr == S_OK, "got 0x%08x\n", hr);
2047 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
2049 /* set initial locale name for whole text, except with a different casing */
2050 range.startPosition = 0;
2051 range.length = 4;
2052 hr = IDWriteTextLayout_SetLocaleName(layout, eNuSW, range);
2053 ok(hr == S_OK, "got 0x%08x\n", hr);
2055 buffW[0] = 0;
2056 range.length = 0;
2057 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), &range);
2058 ok(hr == S_OK, "got 0x%08x\n", hr);
2059 todo_wine
2060 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
2061 ok((range.startPosition == 0 && range.length == ~0u) ||
2062 broken(range.startPosition == 0 && range.length == 4) /* vista/win7 */, "got %u,%u\n", range.startPosition, range.length);
2064 /* check what's returned for positions after the text */
2065 buffW[0] = 0;
2066 range.length = 0;
2067 hr = IDWriteTextLayout_GetLocaleName(layout, 100, buffW, sizeof(buffW)/sizeof(WCHAR), &range);
2068 ok(hr == S_OK, "got 0x%08x\n", hr);
2069 todo_wine
2070 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
2071 ok((range.startPosition == 0 && range.length == ~0u) ||
2072 broken(range.startPosition == 4 && range.length == ~0u-4) /* vista/win7 */, "got %u,%u\n", range.startPosition, range.length);
2074 IDWriteTextLayout_Release(layout);
2075 IDWriteTextFormat_Release(format);
2076 IDWriteFactory_Release(factory);
2079 static void test_SetPairKerning(void)
2081 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
2082 DWRITE_CLUSTER_METRICS clusters[4];
2083 IDWriteTextLayout1 *layout1;
2084 IDWriteTextFormat *format;
2085 IDWriteTextLayout *layout;
2086 DWRITE_TEXT_RANGE range;
2087 IDWriteFactory *factory;
2088 BOOL kerning;
2089 UINT32 count;
2090 HRESULT hr;
2092 factory = create_factory();
2094 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2095 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2096 ok(hr == S_OK, "got 0x%08x\n", hr);
2098 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2099 ok(hr == S_OK, "got 0x%08x\n", hr);
2100 IDWriteTextFormat_Release(format);
2102 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1);
2103 IDWriteTextLayout_Release(layout);
2105 if (hr != S_OK) {
2106 win_skip("SetPairKerning() is not supported.\n");
2107 IDWriteFactory_Release(factory);
2108 return;
2111 if (0) { /* crashes on native */
2112 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, NULL);
2113 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, &range);
2116 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, NULL);
2117 ok(hr == S_OK, "got 0x%08x\n", hr);
2119 range.startPosition = 0;
2120 range.length = 0;
2121 kerning = TRUE;
2122 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
2123 ok(hr == S_OK, "got 0x%08x\n", hr);
2124 ok(!kerning, "got %d\n", kerning);
2125 ok(range.length == ~0u, "got %u\n", range.length);
2127 count = 0;
2128 hr = IDWriteTextLayout1_GetClusterMetrics(layout1, clusters, 4, &count);
2129 ok(hr == S_OK, "got 0x%08x\n", hr);
2130 todo_wine
2131 ok(count == 3, "got %u\n", count);
2132 if (count == 3) {
2133 ok(clusters[0].length == 1, "got %u\n", clusters[0].length);
2134 ok(clusters[1].length == 2, "got %u\n", clusters[1].length);
2135 ok(clusters[2].length == 1, "got %u\n", clusters[2].length);
2137 /* pair kerning flag participates in itemization - combining characters
2138 breaks */
2139 range.startPosition = 0;
2140 range.length = 2;
2141 hr = IDWriteTextLayout1_SetPairKerning(layout1, 2, range);
2142 ok(hr == S_OK, "got 0x%08x\n", hr);
2144 kerning = FALSE;
2145 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
2146 ok(hr == S_OK, "got 0x%08x\n", hr);
2147 ok(kerning == TRUE, "got %d\n", kerning);
2149 count = 0;
2150 hr = IDWriteTextLayout1_GetClusterMetrics(layout1, clusters, 4, &count);
2151 ok(hr == S_OK, "got 0x%08x\n", hr);
2152 ok(count == 4, "got %u\n", count);
2153 ok(clusters[0].length == 1, "got %u\n", clusters[0].length);
2154 ok(clusters[1].length == 1, "got %u\n", clusters[1].length);
2155 ok(clusters[2].length == 1, "got %u\n", clusters[2].length);
2156 ok(clusters[3].length == 1, "got %u\n", clusters[3].length);
2158 IDWriteTextLayout1_Release(layout1);
2159 IDWriteFactory_Release(factory);
2162 static void test_SetVerticalGlyphOrientation(void)
2164 static const WCHAR strW[] = {'a','b','c','d',0};
2165 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation;
2166 IDWriteTextLayout2 *layout2;
2167 IDWriteTextFormat *format;
2168 IDWriteTextLayout *layout;
2169 IDWriteFactory *factory;
2170 HRESULT hr;
2172 factory = create_factory();
2174 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2175 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2176 ok(hr == S_OK, "got 0x%08x\n", hr);
2178 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2179 ok(hr == S_OK, "got 0x%08x\n", hr);
2180 IDWriteTextFormat_Release(format);
2182 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
2183 IDWriteTextLayout_Release(layout);
2185 if (hr != S_OK) {
2186 win_skip("SetVerticalGlyphOrientation() is not supported.\n");
2187 IDWriteFactory_Release(factory);
2188 return;
2191 orientation = IDWriteTextLayout2_GetVerticalGlyphOrientation(layout2);
2192 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT, "got %d\n", orientation);
2194 hr = IDWriteTextLayout2_SetVerticalGlyphOrientation(layout2, DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED+1);
2195 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2197 IDWriteTextLayout2_Release(layout2);
2198 IDWriteFactory_Release(factory);
2201 static void test_fallback(void)
2203 static const WCHAR strW[] = {'a','b','c','d',0};
2204 IDWriteFontFallback *fallback, *fallback2;
2205 IDWriteTextLayout2 *layout2;
2206 IDWriteTextFormat1 *format1;
2207 IDWriteTextFormat *format;
2208 IDWriteTextLayout *layout;
2209 IDWriteFactory2 *factory2;
2210 IDWriteFactory *factory;
2211 HRESULT hr;
2213 factory = create_factory();
2215 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2216 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2217 ok(hr == S_OK, "got 0x%08x\n", hr);
2219 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2220 ok(hr == S_OK, "got 0x%08x\n", hr);
2221 IDWriteTextFormat_Release(format);
2223 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
2224 IDWriteTextLayout_Release(layout);
2226 if (hr != S_OK) {
2227 win_skip("GetFontFallback() is not supported.\n");
2228 IDWriteFactory_Release(factory);
2229 return;
2232 if (0) /* crashes on native */
2233 hr = IDWriteTextLayout2_GetFontFallback(layout2, NULL);
2235 fallback = (void*)0xdeadbeef;
2236 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback);
2237 ok(hr == S_OK, "got 0x%08x\n", hr);
2238 ok(fallback == NULL, "got %p\n", fallback);
2240 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
2241 ok(hr == S_OK, "got 0x%08x\n", hr);
2243 fallback = (void*)0xdeadbeef;
2244 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback);
2245 ok(hr == S_OK, "got 0x%08x\n", hr);
2246 ok(fallback == NULL, "got %p\n", fallback);
2248 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
2249 ok(hr == S_OK, "got 0x%08x\n", hr);
2251 fallback = NULL;
2252 hr = IDWriteFactory2_GetSystemFontFallback(factory2, &fallback);
2253 todo_wine
2254 ok(hr == S_OK, "got 0x%08x\n", hr);
2255 if (hr == S_OK) {
2256 ok(fallback != NULL, "got %p\n", fallback);
2258 hr = IDWriteTextFormat1_SetFontFallback(format1, fallback);
2259 ok(hr == S_OK, "got 0x%08x\n", hr);
2261 fallback2 = (void*)0xdeadbeef;
2262 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback2);
2263 ok(hr == S_OK, "got 0x%08x\n", hr);
2264 ok(fallback2 == fallback, "got %p\n", fallback2);
2266 hr = IDWriteTextLayout2_SetFontFallback(layout2, NULL);
2267 ok(hr == S_OK, "got 0x%08x\n", hr);
2269 fallback2 = (void*)0xdeadbeef;
2270 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback2);
2271 ok(hr == S_OK, "got 0x%08x\n", hr);
2272 ok(fallback2 == NULL, "got %p\n", fallback2);
2274 IDWriteFontFallback_Release(fallback);
2276 IDWriteTextFormat1_Release(format1);
2277 IDWriteTextLayout2_Release(layout2);
2278 IDWriteFactory_Release(factory);
2281 static void test_DetermineMinWidth(void)
2283 static const WCHAR strW[] = {'a','b','c','d',0};
2284 IDWriteTextFormat *format;
2285 IDWriteTextLayout *layout;
2286 IDWriteFactory *factory;
2287 FLOAT minwidth;
2288 HRESULT hr;
2290 factory = create_factory();
2292 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2293 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2294 ok(hr == S_OK, "got 0x%08x\n", hr);
2296 hr = IDWriteFactory_CreateTextLayout(factory, strW, lstrlenW(strW), format, 1000.0, 1000.0, &layout);
2297 ok(hr == S_OK, "got 0x%08x\n", hr);
2299 hr = IDWriteTextLayout_DetermineMinWidth(layout, NULL);
2300 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2302 minwidth = 0.0;
2303 hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
2304 ok(hr == S_OK, "got 0x%08x\n", hr);
2305 ok(minwidth > 0.0, "got %.2f\n", minwidth);
2307 IDWriteTextLayout_Release(layout);
2308 IDWriteTextFormat_Release(format);
2309 IDWriteFactory_Release(factory);
2312 static void test_SetFontSize(void)
2314 static const WCHAR strW[] = {'a','b','c','d',0};
2315 IDWriteTextFormat *format;
2316 IDWriteTextLayout *layout;
2317 IDWriteFactory *factory;
2318 DWRITE_TEXT_RANGE r;
2319 FLOAT size;
2320 HRESULT hr;
2322 factory = create_factory();
2324 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2325 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2326 ok(hr == S_OK, "got 0x%08x\n", hr);
2328 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2329 ok(hr == S_OK, "got 0x%08x\n", hr);
2331 /* negative/zero size */
2332 r.startPosition = 1;
2333 r.length = 1;
2334 hr = IDWriteTextLayout_SetFontSize(layout, -15.0, r);
2335 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2337 hr = IDWriteTextLayout_SetFontSize(layout, 0.0, r);
2338 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2340 r.startPosition = 1;
2341 r.length = 0;
2342 size = 0.0;
2343 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
2344 ok(hr == S_OK, "got 0x%08x\n", hr);
2345 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2346 ok(size == 10.0, "got %.2f\n", size);
2348 r.startPosition = 1;
2349 r.length = 1;
2350 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
2351 ok(hr == S_OK, "got 0x%08x\n", hr);
2353 /* zero length range */
2354 r.startPosition = 1;
2355 r.length = 0;
2356 hr = IDWriteTextLayout_SetFontSize(layout, 123.0, r);
2357 ok(hr == S_OK, "got 0x%08x\n", hr);
2359 size = 0.0;
2360 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
2361 ok(hr == S_OK, "got 0x%08x\n", hr);
2362 ok(size == 15.0, "got %.2f\n", size);
2364 r.startPosition = 0;
2365 r.length = 4;
2366 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
2367 ok(hr == S_OK, "got 0x%08x\n", hr);
2369 size = 0.0;
2370 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
2371 ok(hr == S_OK, "got 0x%08x\n", hr);
2372 ok(size == 15.0, "got %.2f\n", size);
2374 size = 0.0;
2375 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
2376 ok(hr == S_OK, "got 0x%08x\n", hr);
2377 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2378 ok(size == 15.0, "got %.2f\n", size);
2380 size = 15.0;
2381 r.startPosition = r.length = 0;
2382 hr = IDWriteTextLayout_GetFontSize(layout, 20, &size, &r);
2383 ok(hr == S_OK, "got 0x%08x\n", hr);
2384 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2385 ok(size == 10.0, "got %.2f\n", size);
2387 r.startPosition = 100;
2388 r.length = 4;
2389 hr = IDWriteTextLayout_SetFontSize(layout, 25.0, r);
2390 ok(hr == S_OK, "got 0x%08x\n", hr);
2392 size = 15.0;
2393 r.startPosition = r.length = 0;
2394 hr = IDWriteTextLayout_GetFontSize(layout, 100, &size, &r);
2395 ok(hr == S_OK, "got 0x%08x\n", hr);
2396 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2397 ok(size == 25.0, "got %.2f\n", size);
2399 IDWriteTextLayout_Release(layout);
2400 IDWriteTextFormat_Release(format);
2401 IDWriteFactory_Release(factory);
2404 static void test_SetFontFamilyName(void)
2406 static const WCHAR taHomaW[] = {'T','a','H','o','m','a',0};
2407 static const WCHAR arialW[] = {'A','r','i','a','l',0};
2408 static const WCHAR strW[] = {'a','b','c','d',0};
2409 IDWriteTextFormat *format;
2410 IDWriteTextLayout *layout;
2411 IDWriteFactory *factory;
2412 DWRITE_TEXT_RANGE r;
2413 WCHAR nameW[50];
2414 HRESULT hr;
2416 factory = create_factory();
2418 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2419 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2420 ok(hr == S_OK, "got 0x%08x\n", hr);
2422 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2423 ok(hr == S_OK, "got 0x%08x\n", hr);
2425 /* NULL name */
2426 r.startPosition = 1;
2427 r.length = 1;
2428 hr = IDWriteTextLayout_SetFontFamilyName(layout, NULL, r);
2429 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2431 r.startPosition = 1;
2432 r.length = 0;
2433 nameW[0] = 0;
2434 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2435 ok(hr == S_OK, "got 0x%08x\n", hr);
2436 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2438 /* set name only different in casing */
2439 r.startPosition = 1;
2440 r.length = 1;
2441 hr = IDWriteTextLayout_SetFontFamilyName(layout, taHomaW, r);
2442 ok(hr == S_OK, "got 0x%08x\n", hr);
2444 /* zero length range */
2445 r.startPosition = 1;
2446 r.length = 0;
2447 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
2448 ok(hr == S_OK, "got 0x%08x\n", hr);
2450 r.startPosition = 0;
2451 r.length = 0;
2452 nameW[0] = 0;
2453 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2454 ok(hr == S_OK, "got 0x%08x\n", hr);
2455 ok(!lstrcmpW(nameW, taHomaW), "got %s\n", wine_dbgstr_w(nameW));
2456 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2458 r.startPosition = 1;
2459 r.length = 1;
2460 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
2461 ok(hr == S_OK, "got 0x%08x\n", hr);
2463 r.startPosition = 1;
2464 r.length = 0;
2465 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2466 ok(hr == S_OK, "got 0x%08x\n", hr);
2467 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2469 r.startPosition = 0;
2470 r.length = 4;
2471 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
2472 ok(hr == S_OK, "got 0x%08x\n", hr);
2474 nameW[0] = 0;
2475 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2476 ok(hr == S_OK, "got 0x%08x\n", hr);
2477 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2478 ok(!lstrcmpW(nameW, arialW), "got name %s\n", wine_dbgstr_w(nameW));
2480 IDWriteTextLayout_Release(layout);
2481 IDWriteTextFormat_Release(format);
2482 IDWriteFactory_Release(factory);
2485 static void test_SetFontStyle(void)
2487 static const WCHAR strW[] = {'a','b','c','d',0};
2488 IDWriteTextFormat *format;
2489 IDWriteTextLayout *layout;
2490 IDWriteFactory *factory;
2491 DWRITE_FONT_STYLE style;
2492 DWRITE_TEXT_RANGE r;
2493 HRESULT hr;
2495 factory = create_factory();
2497 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2498 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2499 ok(hr == S_OK, "got 0x%08x\n", hr);
2501 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2502 ok(hr == S_OK, "got 0x%08x\n", hr);
2504 /* invalid style value */
2505 r.startPosition = 1;
2506 r.length = 1;
2507 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC+1, r);
2508 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2510 r.startPosition = 1;
2511 r.length = 0;
2512 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
2513 ok(hr == S_OK, "got 0x%08x\n", hr);
2514 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2515 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
2517 r.startPosition = 1;
2518 r.length = 1;
2519 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC, r);
2520 ok(hr == S_OK, "got 0x%08x\n", hr);
2522 /* zero length range */
2523 r.startPosition = 1;
2524 r.length = 0;
2525 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_NORMAL, r);
2526 ok(hr == S_OK, "got 0x%08x\n", hr);
2528 style = DWRITE_FONT_STYLE_NORMAL;
2529 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
2530 ok(hr == S_OK, "got 0x%08x\n", hr);
2531 ok(style == DWRITE_FONT_STYLE_ITALIC, "got %d\n", style);
2533 r.startPosition = 0;
2534 r.length = 4;
2535 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
2536 ok(hr == S_OK, "got 0x%08x\n", hr);
2538 style = DWRITE_FONT_STYLE_ITALIC;
2539 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
2540 ok(hr == S_OK, "got 0x%08x\n", hr);
2541 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2543 style = DWRITE_FONT_STYLE_ITALIC;
2544 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
2545 ok(hr == S_OK, "got 0x%08x\n", hr);
2546 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2547 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2549 style = DWRITE_FONT_STYLE_ITALIC;
2550 r.startPosition = r.length = 0;
2551 hr = IDWriteTextLayout_GetFontStyle(layout, 20, &style, &r);
2552 ok(hr == S_OK, "got 0x%08x\n", hr);
2553 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2554 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
2556 r.startPosition = 100;
2557 r.length = 4;
2558 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
2559 ok(hr == S_OK, "got 0x%08x\n", hr);
2561 style = DWRITE_FONT_STYLE_NORMAL;
2562 r.startPosition = r.length = 0;
2563 hr = IDWriteTextLayout_GetFontStyle(layout, 100, &style, &r);
2564 ok(hr == S_OK, "got 0x%08x\n", hr);
2565 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2566 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2568 IDWriteTextLayout_Release(layout);
2569 IDWriteTextFormat_Release(format);
2570 IDWriteFactory_Release(factory);
2573 static void test_SetFontStretch(void)
2575 static const WCHAR strW[] = {'a','b','c','d',0};
2576 DWRITE_FONT_STRETCH stretch;
2577 IDWriteTextFormat *format;
2578 IDWriteTextLayout *layout;
2579 IDWriteFactory *factory;
2580 DWRITE_TEXT_RANGE r;
2581 HRESULT hr;
2583 factory = create_factory();
2585 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2586 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2587 ok(hr == S_OK, "got 0x%08x\n", hr);
2589 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2590 ok(hr == S_OK, "got 0x%08x\n", hr);
2592 /* invalid stretch value */
2593 r.startPosition = 1;
2594 r.length = 1;
2595 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_ULTRA_EXPANDED+1, r);
2596 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2598 r.startPosition = 1;
2599 r.length = 0;
2600 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2601 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
2602 ok(hr == S_OK, "got 0x%08x\n", hr);
2603 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2604 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
2606 r.startPosition = 1;
2607 r.length = 1;
2608 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_CONDENSED, r);
2609 ok(hr == S_OK, "got 0x%08x\n", hr);
2611 /* zero length range */
2612 r.startPosition = 1;
2613 r.length = 0;
2614 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_NORMAL, r);
2615 ok(hr == S_OK, "got 0x%08x\n", hr);
2617 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2618 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
2619 ok(hr == S_OK, "got 0x%08x\n", hr);
2620 ok(stretch == DWRITE_FONT_STRETCH_CONDENSED, "got %d\n", stretch);
2622 r.startPosition = 0;
2623 r.length = 4;
2624 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
2625 ok(hr == S_OK, "got 0x%08x\n", hr);
2627 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2628 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
2629 ok(hr == S_OK, "got 0x%08x\n", hr);
2630 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
2632 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2633 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
2634 ok(hr == S_OK, "got 0x%08x\n", hr);
2635 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2636 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
2638 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2639 r.startPosition = r.length = 0;
2640 hr = IDWriteTextLayout_GetFontStretch(layout, 20, &stretch, &r);
2641 ok(hr == S_OK, "got 0x%08x\n", hr);
2642 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2643 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
2645 r.startPosition = 100;
2646 r.length = 4;
2647 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
2648 ok(hr == S_OK, "got 0x%08x\n", hr);
2650 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2651 r.startPosition = r.length = 0;
2652 hr = IDWriteTextLayout_GetFontStretch(layout, 100, &stretch, &r);
2653 ok(hr == S_OK, "got 0x%08x\n", hr);
2654 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2655 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
2657 /* trying to set undefined value */
2658 r.startPosition = 0;
2659 r.length = 2;
2660 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_UNDEFINED, r);
2661 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2663 IDWriteTextLayout_Release(layout);
2664 IDWriteTextFormat_Release(format);
2665 IDWriteFactory_Release(factory);
2668 static void test_SetStrikethrough(void)
2670 static const WCHAR strW[] = {'a','b','c','d',0};
2671 IDWriteTextFormat *format;
2672 IDWriteTextLayout *layout;
2673 IDWriteFactory *factory;
2674 DWRITE_TEXT_RANGE r;
2675 BOOL value;
2676 HRESULT hr;
2678 factory = create_factory();
2680 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2681 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2682 ok(hr == S_OK, "got 0x%08x\n", hr);
2684 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2685 ok(hr == S_OK, "got 0x%08x\n", hr);
2687 r.startPosition = 1;
2688 r.length = 0;
2689 value = TRUE;
2690 hr = IDWriteTextLayout_GetStrikethrough(layout, 0, &value, &r);
2691 ok(hr == S_OK, "got 0x%08x\n", hr);
2692 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2693 ok(value == FALSE, "got %d\n", value);
2695 r.startPosition = 1;
2696 r.length = 1;
2697 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, r);
2698 ok(hr == S_OK, "got 0x%08x\n", hr);
2700 value = FALSE;
2701 hr = IDWriteTextLayout_GetStrikethrough(layout, 1, &value, &r);
2702 ok(hr == S_OK, "got 0x%08x\n", hr);
2703 ok(value == TRUE, "got %d\n", value);
2704 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2706 value = TRUE;
2707 r.startPosition = r.length = 0;
2708 hr = IDWriteTextLayout_GetStrikethrough(layout, 20, &value, &r);
2709 ok(hr == S_OK, "got 0x%08x\n", hr);
2710 ok(r.startPosition == 2 && r.length == ~0u-2, "got %u, %u\n", r.startPosition, r.length);
2711 ok(value == FALSE, "got %d\n", value);
2713 r.startPosition = 100;
2714 r.length = 4;
2715 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, r);
2716 ok(hr == S_OK, "got 0x%08x\n", hr);
2718 value = FALSE;
2719 r.startPosition = r.length = 0;
2720 hr = IDWriteTextLayout_GetStrikethrough(layout, 100, &value, &r);
2721 ok(hr == S_OK, "got 0x%08x\n", hr);
2722 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2723 ok(value == TRUE, "got %d\n", value);
2725 IDWriteTextLayout_Release(layout);
2726 IDWriteTextFormat_Release(format);
2727 IDWriteFactory_Release(factory);
2730 static void test_GetMetrics(void)
2732 static const WCHAR str2W[] = {0x2066,')',')',0x661,'(',0x627,')',0};
2733 static const WCHAR strW[] = {'a','b','c','d',0};
2734 static const WCHAR str3W[] = {'a',0};
2735 DWRITE_CLUSTER_METRICS clusters[4];
2736 DWRITE_TEXT_METRICS metrics;
2737 IDWriteTextFormat *format;
2738 IDWriteTextLayout *layout;
2739 IDWriteFactory *factory;
2740 UINT32 count, i;
2741 FLOAT width;
2742 HRESULT hr;
2744 factory = create_factory();
2746 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2747 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2748 ok(hr == S_OK, "got 0x%08x\n", hr);
2750 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2751 ok(hr == S_OK, "got 0x%08x\n", hr);
2753 count = 0;
2754 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count);
2755 ok(hr == S_OK, "got 0x%08x\n", hr);
2756 ok(count == 4, "got %u\n", count);
2757 for (i = 0, width = 0.0; i < count; i++)
2758 width += clusters[i].width;
2760 memset(&metrics, 0xcc, sizeof(metrics));
2761 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
2762 ok(hr == S_OK, "got 0x%08x\n", hr);
2763 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
2764 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
2765 ok(metrics.width == width, "got %.2f, expected %.2f\n", metrics.width, width);
2766 ok(metrics.widthIncludingTrailingWhitespace == width, "got %.2f, expected %.2f\n",
2767 metrics.widthIncludingTrailingWhitespace, width);
2768 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
2769 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
2770 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
2771 ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
2772 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
2774 IDWriteTextLayout_Release(layout);
2776 /* a string with more complex bidi sequence */
2777 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 7, format, 500.0, 1000.0, &layout);
2778 ok(hr == S_OK, "got 0x%08x\n", hr);
2780 memset(&metrics, 0xcc, sizeof(metrics));
2781 metrics.maxBidiReorderingDepth = 0;
2782 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
2783 ok(hr == S_OK, "got 0x%08x\n", hr);
2784 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
2785 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
2786 ok(metrics.width > 0.0, "got %.2f\n", metrics.width);
2787 ok(metrics.widthIncludingTrailingWhitespace > 0.0, "got %.2f\n", metrics.widthIncludingTrailingWhitespace);
2788 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
2789 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
2790 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
2791 todo_wine
2792 ok(metrics.maxBidiReorderingDepth > 1, "got %u\n", metrics.maxBidiReorderingDepth);
2793 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
2795 IDWriteTextLayout_Release(layout);
2797 /* single cluster layout */
2798 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 1, format, 500.0, 1000.0, &layout);
2799 ok(hr == S_OK, "got 0x%08x\n", hr);
2801 count = 0;
2802 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
2803 ok(hr == S_OK, "got 0x%08x\n", hr);
2804 ok(count == 1, "got %u\n", count);
2806 memset(&metrics, 0xcc, sizeof(metrics));
2807 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
2808 ok(hr == S_OK, "got 0x%08x\n", hr);
2809 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
2810 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
2811 ok(metrics.width == clusters[0].width, "got %.2f, expected %.2f\n", metrics.width, clusters[0].width);
2812 ok(metrics.widthIncludingTrailingWhitespace == clusters[0].width, "got %.2f\n", metrics.widthIncludingTrailingWhitespace);
2813 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
2814 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
2815 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
2816 ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
2817 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
2818 IDWriteTextLayout_Release(layout);
2820 IDWriteTextFormat_Release(format);
2821 IDWriteFactory_Release(factory);
2824 static void test_SetFlowDirection(void)
2826 static const WCHAR strW[] = {'a','b','c','d',0};
2827 DWRITE_READING_DIRECTION reading;
2828 DWRITE_FLOW_DIRECTION flow;
2829 IDWriteTextFormat *format;
2830 IDWriteTextLayout *layout;
2831 IDWriteFactory *factory;
2832 HRESULT hr;
2834 factory = create_factory();
2836 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2837 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2838 ok(hr == S_OK, "got 0x%08x\n", hr);
2840 flow = IDWriteTextFormat_GetFlowDirection(format);
2841 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
2843 reading = IDWriteTextFormat_GetReadingDirection(format);
2844 ok(reading == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", reading);
2846 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2847 ok(hr == S_OK, "got 0x%08x\n", hr);
2848 IDWriteTextLayout_Release(layout);
2850 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT);
2851 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* vista,win7 */, "got 0x%08x\n", hr);
2852 if (hr == S_OK) {
2853 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2854 ok(hr == S_OK, "got 0x%08x\n", hr);
2855 IDWriteTextLayout_Release(layout);
2857 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_TOP_TO_BOTTOM);
2858 ok(hr == S_OK, "got 0x%08x\n", hr);
2860 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
2861 ok(hr == S_OK, "got 0x%08x\n", hr);
2863 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2864 ok(hr == S_OK, "got 0x%08x\n", hr);
2865 IDWriteTextLayout_Release(layout);
2867 else
2868 win_skip("DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT is not supported\n");
2870 IDWriteTextFormat_Release(format);
2871 IDWriteFactory_Release(factory);
2874 static const struct drawcall_entry draweffect_seq[] = {
2875 { DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0x0300,0} },
2876 { DRAW_GLYPHRUN, {'d',0} },
2877 { DRAW_LAST_KIND }
2880 static const struct drawcall_entry draweffect2_seq[] = {
2881 { DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0} },
2882 { DRAW_GLYPHRUN, {'c','d',0} },
2883 { DRAW_LAST_KIND }
2886 static const struct drawcall_entry draweffect3_seq[] = {
2887 { DRAW_INLINE|DRAW_EFFECT },
2888 { DRAW_LAST_KIND }
2891 static const struct drawcall_entry draweffect4_seq[] = {
2892 { DRAW_INLINE },
2893 { DRAW_LAST_KIND }
2896 static void test_SetDrawingEffect(void)
2898 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
2899 static const WCHAR str2W[] = {'a','e','c','d',0};
2900 IDWriteInlineObject *sign;
2901 IDWriteTextFormat *format;
2902 IDWriteTextLayout *layout;
2903 IDWriteFactory *factory;
2904 DWRITE_TEXT_RANGE r;
2905 IUnknown *unk;
2906 HRESULT hr;
2908 factory = create_factory();
2910 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2911 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2912 ok(hr == S_OK, "got 0x%08x\n", hr);
2914 /* string with combining mark */
2915 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
2916 ok(hr == S_OK, "got 0x%08x\n", hr);
2918 /* set effect past the end of text */
2919 r.startPosition = 100;
2920 r.length = 10;
2921 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2922 ok(hr == S_OK, "got 0x%08x\n", hr);
2924 r.startPosition = r.length = 0;
2925 hr = IDWriteTextLayout_GetDrawingEffect(layout, 101, &unk, &r);
2926 ok(hr == S_OK, "got 0x%08x\n", hr);
2927 ok(r.startPosition == 100 && r.length == 10, "got %u, %u\n", r.startPosition, r.length);
2929 r.startPosition = r.length = 0;
2930 unk = (void*)0xdeadbeef;
2931 hr = IDWriteTextLayout_GetDrawingEffect(layout, 1000, &unk, &r);
2932 ok(hr == S_OK, "got 0x%08x\n", hr);
2933 ok(r.startPosition == 110 && r.length == ~0u-110, "got %u, %u\n", r.startPosition, r.length);
2934 ok(unk == NULL, "got %p\n", unk);
2936 /* effect is applied to clusters, not individual text positions */
2937 r.startPosition = 0;
2938 r.length = 2;
2939 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2940 ok(hr == S_OK, "got 0x%08x\n", hr);
2942 flush_sequence(sequences, RENDERER_ID);
2943 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
2944 ok(hr == S_OK, "got 0x%08x\n", hr);
2945 ok_sequence(sequences, RENDERER_ID, draweffect_seq, "effect draw test", TRUE);
2946 IDWriteTextLayout_Release(layout);
2948 /* simple string */
2949 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 1000.0, &layout);
2950 ok(hr == S_OK, "got 0x%08x\n", hr);
2952 r.startPosition = 0;
2953 r.length = 2;
2954 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2955 ok(hr == S_OK, "got 0x%08x\n", hr);
2957 flush_sequence(sequences, RENDERER_ID);
2958 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
2959 ok(hr == S_OK, "got 0x%08x\n", hr);
2960 ok_sequence(sequences, RENDERER_ID, draweffect2_seq, "effect draw test 2", TRUE);
2961 IDWriteTextLayout_Release(layout);
2963 /* Inline object - effect set for same range */
2964 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
2965 ok(hr == S_OK, "got 0x%08x\n", hr);
2967 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 1000.0, &layout);
2968 ok(hr == S_OK, "got 0x%08x\n", hr);
2970 r.startPosition = 0;
2971 r.length = 4;
2972 hr = IDWriteTextLayout_SetInlineObject(layout, sign, r);
2973 ok(hr == S_OK, "got 0x%08x\n", hr);
2975 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2976 ok(hr == S_OK, "got 0x%08x\n", hr);
2978 flush_sequence(sequences, RENDERER_ID);
2979 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
2980 ok(hr == S_OK, "got 0x%08x\n", hr);
2981 ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 3", FALSE);
2983 /* now set effect somewhere inside a range replaced by inline object */
2984 hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
2985 ok(hr == S_OK, "got 0x%08x\n", hr);
2987 r.startPosition = 1;
2988 r.length = 1;
2989 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
2990 ok(hr == S_OK, "got 0x%08x\n", hr);
2992 /* no effect is reported in this case */
2993 flush_sequence(sequences, RENDERER_ID);
2994 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
2995 ok(hr == S_OK, "got 0x%08x\n", hr);
2996 ok_sequence(sequences, RENDERER_ID, draweffect4_seq, "effect draw test 4", FALSE);
2998 r.startPosition = 0;
2999 r.length = 4;
3000 hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
3001 ok(hr == S_OK, "got 0x%08x\n", hr);
3003 r.startPosition = 0;
3004 r.length = 1;
3005 hr = IDWriteTextLayout_SetDrawingEffect(layout, &testeffect, r);
3006 ok(hr == S_OK, "got 0x%08x\n", hr);
3008 /* first range position is all that matters for inline ranges */
3009 flush_sequence(sequences, RENDERER_ID);
3010 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3011 ok(hr == S_OK, "got 0x%08x\n", hr);
3012 ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 5", FALSE);
3014 IDWriteTextLayout_Release(layout);
3016 IDWriteInlineObject_Release(sign);
3017 IDWriteTextFormat_Release(format);
3018 IDWriteFactory_Release(factory);
3021 static IDWriteFontFace *get_fontface_from_format(IDWriteTextFormat *format)
3023 IDWriteFontCollection *collection;
3024 IDWriteFontFamily *family;
3025 IDWriteFontFace *fontface;
3026 IDWriteFont *font;
3027 WCHAR nameW[255];
3028 UINT32 index;
3029 BOOL exists;
3030 HRESULT hr;
3032 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
3033 ok(hr == S_OK, "got 0x%08x\n", hr);
3035 hr = IDWriteTextFormat_GetFontFamilyName(format, nameW, sizeof(nameW)/sizeof(WCHAR));
3036 ok(hr == S_OK, "got 0x%08x\n", hr);
3038 hr = IDWriteFontCollection_FindFamilyName(collection, nameW, &index, &exists);
3039 ok(hr == S_OK, "got 0x%08x\n", hr);
3041 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
3042 ok(hr == S_OK, "got 0x%08x\n", hr);
3043 IDWriteFontCollection_Release(collection);
3045 hr = IDWriteFontFamily_GetFirstMatchingFont(family,
3046 IDWriteTextFormat_GetFontWeight(format),
3047 IDWriteTextFormat_GetFontStretch(format),
3048 IDWriteTextFormat_GetFontStyle(format),
3049 &font);
3050 ok(hr == S_OK, "got 0x%08x\n", hr);
3052 hr = IDWriteFont_CreateFontFace(font, &fontface);
3053 ok(hr == S_OK, "got 0x%08x\n", hr);
3055 IDWriteFont_Release(font);
3056 IDWriteFontFamily_Release(family);
3058 return fontface;
3061 static void test_GetLineMetrics(void)
3063 static const WCHAR str3W[] = {'a','\r','b','\n','c','\n','\r','d','\r','\n',0};
3064 static const WCHAR strW[] = {'a','b','c','d',' ',0};
3065 static const WCHAR str2W[] = {'a','b','\r','c','d',0};
3066 DWRITE_FONT_METRICS fontmetrics;
3067 DWRITE_LINE_METRICS metrics[6];
3068 IDWriteTextFormat *format;
3069 IDWriteTextLayout *layout;
3070 IDWriteFontFace *fontface;
3071 IDWriteFactory *factory;
3072 UINT32 count;
3073 HRESULT hr;
3075 factory = create_factory();
3077 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3078 DWRITE_FONT_STRETCH_NORMAL, 2048.0, enusW, &format);
3079 ok(hr == S_OK, "got 0x%08x\n", hr);
3081 hr = IDWriteFactory_CreateTextLayout(factory, strW, 5, format, 30000.0, 1000.0, &layout);
3082 ok(hr == S_OK, "got 0x%08x\n", hr);
3084 count = 0;
3085 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 0, &count);
3086 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3087 ok(count == 1, "got count %u\n", count);
3089 memset(metrics, 0, sizeof(metrics));
3090 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 1, &count);
3091 ok(hr == S_OK, "got 0x%08x\n", hr);
3092 ok(metrics[0].length == 5, "got %u\n", metrics[0].length);
3093 ok(metrics[0].trailingWhitespaceLength == 1, "got %u\n", metrics[0].trailingWhitespaceLength);
3095 ok(metrics[0].newlineLength == 0, "got %u\n", metrics[0].newlineLength);
3096 ok(metrics[0].isTrimmed == FALSE, "got %d\n", metrics[0].isTrimmed);
3098 /* Tahoma doesn't provide BASE table, so baseline is calculated from font metrics */
3099 fontface = get_fontface_from_format(format);
3100 ok(fontface != NULL, "got %p\n", fontface);
3101 IDWriteFontFace_GetMetrics(fontface, &fontmetrics);
3103 ok(metrics[0].baseline == fontmetrics.ascent, "got %.2f, expected %d\n", metrics[0].baseline,
3104 fontmetrics.ascent);
3105 ok(metrics[0].height == fontmetrics.ascent + fontmetrics.descent, "got %.2f, expected %d\n",
3106 metrics[0].height, fontmetrics.ascent + fontmetrics.descent);
3107 IDWriteTextLayout_Release(layout);
3109 /* force 2 lines */
3110 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 5, format, 10000.0, 1000.0, &layout);
3111 ok(hr == S_OK, "got 0x%08x\n", hr);
3113 memset(metrics, 0, sizeof(metrics));
3114 count = 2;
3115 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 2, &count);
3116 ok(hr == S_OK, "got 0x%08x\n", hr);
3117 todo_wine {
3118 ok(count == 2, "got %u\n", count);
3119 /* baseline is relative to a line, and is not accumulated */
3120 ok(metrics[0].baseline == metrics[1].baseline, "got %.2f, %.2f\n", metrics[0].baseline,
3121 metrics[1].baseline);
3123 IDWriteTextLayout_Release(layout);
3124 IDWriteTextFormat_Release(format);
3126 /* line breaks */
3127 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3128 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3129 ok(hr == S_OK, "got 0x%08x\n", hr);
3131 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 10, format, 100.0, 300.0, &layout);
3132 ok(hr == S_OK, "got 0x%08x\n", hr);
3134 memset(metrics, 0xcc, sizeof(metrics));
3135 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 6, &count);
3136 ok(hr == S_OK, "got 0x%08x\n", hr);
3137 todo_wine
3138 ok(count == 6, "got %u\n", count);
3140 todo_wine {
3141 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
3142 ok(metrics[1].length == 2, "got %u\n", metrics[1].length);
3143 ok(metrics[2].length == 2, "got %u\n", metrics[2].length);
3144 ok(metrics[3].length == 1, "got %u\n", metrics[3].length);
3145 ok(metrics[4].length == 3, "got %u\n", metrics[4].length);
3146 ok(metrics[5].length == 0, "got %u\n", metrics[5].length);
3149 todo_wine {
3150 ok(metrics[0].newlineLength == 1, "got %u\n", metrics[0].newlineLength);
3151 ok(metrics[1].newlineLength == 1, "got %u\n", metrics[1].newlineLength);
3152 ok(metrics[2].newlineLength == 1, "got %u\n", metrics[2].newlineLength);
3153 ok(metrics[3].newlineLength == 1, "got %u\n", metrics[3].newlineLength);
3154 ok(metrics[4].newlineLength == 2, "got %u\n", metrics[4].newlineLength);
3155 ok(metrics[5].newlineLength == 0, "got %u\n", metrics[5].newlineLength);
3157 IDWriteTextLayout_Release(layout);
3158 IDWriteTextFormat_Release(format);
3159 IDWriteFontFace_Release(fontface);
3160 IDWriteFactory_Release(factory);
3163 static void test_SetTextAlignment(void)
3165 static const WCHAR str2W[] = {'a','a','a','a','a',0};
3166 static const WCHAR strW[] = {'a',0};
3167 DWRITE_CLUSTER_METRICS clusters[1];
3168 DWRITE_TEXT_METRICS metrics;
3169 IDWriteTextFormat1 *format1;
3170 IDWriteTextFormat *format;
3171 IDWriteTextLayout *layout;
3172 IDWriteFactory *factory;
3173 DWRITE_TEXT_ALIGNMENT v;
3174 UINT32 count;
3175 HRESULT hr;
3177 factory = create_factory();
3179 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3180 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3181 ok(hr == S_OK, "got 0x%08x\n", hr);
3183 v = IDWriteTextFormat_GetTextAlignment(format);
3184 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3186 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3187 ok(hr == S_OK, "got 0x%08x\n", hr);
3189 v = IDWriteTextLayout_GetTextAlignment(layout);
3190 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3192 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
3193 ok(hr == S_OK, "got 0x%08x\n", hr);
3195 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
3196 ok(hr == S_OK, "got 0x%08x\n", hr);
3198 v = IDWriteTextFormat_GetTextAlignment(format);
3199 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3201 v = IDWriteTextLayout_GetTextAlignment(layout);
3202 ok(v == DWRITE_TEXT_ALIGNMENT_TRAILING, "got %d\n", v);
3204 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
3205 if (hr == S_OK) {
3206 hr = IDWriteTextFormat1_SetTextAlignment(format1, DWRITE_TEXT_ALIGNMENT_CENTER);
3207 ok(hr == S_OK, "got 0x%08x\n", hr);
3209 v = IDWriteTextFormat_GetTextAlignment(format);
3210 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3212 v = IDWriteTextLayout_GetTextAlignment(layout);
3213 ok(v == DWRITE_TEXT_ALIGNMENT_CENTER, "got %d\n", v);
3215 v = IDWriteTextFormat1_GetTextAlignment(format1);
3216 ok(v == DWRITE_TEXT_ALIGNMENT_CENTER, "got %d\n", v);
3218 IDWriteTextFormat1_Release(format1);
3220 else
3221 win_skip("IDWriteTextFormat1 is not supported\n");
3223 count = 0;
3224 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
3225 ok(hr == S_OK, "got 0x%08x\n", hr);
3226 ok(count == 1, "got %u\n", count);
3228 /* maxwidth is 500, leading alignment */
3229 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_LEADING);
3230 ok(hr == S_OK, "got 0x%08x\n", hr);
3232 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3233 ok(hr == S_OK, "got 0x%08x\n", hr);
3235 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
3236 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
3237 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3238 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3240 /* maxwidth is 500, trailing alignment */
3241 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
3242 ok(hr == S_OK, "got 0x%08x\n", hr);
3244 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3245 ok(hr == S_OK, "got 0x%08x\n", hr);
3247 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
3248 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
3249 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3250 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3251 IDWriteTextLayout_Release(layout);
3253 /* initially created with trailing alignment */
3254 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_TRAILING);
3255 ok(hr == S_OK, "got 0x%08x\n", hr);
3257 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3258 ok(hr == S_OK, "got 0x%08x\n", hr);
3260 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3261 ok(hr == S_OK, "got 0x%08x\n", hr);
3263 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
3264 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
3265 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3266 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3267 IDWriteTextLayout_Release(layout);
3269 /* max width less than total run width, trailing alignment */
3270 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_NO_WRAP);
3271 ok(hr == S_OK, "got 0x%08x\n", hr);
3273 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 5, format, 2*clusters[0].width, 100.0, &layout);
3274 ok(hr == S_OK, "got 0x%08x\n", hr);
3275 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3276 ok(hr == S_OK, "got 0x%08x\n", hr);
3277 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
3278 todo_wine
3279 ok(metrics.width == 5*clusters[0].width, "got %.2f\n", metrics.width);
3280 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3281 IDWriteTextLayout_Release(layout);
3283 /* maxwidth is 500, centered */
3284 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_CENTER);
3285 ok(hr == S_OK, "got 0x%08x\n", hr);
3287 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 5, format, 500.0, 100.0, &layout);
3288 ok(hr == S_OK, "got 0x%08x\n", hr);
3290 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3291 ok(hr == S_OK, "got 0x%08x\n", hr);
3292 ok(metrics.left == (metrics.layoutWidth - metrics.width) / 2.0, "got %.2f\n", metrics.left);
3293 ok(metrics.width == 5*clusters[0].width, "got %.2f\n", metrics.width);
3294 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3296 IDWriteTextLayout_Release(layout);
3298 IDWriteTextFormat_Release(format);
3299 IDWriteFactory_Release(factory);
3302 static void test_SetParagraphAlignment(void)
3304 static const WCHAR strW[] = {'a',0};
3305 DWRITE_TEXT_METRICS metrics;
3306 IDWriteTextFormat *format;
3307 IDWriteTextLayout *layout;
3308 IDWriteFactory *factory;
3309 DWRITE_PARAGRAPH_ALIGNMENT v;
3310 DWRITE_LINE_METRICS lines[1];
3311 UINT32 count;
3312 HRESULT hr;
3314 factory = create_factory();
3316 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3317 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3318 ok(hr == S_OK, "got 0x%08x\n", hr);
3320 v = IDWriteTextFormat_GetParagraphAlignment(format);
3321 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
3323 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3324 ok(hr == S_OK, "got 0x%08x\n", hr);
3326 v = IDWriteTextLayout_GetParagraphAlignment(layout);
3327 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
3329 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
3330 ok(hr == S_OK, "got 0x%08x\n", hr);
3332 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
3333 ok(hr == S_OK, "got 0x%08x\n", hr);
3335 v = IDWriteTextFormat_GetParagraphAlignment(format);
3336 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
3338 v = IDWriteTextLayout_GetParagraphAlignment(layout);
3339 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_FAR, "got %d\n", v);
3341 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
3342 ok(hr == S_OK, "got 0x%08x\n", hr);
3344 v = IDWriteTextLayout_GetParagraphAlignment(layout);
3345 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_CENTER, "got %d\n", v);
3347 count = 0;
3348 hr = IDWriteTextLayout_GetLineMetrics(layout, lines, 1, &count);
3349 ok(hr == S_OK, "got 0x%08x\n", hr);
3350 ok(count == 1, "got %u\n", count);
3352 /* maxheight is 100, near alignment */
3353 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
3354 ok(hr == S_OK, "got 0x%08x\n", hr);
3356 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3357 ok(hr == S_OK, "got 0x%08x\n", hr);
3359 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3360 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3361 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
3362 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3364 /* maxwidth is 100, far alignment */
3365 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
3366 ok(hr == S_OK, "got 0x%08x\n", hr);
3368 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3369 ok(hr == S_OK, "got 0x%08x\n", hr);
3371 ok(metrics.top == metrics.layoutHeight - metrics.height, "got %.2f\n", metrics.top);
3372 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3373 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
3374 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3375 IDWriteTextLayout_Release(layout);
3377 /* initially created with centered alignment */
3378 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
3379 ok(hr == S_OK, "got 0x%08x\n", hr);
3381 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3382 ok(hr == S_OK, "got 0x%08x\n", hr);
3384 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3385 ok(hr == S_OK, "got 0x%08x\n", hr);
3387 ok(metrics.top == (metrics.layoutHeight - lines[0].height) / 2, "got %.2f\n", metrics.top);
3388 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3389 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3390 IDWriteTextLayout_Release(layout);
3392 IDWriteTextFormat_Release(format);
3393 IDWriteFactory_Release(factory);
3396 static void test_SetReadingDirection(void)
3398 static const WCHAR strW[] = {'a',0};
3399 DWRITE_CLUSTER_METRICS clusters[1];
3400 DWRITE_TEXT_METRICS metrics;
3401 IDWriteTextFormat *format;
3402 IDWriteTextLayout *layout;
3403 IDWriteFactory *factory;
3404 DWRITE_READING_DIRECTION v;
3405 DWRITE_LINE_METRICS lines[1];
3406 UINT32 count;
3407 HRESULT hr;
3409 factory = create_factory();
3411 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3412 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3413 ok(hr == S_OK, "got 0x%08x\n", hr);
3415 v = IDWriteTextFormat_GetReadingDirection(format);
3416 ok(v == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", v);
3418 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3419 ok(hr == S_OK, "got 0x%08x\n", hr);
3421 v = IDWriteTextLayout_GetReadingDirection(layout);
3422 ok(v == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", v);
3424 v = IDWriteTextFormat_GetReadingDirection(format);
3425 ok(v == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", v);
3427 hr = IDWriteTextLayout_SetReadingDirection(layout, DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
3428 ok(hr == S_OK, "got 0x%08x\n", hr);
3430 count = 0;
3431 hr = IDWriteTextLayout_GetLineMetrics(layout, lines, 1, &count);
3432 ok(hr == S_OK, "got 0x%08x\n", hr);
3433 ok(count == 1, "got %u\n", count);
3435 count = 0;
3436 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
3437 ok(hr == S_OK, "got 0x%08x\n", hr);
3438 ok(count == 1, "got %u\n", count);
3440 /* leading alignment, RTL */
3441 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3442 ok(hr == S_OK, "got 0x%08x\n", hr);
3444 ok(metrics.left == metrics.layoutWidth - clusters[0].width, "got %.2f\n", metrics.left);
3445 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3446 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
3447 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3448 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3449 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
3450 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3452 /* trailing alignment, RTL */
3453 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
3454 ok(hr == S_OK, "got 0x%08x\n", hr);
3456 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3457 ok(hr == S_OK, "got 0x%08x\n", hr);
3459 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
3460 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3461 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
3462 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3463 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3464 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
3465 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3467 /* centered alignment, RTL */
3468 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_CENTER);
3469 ok(hr == S_OK, "got 0x%08x\n", hr);
3471 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3472 ok(hr == S_OK, "got 0x%08x\n", hr);
3474 ok(metrics.left == (metrics.layoutWidth - clusters[0].width) / 2.0, "got %.2f\n", metrics.left);
3475 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3476 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
3477 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3478 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3479 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
3480 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3482 IDWriteTextLayout_Release(layout);
3484 IDWriteTextFormat_Release(format);
3485 IDWriteFactory_Release(factory);
3488 static inline FLOAT get_scaled_font_metric(UINT32 metric, FLOAT emSize, const DWRITE_FONT_METRICS *metrics)
3490 return (FLOAT)metric * emSize / (FLOAT)metrics->designUnitsPerEm;
3493 static FLOAT snap_coord(const DWRITE_MATRIX *m, FLOAT ppdip, FLOAT coord)
3495 FLOAT vec[2], det, vec2[2];
3496 BOOL transform;
3498 /* has to be a diagonal matrix */
3499 if ((ppdip <= 0.0) ||
3500 (m->m11 * m->m22 != 0.0 && (m->m12 != 0.0 || m->m21 != 0.0)) ||
3501 (m->m12 * m->m21 != 0.0 && (m->m11 != 0.0 || m->m22 != 0.0)))
3502 return coord;
3504 det = m->m11 * m->m22 - m->m12 * m->m21;
3505 transform = fabsf(det) > 1e-10;
3507 if (transform) {
3508 /* apply transform */
3509 vec[0] = 0.0;
3510 vec[1] = coord * ppdip;
3512 vec2[0] = m->m11 * vec[0] + m->m21 * vec[1] + m->dx;
3513 vec2[1] = m->m12 * vec[0] + m->m22 * vec[1] + m->dy;
3515 /* snap */
3516 vec2[0] = floorf(vec2[0] + 0.5f);
3517 vec2[1] = floorf(vec2[1] + 0.5f);
3519 /* apply inverted transform */
3520 vec[1] = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
3521 vec[1] /= ppdip;
3523 else
3524 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
3525 return vec[1];
3528 static inline BOOL float_eq(FLOAT left, FLOAT right)
3530 int x = *(int *)&left;
3531 int y = *(int *)&right;
3533 if (x < 0)
3534 x = INT_MIN - x;
3535 if (y < 0)
3536 y = INT_MIN - y;
3538 return abs(x - y) <= 16;
3541 struct snapping_test {
3542 DWRITE_MATRIX m;
3543 FLOAT ppdip;
3546 static struct snapping_test snapping_tests[] = {
3547 { { 0.0, 1.0, 2.0, 0.0, 0.2, 0.3 }, 1.0 },
3548 { { 0.0, 1.0, 2.0, 0.0, 0.0, 0.0 }, 1.0 },
3549 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0 }, /* identity transform */
3550 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 0.9 },
3551 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, -1.0 },
3552 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 0.0 },
3553 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.3 }, 1.0 }, /* simple Y shift */
3554 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 10.0 }, /* identity, 10 ppdip */
3555 { { 1.0, 0.0, 0.0, 10.0, 0.0, 0.0 }, 10.0 },
3556 { { 0.0, 1.0, 1.0, 0.0, 0.2, 0.6 }, 1.0 },
3557 { { 0.0, 2.0, 2.0, 0.0, 0.2, 0.6 }, 1.0 },
3558 { { 0.0, 0.5, -0.5, 0.0, 0.2, 0.6 }, 1.0 },
3559 { { 1.0, 2.0, 0.0, 1.0, 0.2, 0.6 }, 1.0 },
3560 { { 1.0, 1.0, 0.0, 1.0, 0.2, 0.6 }, 1.0 },
3561 { { 0.5, 0.5, -0.5, 0.5, 0.2, 0.6 }, 1.0 }, /* 45 degrees rotation */
3562 { { 0.5, 0.5, -0.5, 0.5, 0.0, 0.0 }, 100.0 }, /* 45 degrees rotation */
3563 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 100.0 },
3564 { { 0.0, 1.0, -1.0, 0.0, 0.2, 0.6 }, 1.0 }, /* 90 degrees rotation */
3565 { { -1.0, 0.0, 0.0, -1.0, 0.2, 0.6 }, 1.0 }, /* 180 degrees rotation */
3566 { { 0.0, -1.0, 1.0, 0.0, 0.2, 0.6 }, 1.0 }, /* 270 degrees rotation */
3567 { { 1.0, 0.0, 0.0, 1.0,-0.1, 0.2 }, 1.0 },
3568 { { 0.0, 1.0, -1.0, 0.0,-0.2,-0.3 }, 1.0 }, /* 90 degrees rotation */
3569 { { -1.0, 0.0, 0.0, -1.0,-0.3,-1.6 }, 1.0 }, /* 180 degrees rotation */
3570 { { 0.0, -1.0, 1.0, 0.0,-0.7, 0.6 }, 10.0 }, /* 270 degrees rotation */
3571 { { 0.0, 2.0, 1.0, 0.0, 0.2, 0.6 }, 1.0 },
3572 { { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }, 1.0 },
3573 { { 3.0, 0.0, 0.0, 5.0, 0.2,-0.3 }, 10.0 },
3574 { { 0.0, -3.0, 5.0, 0.0,-0.1, 0.7 }, 10.0 },
3577 static DWRITE_MATRIX compattransforms[] = {
3578 { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
3579 { 1.0, 0.0, 0.0, 1.0, 0.2, 0.3 },
3580 { 2.0, 0.0, 0.0, 2.0, 0.2, 0.3 },
3581 { 2.0, 1.0, 2.0, 2.0, 0.2, 0.3 },
3584 static void test_pixelsnapping(void)
3586 static const WCHAR strW[] = {'a',0};
3587 IDWriteTextLayout *layout, *layout2;
3588 struct renderer_context ctxt;
3589 DWRITE_FONT_METRICS metrics;
3590 IDWriteTextFormat *format;
3591 IDWriteFontFace *fontface;
3592 IDWriteFactory *factory;
3593 FLOAT baseline, originX;
3594 HRESULT hr;
3595 int i, j;
3597 factory = create_factory();
3599 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3600 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3601 ok(hr == S_OK, "got 0x%08x\n", hr);
3603 fontface = get_fontface_from_format(format);
3604 IDWriteFontFace_GetMetrics(fontface, &metrics);
3606 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3607 ok(hr == S_OK, "got 0x%08x\n", hr);
3609 /* disabled snapping */
3610 ctxt.snapping_disabled = TRUE;
3611 ctxt.gdicompat = FALSE;
3612 ctxt.use_gdi_natural = FALSE;
3613 ctxt.ppdip = 1.0f;
3614 memset(&ctxt.m, 0, sizeof(ctxt.m));
3615 ctxt.m.m11 = ctxt.m.m22 = 1.0;
3616 originX = 0.1;
3618 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, originX, 0.0);
3619 ok(hr == S_OK, "got 0x%08x\n", hr);
3621 baseline = get_scaled_font_metric(metrics.ascent, 12.0, &metrics);
3622 ok(ctxt.originX == originX, "got %f, originX %f\n", ctxt.originX, originX);
3623 ok(ctxt.originY == baseline, "got %f, baseline %f\n", ctxt.originY, baseline);
3624 ok(floor(baseline) != baseline, "got %f\n", baseline);
3626 ctxt.snapping_disabled = FALSE;
3628 for (i = 0; i < sizeof(snapping_tests)/sizeof(snapping_tests[0]); i++) {
3629 struct snapping_test *ptr = &snapping_tests[i];
3630 FLOAT expectedY;
3632 ctxt.m = ptr->m;
3633 ctxt.ppdip = ptr->ppdip;
3634 ctxt.originX = 678.9;
3635 ctxt.originY = 678.9;
3637 expectedY = snap_coord(&ctxt.m, ctxt.ppdip, baseline);
3638 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, originX, 0.0);
3639 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
3640 ok(ctxt.originX == originX, "%d: got %f, originX %f\n", i, ctxt.originX, originX);
3641 ok(float_eq(ctxt.originY, expectedY), "%d: got %f, expected %f, baseline %f\n",
3642 i, ctxt.originY, expectedY, baseline);
3644 /* gdicompat layout transform doesn't affect snapping */
3645 for (j = 0; j < sizeof(compattransforms)/sizeof(compattransforms[0]); j++) {
3646 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 1, format, 500.0, 100.0,
3647 1.0, &compattransforms[j], FALSE, &layout2);
3648 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
3650 expectedY = snap_coord(&ctxt.m, ctxt.ppdip, baseline);
3651 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, originX, 0.0);
3652 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
3653 ok(ctxt.originX == originX, "%d: got %f, originX %f\n", i, ctxt.originX, originX);
3654 ok(float_eq(ctxt.originY, expectedY), "%d: got %f, expected %f, baseline %f\n",
3655 i, ctxt.originY, expectedY, baseline);
3657 IDWriteTextLayout_Release(layout2);
3661 IDWriteTextLayout_Release(layout);
3662 IDWriteTextFormat_Release(format);
3663 IDWriteFontFace_Release(fontface);
3664 IDWriteFactory_Release(factory);
3667 static void test_SetWordWrapping(void)
3669 static const WCHAR strW[] = {'a',0};
3670 IDWriteTextFormat *format;
3671 IDWriteTextLayout *layout;
3672 IDWriteFactory *factory;
3673 DWRITE_WORD_WRAPPING v;
3674 HRESULT hr;
3676 factory = create_factory();
3678 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3679 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3680 ok(hr == S_OK, "got 0x%08x\n", hr);
3682 v = IDWriteTextFormat_GetWordWrapping(format);
3683 ok(v == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", v);
3685 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3686 ok(hr == S_OK, "got 0x%08x\n", hr);
3688 v = IDWriteTextLayout_GetWordWrapping(layout);
3689 ok(v == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", v);
3691 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
3692 ok(hr == S_OK, "got 0x%08x\n", hr);
3694 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
3695 ok(hr == S_OK, "got 0x%08x\n", hr);
3697 v = IDWriteTextFormat_GetWordWrapping(format);
3698 ok(v == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", v);
3700 IDWriteTextLayout_Release(layout);
3701 IDWriteTextFormat_Release(format);
3702 IDWriteFactory_Release(factory);
3705 /* Collection dedicated to fallback testing */
3707 static const WCHAR g_blahfontW[] = {'B','l','a','h',0};
3708 static HRESULT WINAPI fontcollection_QI(IDWriteFontCollection *iface, REFIID riid, void **obj)
3710 if (IsEqualIID(riid, &IID_IDWriteFontCollection) || IsEqualIID(riid, &IID_IUnknown)) {
3711 *obj = iface;
3712 IDWriteFontCollection_AddRef(iface);
3713 return S_OK;
3716 *obj = NULL;
3717 return E_NOINTERFACE;
3720 static ULONG WINAPI fontcollection_AddRef(IDWriteFontCollection *iface)
3722 return 2;
3725 static ULONG WINAPI fontcollection_Release(IDWriteFontCollection *iface)
3727 return 1;
3730 static UINT32 WINAPI fontcollection_GetFontFamilyCount(IDWriteFontCollection *iface)
3732 ok(0, "unexpected call\n");
3733 return 0;
3736 static HRESULT WINAPI fontcollection_GetFontFamily(IDWriteFontCollection *iface, UINT32 index, IDWriteFontFamily **family)
3738 if (index == 123456) {
3739 IDWriteFactory *factory = create_factory();
3740 IDWriteFontCollection *syscollection;
3741 BOOL exists;
3742 HRESULT hr;
3744 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
3745 ok(hr == S_OK, "got 0x%08x\n", hr);
3747 hr = IDWriteFontCollection_FindFamilyName(syscollection, tahomaW, &index, &exists);
3748 ok(hr == S_OK, "got 0x%08x\n", hr);
3750 hr = IDWriteFontCollection_GetFontFamily(syscollection, index, family);
3751 ok(hr == S_OK, "got 0x%08x\n", hr);
3753 IDWriteFontCollection_Release(syscollection);
3754 IDWriteFactory_Release(factory);
3755 return S_OK;
3757 ok(0, "unexpected call\n");
3758 return E_NOTIMPL;
3761 static HRESULT WINAPI fontcollection_FindFamilyName(IDWriteFontCollection *iface, WCHAR const *name, UINT32 *index, BOOL *exists)
3763 if (!lstrcmpW(name, g_blahfontW)) {
3764 *index = 123456;
3765 *exists = TRUE;
3766 return S_OK;
3768 ok(0, "unexpected call, name %s\n", wine_dbgstr_w(name));
3769 return E_NOTIMPL;
3772 static HRESULT WINAPI fontcollection_GetFontFromFontFace(IDWriteFontCollection *iface, IDWriteFontFace *face, IDWriteFont **font)
3774 ok(0, "unexpected call\n");
3775 return E_NOTIMPL;
3778 static const IDWriteFontCollectionVtbl fallbackcollectionvtbl = {
3779 fontcollection_QI,
3780 fontcollection_AddRef,
3781 fontcollection_Release,
3782 fontcollection_GetFontFamilyCount,
3783 fontcollection_GetFontFamily,
3784 fontcollection_FindFamilyName,
3785 fontcollection_GetFontFromFontFace
3788 static IDWriteFontCollection fallbackcollection = { &fallbackcollectionvtbl };
3790 static void test_MapCharacters(void)
3792 static const WCHAR strW[] = {'a','b','c',0};
3793 static const WCHAR str2W[] = {'a',0x3058,'b',0};
3794 IDWriteLocalizedStrings *strings;
3795 IDWriteFontFallback *fallback;
3796 IDWriteFactory2 *factory2;
3797 IDWriteFactory *factory;
3798 UINT32 mappedlength;
3799 IDWriteFont *font;
3800 WCHAR buffW[50];
3801 BOOL exists;
3802 FLOAT scale;
3803 HRESULT hr;
3805 factory = create_factory();
3807 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
3808 IDWriteFactory_Release(factory);
3809 if (hr != S_OK) {
3810 win_skip("MapCharacters() is not supported\n");
3811 return;
3814 fallback = NULL;
3815 hr = IDWriteFactory2_GetSystemFontFallback(factory2, &fallback);
3816 todo_wine
3817 ok(hr == S_OK, "got 0x%08x\n", hr);
3818 if (hr == S_OK) {
3819 ok(fallback != NULL, "got %p\n", fallback);
3821 mappedlength = 1;
3822 scale = 0.0f;
3823 font = (void*)0xdeadbeef;
3824 hr = IDWriteFontFallback_MapCharacters(fallback, NULL, 0, 0, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
3825 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
3826 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3827 ok(mappedlength == 0, "got %u\n", mappedlength);
3828 ok(scale == 1.0f, "got %f\n", scale);
3829 ok(font == NULL, "got %p\n", font);
3831 /* zero length source */
3832 g_source = strW;
3833 mappedlength = 1;
3834 scale = 0.0f;
3835 font = (void*)0xdeadbeef;
3836 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 0, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
3837 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
3838 ok(hr == S_OK, "got 0x%08x\n", hr);
3839 ok(mappedlength == 0, "got %u\n", mappedlength);
3840 ok(scale == 1.0f, "got %f\n", scale);
3841 ok(font == NULL, "got %p\n", font);
3843 g_source = strW;
3844 mappedlength = 0;
3845 scale = 0.0f;
3846 font = NULL;
3847 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
3848 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
3849 ok(hr == S_OK, "got 0x%08x\n", hr);
3850 ok(mappedlength == 1, "got %u\n", mappedlength);
3851 ok(scale == 1.0f, "got %f\n", scale);
3852 ok(font != NULL, "got %p\n", font);
3853 IDWriteFont_Release(font);
3855 /* same latin text, full length */
3856 g_source = strW;
3857 mappedlength = 0;
3858 scale = 0.0f;
3859 font = NULL;
3860 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
3861 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
3862 ok(hr == S_OK, "got 0x%08x\n", hr);
3863 ok(mappedlength == 3, "got %u\n", mappedlength);
3864 ok(scale == 1.0f, "got %f\n", scale);
3865 ok(font != NULL, "got %p\n", font);
3866 IDWriteFont_Release(font);
3868 /* string 'a\x3058b' */
3869 g_source = str2W;
3870 mappedlength = 0;
3871 scale = 0.0f;
3872 font = NULL;
3873 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
3874 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
3875 ok(hr == S_OK, "got 0x%08x\n", hr);
3876 ok(mappedlength == 1, "got %u\n", mappedlength);
3877 ok(scale == 1.0f, "got %f\n", scale);
3878 ok(font != NULL, "got %p\n", font);
3879 IDWriteFont_Release(font);
3881 g_source = str2W;
3882 mappedlength = 0;
3883 scale = 0.0f;
3884 font = NULL;
3885 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 1, 2, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
3886 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
3887 ok(hr == S_OK, "got 0x%08x\n", hr);
3888 ok(mappedlength == 1, "got %u\n", mappedlength);
3889 ok(scale == 1.0f, "got %f\n", scale);
3890 ok(font != NULL, "got %p\n", font);
3892 /* font returned for Hiragana character, check if it supports Latin too */
3893 exists = FALSE;
3894 hr = IDWriteFont_HasCharacter(font, 'b', &exists);
3895 ok(hr == S_OK, "got 0x%08x\n", hr);
3896 ok(exists, "got %d\n", exists);
3898 IDWriteFont_Release(font);
3900 /* Try with explicit collection, Tahoma will be forced. */
3901 /* 1. Latin part */
3902 g_source = str2W;
3903 mappedlength = 0;
3904 scale = 0.0f;
3905 font = NULL;
3906 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, &fallbackcollection, g_blahfontW, DWRITE_FONT_WEIGHT_NORMAL,
3907 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
3908 ok(hr == S_OK, "got 0x%08x\n", hr);
3909 ok(mappedlength == 1, "got %u\n", mappedlength);
3910 ok(scale == 1.0f, "got %f\n", scale);
3911 ok(font != NULL, "got %p\n", font);
3913 exists = FALSE;
3914 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
3915 ok(hr == S_OK && exists, "got 0x%08x, exists %d\n", hr, exists);
3916 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
3917 ok(hr == S_OK, "got 0x%08x\n", hr);
3918 ok(!lstrcmpW(buffW, tahomaW), "%s\n", wine_dbgstr_w(buffW));
3919 IDWriteLocalizedStrings_Release(strings);
3921 IDWriteFont_Release(font);
3923 /* 2. Hiragana character, force Tahoma font does not support Japanese */
3924 g_source = str2W;
3925 mappedlength = 0;
3926 scale = 0.0f;
3927 font = NULL;
3928 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 1, 1, &fallbackcollection, g_blahfontW, DWRITE_FONT_WEIGHT_NORMAL,
3929 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
3930 ok(hr == S_OK, "got 0x%08x\n", hr);
3931 ok(mappedlength == 1, "got %u\n", mappedlength);
3932 ok(scale == 1.0f, "got %f\n", scale);
3933 ok(font != NULL, "got %p\n", font);
3935 exists = FALSE;
3936 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
3937 ok(hr == S_OK && exists, "got 0x%08x, exists %d\n", hr, exists);
3938 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
3939 ok(hr == S_OK, "got 0x%08x\n", hr);
3940 ok(lstrcmpW(buffW, tahomaW), "%s\n", wine_dbgstr_w(buffW));
3941 IDWriteLocalizedStrings_Release(strings);
3943 IDWriteFont_Release(font);
3944 IDWriteFontFallback_Release(fallback);
3946 IDWriteFactory2_Release(factory2);
3949 static void test_FontFallbackBuilder(void)
3951 static const WCHAR localeW[] = {'l','o','c','a','l','e',0};
3952 static const WCHAR strW[] = {'A',0};
3953 IDWriteFontFallbackBuilder *builder;
3954 IDWriteFontFallback *fallback;
3955 DWRITE_UNICODE_RANGE range;
3956 IDWriteFactory2 *factory2;
3957 IDWriteFactory *factory;
3958 const WCHAR *familyW;
3959 UINT32 mappedlength;
3960 IDWriteFont *font;
3961 FLOAT scale;
3962 HRESULT hr;
3964 factory = create_factory();
3966 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
3967 IDWriteFactory_Release(factory);
3969 if (factory2)
3970 hr = IDWriteFactory2_CreateFontFallbackBuilder(factory2, &builder);
3972 if (hr != S_OK) {
3973 skip("IDWriteFontFallbackBuilder is not supported\n");
3974 return;
3977 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
3978 ok(hr == S_OK, "got 0x%08x\n", hr);
3980 hr = IDWriteFontFallbackBuilder_AddMapping(builder, NULL, 0, NULL, 0, NULL, NULL, NULL, 0.0f);
3981 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3983 range.first = 'A';
3984 range.last = 'B';
3985 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 0, NULL, 0, NULL, NULL, NULL, 0.0f);
3986 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3988 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 0, NULL, 0, NULL, NULL, NULL, 1.0f);
3989 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3991 /* negative scaling factor */
3992 range.first = range.last = 0;
3993 familyW = g_blahfontW;
3994 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, -1.0f);
3995 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3997 /* empty range */
3998 range.first = range.last = 0;
3999 familyW = g_blahfontW;
4000 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 1.0f);
4001 ok(hr == S_OK, "got 0x%08x\n", hr);
4003 range.first = range.last = 0;
4004 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 2.0f);
4005 ok(hr == S_OK, "got 0x%08x\n", hr);
4007 range.first = range.last = 'A';
4008 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 3.0f);
4009 ok(hr == S_OK, "got 0x%08x\n", hr);
4011 range.first = 'B';
4012 range.last = 'A';
4013 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 4.0f);
4014 ok(hr == S_OK, "got 0x%08x\n", hr);
4016 if (0) /* crashes on native */
4017 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, NULL);
4019 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4020 ok(hr == S_OK, "got 0x%08x\n", hr);
4022 /* fallback font missing from system collection */
4023 g_source = strW;
4024 mappedlength = 0;
4025 scale = 0.0f;
4026 font = (void*)0xdeadbeef;
4027 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4028 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4029 ok(hr == S_OK, "got 0x%08x\n", hr);
4030 ok(mappedlength == 1, "got %u\n", mappedlength);
4031 ok(scale == 1.0f, "got %f\n", scale);
4032 ok(font == NULL, "got %p\n", font);
4034 IDWriteFontFallback_Release(fallback);
4036 /* remap with custom collection */
4037 range.first = range.last = 'A';
4038 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, NULL, NULL, 5.0f);
4039 ok(hr == S_OK, "got 0x%08x\n", hr);
4041 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4042 ok(hr == S_OK, "got 0x%08x\n", hr);
4044 g_source = strW;
4045 mappedlength = 0;
4046 scale = 0.0f;
4047 font = NULL;
4048 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4049 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4050 ok(hr == S_OK, "got 0x%08x\n", hr);
4051 ok(mappedlength == 1, "got %u\n", mappedlength);
4052 ok(scale == 5.0f, "got %f\n", scale);
4053 ok(font != NULL, "got %p\n", font);
4054 IDWriteFont_Release(font);
4056 IDWriteFontFallback_Release(fallback);
4058 range.first = 'B';
4059 range.last = 'A';
4060 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, NULL, NULL, 6.0f);
4061 ok(hr == S_OK, "got 0x%08x\n", hr);
4063 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4064 ok(hr == S_OK, "got 0x%08x\n", hr);
4066 g_source = strW;
4067 mappedlength = 0;
4068 scale = 0.0f;
4069 font = NULL;
4070 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4071 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4072 ok(hr == S_OK, "got 0x%08x\n", hr);
4073 ok(mappedlength == 1, "got %u\n", mappedlength);
4074 ok(scale == 5.0f, "got %f\n", scale);
4075 ok(font != NULL, "got %p\n", font);
4076 IDWriteFont_Release(font);
4078 IDWriteFontFallback_Release(fallback);
4080 /* explicit locale */
4081 range.first = 'A';
4082 range.last = 'B';
4083 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, localeW, NULL, 6.0f);
4084 ok(hr == S_OK, "got 0x%08x\n", hr);
4086 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4087 ok(hr == S_OK, "got 0x%08x\n", hr);
4089 g_source = strW;
4090 mappedlength = 0;
4091 scale = 0.0f;
4092 font = NULL;
4093 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4094 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4095 ok(hr == S_OK, "got 0x%08x\n", hr);
4096 ok(mappedlength == 1, "got %u\n", mappedlength);
4097 ok(scale == 5.0f, "got %f\n", scale);
4098 ok(font != NULL, "got %p\n", font);
4099 IDWriteFont_Release(font);
4101 IDWriteFontFallbackBuilder_Release(builder);
4102 IDWriteFactory2_Release(factory2);
4105 static void test_SetTypography(void)
4107 static const WCHAR strW[] = {'a','f','i','b',0};
4108 IDWriteTypography *typography, *typography2;
4109 IDWriteTextFormat *format;
4110 IDWriteTextLayout *layout;
4111 DWRITE_TEXT_RANGE range;
4112 IDWriteFactory *factory;
4113 HRESULT hr;
4115 factory = create_factory();
4117 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4118 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
4119 ok(hr == S_OK, "got 0x%08x\n", hr);
4121 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
4122 ok(hr == S_OK, "got 0x%08x\n", hr);
4123 IDWriteTextFormat_Release(format);
4125 hr = IDWriteFactory_CreateTypography(factory, &typography);
4126 ok(hr == S_OK, "got 0x%08x\n", hr);
4128 EXPECT_REF(typography, 1);
4129 range.startPosition = 0;
4130 range.length = 2;
4131 hr = IDWriteTextLayout_SetTypography(layout, typography, range);
4132 ok(hr == S_OK, "got 0x%08x\n", hr);
4133 EXPECT_REF(typography, 2);
4135 hr = IDWriteTextLayout_GetTypography(layout, 0, &typography2, NULL);
4136 ok(hr == S_OK, "got 0x%08x\n", hr);
4137 ok(typography2 == typography, "got %p, expected %p\n", typography2, typography);
4138 IDWriteTypography_Release(typography2);
4139 IDWriteTypography_Release(typography);
4141 hr = IDWriteFactory_CreateTypography(factory, &typography2);
4142 ok(hr == S_OK, "got 0x%08x\n", hr);
4144 range.startPosition = 0;
4145 range.length = 1;
4146 hr = IDWriteTextLayout_SetTypography(layout, typography2, range);
4147 ok(hr == S_OK, "got 0x%08x\n", hr);
4148 EXPECT_REF(typography2, 2);
4149 IDWriteTypography_Release(typography2);
4151 hr = IDWriteTextLayout_GetTypography(layout, 0, &typography, &range);
4152 ok(hr == S_OK, "got 0x%08x\n", hr);
4153 ok(range.length == 1, "got %u\n", range.length);
4155 IDWriteTypography_Release(typography);
4157 IDWriteTextLayout_Release(layout);
4158 IDWriteFactory_Release(factory);
4161 static void test_SetLastLineWrapping(void)
4163 static const WCHAR strW[] = {'a',0};
4164 IDWriteTextLayout2 *layout2;
4165 IDWriteTextFormat1 *format1;
4166 IDWriteTextLayout *layout;
4167 IDWriteTextFormat *format;
4168 IDWriteFactory *factory;
4169 HRESULT hr;
4170 BOOL ret;
4172 factory = create_factory();
4174 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4175 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
4176 ok(hr == S_OK, "got 0x%08x\n", hr);
4178 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4179 IDWriteTextFormat_Release(format);
4180 if (hr != S_OK) {
4181 win_skip("SetLastLineWrapping() is not supported\n");
4182 IDWriteFactory_Release(factory);
4183 return;
4186 ret = IDWriteTextFormat1_GetLastLineWrapping(format1);
4187 ok(ret, "got %d\n", ret);
4189 hr = IDWriteTextFormat1_SetLastLineWrapping(format1, FALSE);
4190 ok(hr == S_OK, "got 0x%08x\n", hr);
4192 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, (IDWriteTextFormat*)format1, 1000.0, 1000.0, &layout);
4193 ok(hr == S_OK, "got 0x%08x\n", hr);
4195 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
4196 ok(hr == S_OK, "got 0x%08x\n", hr);
4197 IDWriteTextLayout_Release(layout);
4199 ret = IDWriteTextLayout2_GetLastLineWrapping(layout2);
4200 ok(!ret, "got %d\n", ret);
4202 hr = IDWriteTextLayout2_SetLastLineWrapping(layout2, TRUE);
4203 ok(hr == S_OK, "got 0x%08x\n", hr);
4205 IDWriteFactory_Release(factory);
4208 static void test_SetOpticalAlignment(void)
4210 static const WCHAR strW[] = {'a',0};
4211 DWRITE_OPTICAL_ALIGNMENT alignment;
4212 IDWriteTextLayout2 *layout2;
4213 IDWriteTextFormat1 *format1;
4214 IDWriteTextLayout *layout;
4215 IDWriteTextFormat *format;
4216 IDWriteFactory *factory;
4217 HRESULT hr;
4219 factory = create_factory();
4221 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4222 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
4223 ok(hr == S_OK, "got 0x%08x\n", hr);
4225 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4226 IDWriteTextFormat_Release(format);
4227 if (hr != S_OK) {
4228 win_skip("SetOpticalAlignment() is not supported\n");
4229 IDWriteFactory_Release(factory);
4230 return;
4233 alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4234 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
4236 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, (IDWriteTextFormat*)format1, 1000.0, 1000.0, &layout);
4237 ok(hr == S_OK, "got 0x%08x\n", hr);
4239 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
4240 ok(hr == S_OK, "got 0x%08x\n", hr);
4241 IDWriteTextLayout_Release(layout);
4242 IDWriteTextFormat1_Release(format1);
4244 alignment = IDWriteTextLayout2_GetOpticalAlignment(layout2);
4245 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
4247 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
4248 ok(hr == S_OK, "got 0x%08x\n", hr);
4250 alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4251 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
4253 hr = IDWriteTextLayout2_SetOpticalAlignment(layout2, DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS);
4254 ok(hr == S_OK, "got 0x%08x\n", hr);
4256 hr = IDWriteTextLayout2_SetOpticalAlignment(layout2, DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS+1);
4257 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4259 alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4260 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS, "got %d\n", alignment);
4262 hr = IDWriteTextFormat1_SetOpticalAlignment(format1, DWRITE_OPTICAL_ALIGNMENT_NONE);
4263 ok(hr == S_OK, "got 0x%08x\n", hr);
4265 hr = IDWriteTextFormat1_SetOpticalAlignment(format1, DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS+1);
4266 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4268 alignment = IDWriteTextLayout2_GetOpticalAlignment(layout2);
4269 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
4271 IDWriteTextLayout2_Release(layout2);
4272 IDWriteTextFormat1_Release(format1);
4273 IDWriteFactory_Release(factory);
4276 static const struct drawcall_entry drawunderline_seq[] = {
4277 { DRAW_GLYPHRUN, {'a','e',0x0300,0} }, /* reported runs can't mix different underline values */
4278 { DRAW_GLYPHRUN, {'d',0} },
4279 { DRAW_UNDERLINE },
4280 { DRAW_LAST_KIND }
4283 static void test_SetUnderline(void)
4285 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
4286 DWRITE_CLUSTER_METRICS clusters[4];
4287 IDWriteTextFormat *format;
4288 IDWriteTextLayout *layout;
4289 DWRITE_TEXT_RANGE range;
4290 IDWriteFactory *factory;
4291 UINT32 count;
4292 HRESULT hr;
4294 factory = create_factory();
4296 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4297 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
4298 ok(hr == S_OK, "got 0x%08x\n", hr);
4300 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
4301 ok(hr == S_OK, "got 0x%08x\n", hr);
4302 IDWriteTextFormat_Release(format);
4304 count = 0;
4305 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, sizeof(clusters)/sizeof(clusters[0]), &count);
4306 ok(hr == S_OK, "got 0x%08x\n", hr);
4307 todo_wine
4308 ok(count == 3, "got %u\n", count);
4310 range.startPosition = 0;
4311 range.length = 2;
4312 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
4313 ok(hr == S_OK, "got 0x%08x\n", hr);
4315 count = 0;
4316 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, sizeof(clusters)/sizeof(clusters[0]), &count);
4317 ok(hr == S_OK, "got 0x%08x\n", hr);
4318 todo_wine
4319 ok(count == 3, "got %u\n", count);
4321 flush_sequence(sequences, RENDERER_ID);
4322 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
4323 ok(hr == S_OK, "got 0x%08x\n", hr);
4324 ok_sequence(sequences, RENDERER_ID, drawunderline_seq, "draw underline test", TRUE);
4326 IDWriteTextLayout_Release(layout);
4327 IDWriteFactory_Release(factory);
4330 START_TEST(layout)
4332 static const WCHAR ctrlstrW[] = {0x202a,0};
4333 IDWriteFactory *factory;
4335 if (!(factory = create_factory())) {
4336 win_skip("failed to create factory\n");
4337 return;
4340 /* actual script ids are not fixed */
4341 get_script_analysis(ctrlstrW, 1, &g_control_sa);
4343 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
4344 init_call_sequences(expected_seq, 1);
4346 test_CreateTextLayout();
4347 test_CreateGdiCompatibleTextLayout();
4348 test_CreateTextFormat();
4349 test_GetLocaleName();
4350 test_CreateEllipsisTrimmingSign();
4351 test_fontweight();
4352 test_SetInlineObject();
4353 test_Draw();
4354 test_typography();
4355 test_GetClusterMetrics();
4356 test_SetLocaleName();
4357 test_SetPairKerning();
4358 test_SetVerticalGlyphOrientation();
4359 test_fallback();
4360 test_DetermineMinWidth();
4361 test_SetFontSize();
4362 test_SetFontFamilyName();
4363 test_SetFontStyle();
4364 test_SetFontStretch();
4365 test_SetStrikethrough();
4366 test_GetMetrics();
4367 test_SetFlowDirection();
4368 test_SetDrawingEffect();
4369 test_GetLineMetrics();
4370 test_SetTextAlignment();
4371 test_SetParagraphAlignment();
4372 test_SetReadingDirection();
4373 test_pixelsnapping();
4374 test_SetWordWrapping();
4375 test_MapCharacters();
4376 test_FontFallbackBuilder();
4377 test_SetTypography();
4378 test_SetLastLineWrapping();
4379 test_SetOpticalAlignment();
4380 test_SetUnderline();
4382 IDWriteFactory_Release(factory);