dwrite: Use [0,~0u) as initial text range.
[wine.git] / dlls / dwrite / tests / layout.c
blob4c76f501e83e70c1775b442f12cf773895d2109c
1 /*
2 * Text layout/format tests
4 * Copyright 2012, 2014-2015 Nikolay Sivov for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define COBJMACROS
23 #include <assert.h>
25 #include "windows.h"
26 #include "dwrite.h"
27 #include "dwrite_2.h"
29 #include "wine/test.h"
31 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
32 static const WCHAR enusW[] = {'e','n','-','u','s',0};
34 static DWRITE_SCRIPT_ANALYSIS g_sa;
35 static DWRITE_SCRIPT_ANALYSIS g_control_sa;
37 /* test IDWriteTextAnalysisSink */
38 static HRESULT WINAPI analysissink_QueryInterface(IDWriteTextAnalysisSink *iface, REFIID riid, void **obj)
40 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown))
42 *obj = iface;
43 return S_OK;
46 *obj = NULL;
47 return E_NOINTERFACE;
50 static ULONG WINAPI analysissink_AddRef(IDWriteTextAnalysisSink *iface)
52 return 2;
55 static ULONG WINAPI analysissink_Release(IDWriteTextAnalysisSink *iface)
57 return 1;
60 static HRESULT WINAPI analysissink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
61 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
63 g_sa = *sa;
64 return S_OK;
67 static HRESULT WINAPI analysissink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
68 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
70 ok(0, "unexpected call\n");
71 return E_NOTIMPL;
74 static HRESULT WINAPI analysissink_SetBidiLevel(IDWriteTextAnalysisSink *iface,
75 UINT32 position, UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
77 ok(0, "unexpected\n");
78 return E_NOTIMPL;
81 static HRESULT WINAPI analysissink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
82 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
84 ok(0, "unexpected\n");
85 return E_NOTIMPL;
88 static IDWriteTextAnalysisSinkVtbl analysissinkvtbl = {
89 analysissink_QueryInterface,
90 analysissink_AddRef,
91 analysissink_Release,
92 analysissink_SetScriptAnalysis,
93 analysissink_SetLineBreakpoints,
94 analysissink_SetBidiLevel,
95 analysissink_SetNumberSubstitution
98 static IDWriteTextAnalysisSink analysissink = { &analysissinkvtbl };
100 /* test IDWriteTextAnalysisSource */
101 static HRESULT WINAPI analysissource_QueryInterface(IDWriteTextAnalysisSource *iface,
102 REFIID riid, void **obj)
104 ok(0, "QueryInterface not expected\n");
105 return E_NOTIMPL;
108 static ULONG WINAPI analysissource_AddRef(IDWriteTextAnalysisSource *iface)
110 ok(0, "AddRef not expected\n");
111 return 2;
114 static ULONG WINAPI analysissource_Release(IDWriteTextAnalysisSource *iface)
116 ok(0, "Release not expected\n");
117 return 1;
120 static const WCHAR *g_source;
122 static HRESULT WINAPI analysissource_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
123 UINT32 position, WCHAR const** text, UINT32* text_len)
125 if (position >= lstrlenW(g_source))
127 *text = NULL;
128 *text_len = 0;
130 else
132 *text = &g_source[position];
133 *text_len = lstrlenW(g_source) - position;
136 return S_OK;
139 static HRESULT WINAPI analysissource_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
140 UINT32 position, WCHAR const** text, UINT32* text_len)
142 ok(0, "unexpected\n");
143 return E_NOTIMPL;
146 static DWRITE_READING_DIRECTION WINAPI analysissource_GetParagraphReadingDirection(
147 IDWriteTextAnalysisSource *iface)
149 ok(0, "unexpected\n");
150 return DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
153 static HRESULT WINAPI analysissource_GetLocaleName(IDWriteTextAnalysisSource *iface,
154 UINT32 position, UINT32* text_len, WCHAR const** locale)
156 *locale = NULL;
157 *text_len = 0;
158 return S_OK;
161 static HRESULT WINAPI analysissource_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
162 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
164 ok(0, "unexpected\n");
165 return E_NOTIMPL;
168 static IDWriteTextAnalysisSourceVtbl analysissourcevtbl = {
169 analysissource_QueryInterface,
170 analysissource_AddRef,
171 analysissource_Release,
172 analysissource_GetTextAtPosition,
173 analysissource_GetTextBeforePosition,
174 analysissource_GetParagraphReadingDirection,
175 analysissource_GetLocaleName,
176 analysissource_GetNumberSubstitution
179 static IDWriteTextAnalysisSource analysissource = { &analysissourcevtbl };
181 static IDWriteFactory *create_factory(void)
183 IDWriteFactory *factory;
184 HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory);
185 ok(hr == S_OK, "got 0x%08x\n", hr);
186 return factory;
189 /* obvious limitation is that only last script data is returned, so this
190 helper is suitable for single script strings only */
191 static void get_script_analysis(const WCHAR *str, UINT32 len, DWRITE_SCRIPT_ANALYSIS *sa)
193 IDWriteTextAnalyzer *analyzer;
194 IDWriteFactory *factory;
195 HRESULT hr;
197 g_source = str;
199 factory = create_factory();
200 hr = IDWriteFactory_CreateTextAnalyzer(factory, &analyzer);
201 ok(hr == S_OK, "got 0x%08x\n", hr);
203 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &analysissource, 0, len, &analysissink);
204 ok(hr == S_OK, "got 0x%08x\n", hr);
206 *sa = g_sa;
207 IDWriteFactory_Release(factory);
210 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
211 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
213 ULONG rc = IUnknown_AddRef(obj);
214 IUnknown_Release(obj);
215 ok_(__FILE__,line)(rc-1 == ref, "expected refcount %d, got %d\n", ref, rc-1);
218 enum drawcall_kind {
219 DRAW_GLYPHRUN = 0,
220 DRAW_UNDERLINE,
221 DRAW_STRIKETHROUGH,
222 DRAW_INLINE,
223 DRAW_LAST_KIND
226 static const char *get_draw_kind_name(enum drawcall_kind kind)
228 static const char *kind_names[] = { "GLYPH_RUN", "UNDERLINE", "STRIKETHROUGH", "INLINE", "END_OF_SEQ" };
229 return kind > DRAW_LAST_KIND ? "unknown" : kind_names[kind];
232 struct drawcall_entry {
233 enum drawcall_kind kind;
234 WCHAR string[10]; /* only meaningful for DrawGlyphRun() */
237 struct drawcall_sequence
239 int count;
240 int size;
241 struct drawcall_entry *sequence;
244 struct drawtestcontext {
245 enum drawcall_kind kind;
246 BOOL todo;
247 int *failcount;
248 const char *file;
249 int line;
252 #define NUM_CALL_SEQUENCES 1
253 #define RENDERER_ID 0
254 static struct drawcall_sequence *sequences[NUM_CALL_SEQUENCES];
255 static struct drawcall_sequence *expected_seq[1];
257 static void add_call(struct drawcall_sequence **seq, int sequence_index, const struct drawcall_entry *call)
259 struct drawcall_sequence *call_seq = seq[sequence_index];
261 if (!call_seq->sequence) {
262 call_seq->size = 10;
263 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0, call_seq->size * sizeof (struct drawcall_entry));
266 if (call_seq->count == call_seq->size) {
267 call_seq->size *= 2;
268 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
269 call_seq->sequence,
270 call_seq->size * sizeof (struct drawcall_entry));
273 assert(call_seq->sequence);
274 call_seq->sequence[call_seq->count++] = *call;
277 static inline void flush_sequence(struct drawcall_sequence **seg, int sequence_index)
279 struct drawcall_sequence *call_seq = seg[sequence_index];
281 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
282 call_seq->sequence = NULL;
283 call_seq->count = call_seq->size = 0;
286 static inline void flush_sequences(struct drawcall_sequence **seq, int n)
288 int i;
289 for (i = 0; i < n; i++)
290 flush_sequence(seq, i);
293 static void init_call_sequences(struct drawcall_sequence **seq, int n)
295 int i;
297 for (i = 0; i < n; i++)
298 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct drawcall_sequence));
301 static void ok_sequence_(struct drawcall_sequence **seq, int sequence_index,
302 const struct drawcall_entry *expected, const char *context, BOOL todo,
303 const char *file, int line)
305 static const struct drawcall_entry end_of_sequence = { DRAW_LAST_KIND };
306 struct drawcall_sequence *call_seq = seq[sequence_index];
307 const struct drawcall_entry *actual, *sequence;
308 int failcount = 0;
310 add_call(seq, sequence_index, &end_of_sequence);
312 sequence = call_seq->sequence;
313 actual = sequence;
315 while (expected->kind != DRAW_LAST_KIND && actual->kind != DRAW_LAST_KIND) {
316 if (expected->kind != actual->kind) {
317 if (todo) {
318 failcount++;
319 todo_wine
320 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
321 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
323 flush_sequence(seq, sequence_index);
324 return;
326 else
327 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
328 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
330 else if (expected->kind == DRAW_GLYPHRUN) {
331 int cmp = lstrcmpW(expected->string, actual->string);
332 if (cmp != 0 && todo) {
333 failcount++;
334 todo_wine
335 ok_(file, line) (0, "%s: glyphrun string %s was expected, but got %s instead\n",
336 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
338 else
339 ok_(file, line) (cmp == 0, "%s: glyphrun string %s was expected, but got %s instead\n",
340 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
342 expected++;
343 actual++;
346 if (todo) {
347 todo_wine {
348 if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND) {
349 failcount++;
350 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
351 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
355 else if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND)
356 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
357 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
359 if (todo && !failcount) /* succeeded yet marked todo */
360 todo_wine
361 ok_(file, line)(1, "%s: marked \"todo_wine\" but succeeds\n", context);
363 flush_sequence(seq, sequence_index);
366 #define ok_sequence(seq, index, exp, contx, todo) \
367 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
369 static HRESULT WINAPI testrenderer_QI(IDWriteTextRenderer *iface, REFIID riid, void **obj)
371 if (IsEqualIID(riid, &IID_IDWriteTextRenderer) ||
372 IsEqualIID(riid, &IID_IDWritePixelSnapping) ||
373 IsEqualIID(riid, &IID_IUnknown)
375 *obj = iface;
376 return S_OK;
379 *obj = NULL;
381 /* IDWriteTextRenderer1 overrides drawing calls, ignore for now */
382 if (IsEqualIID(riid, &IID_IDWriteTextRenderer1))
383 return E_NOINTERFACE;
385 ok(0, "unexpected QI %s\n", wine_dbgstr_guid(riid));
386 return E_NOINTERFACE;
389 static ULONG WINAPI testrenderer_AddRef(IDWriteTextRenderer *iface)
391 return 2;
394 static ULONG WINAPI testrenderer_Release(IDWriteTextRenderer *iface)
396 return 1;
399 static HRESULT WINAPI testrenderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
400 void *client_drawingcontext, BOOL *disabled)
402 *disabled = TRUE;
403 return S_OK;
406 static HRESULT WINAPI testrenderer_GetCurrentTransform(IDWriteTextRenderer *iface,
407 void *client_drawingcontext, DWRITE_MATRIX *transform)
409 transform->m11 = 1.0;
410 transform->m12 = 0.0;
411 transform->m21 = 0.0;
412 transform->m22 = 1.0;
413 transform->dx = 0.0;
414 transform->dy = 0.0;
415 return S_OK;
418 static HRESULT WINAPI testrenderer_GetPixelsPerDip(IDWriteTextRenderer *iface,
419 void *client_drawingcontext, FLOAT *pixels_per_dip)
421 *pixels_per_dip = 1.0;
422 return S_OK;
425 static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface,
426 void* client_drawingcontext,
427 FLOAT baselineOriginX,
428 FLOAT baselineOriginY,
429 DWRITE_MEASURING_MODE mode,
430 DWRITE_GLYPH_RUN const *run,
431 DWRITE_GLYPH_RUN_DESCRIPTION const *descr,
432 IUnknown *drawing_effect)
434 struct drawcall_entry entry;
435 DWRITE_SCRIPT_ANALYSIS sa;
437 ok(descr->stringLength < sizeof(entry.string)/sizeof(WCHAR), "string is too long\n");
438 if (descr->stringLength && descr->stringLength < sizeof(entry.string)/sizeof(WCHAR)) {
439 memcpy(entry.string, descr->string, descr->stringLength*sizeof(WCHAR));
440 entry.string[descr->stringLength] = 0;
442 else
443 entry.string[0] = 0;
445 /* see what's reported for control codes runs */
446 get_script_analysis(descr->string, descr->stringLength, &sa);
447 if (sa.script == g_control_sa.script) {
448 /* glyphs are not reported at all for control code runs */
449 ok(run->glyphCount == 0, "got %u\n", run->glyphCount);
450 ok(run->glyphAdvances != NULL, "advances array %p\n", run->glyphAdvances);
451 ok(run->glyphOffsets != NULL, "offsets array %p\n", run->glyphOffsets);
452 ok(run->fontFace != NULL, "got %p\n", run->fontFace);
453 /* text positions are still valid */
454 ok(descr->string != NULL, "got string %p\n", descr->string);
455 ok(descr->stringLength > 0, "got string length %u\n", descr->stringLength);
456 ok(descr->clusterMap != NULL, "clustermap %p\n", descr->clusterMap);
459 entry.kind = DRAW_GLYPHRUN;
460 add_call(sequences, RENDERER_ID, &entry);
461 return S_OK;
464 static HRESULT WINAPI testrenderer_DrawUnderline(IDWriteTextRenderer *iface,
465 void *client_drawingcontext,
466 FLOAT baselineOriginX,
467 FLOAT baselineOriginY,
468 DWRITE_UNDERLINE const* underline,
469 IUnknown *drawing_effect)
471 struct drawcall_entry entry;
472 entry.kind = DRAW_UNDERLINE;
473 add_call(sequences, RENDERER_ID, &entry);
474 return S_OK;
477 static HRESULT WINAPI testrenderer_DrawStrikethrough(IDWriteTextRenderer *iface,
478 void *client_drawingcontext,
479 FLOAT baselineOriginX,
480 FLOAT baselineOriginY,
481 DWRITE_STRIKETHROUGH const* strikethrough,
482 IUnknown *drawing_effect)
484 struct drawcall_entry entry;
485 entry.kind = DRAW_STRIKETHROUGH;
486 add_call(sequences, RENDERER_ID, &entry);
487 return S_OK;
490 static HRESULT WINAPI testrenderer_DrawInlineObject(IDWriteTextRenderer *iface,
491 void *client_drawingcontext,
492 FLOAT originX,
493 FLOAT originY,
494 IDWriteInlineObject *object,
495 BOOL is_sideways,
496 BOOL is_rtl,
497 IUnknown *drawing_effect)
499 struct drawcall_entry entry;
500 entry.kind = DRAW_INLINE;
501 add_call(sequences, RENDERER_ID, &entry);
502 return S_OK;
505 static const IDWriteTextRendererVtbl testrenderervtbl = {
506 testrenderer_QI,
507 testrenderer_AddRef,
508 testrenderer_Release,
509 testrenderer_IsPixelSnappingDisabled,
510 testrenderer_GetCurrentTransform,
511 testrenderer_GetPixelsPerDip,
512 testrenderer_DrawGlyphRun,
513 testrenderer_DrawUnderline,
514 testrenderer_DrawStrikethrough,
515 testrenderer_DrawInlineObject
518 static IDWriteTextRenderer testrenderer = { &testrenderervtbl };
520 /* test IDWriteInlineObject */
521 static HRESULT WINAPI testinlineobj_QI(IDWriteInlineObject *iface, REFIID riid, void **obj)
523 if (IsEqualIID(riid, &IID_IDWriteInlineObject) || IsEqualIID(riid, &IID_IUnknown)) {
524 *obj = iface;
525 IDWriteInlineObject_AddRef(iface);
526 return S_OK;
529 *obj = NULL;
530 return E_NOINTERFACE;
533 static ULONG WINAPI testinlineobj_AddRef(IDWriteInlineObject *iface)
535 return 2;
538 static ULONG WINAPI testinlineobj_Release(IDWriteInlineObject *iface)
540 return 1;
543 static HRESULT WINAPI testinlineobj_Draw(IDWriteInlineObject *iface,
544 void* client_drawingontext, IDWriteTextRenderer* renderer,
545 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *drawing_effect)
547 ok(0, "unexpected call\n");
548 return E_NOTIMPL;
551 static HRESULT WINAPI testinlineobj_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
553 metrics->width = 123.0;
554 return 0x8faecafe;
557 static HRESULT WINAPI testinlineobj_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
559 ok(0, "unexpected call\n");
560 return E_NOTIMPL;
563 static HRESULT WINAPI testinlineobj_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
564 DWRITE_BREAK_CONDITION *after)
566 *before = *after = DWRITE_BREAK_CONDITION_MUST_BREAK;
567 return 0x8feacafe;
570 static IDWriteInlineObjectVtbl testinlineobjvtbl = {
571 testinlineobj_QI,
572 testinlineobj_AddRef,
573 testinlineobj_Release,
574 testinlineobj_Draw,
575 testinlineobj_GetMetrics,
576 testinlineobj_GetOverhangMetrics,
577 testinlineobj_GetBreakConditions
580 static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl };
581 static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
583 static void test_CreateTextLayout(void)
585 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
586 IDWriteTextLayout2 *layout2;
587 IDWriteTextLayout *layout;
588 IDWriteTextFormat *format;
589 IDWriteFactory *factory;
590 HRESULT hr;
592 factory = create_factory();
594 hr = IDWriteFactory_CreateTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, &layout);
595 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
597 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 0.0, &layout);
598 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
600 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1.0, 0.0, &layout);
601 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
603 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 1.0, &layout);
604 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
606 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, &layout);
607 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
609 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
610 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
611 ok(hr == S_OK, "got 0x%08x\n", hr);
613 EXPECT_REF(format, 1);
614 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 1000.0, 1000.0, &layout);
615 ok(hr == S_OK, "got 0x%08x\n", hr);
616 EXPECT_REF(format, 1);
618 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
619 if (hr == S_OK) {
620 IDWriteTextLayout1 *layout1;
621 IDWriteTextFormat1 *format1;
622 IDWriteTextFormat *format;
624 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextLayout1, (void**)&layout1);
625 ok(hr == S_OK, "got 0x%08x\n", hr);
626 IDWriteTextLayout1_Release(layout1);
628 EXPECT_REF(layout2, 2);
629 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
630 ok(hr == S_OK, "got 0x%08x\n", hr);
631 EXPECT_REF(layout2, 3);
633 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat, (void**)&format);
634 ok(hr == S_OK, "got 0x%08x\n", hr);
635 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
636 ok(format != (IDWriteTextFormat*)layout2, "got %p, %p\n", format, layout2);
637 EXPECT_REF(layout2, 4);
639 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextLayout1, (void**)&layout1);
640 ok(hr == S_OK, "got 0x%08x\n", hr);
641 IDWriteTextLayout1_Release(layout1);
643 IDWriteTextFormat1_Release(format1);
644 IDWriteTextFormat_Release(format);
646 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
647 ok(hr == S_OK, "got 0x%08x\n", hr);
648 EXPECT_REF(layout2, 3);
650 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format);
651 ok(hr == S_OK, "got 0x%08x\n", hr);
652 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
653 EXPECT_REF(layout2, 4);
655 IDWriteTextFormat1_Release(format1);
656 IDWriteTextFormat_Release(format);
657 IDWriteTextLayout2_Release(layout2);
659 else
660 win_skip("IDWriteTextLayout2 is not supported.\n");
662 IDWriteTextLayout_Release(layout);
663 IDWriteTextFormat_Release(format);
664 IDWriteFactory_Release(factory);
667 static void test_CreateGdiCompatibleTextLayout(void)
669 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
670 IDWriteTextLayout *layout;
671 IDWriteTextFormat *format;
672 IDWriteFactory *factory;
673 FLOAT dimension;
674 HRESULT hr;
676 factory = create_factory();
678 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
679 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
681 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
682 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
684 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 0.0, NULL, FALSE, &layout);
685 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
687 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 1.0, NULL, FALSE, &layout);
688 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
690 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, 1.0, NULL, FALSE, &layout);
691 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
693 /* create with text format */
694 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
695 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
696 ok(hr == S_OK, "got 0x%08x\n", hr);
697 EXPECT_REF(format, 1);
699 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
700 ok(hr == S_OK, "got 0x%08x\n", hr);
701 EXPECT_REF(format, 1);
702 EXPECT_REF(layout, 1);
704 IDWriteTextLayout_AddRef(layout);
705 EXPECT_REF(format, 1);
706 EXPECT_REF(layout, 2);
707 IDWriteTextLayout_Release(layout);
708 IDWriteTextLayout_Release(layout);
710 /* zero length string is okay */
711 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
712 ok(hr == S_OK, "got 0x%08x\n", hr);
714 dimension = IDWriteTextLayout_GetMaxWidth(layout);
715 ok(dimension == 100.0, "got %f\n", dimension);
717 dimension = IDWriteTextLayout_GetMaxHeight(layout);
718 ok(dimension == 100.0, "got %f\n", dimension);
720 IDWriteTextLayout_Release(layout);
721 IDWriteTextFormat_Release(format);
722 IDWriteFactory_Release(factory);
725 static void test_CreateTextFormat(void)
727 IDWriteFontCollection *collection, *syscoll;
728 DWRITE_PARAGRAPH_ALIGNMENT paralign;
729 DWRITE_READING_DIRECTION readdir;
730 DWRITE_WORD_WRAPPING wrapping;
731 DWRITE_TEXT_ALIGNMENT align;
732 DWRITE_FLOW_DIRECTION flow;
733 DWRITE_LINE_SPACING_METHOD method;
734 DWRITE_TRIMMING trimming;
735 IDWriteTextFormat *format;
736 FLOAT spacing, baseline;
737 IDWriteInlineObject *trimmingsign;
738 IDWriteFactory *factory;
739 HRESULT hr;
741 factory = create_factory();
743 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
744 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
745 ok(hr == S_OK, "got 0x%08x\n", hr);
747 if (0) /* crashes on native */
748 hr = IDWriteTextFormat_GetFontCollection(format, NULL);
750 collection = NULL;
751 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
752 ok(hr == S_OK, "got 0x%08x\n", hr);
753 ok(collection != NULL, "got %p\n", collection);
755 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
756 ok(hr == S_OK, "got 0x%08x\n", hr);
757 ok(collection == syscoll, "got %p, was %p\n", syscoll, collection);
758 IDWriteFontCollection_Release(syscoll);
759 IDWriteFontCollection_Release(collection);
761 /* default format properties */
762 align = IDWriteTextFormat_GetTextAlignment(format);
763 ok(align == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", align);
765 paralign = IDWriteTextFormat_GetParagraphAlignment(format);
766 ok(paralign == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", paralign);
768 wrapping = IDWriteTextFormat_GetWordWrapping(format);
769 ok(wrapping == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", wrapping);
771 readdir = IDWriteTextFormat_GetReadingDirection(format);
772 ok(readdir == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", readdir);
774 flow = IDWriteTextFormat_GetFlowDirection(format);
775 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
777 hr = IDWriteTextFormat_GetLineSpacing(format, &method, &spacing, &baseline);
778 ok(hr == S_OK, "got 0x%08x\n", hr);
779 ok(spacing == 0.0, "got %f\n", spacing);
780 ok(baseline == 0.0, "got %f\n", baseline);
781 ok(method == DWRITE_LINE_SPACING_METHOD_DEFAULT, "got %d\n", method);
783 trimming.granularity = DWRITE_TRIMMING_GRANULARITY_WORD;
784 trimming.delimiter = 10;
785 trimming.delimiterCount = 10;
786 trimmingsign = (void*)0xdeadbeef;
787 hr = IDWriteTextFormat_GetTrimming(format, &trimming, &trimmingsign);
788 ok(hr == S_OK, "got 0x%08x\n", hr);
789 ok(trimming.granularity == DWRITE_TRIMMING_GRANULARITY_NONE, "got %d\n", trimming.granularity);
790 ok(trimming.delimiter == 0, "got %d\n", trimming.delimiter);
791 ok(trimming.delimiterCount == 0, "got %d\n", trimming.delimiterCount);
792 ok(trimmingsign == NULL, "got %p\n", trimmingsign);
794 /* setters */
795 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING);
796 ok(hr == S_OK, "got 0x%08x\n", hr);
798 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
799 ok(hr == S_OK, "got 0x%08x\n", hr);
801 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_WRAP);
802 ok(hr == S_OK, "got 0x%08x\n", hr);
804 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
805 ok(hr == S_OK, "got 0x%08x\n", hr);
807 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
808 ok(hr == S_OK, "got 0x%08x\n", hr);
810 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0, 0.0);
811 ok(hr == S_OK, "got 0x%08x\n", hr);
813 hr = IDWriteTextFormat_SetTrimming(format, &trimming, NULL);
814 ok(hr == S_OK, "got 0x%08x\n", hr);
816 IDWriteTextFormat_Release(format);
817 IDWriteFactory_Release(factory);
820 static void test_GetLocaleName(void)
822 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
823 static const WCHAR ruW[] = {'r','u',0};
824 IDWriteTextLayout *layout;
825 IDWriteTextFormat *format, *format2;
826 IDWriteFactory *factory;
827 WCHAR buff[10];
828 UINT32 len;
829 HRESULT hr;
831 factory = create_factory();
833 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
834 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
835 ok(hr == S_OK, "got 0x%08x\n", hr);
837 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
838 ok(hr == S_OK, "got 0x%08x\n", hr);
840 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format2);
841 ok(hr == S_OK, "got 0x%08x\n", hr);
843 len = IDWriteTextFormat_GetLocaleNameLength(format2);
844 ok(len == 2, "got %u\n", len);
845 len = IDWriteTextFormat_GetLocaleNameLength(format);
846 ok(len == 2, "got %u\n", len);
847 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len);
848 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
849 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len+1);
850 ok(hr == S_OK, "got 0x%08x\n", hr);
851 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
852 hr = IDWriteTextFormat_GetLocaleName(format, buff, len);
853 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
854 hr = IDWriteTextFormat_GetLocaleName(format, buff, len+1);
855 ok(hr == S_OK, "got 0x%08x\n", hr);
856 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
858 IDWriteTextLayout_Release(layout);
859 IDWriteTextFormat_Release(format);
860 IDWriteTextFormat_Release(format2);
861 IDWriteFactory_Release(factory);
864 static void test_CreateEllipsisTrimmingSign(void)
866 DWRITE_BREAK_CONDITION before, after;
867 IDWriteTextFormat *format;
868 IDWriteInlineObject *sign;
869 IDWriteFactory *factory;
870 HRESULT hr;
872 factory = create_factory();
874 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
875 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
876 ok(hr == S_OK, "got 0x%08x\n", hr);
878 EXPECT_REF(format, 1);
879 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
880 ok(hr == S_OK, "got 0x%08x\n", hr);
881 EXPECT_REF(format, 1);
883 if (0) /* crashes on native */
884 hr = IDWriteInlineObject_GetBreakConditions(sign, NULL, NULL);
886 before = after = DWRITE_BREAK_CONDITION_CAN_BREAK;
887 hr = IDWriteInlineObject_GetBreakConditions(sign, &before, &after);
888 ok(hr == S_OK, "got 0x%08x\n", hr);
889 ok(before == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", before);
890 ok(after == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", after);
892 IDWriteInlineObject_Release(sign);
893 IDWriteTextFormat_Release(format);
894 IDWriteFactory_Release(factory);
897 static void test_fontweight(void)
899 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
900 static const WCHAR ruW[] = {'r','u',0};
901 IDWriteTextFormat *format, *fmt2;
902 IDWriteTextLayout *layout;
903 DWRITE_FONT_WEIGHT weight;
904 DWRITE_TEXT_RANGE range;
905 IDWriteFactory *factory;
906 FLOAT size;
907 HRESULT hr;
909 factory = create_factory();
911 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
912 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
913 ok(hr == S_OK, "got 0x%08x\n", hr);
915 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
916 ok(hr == S_OK, "got 0x%08x\n", hr);
918 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&fmt2);
919 ok(hr == S_OK, "got 0x%08x\n", hr);
921 weight = IDWriteTextFormat_GetFontWeight(fmt2);
922 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
924 range.startPosition = range.length = 0;
925 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
926 ok(hr == S_OK, "got 0x%08x\n", hr);
927 ok(range.startPosition == 0 && range.length == ~0u, "got %u, %u\n", range.startPosition, range.length);
929 range.startPosition = 0;
930 range.length = 6;
931 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_NORMAL, range);
932 ok(hr == S_OK, "got 0x%08x\n", hr);
934 range.startPosition = range.length = 0;
935 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
936 ok(hr == S_OK, "got 0x%08x\n", hr);
937 ok(range.startPosition == 0 && range.length == 6, "got %u, %u\n", range.startPosition, range.length);
939 /* IDWriteTextFormat methods output doesn't reflect layout changes */
940 weight = IDWriteTextFormat_GetFontWeight(fmt2);
941 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
943 range.length = 0;
944 weight = DWRITE_FONT_WEIGHT_BOLD;
945 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
946 ok(hr == S_OK, "got 0x%08x\n", hr);
947 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
948 ok(range.length == 6, "got %d\n", range.length);
950 size = IDWriteTextLayout_GetMaxWidth(layout);
951 ok(size == 100.0, "got %.2f\n", size);
953 hr = IDWriteTextLayout_SetMaxWidth(layout, 0.0);
954 ok(hr == S_OK, "got 0x%08x\n", hr);
956 size = IDWriteTextLayout_GetMaxWidth(layout);
957 ok(size == 0.0, "got %.2f\n", size);
959 hr = IDWriteTextLayout_SetMaxWidth(layout, -1.0);
960 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
962 size = IDWriteTextLayout_GetMaxWidth(layout);
963 ok(size == 0.0, "got %.2f\n", size);
965 hr = IDWriteTextLayout_SetMaxWidth(layout, 100.0);
966 ok(hr == S_OK, "got 0x%08x\n", hr);
968 size = IDWriteTextLayout_GetMaxWidth(layout);
969 ok(size == 100.0, "got %.2f\n", size);
971 size = IDWriteTextLayout_GetMaxHeight(layout);
972 ok(size == 100.0, "got %.2f\n", size);
974 hr = IDWriteTextLayout_SetMaxHeight(layout, 0.0);
975 ok(hr == S_OK, "got 0x%08x\n", hr);
977 size = IDWriteTextLayout_GetMaxHeight(layout);
978 ok(size == 0.0, "got %.2f\n", size);
980 hr = IDWriteTextLayout_SetMaxHeight(layout, -1.0);
981 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
983 size = IDWriteTextLayout_GetMaxHeight(layout);
984 ok(size == 0.0, "got %.2f\n", size);
986 hr = IDWriteTextLayout_SetMaxHeight(layout, 100.0);
987 ok(hr == S_OK, "got 0x%08x\n", hr);
989 size = IDWriteTextLayout_GetMaxHeight(layout);
990 ok(size == 100.0, "got %.2f\n", size);
992 IDWriteTextLayout_Release(layout);
993 IDWriteTextFormat_Release(fmt2);
994 IDWriteTextFormat_Release(format);
995 IDWriteFactory_Release(factory);
998 static void test_SetInlineObject(void)
1000 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1001 static const WCHAR ruW[] = {'r','u',0};
1003 IDWriteInlineObject *inlineobj, *inlineobj2, *inlinetest;
1004 IDWriteTextFormat *format;
1005 IDWriteTextLayout *layout;
1006 DWRITE_TEXT_RANGE range, r2;
1007 IDWriteFactory *factory;
1008 HRESULT hr;
1010 factory = create_factory();
1012 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1013 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1014 ok(hr == S_OK, "got 0x%08x\n", hr);
1016 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1017 ok(hr == S_OK, "got 0x%08x\n", hr);
1019 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1020 ok(hr == S_OK, "got 0x%08x\n", hr);
1022 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj2);
1023 ok(hr == S_OK, "got 0x%08x\n", hr);
1025 EXPECT_REF(inlineobj, 1);
1026 EXPECT_REF(inlineobj2, 1);
1028 inlinetest = (void*)0x1;
1029 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, NULL);
1030 ok(hr == S_OK, "got 0x%08x\n", hr);
1031 ok(inlinetest == NULL, "got %p\n", inlinetest);
1033 range.startPosition = 0;
1034 range.length = 2;
1035 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1036 ok(hr == S_OK, "got 0x%08x\n", hr);
1038 EXPECT_REF(inlineobj, 2);
1040 inlinetest = (void*)0x1;
1041 hr = IDWriteTextLayout_GetInlineObject(layout, 2, &inlinetest, NULL);
1042 ok(hr == S_OK, "got 0x%08x\n", hr);
1043 ok(inlinetest == NULL, "got %p\n", inlinetest);
1045 inlinetest = NULL;
1046 r2.startPosition = r2.length = 100;
1047 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1048 ok(hr == S_OK, "got 0x%08x\n", hr);
1049 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1050 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1051 IDWriteInlineObject_Release(inlinetest);
1053 EXPECT_REF(inlineobj, 2);
1055 /* get from somewhere inside a range */
1056 inlinetest = NULL;
1057 r2.startPosition = r2.length = 100;
1058 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1059 ok(hr == S_OK, "got 0x%08x\n", hr);
1060 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1061 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1062 IDWriteInlineObject_Release(inlinetest);
1064 EXPECT_REF(inlineobj, 2);
1066 range.startPosition = 1;
1067 range.length = 1;
1068 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj2, range);
1069 ok(hr == S_OK, "got 0x%08x\n", hr);
1071 inlinetest = NULL;
1072 r2.startPosition = r2.length = 100;
1073 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1074 ok(hr == S_OK, "got 0x%08x\n", hr);
1075 ok(inlinetest == inlineobj2, "got %p\n", inlinetest);
1076 ok(r2.startPosition == 1 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1077 IDWriteInlineObject_Release(inlinetest);
1079 EXPECT_REF(inlineobj, 2);
1080 EXPECT_REF(inlineobj2, 2);
1082 inlinetest = NULL;
1083 r2.startPosition = r2.length = 100;
1084 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1085 ok(hr == S_OK, "got 0x%08x\n", hr);
1086 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1087 ok(r2.startPosition == 0 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1088 IDWriteInlineObject_Release(inlinetest);
1090 EXPECT_REF(inlineobj, 2);
1092 range.startPosition = 1;
1093 range.length = 1;
1094 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1095 ok(hr == S_OK, "got 0x%08x\n", hr);
1097 r2.startPosition = r2.length = 100;
1098 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1099 ok(hr == S_OK, "got 0x%08x\n", hr);
1100 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1101 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1102 IDWriteInlineObject_Release(inlinetest);
1104 EXPECT_REF(inlineobj, 2);
1106 range.startPosition = 1;
1107 range.length = 2;
1108 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1109 ok(hr == S_OK, "got 0x%08x\n", hr);
1111 EXPECT_REF(inlineobj, 2);
1113 r2.startPosition = r2.length = 100;
1114 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1115 ok(hr == S_OK, "got 0x%08x\n", hr);
1116 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1117 ok(r2.startPosition == 0 && r2.length == 3, "got %d, %d\n", r2.startPosition, r2.length);
1118 IDWriteInlineObject_Release(inlinetest);
1120 EXPECT_REF(inlineobj, 2);
1121 EXPECT_REF(inlineobj2, 1);
1123 IDWriteTextLayout_Release(layout);
1125 EXPECT_REF(inlineobj, 1);
1127 IDWriteInlineObject_Release(inlineobj);
1128 IDWriteInlineObject_Release(inlineobj2);
1129 IDWriteTextFormat_Release(format);
1130 IDWriteFactory_Release(factory);
1133 /* drawing calls sequence doesn't depend on run order, instead all runs are
1134 drawn first, inline objects next and then underline/strikes */
1135 static const struct drawcall_entry draw_seq[] = {
1136 { DRAW_GLYPHRUN, {'s',0} },
1137 { DRAW_GLYPHRUN, {'r','i',0} },
1138 { DRAW_GLYPHRUN, {'n',0} },
1139 { DRAW_GLYPHRUN, {'g',0} },
1140 { DRAW_INLINE },
1141 { DRAW_UNDERLINE },
1142 { DRAW_STRIKETHROUGH },
1143 { DRAW_LAST_KIND }
1146 static const struct drawcall_entry draw_seq2[] = {
1147 { DRAW_GLYPHRUN, {'s',0} },
1148 { DRAW_GLYPHRUN, {'t',0} },
1149 { DRAW_GLYPHRUN, {'r',0} },
1150 { DRAW_GLYPHRUN, {'i',0} },
1151 { DRAW_GLYPHRUN, {'n',0} },
1152 { DRAW_GLYPHRUN, {'g',0} },
1153 { DRAW_LAST_KIND }
1156 static const struct drawcall_entry draw_seq3[] = {
1157 { DRAW_GLYPHRUN },
1158 { DRAW_GLYPHRUN, {'a','b',0} },
1159 { DRAW_LAST_KIND }
1162 static const struct drawcall_entry draw_seq4[] = {
1163 { DRAW_GLYPHRUN, {'s','t','r',0} },
1164 { DRAW_GLYPHRUN, {'i','n','g',0} },
1165 { DRAW_STRIKETHROUGH },
1166 { DRAW_LAST_KIND }
1169 static const struct drawcall_entry draw_seq5[] = {
1170 { DRAW_GLYPHRUN, {'s','t',0} },
1171 { DRAW_GLYPHRUN, {'r','i',0} },
1172 { DRAW_GLYPHRUN, {'n','g',0} },
1173 { DRAW_STRIKETHROUGH },
1174 { DRAW_LAST_KIND }
1177 static void test_Draw(void)
1179 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1180 static const WCHAR str2W[] = {0x202a,0x202c,'a','b',0};
1181 static const WCHAR ruW[] = {'r','u',0};
1183 IDWriteInlineObject *inlineobj;
1184 IDWriteTextFormat *format;
1185 IDWriteTextLayout *layout;
1186 DWRITE_TEXT_RANGE range;
1187 IDWriteFactory *factory;
1188 HRESULT hr;
1190 factory = create_factory();
1192 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1193 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1194 ok(hr == S_OK, "got 0x%08x\n", hr);
1196 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 100.0, 100.0, &layout);
1197 ok(hr == S_OK, "got 0x%08x\n", hr);
1199 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1200 ok(hr == S_OK, "got 0x%08x\n", hr);
1202 range.startPosition = 5;
1203 range.length = 1;
1204 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1205 ok(hr == S_OK, "got 0x%08x\n", hr);
1207 range.startPosition = 1;
1208 range.length = 1;
1209 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1210 ok(hr == S_OK, "got 0x%08x\n", hr);
1212 range.startPosition = 4;
1213 range.length = 1;
1214 hr = IDWriteTextLayout_SetDrawingEffect(layout, (IUnknown*)inlineobj, range);
1215 ok(hr == S_OK, "got 0x%08x\n", hr);
1217 range.startPosition = 0;
1218 range.length = 1;
1219 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
1220 ok(hr == S_OK, "got 0x%08x\n", hr);
1222 flush_sequence(sequences, RENDERER_ID);
1223 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1224 ok(hr == S_OK, "got 0x%08x\n", hr);
1225 ok_sequence(sequences, RENDERER_ID, draw_seq, "draw test", TRUE);
1226 IDWriteTextLayout_Release(layout);
1228 /* with reduced width DrawGlyphRun() is called for every line */
1229 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 5.0, 100.0, &layout);
1230 ok(hr == S_OK, "got 0x%08x\n", hr);
1231 flush_sequence(sequences, RENDERER_ID);
1232 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1233 ok(hr == S_OK, "got 0x%08x\n", hr);
1234 ok_sequence(sequences, RENDERER_ID, draw_seq2, "draw test 2", TRUE);
1235 IDWriteTextLayout_Release(layout);
1237 /* string with control characters */
1238 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 100.0, &layout);
1239 ok(hr == S_OK, "got 0x%08x\n", hr);
1240 flush_sequence(sequences, RENDERER_ID);
1241 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1242 ok(hr == S_OK, "got 0x%08x\n", hr);
1243 ok_sequence(sequences, RENDERER_ID, draw_seq3, "draw test 3", TRUE);
1244 IDWriteTextLayout_Release(layout);
1246 /* strikethrough splits ranges from renderer point of view, but doesn't break
1247 shaping */
1248 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1249 ok(hr == S_OK, "got 0x%08x\n", hr);
1250 flush_sequence(sequences, RENDERER_ID);
1252 range.startPosition = 0;
1253 range.length = 3;
1254 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1255 ok(hr == S_OK, "got 0x%08x\n", hr);
1257 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1258 ok(hr == S_OK, "got 0x%08x\n", hr);
1259 ok_sequence(sequences, RENDERER_ID, draw_seq4, "draw test 4", FALSE);
1260 IDWriteTextLayout_Release(layout);
1262 /* strikethrough somewhere in the middle */
1263 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1264 ok(hr == S_OK, "got 0x%08x\n", hr);
1265 flush_sequence(sequences, RENDERER_ID);
1267 range.startPosition = 2;
1268 range.length = 2;
1269 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1270 ok(hr == S_OK, "got 0x%08x\n", hr);
1272 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
1273 ok(hr == S_OK, "got 0x%08x\n", hr);
1274 ok_sequence(sequences, RENDERER_ID, draw_seq5, "draw test 5", FALSE);
1275 IDWriteTextLayout_Release(layout);
1277 IDWriteTextFormat_Release(format);
1278 IDWriteFactory_Release(factory);
1281 static void test_typography(void)
1283 DWRITE_FONT_FEATURE feature;
1284 IDWriteTypography *typography;
1285 IDWriteFactory *factory;
1286 UINT32 count;
1287 HRESULT hr;
1289 factory = create_factory();
1291 hr = IDWriteFactory_CreateTypography(factory, &typography);
1292 ok(hr == S_OK, "got 0x%08x\n", hr);
1294 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1295 feature.parameter = 1;
1296 hr = IDWriteTypography_AddFontFeature(typography, feature);
1297 ok(hr == S_OK, "got 0x%08x\n", hr);
1299 count = IDWriteTypography_GetFontFeatureCount(typography);
1300 ok(count == 1, "got %u\n", count);
1302 /* duplicated features work just fine */
1303 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1304 feature.parameter = 0;
1305 hr = IDWriteTypography_AddFontFeature(typography, feature);
1306 ok(hr == S_OK, "got 0x%08x\n", hr);
1308 count = IDWriteTypography_GetFontFeatureCount(typography);
1309 ok(count == 2, "got %u\n", count);
1311 memset(&feature, 0, sizeof(feature));
1312 hr = IDWriteTypography_GetFontFeature(typography, 0, &feature);
1313 ok(hr == S_OK, "got 0x%08x\n", hr);
1314 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1315 ok(feature.parameter == 1, "got %u\n", feature.parameter);
1317 memset(&feature, 0, sizeof(feature));
1318 hr = IDWriteTypography_GetFontFeature(typography, 1, &feature);
1319 ok(hr == S_OK, "got 0x%08x\n", hr);
1320 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1321 ok(feature.parameter == 0, "got %u\n", feature.parameter);
1323 hr = IDWriteTypography_GetFontFeature(typography, 2, &feature);
1324 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1326 IDWriteTypography_Release(typography);
1327 IDWriteFactory_Release(factory);
1330 static void test_GetClusterMetrics(void)
1332 static const WCHAR str2W[] = {0x202a,0x202c,'a',0};
1333 static const WCHAR strW[] = {'a','b','c','d',0};
1334 DWRITE_INLINE_OBJECT_METRICS inline_metrics;
1335 DWRITE_CLUSTER_METRICS metrics[4];
1336 IDWriteTextLayout1 *layout1;
1337 IDWriteInlineObject *trimm;
1338 IDWriteTextFormat *format;
1339 IDWriteTextLayout *layout;
1340 DWRITE_TEXT_RANGE range;
1341 IDWriteFactory *factory;
1342 UINT32 count, i;
1343 HRESULT hr;
1345 factory = create_factory();
1347 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1348 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1349 ok(hr == S_OK, "got 0x%08x\n", hr);
1351 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1352 ok(hr == S_OK, "got 0x%08x\n", hr);
1354 count = 0;
1355 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1356 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1357 ok(count == 4, "got %u\n", count);
1359 /* check every cluster width */
1360 count = 0;
1361 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
1362 ok(hr == S_OK, "got 0x%08x\n", hr);
1363 ok(count == 4, "got %u\n", count);
1364 for (i = 0; i < count; i++) {
1365 ok(metrics[i].width > 0.0, "%u: got width %.2f\n", i, metrics[i].width);
1366 ok(metrics[i].length == 1, "%u: got length %u\n", i, metrics[i].length);
1369 /* apply spacing and check widths again */
1370 if (IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1) == S_OK) {
1371 DWRITE_CLUSTER_METRICS metrics2[4];
1372 FLOAT leading, trailing, min_advance;
1373 DWRITE_TEXT_RANGE r;
1375 leading = trailing = min_advance = 2.0;
1376 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 0, &leading, &trailing,
1377 &min_advance, NULL);
1378 todo_wine {
1379 ok(hr == S_OK, "got 0x%08x\n", hr);
1380 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
1381 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
1383 r.startPosition = 0;
1384 r.length = 4;
1385 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 10.0, 15.0, 0.0, r);
1386 todo_wine
1387 ok(hr == S_OK, "got 0x%08x\n", hr);
1389 count = 0;
1390 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics2, sizeof(metrics2)/sizeof(metrics2[0]), &count);
1391 ok(hr == S_OK, "got 0x%08x\n", hr);
1392 ok(count == 4, "got %u\n", count);
1393 for (i = 0; i < count; i++) {
1394 todo_wine
1395 ok(metrics2[i].width > metrics[i].width, "%u: got width %.2f, was %.2f\n", i, metrics2[i].width,
1396 metrics[i].width);
1397 ok(metrics2[i].length == 1, "%u: got length %u\n", i, metrics2[i].length);
1400 /* back to defaults */
1401 r.startPosition = 0;
1402 r.length = 4;
1403 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, 0.0, r);
1404 todo_wine
1405 ok(hr == S_OK, "got 0x%08x\n", hr);
1407 IDWriteTextLayout1_Release(layout1);
1409 else
1410 win_skip("IDWriteTextLayout1 is not supported, cluster spacing test skipped.\n");
1412 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &trimm);
1413 ok(hr == S_OK, "got 0x%08x\n", hr);
1415 range.startPosition = 0;
1416 range.length = 2;
1417 hr = IDWriteTextLayout_SetInlineObject(layout, trimm, range);
1418 ok(hr == S_OK, "got 0x%08x\n", hr);
1420 /* inline object takes a separate cluster, replaced codepoints number doesn't matter */
1421 count = 0;
1422 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1423 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1424 ok(count == 3, "got %u\n", count);
1426 count = 0;
1427 memset(&metrics, 0, sizeof(metrics));
1428 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
1429 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1430 ok(count == 3, "got %u\n", count);
1431 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
1433 hr = IDWriteInlineObject_GetMetrics(trimm, &inline_metrics);
1434 ok(hr == S_OK, "got 0x%08x\n", hr);
1435 todo_wine
1436 ok(inline_metrics.width > 0.0 && inline_metrics.width == metrics[0].width, "got %.2f, expected %.2f\n",
1437 inline_metrics.width, metrics[0].width);
1439 IDWriteTextLayout_Release(layout);
1441 /* text with non-visual control codes */
1442 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 3, format, 1000.0, 1000.0, &layout);
1443 ok(hr == S_OK, "got 0x%08x\n", hr);
1445 /* bidi control codes take a separate cluster */
1446 count = 0;
1447 memset(metrics, 0, sizeof(metrics));
1448 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1449 ok(hr == S_OK, "got 0x%08x\n", hr);
1450 ok(count == 3, "got %u\n", count);
1452 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1453 ok(metrics[0].length == 1, "got %d\n", metrics[0].length);
1454 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
1455 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1456 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1457 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1458 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1460 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
1461 ok(metrics[1].length == 1, "got %d\n", metrics[1].length);
1462 ok(metrics[1].canWrapLineAfter == 0, "got %d\n", metrics[1].canWrapLineAfter);
1463 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
1464 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
1465 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
1466 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
1468 ok(metrics[2].width > 0.0, "got %.2f\n", metrics[2].width);
1469 ok(metrics[2].length == 1, "got %d\n", metrics[2].length);
1470 todo_wine
1471 ok(metrics[2].canWrapLineAfter == 1, "got %d\n", metrics[2].canWrapLineAfter);
1472 ok(metrics[2].isWhitespace == 0, "got %d\n", metrics[2].isWhitespace);
1473 ok(metrics[2].isNewline == 0, "got %d\n", metrics[2].isNewline);
1474 ok(metrics[2].isSoftHyphen == 0, "got %d\n", metrics[2].isSoftHyphen);
1475 ok(metrics[2].isRightToLeft == 0, "got %d\n", metrics[2].isRightToLeft);
1477 IDWriteTextLayout_Release(layout);
1479 /* single inline object that fails to report its metrics */
1480 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1481 ok(hr == S_OK, "got 0x%08x\n", hr);
1483 range.startPosition = 0;
1484 range.length = 4;
1485 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj, range);
1486 ok(hr == S_OK, "got 0x%08x\n", hr);
1488 count = 0;
1489 memset(metrics, 0, sizeof(metrics));
1490 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1491 ok(hr == S_OK, "got 0x%08x\n", hr);
1492 ok(count == 1, "got %u\n", count);
1494 /* object sets a width to 123.0, but returns failure from GetMetrics() */
1495 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1496 ok(metrics[0].length == 4, "got %d\n", metrics[0].length);
1497 todo_wine
1498 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
1499 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1500 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1501 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1502 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1504 /* now set two inline object for [0,1] and [2,3], both fail to report break conditions */
1505 range.startPosition = 2;
1506 range.length = 2;
1507 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj2, range);
1508 ok(hr == S_OK, "got 0x%08x\n", hr);
1510 count = 0;
1511 memset(metrics, 0, sizeof(metrics));
1512 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
1513 ok(hr == S_OK, "got 0x%08x\n", hr);
1514 ok(count == 2, "got %u\n", count);
1516 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
1517 ok(metrics[0].length == 2, "got %d\n", metrics[0].length);
1518 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
1519 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
1520 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
1521 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
1522 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
1524 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
1525 ok(metrics[1].length == 2, "got %d\n", metrics[1].length);
1526 todo_wine
1527 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
1528 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
1529 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
1530 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
1531 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
1533 IDWriteTextLayout_Release(layout);
1535 IDWriteInlineObject_Release(trimm);
1536 IDWriteTextFormat_Release(format);
1537 IDWriteFactory_Release(factory);
1540 static void test_SetLocaleName(void)
1542 static const WCHAR strW[] = {'a','b','c','d',0};
1543 WCHAR buffW[LOCALE_NAME_MAX_LENGTH+sizeof(strW)/sizeof(WCHAR)];
1544 IDWriteTextFormat *format;
1545 IDWriteTextLayout *layout;
1546 DWRITE_TEXT_RANGE range;
1547 IDWriteFactory *factory;
1548 HRESULT hr;
1550 factory = create_factory();
1552 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1553 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1554 ok(hr == S_OK, "got 0x%08x\n", hr);
1556 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1557 ok(hr == S_OK, "got 0x%08x\n", hr);
1559 range.startPosition = 0;
1560 range.length = 1;
1561 hr = IDWriteTextLayout_SetLocaleName(layout, enusW, range);
1562 ok(hr == S_OK, "got 0x%08x\n", hr);
1564 hr = IDWriteTextLayout_SetLocaleName(layout, NULL, range);
1565 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1567 /* invalid locale name is allowed */
1568 hr = IDWriteTextLayout_SetLocaleName(layout, strW, range);
1569 ok(hr == S_OK, "got 0x%08x\n", hr);
1571 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 0, NULL);
1572 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1574 if (0) /* crashes on native */
1575 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 1, NULL);
1577 buffW[0] = 0;
1578 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), NULL);
1579 ok(hr == S_OK, "got 0x%08x\n", hr);
1580 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
1582 /* get with a shorter buffer */
1583 buffW[0] = 0xa;
1584 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, 1, NULL);
1585 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1586 ok(buffW[0] == 0, "got %x\n", buffW[0]);
1588 /* name is too long */
1589 lstrcpyW(buffW, strW);
1590 while (lstrlenW(buffW) <= LOCALE_NAME_MAX_LENGTH)
1591 lstrcatW(buffW, strW);
1593 range.startPosition = 0;
1594 range.length = 1;
1595 hr = IDWriteTextLayout_SetLocaleName(layout, buffW, range);
1596 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1598 buffW[0] = 0;
1599 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), NULL);
1600 ok(hr == S_OK, "got 0x%08x\n", hr);
1601 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
1603 IDWriteTextLayout_Release(layout);
1604 IDWriteTextFormat_Release(format);
1605 IDWriteFactory_Release(factory);
1608 static void test_SetPairKerning(void)
1610 static const WCHAR strW[] = {'a','b','c','d',0};
1611 IDWriteTextLayout1 *layout1;
1612 IDWriteTextFormat *format;
1613 IDWriteTextLayout *layout;
1614 DWRITE_TEXT_RANGE range;
1615 IDWriteFactory *factory;
1616 BOOL kerning;
1617 HRESULT hr;
1619 factory = create_factory();
1621 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1622 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1623 ok(hr == S_OK, "got 0x%08x\n", hr);
1625 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1626 ok(hr == S_OK, "got 0x%08x\n", hr);
1627 IDWriteTextFormat_Release(format);
1629 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1);
1630 IDWriteTextLayout_Release(layout);
1632 if (hr != S_OK) {
1633 win_skip("SetPairKerning() is not supported.\n");
1634 IDWriteFactory_Release(factory);
1635 return;
1638 if (0) { /* crashes on native */
1639 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, NULL);
1640 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, &range);
1643 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, NULL);
1644 ok(hr == S_OK, "got 0x%08x\n", hr);
1646 range.startPosition = 0;
1647 range.length = 0;
1648 kerning = TRUE;
1649 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
1650 ok(hr == S_OK, "got 0x%08x\n", hr);
1651 ok(!kerning, "got %d\n", kerning);
1653 range.startPosition = 0;
1654 range.length = 1;
1655 hr = IDWriteTextLayout1_SetPairKerning(layout1, 2, range);
1656 ok(hr == S_OK, "got 0x%08x\n", hr);
1658 kerning = FALSE;
1659 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
1660 ok(hr == S_OK, "got 0x%08x\n", hr);
1661 ok(kerning == TRUE, "got %d\n", kerning);
1663 IDWriteTextLayout1_Release(layout1);
1664 IDWriteFactory_Release(factory);
1667 static void test_SetVerticalGlyphOrientation(void)
1669 static const WCHAR strW[] = {'a','b','c','d',0};
1670 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation;
1671 IDWriteTextLayout2 *layout2;
1672 IDWriteTextFormat *format;
1673 IDWriteTextLayout *layout;
1674 IDWriteFactory *factory;
1675 HRESULT hr;
1677 factory = create_factory();
1679 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1680 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1681 ok(hr == S_OK, "got 0x%08x\n", hr);
1683 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1684 ok(hr == S_OK, "got 0x%08x\n", hr);
1685 IDWriteTextFormat_Release(format);
1687 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
1688 IDWriteTextLayout_Release(layout);
1690 if (hr != S_OK) {
1691 win_skip("SetVerticalGlyphOrientation() is not supported.\n");
1692 IDWriteFactory_Release(factory);
1693 return;
1696 orientation = IDWriteTextLayout2_GetVerticalGlyphOrientation(layout2);
1697 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT, "got %d\n", orientation);
1699 hr = IDWriteTextLayout2_SetVerticalGlyphOrientation(layout2, DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED+1);
1700 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1702 IDWriteTextLayout2_Release(layout2);
1703 IDWriteFactory_Release(factory);
1706 static void test_fallback(void)
1708 static const WCHAR strW[] = {'a','b','c','d',0};
1709 IDWriteFontFallback *fallback, *fallback2;
1710 IDWriteTextLayout2 *layout2;
1711 IDWriteTextFormat1 *format1;
1712 IDWriteTextFormat *format;
1713 IDWriteTextLayout *layout;
1714 IDWriteFactory2 *factory2;
1715 IDWriteFactory *factory;
1716 HRESULT hr;
1718 factory = create_factory();
1720 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1721 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1722 ok(hr == S_OK, "got 0x%08x\n", hr);
1724 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1725 ok(hr == S_OK, "got 0x%08x\n", hr);
1726 IDWriteTextFormat_Release(format);
1728 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
1729 IDWriteTextLayout_Release(layout);
1731 if (hr != S_OK) {
1732 win_skip("GetFontFallback() is not supported.\n");
1733 IDWriteFactory_Release(factory);
1734 return;
1737 if (0) /* crashes on native */
1738 hr = IDWriteTextLayout2_GetFontFallback(layout2, NULL);
1740 fallback = (void*)0xdeadbeef;
1741 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback);
1742 ok(hr == S_OK, "got 0x%08x\n", hr);
1743 ok(fallback == NULL, "got %p\n", fallback);
1745 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
1746 ok(hr == S_OK, "got 0x%08x\n", hr);
1748 fallback = (void*)0xdeadbeef;
1749 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback);
1750 ok(hr == S_OK, "got 0x%08x\n", hr);
1751 ok(fallback == NULL, "got %p\n", fallback);
1753 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
1754 ok(hr == S_OK, "got 0x%08x\n", hr);
1756 fallback = NULL;
1757 hr = IDWriteFactory2_GetSystemFontFallback(factory2, &fallback);
1758 todo_wine
1759 ok(hr == S_OK, "got 0x%08x\n", hr);
1760 if (hr == S_OK) {
1761 ok(fallback != NULL, "got %p\n", fallback);
1763 hr = IDWriteTextFormat1_SetFontFallback(format1, fallback);
1764 ok(hr == S_OK, "got 0x%08x\n", hr);
1766 fallback2 = (void*)0xdeadbeef;
1767 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback2);
1768 ok(hr == S_OK, "got 0x%08x\n", hr);
1769 ok(fallback2 == fallback, "got %p\n", fallback2);
1771 hr = IDWriteTextLayout2_SetFontFallback(layout2, NULL);
1772 ok(hr == S_OK, "got 0x%08x\n", hr);
1774 fallback2 = (void*)0xdeadbeef;
1775 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback2);
1776 ok(hr == S_OK, "got 0x%08x\n", hr);
1777 ok(fallback2 == NULL, "got %p\n", fallback2);
1779 IDWriteFontFallback_Release(fallback);
1781 IDWriteTextFormat1_Release(format1);
1782 IDWriteTextLayout2_Release(layout2);
1783 IDWriteFactory_Release(factory);
1786 static void test_DetermineMinWidth(void)
1788 static const WCHAR strW[] = {'a','b','c','d',0};
1789 IDWriteTextFormat *format;
1790 IDWriteTextLayout *layout;
1791 IDWriteFactory *factory;
1792 FLOAT minwidth;
1793 HRESULT hr;
1795 factory = create_factory();
1797 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1798 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1799 ok(hr == S_OK, "got 0x%08x\n", hr);
1801 hr = IDWriteFactory_CreateTextLayout(factory, strW, lstrlenW(strW), format, 1000.0, 1000.0, &layout);
1802 ok(hr == S_OK, "got 0x%08x\n", hr);
1804 hr = IDWriteTextLayout_DetermineMinWidth(layout, NULL);
1805 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1807 minwidth = 0.0;
1808 hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
1809 ok(hr == S_OK, "got 0x%08x\n", hr);
1810 ok(minwidth > 0.0, "got %.2f\n", minwidth);
1812 IDWriteTextLayout_Release(layout);
1813 IDWriteTextFormat_Release(format);
1816 static void test_SetFontSize(void)
1818 static const WCHAR strW[] = {'a','b','c','d',0};
1819 IDWriteTextFormat *format;
1820 IDWriteTextLayout *layout;
1821 IDWriteFactory *factory;
1822 DWRITE_TEXT_RANGE r;
1823 FLOAT size;
1824 HRESULT hr;
1826 factory = create_factory();
1828 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1829 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1830 ok(hr == S_OK, "got 0x%08x\n", hr);
1832 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1833 ok(hr == S_OK, "got 0x%08x\n", hr);
1835 r.startPosition = 1;
1836 r.length = 0;
1837 size = 0.0;
1838 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
1839 ok(hr == S_OK, "got 0x%08x\n", hr);
1840 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
1841 ok(size == 10.0, "got %.2f\n", size);
1843 r.startPosition = 1;
1844 r.length = 1;
1845 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
1846 ok(hr == S_OK, "got 0x%08x\n", hr);
1848 size = 0.0;
1849 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
1850 ok(hr == S_OK, "got 0x%08x\n", hr);
1851 ok(size == 15.0, "got %.2f\n", size);
1853 r.startPosition = 0;
1854 r.length = 4;
1855 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
1856 ok(hr == S_OK, "got 0x%08x\n", hr);
1858 size = 0.0;
1859 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
1860 ok(hr == S_OK, "got 0x%08x\n", hr);
1861 ok(size == 15.0, "got %.2f\n", size);
1863 size = 0.0;
1864 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
1865 ok(hr == S_OK, "got 0x%08x\n", hr);
1866 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
1867 ok(size == 15.0, "got %.2f\n", size);
1869 size = 15.0;
1870 r.startPosition = r.length = 0;
1871 hr = IDWriteTextLayout_GetFontSize(layout, 20, &size, &r);
1872 ok(hr == S_OK, "got 0x%08x\n", hr);
1873 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
1874 ok(size == 10.0, "got %.2f\n", size);
1876 r.startPosition = 100;
1877 r.length = 4;
1878 hr = IDWriteTextLayout_SetFontSize(layout, 25.0, r);
1879 ok(hr == S_OK, "got 0x%08x\n", hr);
1881 size = 15.0;
1882 r.startPosition = r.length = 0;
1883 hr = IDWriteTextLayout_GetFontSize(layout, 100, &size, &r);
1884 ok(hr == S_OK, "got 0x%08x\n", hr);
1885 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
1886 ok(size == 25.0, "got %.2f\n", size);
1888 IDWriteTextLayout_Release(layout);
1889 IDWriteTextFormat_Release(format);
1892 static void test_SetFontFamilyName(void)
1894 static const WCHAR arialW[] = {'A','r','i','a','l',0};
1895 static const WCHAR strW[] = {'a','b','c','d',0};
1896 IDWriteTextFormat *format;
1897 IDWriteTextLayout *layout;
1898 IDWriteFactory *factory;
1899 DWRITE_TEXT_RANGE r;
1900 WCHAR nameW[50];
1901 HRESULT hr;
1903 factory = create_factory();
1905 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1906 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1907 ok(hr == S_OK, "got 0x%08x\n", hr);
1909 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1910 ok(hr == S_OK, "got 0x%08x\n", hr);
1912 r.startPosition = 1;
1913 r.length = 0;
1914 nameW[0] = 0;
1915 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
1916 ok(hr == S_OK, "got 0x%08x\n", hr);
1917 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
1919 r.startPosition = 1;
1920 r.length = 1;
1921 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
1922 ok(hr == S_OK, "got 0x%08x\n", hr);
1924 r.startPosition = 1;
1925 r.length = 0;
1926 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
1927 ok(hr == S_OK, "got 0x%08x\n", hr);
1928 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
1930 r.startPosition = 0;
1931 r.length = 4;
1932 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
1933 ok(hr == S_OK, "got 0x%08x\n", hr);
1935 nameW[0] = 0;
1936 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
1937 ok(hr == S_OK, "got 0x%08x\n", hr);
1938 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
1939 ok(!lstrcmpW(nameW, arialW), "got name %s\n", wine_dbgstr_w(nameW));
1941 IDWriteTextLayout_Release(layout);
1942 IDWriteTextFormat_Release(format);
1945 static void test_SetFontStyle(void)
1947 static const WCHAR strW[] = {'a','b','c','d',0};
1948 IDWriteTextFormat *format;
1949 IDWriteTextLayout *layout;
1950 IDWriteFactory *factory;
1951 DWRITE_FONT_STYLE style;
1952 DWRITE_TEXT_RANGE r;
1953 HRESULT hr;
1955 factory = create_factory();
1957 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1958 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1959 ok(hr == S_OK, "got 0x%08x\n", hr);
1961 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1962 ok(hr == S_OK, "got 0x%08x\n", hr);
1964 r.startPosition = 1;
1965 r.length = 0;
1966 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
1967 ok(hr == S_OK, "got 0x%08x\n", hr);
1968 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
1969 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
1971 r.startPosition = 1;
1972 r.length = 1;
1973 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC, r);
1974 ok(hr == S_OK, "got 0x%08x\n", hr);
1976 style = DWRITE_FONT_STYLE_NORMAL;
1977 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
1978 ok(hr == S_OK, "got 0x%08x\n", hr);
1979 ok(style == DWRITE_FONT_STYLE_ITALIC, "got %d\n", style);
1981 r.startPosition = 0;
1982 r.length = 4;
1983 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
1984 ok(hr == S_OK, "got 0x%08x\n", hr);
1986 style = DWRITE_FONT_STYLE_ITALIC;
1987 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
1988 ok(hr == S_OK, "got 0x%08x\n", hr);
1989 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
1991 style = DWRITE_FONT_STYLE_ITALIC;
1992 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
1993 ok(hr == S_OK, "got 0x%08x\n", hr);
1994 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
1995 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
1997 style = DWRITE_FONT_STYLE_ITALIC;
1998 r.startPosition = r.length = 0;
1999 hr = IDWriteTextLayout_GetFontStyle(layout, 20, &style, &r);
2000 ok(hr == S_OK, "got 0x%08x\n", hr);
2001 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2002 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
2004 r.startPosition = 100;
2005 r.length = 4;
2006 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
2007 ok(hr == S_OK, "got 0x%08x\n", hr);
2009 style = DWRITE_FONT_STYLE_NORMAL;
2010 r.startPosition = r.length = 0;
2011 hr = IDWriteTextLayout_GetFontStyle(layout, 100, &style, &r);
2012 ok(hr == S_OK, "got 0x%08x\n", hr);
2013 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2014 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2016 IDWriteTextLayout_Release(layout);
2017 IDWriteTextFormat_Release(format);
2020 static void test_SetFontStretch(void)
2022 static const WCHAR strW[] = {'a','b','c','d',0};
2023 DWRITE_FONT_STRETCH stretch;
2024 IDWriteTextFormat *format;
2025 IDWriteTextLayout *layout;
2026 IDWriteFactory *factory;
2027 DWRITE_TEXT_RANGE r;
2028 HRESULT hr;
2030 factory = create_factory();
2032 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2033 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2034 ok(hr == S_OK, "got 0x%08x\n", hr);
2036 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2037 ok(hr == S_OK, "got 0x%08x\n", hr);
2039 r.startPosition = 1;
2040 r.length = 0;
2041 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2042 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
2043 ok(hr == S_OK, "got 0x%08x\n", hr);
2044 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2045 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
2047 r.startPosition = 1;
2048 r.length = 1;
2049 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_CONDENSED, r);
2050 ok(hr == S_OK, "got 0x%08x\n", hr);
2052 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2053 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
2054 ok(hr == S_OK, "got 0x%08x\n", hr);
2055 ok(stretch == DWRITE_FONT_STRETCH_CONDENSED, "got %d\n", stretch);
2057 r.startPosition = 0;
2058 r.length = 4;
2059 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
2060 ok(hr == S_OK, "got 0x%08x\n", hr);
2062 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2063 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
2064 ok(hr == S_OK, "got 0x%08x\n", hr);
2065 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
2067 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2068 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
2069 ok(hr == S_OK, "got 0x%08x\n", hr);
2070 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2071 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
2073 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2074 r.startPosition = r.length = 0;
2075 hr = IDWriteTextLayout_GetFontStretch(layout, 20, &stretch, &r);
2076 ok(hr == S_OK, "got 0x%08x\n", hr);
2077 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2078 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
2080 r.startPosition = 100;
2081 r.length = 4;
2082 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
2083 ok(hr == S_OK, "got 0x%08x\n", hr);
2085 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
2086 r.startPosition = r.length = 0;
2087 hr = IDWriteTextLayout_GetFontStretch(layout, 100, &stretch, &r);
2088 ok(hr == S_OK, "got 0x%08x\n", hr);
2089 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2090 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
2092 /* trying to set undefined value */
2093 r.startPosition = 0;
2094 r.length = 2;
2095 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_UNDEFINED, r);
2096 todo_wine
2097 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2099 IDWriteTextLayout_Release(layout);
2100 IDWriteTextFormat_Release(format);
2103 START_TEST(layout)
2105 static const WCHAR ctrlstrW[] = {0x202a,0};
2106 IDWriteFactory *factory;
2108 if (!(factory = create_factory())) {
2109 win_skip("failed to create factory\n");
2110 return;
2113 /* actual script ids are not fixed */
2114 get_script_analysis(ctrlstrW, 1, &g_control_sa);
2116 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
2117 init_call_sequences(expected_seq, 1);
2119 test_CreateTextLayout();
2120 test_CreateGdiCompatibleTextLayout();
2121 test_CreateTextFormat();
2122 test_GetLocaleName();
2123 test_CreateEllipsisTrimmingSign();
2124 test_fontweight();
2125 test_SetInlineObject();
2126 test_Draw();
2127 test_typography();
2128 test_GetClusterMetrics();
2129 test_SetLocaleName();
2130 test_SetPairKerning();
2131 test_SetVerticalGlyphOrientation();
2132 test_fallback();
2133 test_DetermineMinWidth();
2134 test_SetFontSize();
2135 test_SetFontFamilyName();
2136 test_SetFontStyle();
2137 test_SetFontStretch();
2139 IDWriteFactory_Release(factory);