dwrite: Don't use drawing effect for trimming signs.
[wine.git] / dlls / dwrite / tests / layout.c
blobc03d68405444dabac41b7c84e11b4cc2ff0db3dc
1 /*
2 * Text layout/format tests
4 * Copyright 2012, 2014-2017 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_3.h"
30 #include "wine/test.h"
32 static const WCHAR tahomaW[] = {'T','a','h','o','m','a',0};
33 static const WCHAR enusW[] = {'e','n','-','u','s',0};
35 struct testanalysissink
37 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
38 DWRITE_SCRIPT_ANALYSIS sa; /* last analysis, with SetScriptAnalysis() */
41 static inline struct testanalysissink *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
43 return CONTAINING_RECORD(iface, struct testanalysissink, IDWriteTextAnalysisSink_iface);
46 /* test IDWriteTextAnalysisSink */
47 static HRESULT WINAPI analysissink_QueryInterface(IDWriteTextAnalysisSink *iface, REFIID riid, void **obj)
49 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown))
51 *obj = iface;
52 return S_OK;
55 *obj = NULL;
56 return E_NOINTERFACE;
59 static ULONG WINAPI analysissink_AddRef(IDWriteTextAnalysisSink *iface)
61 return 2;
64 static ULONG WINAPI analysissink_Release(IDWriteTextAnalysisSink *iface)
66 return 1;
69 static HRESULT WINAPI analysissink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
70 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
72 struct testanalysissink *sink = impl_from_IDWriteTextAnalysisSink(iface);
73 sink->sa = *sa;
74 return S_OK;
77 static HRESULT WINAPI analysissink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
78 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
80 ok(0, "unexpected call\n");
81 return E_NOTIMPL;
84 static HRESULT WINAPI analysissink_SetBidiLevel(IDWriteTextAnalysisSink *iface,
85 UINT32 position, UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
87 ok(0, "unexpected\n");
88 return E_NOTIMPL;
91 static HRESULT WINAPI analysissink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
92 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
94 ok(0, "unexpected\n");
95 return E_NOTIMPL;
98 static IDWriteTextAnalysisSinkVtbl analysissinkvtbl = {
99 analysissink_QueryInterface,
100 analysissink_AddRef,
101 analysissink_Release,
102 analysissink_SetScriptAnalysis,
103 analysissink_SetLineBreakpoints,
104 analysissink_SetBidiLevel,
105 analysissink_SetNumberSubstitution
108 static struct testanalysissink analysissink = {
109 { &analysissinkvtbl },
110 { 0 }
113 /* test IDWriteTextAnalysisSource */
114 static HRESULT WINAPI analysissource_QueryInterface(IDWriteTextAnalysisSource *iface,
115 REFIID riid, void **obj)
117 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) || IsEqualIID(riid, &IID_IUnknown)) {
118 *obj = iface;
119 IDWriteTextAnalysisSource_AddRef(iface);
120 return S_OK;
122 return E_NOINTERFACE;
125 static ULONG WINAPI analysissource_AddRef(IDWriteTextAnalysisSource *iface)
127 return 2;
130 static ULONG WINAPI analysissource_Release(IDWriteTextAnalysisSource *iface)
132 return 1;
135 static const WCHAR *g_source;
137 static HRESULT WINAPI analysissource_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
138 UINT32 position, WCHAR const** text, UINT32* text_len)
140 if (position >= lstrlenW(g_source))
142 *text = NULL;
143 *text_len = 0;
145 else
147 *text = &g_source[position];
148 *text_len = lstrlenW(g_source) - position;
151 return S_OK;
154 static HRESULT WINAPI analysissource_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
155 UINT32 position, WCHAR const** text, UINT32* text_len)
157 ok(0, "unexpected\n");
158 return E_NOTIMPL;
161 static DWRITE_READING_DIRECTION WINAPI analysissource_GetParagraphReadingDirection(
162 IDWriteTextAnalysisSource *iface)
164 ok(0, "unexpected\n");
165 return DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
168 static HRESULT WINAPI analysissource_GetLocaleName(IDWriteTextAnalysisSource *iface,
169 UINT32 position, UINT32* text_len, WCHAR const** locale)
171 *locale = NULL;
172 *text_len = 0;
173 return S_OK;
176 static HRESULT WINAPI analysissource_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
177 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
179 ok(0, "unexpected\n");
180 return E_NOTIMPL;
183 static IDWriteTextAnalysisSourceVtbl analysissourcevtbl = {
184 analysissource_QueryInterface,
185 analysissource_AddRef,
186 analysissource_Release,
187 analysissource_GetTextAtPosition,
188 analysissource_GetTextBeforePosition,
189 analysissource_GetParagraphReadingDirection,
190 analysissource_GetLocaleName,
191 analysissource_GetNumberSubstitution
194 static IDWriteTextAnalysisSource analysissource = { &analysissourcevtbl };
196 static IDWriteFactory *create_factory(void)
198 IDWriteFactory *factory;
199 HRESULT hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory);
200 ok(hr == S_OK, "got 0x%08x\n", hr);
201 return factory;
204 /* obvious limitation is that only last script data is returned, so this
205 helper is suitable for single script strings only */
206 static void get_script_analysis(const WCHAR *str, UINT32 len, DWRITE_SCRIPT_ANALYSIS *sa)
208 IDWriteTextAnalyzer *analyzer;
209 IDWriteFactory *factory;
210 HRESULT hr;
212 g_source = str;
214 factory = create_factory();
215 hr = IDWriteFactory_CreateTextAnalyzer(factory, &analyzer);
216 ok(hr == S_OK, "got 0x%08x\n", hr);
218 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &analysissource, 0, len, &analysissink.IDWriteTextAnalysisSink_iface);
219 ok(hr == S_OK, "got 0x%08x\n", hr);
221 *sa = analysissink.sa;
222 IDWriteFactory_Release(factory);
225 static IDWriteFontFace *get_fontface_from_format(IDWriteTextFormat *format)
227 IDWriteFontCollection *collection;
228 IDWriteFontFamily *family;
229 IDWriteFontFace *fontface;
230 IDWriteFont *font;
231 WCHAR nameW[255];
232 UINT32 index;
233 BOOL exists;
234 HRESULT hr;
236 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
237 ok(hr == S_OK, "got 0x%08x\n", hr);
239 hr = IDWriteTextFormat_GetFontFamilyName(format, nameW, sizeof(nameW)/sizeof(WCHAR));
240 ok(hr == S_OK, "got 0x%08x\n", hr);
242 hr = IDWriteFontCollection_FindFamilyName(collection, nameW, &index, &exists);
243 ok(hr == S_OK, "got 0x%08x\n", hr);
245 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
246 ok(hr == S_OK, "got 0x%08x\n", hr);
247 IDWriteFontCollection_Release(collection);
249 hr = IDWriteFontFamily_GetFirstMatchingFont(family,
250 IDWriteTextFormat_GetFontWeight(format),
251 IDWriteTextFormat_GetFontStretch(format),
252 IDWriteTextFormat_GetFontStyle(format),
253 &font);
254 ok(hr == S_OK, "got 0x%08x\n", hr);
256 hr = IDWriteFont_CreateFontFace(font, &fontface);
257 ok(hr == S_OK, "got 0x%08x\n", hr);
259 IDWriteFont_Release(font);
260 IDWriteFontFamily_Release(family);
262 return fontface;
265 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
266 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
268 ULONG rc;
269 IUnknown_AddRef(obj);
270 rc = IUnknown_Release(obj);
271 ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
274 enum drawcall_modifiers_kind {
275 DRAW_EFFECT = 0x1000
278 enum drawcall_kind {
279 DRAW_GLYPHRUN = 0,
280 DRAW_UNDERLINE = 1,
281 DRAW_STRIKETHROUGH = 2,
282 DRAW_INLINE = 3,
283 DRAW_LAST_KIND = 4,
284 DRAW_TOTAL_KINDS = 5,
285 DRAW_KINDS_MASK = 0xff
288 static const char *get_draw_kind_name(unsigned short kind)
290 static const char *kind_names[] = {
291 "GLYPH_RUN",
292 "UNDERLINE",
293 "STRIKETHROUGH",
294 "INLINE",
295 "END_OF_SEQ",
297 "GLYPH_RUN|EFFECT",
298 "UNDERLINE|EFFECT",
299 "STRIKETHROUGH|EFFECT",
300 "INLINE|EFFECT",
301 "END_OF_SEQ"
303 if ((kind & DRAW_KINDS_MASK) > DRAW_LAST_KIND)
304 return "unknown";
305 return (kind & DRAW_EFFECT) ? kind_names[(kind & DRAW_KINDS_MASK) + DRAW_TOTAL_KINDS] :
306 kind_names[kind];
309 struct drawcall_entry {
310 enum drawcall_kind kind;
311 WCHAR string[10]; /* only meaningful for DrawGlyphRun() */
312 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
313 UINT32 glyphcount; /* only meaningful for DrawGlyphRun() */
316 struct drawcall_sequence
318 int count;
319 int size;
320 struct drawcall_entry *sequence;
323 struct drawtestcontext {
324 unsigned short kind;
325 BOOL todo;
326 int *failcount;
327 const char *file;
328 int line;
331 #define NUM_CALL_SEQUENCES 1
332 #define RENDERER_ID 0
333 static struct drawcall_sequence *sequences[NUM_CALL_SEQUENCES];
334 static struct drawcall_sequence *expected_seq[1];
336 static void add_call(struct drawcall_sequence **seq, int sequence_index, const struct drawcall_entry *call)
338 struct drawcall_sequence *call_seq = seq[sequence_index];
340 if (!call_seq->sequence) {
341 call_seq->size = 10;
342 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0, call_seq->size * sizeof (struct drawcall_entry));
345 if (call_seq->count == call_seq->size) {
346 call_seq->size *= 2;
347 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
348 call_seq->sequence,
349 call_seq->size * sizeof (struct drawcall_entry));
352 assert(call_seq->sequence);
353 call_seq->sequence[call_seq->count++] = *call;
356 static inline void flush_sequence(struct drawcall_sequence **seg, int sequence_index)
358 struct drawcall_sequence *call_seq = seg[sequence_index];
360 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
361 call_seq->sequence = NULL;
362 call_seq->count = call_seq->size = 0;
365 static void init_call_sequences(struct drawcall_sequence **seq, int n)
367 int i;
369 for (i = 0; i < n; i++)
370 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct drawcall_sequence));
373 static void ok_sequence_(struct drawcall_sequence **seq, int sequence_index,
374 const struct drawcall_entry *expected, const char *context, BOOL todo,
375 const char *file, int line)
377 static const struct drawcall_entry end_of_sequence = { DRAW_LAST_KIND };
378 struct drawcall_sequence *call_seq = seq[sequence_index];
379 const struct drawcall_entry *actual, *sequence;
380 int failcount = 0;
382 add_call(seq, sequence_index, &end_of_sequence);
384 sequence = call_seq->sequence;
385 actual = sequence;
387 while (expected->kind != DRAW_LAST_KIND && actual->kind != DRAW_LAST_KIND) {
388 if (expected->kind != actual->kind) {
389 if (todo) {
390 failcount++;
391 todo_wine
392 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
393 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
395 flush_sequence(seq, sequence_index);
396 return;
398 else
399 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
400 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
402 else if ((expected->kind & DRAW_KINDS_MASK) == DRAW_GLYPHRUN) {
403 int cmp = lstrcmpW(expected->string, actual->string);
404 if (cmp != 0 && todo) {
405 failcount++;
406 todo_wine
407 ok_(file, line) (0, "%s: glyphrun string %s was expected, but got %s instead\n",
408 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
410 else
411 ok_(file, line) (cmp == 0, "%s: glyphrun string %s was expected, but got %s instead\n",
412 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
414 cmp = lstrcmpW(expected->locale, actual->locale);
415 if (cmp != 0 && todo) {
416 failcount++;
417 todo_wine
418 ok_(file, line) (0, "%s: glyph run locale %s was expected, but got %s instead\n",
419 context, wine_dbgstr_w(expected->locale), wine_dbgstr_w(actual->locale));
421 else
422 ok_(file, line) (cmp == 0, "%s: glyph run locale %s was expected, but got %s instead\n",
423 context, wine_dbgstr_w(expected->locale), wine_dbgstr_w(actual->locale));
425 if (expected->glyphcount != actual->glyphcount && todo) {
426 failcount++;
427 todo_wine
428 ok_(file, line) (0, "%s: wrong glyph count, %u was expected, but got %u instead\n",
429 context, expected->glyphcount, actual->glyphcount);
431 else
432 ok_(file, line) (expected->glyphcount == actual->glyphcount,
433 "%s: wrong glyph count, %u was expected, but got %u instead\n",
434 context, expected->glyphcount, actual->glyphcount);
436 else if ((expected->kind & DRAW_KINDS_MASK) == DRAW_UNDERLINE) {
437 int cmp = lstrcmpW(expected->locale, actual->locale);
438 if (cmp != 0 && todo) {
439 failcount++;
440 todo_wine
441 ok_(file, line) (0, "%s: underline locale %s was expected, but got %s instead\n",
442 context, wine_dbgstr_w(expected->locale), wine_dbgstr_w(actual->locale));
444 else
445 ok_(file, line) (cmp == 0, "%s: underline locale %s was expected, but got %s instead\n",
446 context, wine_dbgstr_w(expected->locale), wine_dbgstr_w(actual->locale));
448 expected++;
449 actual++;
452 if (todo) {
453 todo_wine {
454 if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND) {
455 failcount++;
456 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
457 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
461 else if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND)
462 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
463 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
465 if (todo && !failcount) /* succeeded yet marked todo */
466 todo_wine
467 ok_(file, line)(1, "%s: marked \"todo_wine\" but succeeds\n", context);
469 flush_sequence(seq, sequence_index);
472 #define ok_sequence(seq, index, exp, contx, todo) \
473 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
475 static HRESULT WINAPI testrenderer_QI(IDWriteTextRenderer *iface, REFIID riid, void **obj)
477 if (IsEqualIID(riid, &IID_IDWriteTextRenderer) ||
478 IsEqualIID(riid, &IID_IDWritePixelSnapping) ||
479 IsEqualIID(riid, &IID_IUnknown)
481 *obj = iface;
482 return S_OK;
485 *obj = NULL;
487 /* IDWriteTextRenderer1 overrides drawing calls, ignore for now */
488 if (IsEqualIID(riid, &IID_IDWriteTextRenderer1))
489 return E_NOINTERFACE;
491 ok(0, "unexpected QI %s\n", wine_dbgstr_guid(riid));
492 return E_NOINTERFACE;
495 static ULONG WINAPI testrenderer_AddRef(IDWriteTextRenderer *iface)
497 return 2;
500 static ULONG WINAPI testrenderer_Release(IDWriteTextRenderer *iface)
502 return 1;
505 struct renderer_context {
506 BOOL gdicompat;
507 BOOL use_gdi_natural;
508 BOOL snapping_disabled;
509 DWRITE_MATRIX m;
510 FLOAT ppdip;
511 FLOAT originX;
512 FLOAT originY;
513 IDWriteTextFormat *format;
514 const WCHAR *familyW;
517 static HRESULT WINAPI testrenderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
518 void *context, BOOL *disabled)
520 struct renderer_context *ctxt = (struct renderer_context*)context;
521 if (ctxt)
522 *disabled = ctxt->snapping_disabled;
523 else
524 *disabled = TRUE;
525 return S_OK;
528 static HRESULT WINAPI testrenderer_GetCurrentTransform(IDWriteTextRenderer *iface,
529 void *context, DWRITE_MATRIX *m)
531 struct renderer_context *ctxt = (struct renderer_context*)context;
532 ok(!ctxt->snapping_disabled, "expected enabled snapping\n");
533 *m = ctxt->m;
534 return S_OK;
537 static HRESULT WINAPI testrenderer_GetPixelsPerDip(IDWriteTextRenderer *iface,
538 void *context, FLOAT *pixels_per_dip)
540 struct renderer_context *ctxt = (struct renderer_context*)context;
541 *pixels_per_dip = ctxt->ppdip;
542 return S_OK;
545 #define TEST_MEASURING_MODE(ctxt, mode) test_measuring_mode(ctxt, mode, __LINE__)
546 static void test_measuring_mode(const struct renderer_context *ctxt, DWRITE_MEASURING_MODE mode, int line)
548 if (ctxt->gdicompat) {
549 if (ctxt->use_gdi_natural)
550 ok_(__FILE__, line)(mode == DWRITE_MEASURING_MODE_GDI_NATURAL, "got %d\n", mode);
551 else
552 ok_(__FILE__, line)(mode == DWRITE_MEASURING_MODE_GDI_CLASSIC, "got %d\n", mode);
554 else
555 ok_(__FILE__, line)(mode == DWRITE_MEASURING_MODE_NATURAL, "got %d\n", mode);
558 static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface,
559 void *context,
560 FLOAT baselineOriginX,
561 FLOAT baselineOriginY,
562 DWRITE_MEASURING_MODE mode,
563 DWRITE_GLYPH_RUN const *run,
564 DWRITE_GLYPH_RUN_DESCRIPTION const *descr,
565 IUnknown *effect)
567 struct renderer_context *ctxt = (struct renderer_context*)context;
568 struct drawcall_entry entry;
569 DWRITE_SCRIPT_ANALYSIS sa;
571 if (ctxt) {
572 TEST_MEASURING_MODE(ctxt, mode);
573 ctxt->originX = baselineOriginX;
574 ctxt->originY = baselineOriginY;
577 ok(descr->stringLength < sizeof(entry.string)/sizeof(WCHAR), "string is too long\n");
578 if (descr->stringLength && descr->stringLength < sizeof(entry.string)/sizeof(WCHAR)) {
579 memcpy(entry.string, descr->string, descr->stringLength*sizeof(WCHAR));
580 entry.string[descr->stringLength] = 0;
582 else
583 entry.string[0] = 0;
585 /* see what's reported for control codes runs */
586 get_script_analysis(descr->string, descr->stringLength, &sa);
587 if (sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
588 UINT32 i;
590 /* glyphs are not reported at all for control code runs */
591 ok(run->glyphCount == 0, "got %u\n", run->glyphCount);
592 ok(run->glyphAdvances != NULL, "advances array %p\n", run->glyphAdvances);
593 ok(run->glyphOffsets != NULL, "offsets array %p\n", run->glyphOffsets);
594 ok(run->fontFace != NULL, "got %p\n", run->fontFace);
595 /* text positions are still valid */
596 ok(descr->string != NULL, "got string %p\n", descr->string);
597 ok(descr->stringLength > 0, "got string length %u\n", descr->stringLength);
598 ok(descr->clusterMap != NULL, "clustermap %p\n", descr->clusterMap);
599 for (i = 0; i < descr->stringLength; i++)
600 ok(descr->clusterMap[i] == i, "got %u\n", descr->clusterMap[i]);
603 entry.kind = DRAW_GLYPHRUN;
604 if (effect)
605 entry.kind |= DRAW_EFFECT;
606 ok(lstrlenW(descr->localeName) < LOCALE_NAME_MAX_LENGTH, "unexpectedly long locale name\n");
607 lstrcpyW(entry.locale, descr->localeName);
608 entry.glyphcount = run->glyphCount;
609 add_call(sequences, RENDERER_ID, &entry);
610 return S_OK;
613 static HRESULT WINAPI testrenderer_DrawUnderline(IDWriteTextRenderer *iface,
614 void *context,
615 FLOAT baselineOriginX,
616 FLOAT baselineOriginY,
617 DWRITE_UNDERLINE const* underline,
618 IUnknown *effect)
620 struct renderer_context *ctxt = (struct renderer_context*)context;
621 struct drawcall_entry entry = { 0 };
623 if (ctxt)
624 TEST_MEASURING_MODE(ctxt, underline->measuringMode);
626 ok(underline->runHeight > 0.0f, "Expected non-zero run height\n");
627 if (ctxt && ctxt->format) {
628 DWRITE_FONT_METRICS metrics;
629 IDWriteFontFace *fontface;
630 FLOAT emsize;
632 fontface = get_fontface_from_format(ctxt->format);
633 emsize = IDWriteTextFormat_GetFontSize(ctxt->format);
634 IDWriteFontFace_GetMetrics(fontface, &metrics);
636 ok(emsize == metrics.designUnitsPerEm, "Unexpected font size %f\n", emsize);
637 /* Expected height is in design units, allow some absolute difference from it. Seems to only happen on Vista */
638 ok(abs(metrics.capHeight - underline->runHeight) < 2.0f, "Expected runHeight %u, got %f, family %s\n",
639 metrics.capHeight, underline->runHeight, wine_dbgstr_w(ctxt->familyW));
641 IDWriteFontFace_Release(fontface);
644 entry.kind = DRAW_UNDERLINE;
645 if (effect)
646 entry.kind |= DRAW_EFFECT;
647 lstrcpyW(entry.locale, underline->localeName);
648 add_call(sequences, RENDERER_ID, &entry);
649 return S_OK;
652 static HRESULT WINAPI testrenderer_DrawStrikethrough(IDWriteTextRenderer *iface,
653 void *context,
654 FLOAT baselineOriginX,
655 FLOAT baselineOriginY,
656 DWRITE_STRIKETHROUGH const* strikethrough,
657 IUnknown *effect)
659 struct renderer_context *ctxt = (struct renderer_context*)context;
660 struct drawcall_entry entry = { 0 };
662 if (ctxt)
663 TEST_MEASURING_MODE(ctxt, strikethrough->measuringMode);
665 entry.kind = DRAW_STRIKETHROUGH;
666 if (effect)
667 entry.kind |= DRAW_EFFECT;
668 add_call(sequences, RENDERER_ID, &entry);
669 return S_OK;
672 static HRESULT WINAPI testrenderer_DrawInlineObject(IDWriteTextRenderer *iface,
673 void *context,
674 FLOAT originX,
675 FLOAT originY,
676 IDWriteInlineObject *object,
677 BOOL is_sideways,
678 BOOL is_rtl,
679 IUnknown *effect)
681 struct drawcall_entry entry = { 0 };
682 entry.kind = DRAW_INLINE;
683 if (effect)
684 entry.kind |= DRAW_EFFECT;
685 add_call(sequences, RENDERER_ID, &entry);
686 return S_OK;
689 static const IDWriteTextRendererVtbl testrenderervtbl = {
690 testrenderer_QI,
691 testrenderer_AddRef,
692 testrenderer_Release,
693 testrenderer_IsPixelSnappingDisabled,
694 testrenderer_GetCurrentTransform,
695 testrenderer_GetPixelsPerDip,
696 testrenderer_DrawGlyphRun,
697 testrenderer_DrawUnderline,
698 testrenderer_DrawStrikethrough,
699 testrenderer_DrawInlineObject
702 static IDWriteTextRenderer testrenderer = { &testrenderervtbl };
704 /* test IDWriteInlineObject */
705 static HRESULT WINAPI testinlineobj_QI(IDWriteInlineObject *iface, REFIID riid, void **obj)
707 if (IsEqualIID(riid, &IID_IDWriteInlineObject) || IsEqualIID(riid, &IID_IUnknown)) {
708 *obj = iface;
709 IDWriteInlineObject_AddRef(iface);
710 return S_OK;
713 *obj = NULL;
714 return E_NOINTERFACE;
717 static ULONG WINAPI testinlineobj_AddRef(IDWriteInlineObject *iface)
719 return 2;
722 static ULONG WINAPI testinlineobj_Release(IDWriteInlineObject *iface)
724 return 1;
727 static HRESULT WINAPI testinlineobj_Draw(IDWriteInlineObject *iface,
728 void* client_drawingontext, IDWriteTextRenderer* renderer,
729 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *drawing_effect)
731 ok(0, "unexpected call\n");
732 return E_NOTIMPL;
735 static HRESULT WINAPI testinlineobj_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
737 metrics->width = 123.0;
738 return 0x8faecafe;
741 static HRESULT WINAPI testinlineobj_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
743 ok(0, "unexpected call\n");
744 return E_NOTIMPL;
747 static HRESULT WINAPI testinlineobj_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
748 DWRITE_BREAK_CONDITION *after)
750 *before = *after = DWRITE_BREAK_CONDITION_MUST_BREAK;
751 return 0x8feacafe;
754 static HRESULT WINAPI testinlineobj2_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
755 DWRITE_BREAK_CONDITION *after)
757 *before = *after = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
758 return S_OK;
761 static IDWriteInlineObjectVtbl testinlineobjvtbl = {
762 testinlineobj_QI,
763 testinlineobj_AddRef,
764 testinlineobj_Release,
765 testinlineobj_Draw,
766 testinlineobj_GetMetrics,
767 testinlineobj_GetOverhangMetrics,
768 testinlineobj_GetBreakConditions
771 static IDWriteInlineObjectVtbl testinlineobjvtbl2 = {
772 testinlineobj_QI,
773 testinlineobj_AddRef,
774 testinlineobj_Release,
775 testinlineobj_Draw,
776 testinlineobj_GetMetrics,
777 testinlineobj_GetOverhangMetrics,
778 testinlineobj2_GetBreakConditions
781 static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl };
782 static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
783 static IDWriteInlineObject testinlineobj3 = { &testinlineobjvtbl2 };
785 struct test_effect
787 IUnknown IUnknown_iface;
788 LONG ref;
791 static inline struct test_effect *test_effect_from_IUnknown(IUnknown *iface)
793 return CONTAINING_RECORD(iface, struct test_effect, IUnknown_iface);
796 static HRESULT WINAPI testeffect_QI(IUnknown *iface, REFIID riid, void **obj)
798 if (IsEqualIID(riid, &IID_IUnknown)) {
799 *obj = iface;
800 IUnknown_AddRef(iface);
801 return S_OK;
804 ok(0, "Unexpected riid %s.\n", wine_dbgstr_guid(riid));
805 *obj = NULL;
806 return E_NOINTERFACE;
809 static ULONG WINAPI testeffect_AddRef(IUnknown *iface)
811 struct test_effect *effect = test_effect_from_IUnknown(iface);
812 return InterlockedIncrement(&effect->ref);
815 static ULONG WINAPI testeffect_Release(IUnknown *iface)
817 struct test_effect *effect = test_effect_from_IUnknown(iface);
818 LONG ref = InterlockedDecrement(&effect->ref);
820 if (!ref)
821 HeapFree(GetProcessHeap(), 0, effect);
823 return ref;
826 static const IUnknownVtbl testeffectvtbl = {
827 testeffect_QI,
828 testeffect_AddRef,
829 testeffect_Release
832 static IUnknown *create_test_effect(void)
834 struct test_effect *effect;
836 effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*effect));
837 effect->IUnknown_iface.lpVtbl = &testeffectvtbl;
838 effect->ref = 1;
840 return &effect->IUnknown_iface;
843 static void test_CreateTextLayout(void)
845 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
846 IDWriteTextLayout2 *layout2;
847 IDWriteTextLayout *layout;
848 IDWriteTextFormat *format;
849 IDWriteFactory *factory;
850 HRESULT hr;
852 factory = create_factory();
854 layout = (void*)0xdeadbeef;
855 hr = IDWriteFactory_CreateTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, &layout);
856 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
857 ok(layout == NULL, "got %p\n", layout);
859 layout = (void*)0xdeadbeef;
860 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 0.0, &layout);
861 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
862 ok(layout == NULL, "got %p\n", layout);
864 layout = (void*)0xdeadbeef;
865 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1.0, 0.0, &layout);
866 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
867 ok(layout == NULL, "got %p\n", layout);
869 layout = (void*)0xdeadbeef;
870 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 0.0, 1.0, &layout);
871 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
872 ok(layout == NULL, "got %p\n", layout);
874 layout = (void*)0xdeadbeef;
875 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, &layout);
876 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
877 ok(layout == NULL, "got %p\n", layout);
879 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
880 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
881 ok(hr == S_OK, "got 0x%08x\n", hr);
883 layout = (void*)0xdeadbeef;
884 hr = IDWriteFactory_CreateTextLayout(factory, NULL, 0, format, 100.0f, 100.0f, &layout);
885 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
886 ok(layout == NULL, "got %p\n", layout);
888 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 0.0f, 0.0f, &layout);
889 ok(hr == S_OK, "got 0x%08x\n", hr);
890 IDWriteTextLayout_Release(layout);
892 EXPECT_REF(format, 1);
893 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 1000.0, 1000.0, &layout);
894 ok(hr == S_OK, "got 0x%08x\n", hr);
895 EXPECT_REF(format, 1);
897 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
898 if (hr == S_OK) {
899 IDWriteTextLayout1 *layout1;
900 IDWriteTextFormat1 *format1;
901 IDWriteTextFormat *format;
903 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextLayout1, (void**)&layout1);
904 ok(hr == S_OK, "got 0x%08x\n", hr);
905 IDWriteTextLayout1_Release(layout1);
907 EXPECT_REF(layout2, 2);
908 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
909 ok(hr == S_OK, "got 0x%08x\n", hr);
910 EXPECT_REF(layout2, 3);
912 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat, (void**)&format);
913 ok(hr == S_OK, "got 0x%08x\n", hr);
914 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
915 ok(format != (IDWriteTextFormat*)layout2, "got %p, %p\n", format, layout2);
916 EXPECT_REF(layout2, 4);
918 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextLayout1, (void**)&layout1);
919 ok(hr == S_OK, "got 0x%08x\n", hr);
920 IDWriteTextLayout1_Release(layout1);
922 IDWriteTextFormat1_Release(format1);
923 IDWriteTextFormat_Release(format);
925 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
926 ok(hr == S_OK, "got 0x%08x\n", hr);
927 EXPECT_REF(layout2, 3);
929 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format);
930 ok(hr == S_OK, "got 0x%08x\n", hr);
931 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
932 EXPECT_REF(layout2, 4);
934 IDWriteTextFormat1_Release(format1);
935 IDWriteTextFormat_Release(format);
936 IDWriteTextLayout2_Release(layout2);
938 else
939 win_skip("IDWriteTextLayout2 is not supported.\n");
941 IDWriteTextLayout_Release(layout);
942 IDWriteTextFormat_Release(format);
943 IDWriteFactory_Release(factory);
946 static DWRITE_MATRIX layoutcreate_transforms[] = {
947 { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
948 { 1.0, 0.0, 0.0, 1.0, 0.3, 0.2 },
949 { 1.0, 0.0, 0.0, 1.0,-0.3,-0.2 },
951 { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
952 { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
953 { 1.0, 2.0, 0.5, 1.0, 0.0, 0.0 },
956 static void test_CreateGdiCompatibleTextLayout(void)
958 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
959 IDWriteTextLayout *layout;
960 IDWriteTextFormat *format;
961 IDWriteFactory *factory;
962 FLOAT dimension;
963 HRESULT hr;
964 int i;
966 factory = create_factory();
968 layout = (void*)0xdeadbeef;
969 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, NULL, 0, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
970 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
971 ok(layout == NULL, "got %p\n", layout);
973 layout = (void*)0xdeadbeef;
974 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 0.0, 0.0, 0.0, NULL, FALSE, &layout);
975 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
976 ok(layout == NULL, "got %p\n", layout);
978 layout = (void*)0xdeadbeef;
979 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 0.0, NULL, FALSE, &layout);
980 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
981 ok(layout == NULL, "got %p\n", layout);
983 layout = (void*)0xdeadbeef;
984 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1.0, 0.0, 1.0, NULL, FALSE, &layout);
985 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
986 ok(layout == NULL, "got %p\n", layout);
988 layout = (void*)0xdeadbeef;
989 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, NULL, 1000.0, 1000.0, 1.0, NULL, FALSE, &layout);
990 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
991 ok(layout == NULL, "got %p\n", layout);
993 /* create with text format */
994 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
995 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
996 ok(hr == S_OK, "got 0x%08x\n", hr);
997 EXPECT_REF(format, 1);
999 layout = (void*)0xdeadbeef;
1000 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, NULL, 0, format, 100.0f, 100.0f, 1.0f, NULL, FALSE, &layout);
1001 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1002 ok(layout == NULL, "got %p\n", layout);
1004 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1005 ok(hr == S_OK, "got 0x%08x\n", hr);
1006 EXPECT_REF(format, 1);
1007 EXPECT_REF(layout, 1);
1009 IDWriteTextLayout_AddRef(layout);
1010 EXPECT_REF(format, 1);
1011 EXPECT_REF(layout, 2);
1012 IDWriteTextLayout_Release(layout);
1013 IDWriteTextLayout_Release(layout);
1015 /* zero length string is okay */
1016 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1017 ok(hr == S_OK, "got 0x%08x\n", hr);
1019 dimension = IDWriteTextLayout_GetMaxWidth(layout);
1020 ok(dimension == 100.0, "got %f\n", dimension);
1022 dimension = IDWriteTextLayout_GetMaxHeight(layout);
1023 ok(dimension == 100.0, "got %f\n", dimension);
1025 IDWriteTextLayout_Release(layout);
1027 /* negative, zero ppdip */
1028 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 1, format, 100.0, 100.0, -1.0, NULL, FALSE, &layout);
1029 ok(hr == S_OK, "got 0x%08x\n", hr);
1030 IDWriteTextLayout_Release(layout);
1032 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 1, format, 100.0, 100.0, 0.0, NULL, FALSE, &layout);
1033 ok(hr == S_OK, "got 0x%08x\n", hr);
1034 IDWriteTextLayout_Release(layout);
1036 /* transforms */
1037 for (i = 0; i < sizeof(layoutcreate_transforms)/sizeof(layoutcreate_transforms[0]); i++) {
1038 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 1, format, 100.0, 100.0, 1.0,
1039 &layoutcreate_transforms[i], FALSE, &layout);
1040 ok(hr == S_OK, "got 0x%08x\n", hr);
1041 IDWriteTextLayout_Release(layout);
1044 IDWriteTextFormat_Release(format);
1045 IDWriteFactory_Release(factory);
1048 static void test_CreateTextFormat(void)
1050 static const WCHAR emptyW[] = {0};
1051 IDWriteFontCollection *collection, *syscoll;
1052 DWRITE_PARAGRAPH_ALIGNMENT paralign;
1053 DWRITE_READING_DIRECTION readdir;
1054 DWRITE_WORD_WRAPPING wrapping;
1055 DWRITE_TEXT_ALIGNMENT align;
1056 DWRITE_FLOW_DIRECTION flow;
1057 DWRITE_LINE_SPACING_METHOD method;
1058 DWRITE_TRIMMING trimming;
1059 IDWriteTextFormat *format;
1060 FLOAT spacing, baseline;
1061 IDWriteInlineObject *trimmingsign;
1062 IDWriteFactory *factory;
1063 HRESULT hr;
1065 factory = create_factory();
1067 /* zero/negative font size */
1068 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1069 DWRITE_FONT_STRETCH_NORMAL, 0.0f, enusW, &format);
1070 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1072 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1073 DWRITE_FONT_STRETCH_NORMAL, -10.0f, enusW, &format);
1074 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1076 /* invalid font properties */
1077 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, 1000, DWRITE_FONT_STYLE_NORMAL,
1078 DWRITE_FONT_STRETCH_NORMAL, 10.0f, enusW, &format);
1079 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1081 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_ITALIC + 1,
1082 DWRITE_FONT_STRETCH_NORMAL, 10.0f, enusW, &format);
1083 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1085 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_ITALIC,
1086 10, 10.0f, enusW, &format);
1087 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1089 /* empty family name */
1090 hr = IDWriteFactory_CreateTextFormat(factory, emptyW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1091 DWRITE_FONT_STRETCH_NORMAL, 10.0f, enusW, &format);
1092 ok(hr == S_OK, "got 0x%08x\n", hr);
1093 IDWriteTextFormat_Release(format);
1095 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1096 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1097 ok(hr == S_OK, "got 0x%08x\n", hr);
1099 if (0) /* crashes on native */
1100 hr = IDWriteTextFormat_GetFontCollection(format, NULL);
1102 collection = NULL;
1103 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
1104 ok(hr == S_OK, "got 0x%08x\n", hr);
1105 ok(collection != NULL, "got %p\n", collection);
1107 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1108 ok(hr == S_OK, "got 0x%08x\n", hr);
1109 ok(collection == syscoll, "got %p, was %p\n", syscoll, collection);
1110 IDWriteFontCollection_Release(syscoll);
1111 IDWriteFontCollection_Release(collection);
1113 /* default format properties */
1114 align = IDWriteTextFormat_GetTextAlignment(format);
1115 ok(align == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", align);
1117 paralign = IDWriteTextFormat_GetParagraphAlignment(format);
1118 ok(paralign == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", paralign);
1120 wrapping = IDWriteTextFormat_GetWordWrapping(format);
1121 ok(wrapping == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", wrapping);
1123 readdir = IDWriteTextFormat_GetReadingDirection(format);
1124 ok(readdir == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", readdir);
1126 flow = IDWriteTextFormat_GetFlowDirection(format);
1127 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
1129 hr = IDWriteTextFormat_GetLineSpacing(format, &method, &spacing, &baseline);
1130 ok(hr == S_OK, "got 0x%08x\n", hr);
1131 ok(spacing == 0.0, "got %f\n", spacing);
1132 ok(baseline == 0.0, "got %f\n", baseline);
1133 ok(method == DWRITE_LINE_SPACING_METHOD_DEFAULT, "got %d\n", method);
1135 trimming.granularity = DWRITE_TRIMMING_GRANULARITY_WORD;
1136 trimming.delimiter = 10;
1137 trimming.delimiterCount = 10;
1138 trimmingsign = (void*)0xdeadbeef;
1139 hr = IDWriteTextFormat_GetTrimming(format, &trimming, &trimmingsign);
1140 ok(hr == S_OK, "got 0x%08x\n", hr);
1141 ok(trimming.granularity == DWRITE_TRIMMING_GRANULARITY_NONE, "got %d\n", trimming.granularity);
1142 ok(trimming.delimiter == 0, "got %d\n", trimming.delimiter);
1143 ok(trimming.delimiterCount == 0, "got %d\n", trimming.delimiterCount);
1144 ok(trimmingsign == NULL, "got %p\n", trimmingsign);
1146 /* setters */
1147 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING);
1148 ok(hr == S_OK, "got 0x%08x\n", hr);
1150 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_JUSTIFIED+1);
1151 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1153 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
1154 ok(hr == S_OK, "got 0x%08x\n", hr);
1156 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_CENTER+1);
1157 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1159 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_WRAP);
1160 ok(hr == S_OK, "got 0x%08x\n", hr);
1162 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_CHARACTER+1);
1163 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1165 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
1166 ok(hr == S_OK, "got 0x%08x\n", hr);
1168 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
1169 ok(hr == S_OK, "got 0x%08x\n", hr);
1172 hr = IDWriteTextFormat_SetTrimming(format, &trimming, NULL);
1173 ok(hr == S_OK, "got 0x%08x\n", hr);
1175 /* invalid granularity */
1176 trimming.granularity = 10;
1177 trimming.delimiter = 0;
1178 trimming.delimiterCount = 0;
1179 hr = IDWriteTextFormat_SetTrimming(format, &trimming, NULL);
1180 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1182 IDWriteTextFormat_Release(format);
1183 IDWriteFactory_Release(factory);
1186 static void test_GetLocaleName(void)
1188 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1189 static const WCHAR ruW[] = {'r','u',0};
1190 IDWriteTextLayout *layout;
1191 IDWriteTextFormat *format, *format2;
1192 IDWriteFactory *factory;
1193 WCHAR buff[10];
1194 UINT32 len;
1195 HRESULT hr;
1197 factory = create_factory();
1199 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1200 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1201 ok(hr == S_OK, "got 0x%08x\n", hr);
1203 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 0, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1204 ok(hr == S_OK, "got 0x%08x\n", hr);
1206 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format2);
1207 ok(hr == S_OK, "got 0x%08x\n", hr);
1209 len = IDWriteTextFormat_GetLocaleNameLength(format2);
1210 ok(len == 2, "got %u\n", len);
1211 len = IDWriteTextFormat_GetLocaleNameLength(format);
1212 ok(len == 2, "got %u\n", len);
1213 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len);
1214 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1215 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len+1);
1216 ok(hr == S_OK, "got 0x%08x\n", hr);
1217 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
1218 hr = IDWriteTextFormat_GetLocaleName(format, buff, len);
1219 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1220 hr = IDWriteTextFormat_GetLocaleName(format, buff, len+1);
1221 ok(hr == S_OK, "got 0x%08x\n", hr);
1222 ok(!lstrcmpW(buff, ruW), "got %s\n", wine_dbgstr_w(buff));
1224 IDWriteTextLayout_Release(layout);
1225 IDWriteTextFormat_Release(format);
1226 IDWriteTextFormat_Release(format2);
1227 IDWriteFactory_Release(factory);
1230 static const struct drawcall_entry drawellipsis_seq[] = {
1231 { DRAW_GLYPHRUN, {0x2026, 0}, {'e','n','-','g','b',0}, 1 },
1232 { DRAW_LAST_KIND }
1235 static void test_CreateEllipsisTrimmingSign(void)
1237 static const WCHAR engbW[] = {'e','n','-','G','B',0};
1238 DWRITE_INLINE_OBJECT_METRICS metrics;
1239 DWRITE_BREAK_CONDITION before, after;
1240 IDWriteTextFormat *format;
1241 IDWriteInlineObject *sign;
1242 IDWriteFactory *factory;
1243 IUnknown *unk, *effect;
1244 HRESULT hr;
1246 factory = create_factory();
1248 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1249 DWRITE_FONT_STRETCH_NORMAL, 10.0, engbW, &format);
1250 ok(hr == S_OK, "got 0x%08x\n", hr);
1252 EXPECT_REF(format, 1);
1253 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
1254 ok(hr == S_OK, "got 0x%08x\n", hr);
1255 EXPECT_REF(format, 1);
1257 hr = IDWriteInlineObject_QueryInterface(sign, &IID_IDWriteTextLayout, (void**)&unk);
1258 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1260 if (0) {/* crashes on native */
1261 hr = IDWriteInlineObject_GetBreakConditions(sign, NULL, NULL);
1262 hr = IDWriteInlineObject_GetMetrics(sign, NULL);
1264 metrics.width = 0.0;
1265 metrics.height = 123.0;
1266 metrics.baseline = 123.0;
1267 metrics.supportsSideways = TRUE;
1268 hr = IDWriteInlineObject_GetMetrics(sign, &metrics);
1269 ok(hr == S_OK, "got 0x%08x\n", hr);
1270 ok(metrics.width > 0.0, "got %.2f\n", metrics.width);
1271 ok(metrics.height == 0.0, "got %.2f\n", metrics.height);
1272 ok(metrics.baseline == 0.0, "got %.2f\n", metrics.baseline);
1273 ok(!metrics.supportsSideways, "got %d\n", metrics.supportsSideways);
1275 before = after = DWRITE_BREAK_CONDITION_CAN_BREAK;
1276 hr = IDWriteInlineObject_GetBreakConditions(sign, &before, &after);
1277 ok(hr == S_OK, "got 0x%08x\n", hr);
1278 ok(before == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", before);
1279 ok(after == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", after);
1281 /* Draw tests */
1282 flush_sequence(sequences, RENDERER_ID);
1283 hr = IDWriteInlineObject_Draw(sign, NULL, &testrenderer, 0.0, 0.0, FALSE, FALSE, NULL);
1284 ok(hr == S_OK, "got 0x%08x\n", hr);
1285 ok_sequence(sequences, RENDERER_ID, drawellipsis_seq, "ellipsis sign draw test", FALSE);
1287 effect = create_test_effect();
1289 EXPECT_REF(effect, 1);
1290 flush_sequence(sequences, RENDERER_ID);
1291 hr = IDWriteInlineObject_Draw(sign, NULL, &testrenderer, 0.0f, 0.0f, FALSE, FALSE, effect);
1292 ok(hr == S_OK, "Failed to draw trimming sign, hr %#x.\n", hr);
1293 ok_sequence(sequences, RENDERER_ID, drawellipsis_seq, "ellipsis sign draw with effect test", FALSE);
1294 EXPECT_REF(effect, 1);
1296 IUnknown_Release(effect);
1298 flush_sequence(sequences, RENDERER_ID);
1299 hr = IDWriteInlineObject_Draw(sign, NULL, &testrenderer, 0.0f, 0.0f, FALSE, FALSE, (void *)0xdeadbeef);
1300 ok(hr == S_OK, "Failed to draw trimming sign, hr %#x.\n", hr);
1301 ok_sequence(sequences, RENDERER_ID, drawellipsis_seq, "ellipsis sign draw with effect test", FALSE);
1303 IDWriteInlineObject_Release(sign);
1305 /* non-orthogonal flow/reading combination */
1306 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
1307 ok(hr == S_OK, "got 0x%08x\n", hr);
1309 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT);
1310 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* vista, win7 */, "got 0x%08x\n", hr);
1311 if (hr == S_OK) {
1312 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
1313 ok(hr == DWRITE_E_FLOWDIRECTIONCONFLICTS, "got 0x%08x\n", hr);
1316 IDWriteTextFormat_Release(format);
1317 IDWriteFactory_Release(factory);
1320 static void test_fontweight(void)
1322 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1323 static const WCHAR ruW[] = {'r','u',0};
1324 IDWriteTextFormat *format, *fmt2;
1325 IDWriteTextLayout *layout;
1326 DWRITE_FONT_WEIGHT weight;
1327 DWRITE_TEXT_RANGE range;
1328 IDWriteFactory *factory;
1329 FLOAT size;
1330 HRESULT hr;
1332 factory = create_factory();
1334 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1335 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1336 ok(hr == S_OK, "got 0x%08x\n", hr);
1338 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1339 ok(hr == S_OK, "got 0x%08x\n", hr);
1341 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&fmt2);
1342 ok(hr == S_OK, "got 0x%08x\n", hr);
1344 weight = IDWriteTextFormat_GetFontWeight(fmt2);
1345 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
1347 range.startPosition = range.length = 0;
1348 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1349 ok(hr == S_OK, "got 0x%08x\n", hr);
1350 ok(range.startPosition == 0 && range.length == ~0u, "got %u, %u\n", range.startPosition, range.length);
1352 range.startPosition = 0;
1353 range.length = 6;
1354 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_NORMAL, range);
1355 ok(hr == S_OK, "got 0x%08x\n", hr);
1357 range.startPosition = range.length = 0;
1358 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1359 ok(hr == S_OK, "got 0x%08x\n", hr);
1360 ok(range.startPosition == 0 && range.length == 6, "got %u, %u\n", range.startPosition, range.length);
1362 /* IDWriteTextFormat methods output doesn't reflect layout changes */
1363 weight = IDWriteTextFormat_GetFontWeight(fmt2);
1364 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
1366 range.length = 0;
1367 weight = DWRITE_FONT_WEIGHT_BOLD;
1368 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1369 ok(hr == S_OK, "got 0x%08x\n", hr);
1370 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
1371 ok(range.length == 6, "got %d\n", range.length);
1373 range.startPosition = 0;
1374 range.length = 6;
1375 hr = IDWriteTextLayout_SetFontWeight(layout, 1000, range);
1376 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1378 size = IDWriteTextLayout_GetMaxWidth(layout);
1379 ok(size == 100.0, "got %.2f\n", size);
1381 hr = IDWriteTextLayout_SetMaxWidth(layout, 0.0);
1382 ok(hr == S_OK, "got 0x%08x\n", hr);
1384 size = IDWriteTextLayout_GetMaxWidth(layout);
1385 ok(size == 0.0, "got %.2f\n", size);
1387 hr = IDWriteTextLayout_SetMaxWidth(layout, -1.0);
1388 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1390 size = IDWriteTextLayout_GetMaxWidth(layout);
1391 ok(size == 0.0, "got %.2f\n", size);
1393 hr = IDWriteTextLayout_SetMaxWidth(layout, 100.0);
1394 ok(hr == S_OK, "got 0x%08x\n", hr);
1396 size = IDWriteTextLayout_GetMaxWidth(layout);
1397 ok(size == 100.0, "got %.2f\n", size);
1399 size = IDWriteTextLayout_GetMaxHeight(layout);
1400 ok(size == 100.0, "got %.2f\n", size);
1402 hr = IDWriteTextLayout_SetMaxHeight(layout, 0.0);
1403 ok(hr == S_OK, "got 0x%08x\n", hr);
1405 size = IDWriteTextLayout_GetMaxHeight(layout);
1406 ok(size == 0.0, "got %.2f\n", size);
1408 hr = IDWriteTextLayout_SetMaxHeight(layout, -1.0);
1409 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1411 size = IDWriteTextLayout_GetMaxHeight(layout);
1412 ok(size == 0.0, "got %.2f\n", size);
1414 hr = IDWriteTextLayout_SetMaxHeight(layout, 100.0);
1415 ok(hr == S_OK, "got 0x%08x\n", hr);
1417 size = IDWriteTextLayout_GetMaxHeight(layout);
1418 ok(size == 100.0, "got %.2f\n", size);
1420 IDWriteTextLayout_Release(layout);
1421 IDWriteTextFormat_Release(fmt2);
1422 IDWriteTextFormat_Release(format);
1423 IDWriteFactory_Release(factory);
1426 static void test_SetInlineObject(void)
1428 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1429 static const WCHAR ruW[] = {'r','u',0};
1431 IDWriteInlineObject *inlineobj, *inlineobj2, *inlinetest;
1432 IDWriteTextFormat *format;
1433 IDWriteTextLayout *layout;
1434 DWRITE_TEXT_RANGE range, r2;
1435 IDWriteFactory *factory;
1436 HRESULT hr;
1438 factory = create_factory();
1440 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1441 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1442 ok(hr == S_OK, "got 0x%08x\n", hr);
1444 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1445 ok(hr == S_OK, "got 0x%08x\n", hr);
1447 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1448 ok(hr == S_OK, "got 0x%08x\n", hr);
1450 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj2);
1451 ok(hr == S_OK, "got 0x%08x\n", hr);
1453 EXPECT_REF(inlineobj, 1);
1454 EXPECT_REF(inlineobj2, 1);
1456 inlinetest = (void*)0x1;
1457 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, NULL);
1458 ok(hr == S_OK, "got 0x%08x\n", hr);
1459 ok(inlinetest == NULL, "got %p\n", inlinetest);
1461 range.startPosition = 0;
1462 range.length = 2;
1463 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1464 ok(hr == S_OK, "got 0x%08x\n", hr);
1466 EXPECT_REF(inlineobj, 2);
1468 inlinetest = (void*)0x1;
1469 hr = IDWriteTextLayout_GetInlineObject(layout, 2, &inlinetest, NULL);
1470 ok(hr == S_OK, "got 0x%08x\n", hr);
1471 ok(inlinetest == NULL, "got %p\n", inlinetest);
1473 inlinetest = NULL;
1474 r2.startPosition = r2.length = 100;
1475 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1476 ok(hr == S_OK, "got 0x%08x\n", hr);
1477 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1478 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1479 IDWriteInlineObject_Release(inlinetest);
1481 EXPECT_REF(inlineobj, 2);
1483 /* get from somewhere inside a range */
1484 inlinetest = NULL;
1485 r2.startPosition = r2.length = 100;
1486 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1487 ok(hr == S_OK, "got 0x%08x\n", hr);
1488 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1489 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1490 IDWriteInlineObject_Release(inlinetest);
1492 EXPECT_REF(inlineobj, 2);
1494 range.startPosition = 1;
1495 range.length = 1;
1496 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj2, range);
1497 ok(hr == S_OK, "got 0x%08x\n", hr);
1499 inlinetest = NULL;
1500 r2.startPosition = r2.length = 100;
1501 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1502 ok(hr == S_OK, "got 0x%08x\n", hr);
1503 ok(inlinetest == inlineobj2, "got %p\n", inlinetest);
1504 ok(r2.startPosition == 1 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1505 IDWriteInlineObject_Release(inlinetest);
1507 EXPECT_REF(inlineobj, 2);
1508 EXPECT_REF(inlineobj2, 2);
1510 inlinetest = NULL;
1511 r2.startPosition = r2.length = 100;
1512 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1513 ok(hr == S_OK, "got 0x%08x\n", hr);
1514 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1515 ok(r2.startPosition == 0 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1516 IDWriteInlineObject_Release(inlinetest);
1518 EXPECT_REF(inlineobj, 2);
1520 range.startPosition = 1;
1521 range.length = 1;
1522 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1523 ok(hr == S_OK, "got 0x%08x\n", hr);
1525 r2.startPosition = r2.length = 100;
1526 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1527 ok(hr == S_OK, "got 0x%08x\n", hr);
1528 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1529 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1530 IDWriteInlineObject_Release(inlinetest);
1532 EXPECT_REF(inlineobj, 2);
1534 range.startPosition = 1;
1535 range.length = 2;
1536 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1537 ok(hr == S_OK, "got 0x%08x\n", hr);
1539 EXPECT_REF(inlineobj, 2);
1541 r2.startPosition = r2.length = 100;
1542 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1543 ok(hr == S_OK, "got 0x%08x\n", hr);
1544 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1545 ok(r2.startPosition == 0 && r2.length == 3, "got %d, %d\n", r2.startPosition, r2.length);
1546 IDWriteInlineObject_Release(inlinetest);
1548 EXPECT_REF(inlineobj, 2);
1549 EXPECT_REF(inlineobj2, 1);
1551 IDWriteTextLayout_Release(layout);
1553 EXPECT_REF(inlineobj, 1);
1555 IDWriteInlineObject_Release(inlineobj);
1556 IDWriteInlineObject_Release(inlineobj2);
1557 IDWriteTextFormat_Release(format);
1558 IDWriteFactory_Release(factory);
1561 /* drawing calls sequence doesn't depend on run order, instead all runs are
1562 drawn first, inline objects next and then underline/strikes */
1563 static const struct drawcall_entry draw_seq[] = {
1564 { DRAW_GLYPHRUN, {'s',0}, {'r','u',0}, 1 },
1565 { DRAW_GLYPHRUN, {'r','i',0}, {'r','u',0}, 2 },
1566 { DRAW_GLYPHRUN|DRAW_EFFECT, {'n',0}, {'r','u',0}, 1 },
1567 { DRAW_GLYPHRUN, {'g',0}, {'r','u',0}, 1 },
1568 { DRAW_INLINE },
1569 { DRAW_UNDERLINE, {0}, {'r','u',0} },
1570 { DRAW_STRIKETHROUGH },
1571 { DRAW_LAST_KIND }
1574 static const struct drawcall_entry draw_seq2[] = {
1575 { DRAW_GLYPHRUN, {'s',0}, {'r','u',0}, 1 },
1576 { DRAW_GLYPHRUN, {'t',0}, {'r','u',0}, 1 },
1577 { DRAW_GLYPHRUN, {'r',0}, {'r','u',0}, 1 },
1578 { DRAW_GLYPHRUN, {'i',0}, {'r','u',0}, 1 },
1579 { DRAW_GLYPHRUN, {'n',0}, {'r','u',0}, 1 },
1580 { DRAW_GLYPHRUN, {'g',0}, {'r','u',0}, 1 },
1581 { DRAW_LAST_KIND }
1584 static const struct drawcall_entry draw_seq3[] = {
1585 { DRAW_GLYPHRUN, {0x202a,0x202c,0}, {'r','u',0}, 0 },
1586 { DRAW_GLYPHRUN, {'a','b',0}, {'r','u',0}, 2 },
1587 { DRAW_LAST_KIND }
1590 static const struct drawcall_entry draw_seq4[] = {
1591 { DRAW_GLYPHRUN, {'s','t','r',0}, {'r','u',0}, 3 },
1592 { DRAW_GLYPHRUN, {'i','n','g',0}, {'r','u',0}, 3 },
1593 { DRAW_STRIKETHROUGH },
1594 { DRAW_LAST_KIND }
1597 static const struct drawcall_entry draw_seq5[] = {
1598 { DRAW_GLYPHRUN, {'s','t',0}, {'r','u',0}, 2 },
1599 { DRAW_GLYPHRUN, {'r','i',0}, {'r','u',0}, 2 },
1600 { DRAW_GLYPHRUN, {'n','g',0}, {'r','u',0}, 2 },
1601 { DRAW_STRIKETHROUGH },
1602 { DRAW_LAST_KIND }
1605 static const struct drawcall_entry empty_seq[] = {
1606 { DRAW_LAST_KIND }
1609 static const struct drawcall_entry draw_single_run_seq[] = {
1610 { DRAW_GLYPHRUN, {'s','t','r','i','n','g',0}, {'r','u',0}, 6 },
1611 { DRAW_LAST_KIND }
1614 static const struct drawcall_entry draw_reordered_run_seq[] = {
1615 { DRAW_GLYPHRUN, {'1','2','3','-','5','2',0}, {'r','u',0}, 6 },
1616 { DRAW_GLYPHRUN, {0x64a,0x64f,0x633,0x627,0x648,0x650,0x64a,0}, {'r','u',0}, 7 },
1617 { DRAW_GLYPHRUN, {'7','1',0}, {'r','u',0}, 2 },
1618 { DRAW_GLYPHRUN, {'.',0}, {'r','u',0}, 1 },
1619 { DRAW_LAST_KIND }
1622 static void test_Draw(void)
1624 static const WCHAR str3W[] = {'1','2','3','-','5','2',0x64a,0x64f,0x633,0x627,0x648,0x650,
1625 0x64a,'7','1','.',0};
1626 static const WCHAR strW[] = {'s','t','r','i','n','g',0};
1627 static const WCHAR str2W[] = {0x202a,0x202c,'a','b',0};
1628 static const WCHAR ruW[] = {'r','u',0};
1629 IDWriteInlineObject *inlineobj;
1630 struct renderer_context ctxt;
1631 IDWriteTextFormat *format;
1632 IDWriteTextLayout *layout;
1633 DWRITE_TEXT_RANGE range;
1634 IDWriteFactory *factory;
1635 DWRITE_TEXT_METRICS tm;
1636 DWRITE_MATRIX m;
1637 HRESULT hr;
1639 factory = create_factory();
1641 memset(&ctxt, 0, sizeof(ctxt));
1642 ctxt.snapping_disabled = TRUE;
1644 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1645 DWRITE_FONT_STRETCH_NORMAL, 10.0, ruW, &format);
1646 ok(hr == S_OK, "got 0x%08x\n", hr);
1648 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 100.0, 100.0, &layout);
1649 ok(hr == S_OK, "got 0x%08x\n", hr);
1651 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1652 ok(hr == S_OK, "got 0x%08x\n", hr);
1654 range.startPosition = 5;
1655 range.length = 1;
1656 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1657 ok(hr == S_OK, "got 0x%08x\n", hr);
1659 range.startPosition = 1;
1660 range.length = 1;
1661 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1662 ok(hr == S_OK, "got 0x%08x\n", hr);
1664 range.startPosition = 4;
1665 range.length = 1;
1666 hr = IDWriteTextLayout_SetDrawingEffect(layout, (IUnknown*)inlineobj, range);
1667 ok(hr == S_OK, "got 0x%08x\n", hr);
1669 range.startPosition = 0;
1670 range.length = 1;
1671 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
1672 ok(hr == S_OK, "got 0x%08x\n", hr);
1674 flush_sequence(sequences, RENDERER_ID);
1675 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1676 ok(hr == S_OK, "got 0x%08x\n", hr);
1677 ok_sequence(sequences, RENDERER_ID, draw_seq, "draw test", FALSE);
1678 IDWriteTextLayout_Release(layout);
1680 /* with reduced width DrawGlyphRun() is called for every line */
1681 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 5.0, 100.0, &layout);
1682 ok(hr == S_OK, "got 0x%08x\n", hr);
1683 flush_sequence(sequences, RENDERER_ID);
1684 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1685 ok(hr == S_OK, "got 0x%08x\n", hr);
1686 ok_sequence(sequences, RENDERER_ID, draw_seq2, "draw test 2", TRUE);
1687 hr = IDWriteTextLayout_GetMetrics(layout, &tm);
1688 ok(hr == S_OK, "got 0x%08x\n", hr);
1689 todo_wine
1690 ok(tm.lineCount == 6, "got %u\n", tm.lineCount);
1691 IDWriteTextLayout_Release(layout);
1693 /* string with control characters */
1694 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 100.0, &layout);
1695 ok(hr == S_OK, "got 0x%08x\n", hr);
1696 flush_sequence(sequences, RENDERER_ID);
1697 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1698 ok(hr == S_OK, "got 0x%08x\n", hr);
1699 ok_sequence(sequences, RENDERER_ID, draw_seq3, "draw test 3", FALSE);
1700 IDWriteTextLayout_Release(layout);
1702 /* strikethrough splits ranges from renderer point of view, but doesn't break
1703 shaping */
1704 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1705 ok(hr == S_OK, "got 0x%08x\n", hr);
1706 flush_sequence(sequences, RENDERER_ID);
1708 range.startPosition = 0;
1709 range.length = 3;
1710 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1711 ok(hr == S_OK, "got 0x%08x\n", hr);
1713 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1714 ok(hr == S_OK, "got 0x%08x\n", hr);
1715 ok_sequence(sequences, RENDERER_ID, draw_seq4, "draw test 4", FALSE);
1716 IDWriteTextLayout_Release(layout);
1718 /* strikethrough somewhere in the middle */
1719 hr = IDWriteFactory_CreateTextLayout(factory, strW, 6, format, 500.0, 100.0, &layout);
1720 ok(hr == S_OK, "got 0x%08x\n", hr);
1721 flush_sequence(sequences, RENDERER_ID);
1723 range.startPosition = 2;
1724 range.length = 2;
1725 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1726 ok(hr == S_OK, "got 0x%08x\n", hr);
1728 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1729 ok(hr == S_OK, "got 0x%08x\n", hr);
1730 ok_sequence(sequences, RENDERER_ID, draw_seq5, "draw test 5", FALSE);
1731 IDWriteTextLayout_Release(layout);
1733 /* empty string */
1734 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 500.0, 100.0, &layout);
1735 ok(hr == S_OK, "got 0x%08x\n", hr);
1737 flush_sequence(sequences, RENDERER_ID);
1738 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1739 ok(hr == S_OK, "got 0x%08x\n", hr);
1740 ok_sequence(sequences, RENDERER_ID, empty_seq, "draw test 6", FALSE);
1741 IDWriteTextLayout_Release(layout);
1743 ctxt.gdicompat = TRUE;
1744 ctxt.use_gdi_natural = TRUE;
1746 /* different parameter combinations with gdi-compatible layout */
1747 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, TRUE, &layout);
1748 ok(hr == S_OK, "got 0x%08x\n", hr);
1749 flush_sequence(sequences, RENDERER_ID);
1750 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1751 ok(hr == S_OK, "got 0x%08x\n", hr);
1752 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 7", FALSE);
1754 /* text alignment keeps pixel-aligned origin */
1755 hr = IDWriteTextLayout_GetMetrics(layout, &tm);
1756 ok(hr == S_OK, "got 0x%08x\n", hr);
1757 ok(tm.width == floorf(tm.width), "got %f\n", tm.width);
1759 hr = IDWriteTextLayout_SetMaxWidth(layout, tm.width + 3.0);
1760 ok(hr == S_OK, "got 0x%08x\n", hr);
1761 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_CENTER);
1762 ok(hr == S_OK, "got 0x%08x\n", hr);
1764 ctxt.originX = ctxt.originY = 0.0;
1765 flush_sequence(sequences, RENDERER_ID);
1766 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1767 ok(hr == S_OK, "got 0x%08x\n", hr);
1768 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 7", FALSE);
1769 ok(ctxt.originX != 0.0 && ctxt.originX == floorf(ctxt.originX), "got %f\n", ctxt.originX);
1771 IDWriteTextLayout_Release(layout);
1773 ctxt.gdicompat = TRUE;
1774 ctxt.use_gdi_natural = FALSE;
1776 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
1777 ok(hr == S_OK, "got 0x%08x\n", hr);
1778 flush_sequence(sequences, RENDERER_ID);
1779 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1780 ok(hr == S_OK, "got 0x%08x\n", hr);
1781 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 8", FALSE);
1782 IDWriteTextLayout_Release(layout);
1784 ctxt.gdicompat = TRUE;
1785 ctxt.use_gdi_natural = TRUE;
1787 m.m11 = m.m22 = 2.0;
1788 m.m12 = m.m21 = m.dx = m.dy = 0.0;
1789 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, &m, TRUE, &layout);
1790 ok(hr == S_OK, "got 0x%08x\n", hr);
1791 flush_sequence(sequences, RENDERER_ID);
1792 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1793 ok(hr == S_OK, "got 0x%08x\n", hr);
1794 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 9", FALSE);
1795 IDWriteTextLayout_Release(layout);
1797 ctxt.gdicompat = TRUE;
1798 ctxt.use_gdi_natural = FALSE;
1800 m.m11 = m.m22 = 2.0;
1801 m.m12 = m.m21 = m.dx = m.dy = 0.0;
1802 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 6, format, 100.0, 100.0, 1.0, &m, FALSE, &layout);
1803 ok(hr == S_OK, "got 0x%08x\n", hr);
1804 flush_sequence(sequences, RENDERER_ID);
1805 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1806 ok(hr == S_OK, "got 0x%08x\n", hr);
1807 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 10", FALSE);
1808 IDWriteTextLayout_Release(layout);
1810 IDWriteInlineObject_Release(inlineobj);
1812 /* text that triggers bidi run reordering */
1813 hr = IDWriteFactory_CreateTextLayout(factory, str3W, lstrlenW(str3W), format, 1000.0f, 100.0f, &layout);
1814 ok(hr == S_OK, "got 0x%08x\n", hr);
1816 ctxt.gdicompat = FALSE;
1817 ctxt.use_gdi_natural = FALSE;
1818 ctxt.snapping_disabled = TRUE;
1820 flush_sequence(sequences, RENDERER_ID);
1821 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0f, 0.0f);
1822 ok(hr == S_OK, "got 0x%08x\n", hr);
1823 ok_sequence(sequences, RENDERER_ID, draw_reordered_run_seq, "draw test 11", FALSE);
1825 IDWriteTextLayout_Release(layout);
1827 IDWriteTextFormat_Release(format);
1828 IDWriteFactory_Release(factory);
1831 static void test_typography(void)
1833 DWRITE_FONT_FEATURE feature;
1834 IDWriteTypography *typography;
1835 IDWriteFactory *factory;
1836 UINT32 count;
1837 HRESULT hr;
1839 factory = create_factory();
1841 hr = IDWriteFactory_CreateTypography(factory, &typography);
1842 ok(hr == S_OK, "got 0x%08x\n", hr);
1844 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1845 feature.parameter = 1;
1846 hr = IDWriteTypography_AddFontFeature(typography, feature);
1847 ok(hr == S_OK, "got 0x%08x\n", hr);
1849 count = IDWriteTypography_GetFontFeatureCount(typography);
1850 ok(count == 1, "got %u\n", count);
1852 /* duplicated features work just fine */
1853 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1854 feature.parameter = 0;
1855 hr = IDWriteTypography_AddFontFeature(typography, feature);
1856 ok(hr == S_OK, "got 0x%08x\n", hr);
1858 count = IDWriteTypography_GetFontFeatureCount(typography);
1859 ok(count == 2, "got %u\n", count);
1861 memset(&feature, 0xcc, sizeof(feature));
1862 hr = IDWriteTypography_GetFontFeature(typography, 0, &feature);
1863 ok(hr == S_OK, "got 0x%08x\n", hr);
1864 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1865 ok(feature.parameter == 1, "got %u\n", feature.parameter);
1867 memset(&feature, 0xcc, sizeof(feature));
1868 hr = IDWriteTypography_GetFontFeature(typography, 1, &feature);
1869 ok(hr == S_OK, "got 0x%08x\n", hr);
1870 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1871 ok(feature.parameter == 0, "got %u\n", feature.parameter);
1873 hr = IDWriteTypography_GetFontFeature(typography, 2, &feature);
1874 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1876 /* duplicated with same parameter value */
1877 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1878 feature.parameter = 0;
1879 hr = IDWriteTypography_AddFontFeature(typography, feature);
1880 ok(hr == S_OK, "got 0x%08x\n", hr);
1882 count = IDWriteTypography_GetFontFeatureCount(typography);
1883 ok(count == 3, "got %u\n", count);
1885 memset(&feature, 0xcc, sizeof(feature));
1886 hr = IDWriteTypography_GetFontFeature(typography, 2, &feature);
1887 ok(hr == S_OK, "got 0x%08x\n", hr);
1888 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
1889 ok(feature.parameter == 0, "got %u\n", feature.parameter);
1891 IDWriteTypography_Release(typography);
1892 IDWriteFactory_Release(factory);
1895 static void test_GetClusterMetrics(void)
1897 static const WCHAR str_white_spaceW[] = {
1898 /* BK - FORM FEED, LINE TABULATION, LINE SEP, PARA SEP */ 0xc, 0xb, 0x2028, 0x2029,
1899 /* ZW - ZERO WIDTH SPACE */ 0x200b,
1900 /* SP - SPACE */ 0x20
1902 static const WCHAR str5W[] = {'a','\r','b','\n','c','\n','\r','d','\r','\n','e',0xb,'f',0xc,
1903 'g',0x0085,'h',0x2028,'i',0x2029,0xad,0xa,0};
1904 static const WCHAR str3W[] = {0x2066,')',')',0x661,'(',0x627,')',0};
1905 static const WCHAR str2W[] = {0x202a,0x202c,'a',0};
1906 static const WCHAR strW[] = {'a','b','c','d',0};
1907 static const WCHAR str4W[] = {'a',' ',0};
1908 static const WCHAR str6W[] = {'a',' ','b',0};
1909 DWRITE_INLINE_OBJECT_METRICS inline_metrics;
1910 DWRITE_CLUSTER_METRICS metrics[22];
1911 DWRITE_TEXT_METRICS text_metrics;
1912 DWRITE_TRIMMING trimming_options;
1913 IDWriteTextLayout1 *layout1;
1914 IDWriteInlineObject *trimm;
1915 IDWriteTextFormat *format;
1916 IDWriteTextLayout *layout;
1917 DWRITE_LINE_METRICS line;
1918 DWRITE_TEXT_RANGE range;
1919 IDWriteFactory *factory;
1920 UINT32 count, i;
1921 FLOAT width;
1922 HRESULT hr;
1924 factory = create_factory();
1926 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1927 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
1928 ok(hr == S_OK, "got 0x%08x\n", hr);
1930 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 7, format, 1000.0, 1000.0, &layout);
1931 ok(hr == S_OK, "got 0x%08x\n", hr);
1932 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1933 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1934 ok(count == 7, "got %u\n", count);
1935 IDWriteTextLayout_Release(layout);
1937 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
1938 ok(hr == S_OK, "got 0x%08x\n", hr);
1940 count = 0;
1941 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
1942 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1943 ok(count == 4, "got %u\n", count);
1945 /* check every cluster width */
1946 count = 0;
1947 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
1948 ok(hr == S_OK, "got 0x%08x\n", hr);
1949 ok(count == 4, "got %u\n", count);
1950 for (i = 0; i < count; i++) {
1951 ok(metrics[i].width > 0.0, "%u: got width %.2f\n", i, metrics[i].width);
1952 ok(metrics[i].length == 1, "%u: got length %u\n", i, metrics[i].length);
1955 /* apply spacing and check widths again */
1956 if (IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1) == S_OK) {
1957 DWRITE_CLUSTER_METRICS metrics2[4];
1958 FLOAT leading, trailing, min_advance;
1959 DWRITE_TEXT_RANGE r;
1961 leading = trailing = min_advance = 2.0;
1962 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 500, &leading, &trailing,
1963 &min_advance, &r);
1964 ok(hr == S_OK, "got 0x%08x\n", hr);
1965 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
1966 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
1967 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
1969 leading = trailing = min_advance = 2.0;
1970 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 0, &leading, &trailing,
1971 &min_advance, NULL);
1972 ok(hr == S_OK, "got 0x%08x\n", hr);
1973 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
1974 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
1976 r.startPosition = 0;
1977 r.length = 4;
1978 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 10.0, 15.0, 0.0, r);
1979 ok(hr == S_OK, "got 0x%08x\n", hr);
1981 count = 0;
1982 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics2, sizeof(metrics2)/sizeof(metrics2[0]), &count);
1983 ok(hr == S_OK, "got 0x%08x\n", hr);
1984 ok(count == 4, "got %u\n", count);
1985 for (i = 0; i < count; i++) {
1986 todo_wine
1987 ok(metrics2[i].width > metrics[i].width, "%u: got width %.2f, was %.2f\n", i, metrics2[i].width,
1988 metrics[i].width);
1989 ok(metrics2[i].length == 1, "%u: got length %u\n", i, metrics2[i].length);
1992 /* back to defaults */
1993 r.startPosition = 0;
1994 r.length = 4;
1995 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, 0.0, r);
1996 ok(hr == S_OK, "got 0x%08x\n", hr);
1998 /* negative advance limit */
1999 r.startPosition = 0;
2000 r.length = 4;
2001 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, -10.0, r);
2002 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2004 IDWriteTextLayout1_Release(layout1);
2006 else
2007 win_skip("IDWriteTextLayout1 is not supported, cluster spacing test skipped.\n");
2009 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &trimm);
2010 ok(hr == S_OK, "got 0x%08x\n", hr);
2012 range.startPosition = 0;
2013 range.length = 2;
2014 hr = IDWriteTextLayout_SetInlineObject(layout, trimm, range);
2015 ok(hr == S_OK, "got 0x%08x\n", hr);
2017 /* inline object takes a separate cluster, replaced codepoints number doesn't matter */
2018 count = 0;
2019 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
2020 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2021 ok(count == 3, "got %u\n", count);
2023 count = 0;
2024 memset(&metrics, 0, sizeof(metrics));
2025 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
2026 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2027 ok(count == 3, "got %u\n", count);
2028 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
2030 hr = IDWriteInlineObject_GetMetrics(trimm, &inline_metrics);
2031 ok(hr == S_OK, "got 0x%08x\n", hr);
2032 ok(inline_metrics.width > 0.0 && inline_metrics.width == metrics[0].width, "got %.2f, expected %.2f\n",
2033 inline_metrics.width, metrics[0].width);
2035 IDWriteTextLayout_Release(layout);
2037 /* text with non-visual control codes */
2038 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 3, format, 1000.0, 1000.0, &layout);
2039 ok(hr == S_OK, "got 0x%08x\n", hr);
2041 /* bidi control codes take a separate cluster */
2042 count = 0;
2043 memset(metrics, 0, sizeof(metrics));
2044 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2045 ok(hr == S_OK, "got 0x%08x\n", hr);
2046 ok(count == 3, "got %u\n", count);
2048 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
2049 ok(metrics[0].length == 1, "got %d\n", metrics[0].length);
2050 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
2051 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
2052 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
2053 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
2054 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
2056 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
2057 ok(metrics[1].length == 1, "got %d\n", metrics[1].length);
2058 ok(metrics[1].canWrapLineAfter == 0, "got %d\n", metrics[1].canWrapLineAfter);
2059 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
2060 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
2061 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
2062 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
2064 ok(metrics[2].width > 0.0, "got %.2f\n", metrics[2].width);
2065 ok(metrics[2].length == 1, "got %d\n", metrics[2].length);
2066 ok(metrics[2].canWrapLineAfter == 1, "got %d\n", metrics[2].canWrapLineAfter);
2067 ok(metrics[2].isWhitespace == 0, "got %d\n", metrics[2].isWhitespace);
2068 ok(metrics[2].isNewline == 0, "got %d\n", metrics[2].isNewline);
2069 ok(metrics[2].isSoftHyphen == 0, "got %d\n", metrics[2].isSoftHyphen);
2070 ok(metrics[2].isRightToLeft == 0, "got %d\n", metrics[2].isRightToLeft);
2072 IDWriteTextLayout_Release(layout);
2074 /* single inline object that fails to report its metrics */
2075 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2076 ok(hr == S_OK, "got 0x%08x\n", hr);
2078 range.startPosition = 0;
2079 range.length = 4;
2080 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj, range);
2081 ok(hr == S_OK, "got 0x%08x\n", hr);
2083 count = 0;
2084 memset(metrics, 0, sizeof(metrics));
2085 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2086 ok(hr == S_OK, "got 0x%08x\n", hr);
2087 ok(count == 1, "got %u\n", count);
2089 /* object sets a width to 123.0, but returns failure from GetMetrics() */
2090 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
2091 ok(metrics[0].length == 4, "got %d\n", metrics[0].length);
2092 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
2093 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
2094 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
2095 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
2096 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
2098 /* now set two inline object for [0,1] and [2,3], both fail to report break conditions */
2099 range.startPosition = 2;
2100 range.length = 2;
2101 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj2, range);
2102 ok(hr == S_OK, "got 0x%08x\n", hr);
2104 count = 0;
2105 memset(metrics, 0, sizeof(metrics));
2106 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2107 ok(hr == S_OK, "got 0x%08x\n", hr);
2108 ok(count == 2, "got %u\n", count);
2110 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
2111 ok(metrics[0].length == 2, "got %d\n", metrics[0].length);
2112 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
2113 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
2114 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
2115 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
2116 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
2118 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
2119 ok(metrics[1].length == 2, "got %d\n", metrics[1].length);
2120 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
2121 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
2122 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
2123 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
2124 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
2126 IDWriteTextLayout_Release(layout);
2128 /* zero length string */
2129 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 1000.0, 1000.0, &layout);
2130 ok(hr == S_OK, "got 0x%08x\n", hr);
2132 count = 1;
2133 memset(metrics, 0, sizeof(metrics));
2134 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2135 ok(hr == S_OK, "got 0x%08x\n", hr);
2136 ok(count == 0, "got %u\n", count);
2137 IDWriteTextLayout_Release(layout);
2139 /* whitespace */
2140 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 2, format, 1000.0, 1000.0, &layout);
2141 ok(hr == S_OK, "got 0x%08x\n", hr);
2143 count = 0;
2144 memset(metrics, 0, sizeof(metrics));
2145 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 2, &count);
2146 ok(hr == S_OK, "got 0x%08x\n", hr);
2147 ok(count == 2, "got %u\n", count);
2148 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
2149 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
2150 ok(metrics[1].isWhitespace == 1, "got %d\n", metrics[1].isWhitespace);
2151 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
2152 IDWriteTextLayout_Release(layout);
2154 /* layout is fully covered by inline object with after condition DWRITE_BREAK_CONDITION_MAY_NOT_BREAK */
2155 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 2, format, 1000.0, 1000.0, &layout);
2156 ok(hr == S_OK, "got 0x%08x\n", hr);
2158 range.startPosition = 0;
2159 range.length = ~0u;
2160 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj3, range);
2161 ok(hr == S_OK, "got 0x%08x\n", hr);
2163 count = 0;
2164 memset(metrics, 0, sizeof(metrics));
2165 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 2, &count);
2166 ok(hr == S_OK, "got 0x%08x\n", hr);
2167 ok(count == 1, "got %u\n", count);
2168 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
2170 IDWriteTextLayout_Release(layout);
2172 /* compare natural cluster width with gdi layout */
2173 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 1, format, 100.0, 100.0, &layout);
2174 ok(hr == S_OK, "got 0x%08x\n", hr);
2176 count = 0;
2177 memset(metrics, 0, sizeof(metrics));
2178 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
2179 ok(hr == S_OK, "got 0x%08x\n", hr);
2180 ok(count == 1, "got %u\n", count);
2181 ok(metrics[0].width != floorf(metrics[0].width), "got %f\n", metrics[0].width);
2183 IDWriteTextLayout_Release(layout);
2185 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, str4W, 1, format, 100.0, 100.0, 1.0, NULL, FALSE, &layout);
2186 ok(hr == S_OK, "got 0x%08x\n", hr);
2188 count = 0;
2189 memset(metrics, 0, sizeof(metrics));
2190 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
2191 ok(hr == S_OK, "got 0x%08x\n", hr);
2192 ok(count == 1, "got %u\n", count);
2193 ok(metrics[0].width == floorf(metrics[0].width), "got %f\n", metrics[0].width);
2195 IDWriteTextLayout_Release(layout);
2197 /* isNewline tests */
2198 hr = IDWriteFactory_CreateTextLayout(factory, str5W, lstrlenW(str5W), format, 100.0f, 200.0f, &layout);
2199 ok(hr == S_OK, "got 0x%08x\n", hr);
2201 count = 0;
2202 memset(metrics, 0, sizeof(metrics));
2203 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
2204 ok(hr == S_OK, "got 0x%08x\n", hr);
2205 ok(count == 22, "got %u\n", count);
2207 ok(metrics[1].isNewline == 1, "got %d\n", metrics[1].isNewline);
2208 ok(metrics[3].isNewline == 1, "got %d\n", metrics[3].isNewline);
2209 ok(metrics[5].isNewline == 1, "got %d\n", metrics[5].isNewline);
2210 ok(metrics[6].isNewline == 1, "got %d\n", metrics[6].isNewline);
2211 ok(metrics[9].isNewline == 1, "got %d\n", metrics[9].isNewline);
2212 ok(metrics[11].isNewline == 1, "got %d\n", metrics[11].isNewline);
2213 ok(metrics[13].isNewline == 1, "got %d\n", metrics[13].isNewline);
2214 ok(metrics[15].isNewline == 1, "got %d\n", metrics[15].isNewline);
2215 ok(metrics[17].isNewline == 1, "got %d\n", metrics[17].isNewline);
2216 ok(metrics[19].isNewline == 1, "got %d\n", metrics[19].isNewline);
2217 ok(metrics[21].isNewline == 1, "got %d\n", metrics[21].isNewline);
2219 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
2220 ok(metrics[2].isNewline == 0, "got %d\n", metrics[2].isNewline);
2221 ok(metrics[4].isNewline == 0, "got %d\n", metrics[4].isNewline);
2222 ok(metrics[7].isNewline == 0, "got %d\n", metrics[7].isNewline);
2223 ok(metrics[8].isNewline == 0, "got %d\n", metrics[8].isNewline);
2224 ok(metrics[10].isNewline == 0, "got %d\n", metrics[10].isNewline);
2225 ok(metrics[12].isNewline == 0, "got %d\n", metrics[12].isNewline);
2226 ok(metrics[14].isNewline == 0, "got %d\n", metrics[14].isNewline);
2227 ok(metrics[16].isNewline == 0, "got %d\n", metrics[16].isNewline);
2228 ok(metrics[18].isNewline == 0, "got %d\n", metrics[18].isNewline);
2229 ok(metrics[20].isNewline == 0, "got %d\n", metrics[20].isNewline);
2231 for (i = 0; i < count; i++) {
2232 ok(metrics[i].length == 1, "%d: got %d\n", i, metrics[i].length);
2233 ok(metrics[i].isSoftHyphen == (i == count - 2), "%d: got %d\n", i, metrics[i].isSoftHyphen);
2234 if (metrics[i].isSoftHyphen)
2235 ok(!metrics[i].isWhitespace, "%u: got %d\n", i, metrics[i].isWhitespace);
2236 if (metrics[i].isNewline) {
2237 ok(metrics[i].width == 0.0f, "%u: got width %f\n", i, metrics[i].width);
2238 ok(metrics[i].isWhitespace == 1, "%u: got %d\n", i, metrics[i].isWhitespace);
2239 ok(metrics[i].canWrapLineAfter == 1, "%u: got %d\n", i, metrics[i].canWrapLineAfter);
2243 IDWriteTextLayout_Release(layout);
2245 /* Test whitespace resolution from linebreaking classes BK, ZW, and SP */
2246 hr = IDWriteFactory_CreateTextLayout(factory, str_white_spaceW, sizeof(str_white_spaceW)/sizeof(WCHAR), format,
2247 100.0f, 200.0f, &layout);
2248 ok(hr == S_OK, "got 0x%08x\n", hr);
2250 count = 0;
2251 memset(metrics, 0, sizeof(metrics));
2252 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 20, &count);
2253 ok(hr == S_OK, "got 0x%08x\n", hr);
2254 ok(count == 6, "got %u\n", count);
2256 ok(metrics[0].isWhitespace == 1, "got %d\n", metrics[0].isWhitespace);
2257 ok(metrics[1].isWhitespace == 1, "got %d\n", metrics[1].isWhitespace);
2258 ok(metrics[2].isWhitespace == 1, "got %d\n", metrics[2].isWhitespace);
2259 ok(metrics[3].isWhitespace == 1, "got %d\n", metrics[3].isWhitespace);
2260 ok(metrics[4].isWhitespace == 0, "got %d\n", metrics[4].isWhitespace);
2261 ok(metrics[5].isWhitespace == 1, "got %d\n", metrics[5].isWhitespace);
2263 IDWriteTextLayout_Release(layout);
2265 /* trigger line trimming */
2266 hr = IDWriteFactory_CreateTextLayout(factory, strW, lstrlenW(strW), format, 100.0f, 200.0f, &layout);
2267 ok(hr == S_OK, "got 0x%08x\n", hr);
2269 count = 0;
2270 memset(metrics, 0, sizeof(metrics));
2271 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 4, &count);
2272 ok(hr == S_OK, "got 0x%08x\n", hr);
2273 ok(count == 4, "got %u\n", count);
2275 hr = IDWriteTextLayout_GetMetrics(layout, &text_metrics);
2276 ok(hr == S_OK, "got 0x%08x\n", hr);
2278 width = metrics[0].width + inline_metrics.width;
2279 ok(width < text_metrics.width, "unexpected trimming sign width\n");
2281 /* enable trimming, reduce layout width so only first cluster and trimming sign fits */
2282 trimming_options.granularity = DWRITE_TRIMMING_GRANULARITY_CHARACTER;
2283 trimming_options.delimiter = 0;
2284 trimming_options.delimiterCount = 0;
2285 hr = IDWriteTextLayout_SetTrimming(layout, &trimming_options, trimm);
2286 ok(hr == S_OK, "got 0x%08x\n", hr);
2288 hr = IDWriteTextLayout_SetMaxWidth(layout, width);
2289 ok(hr == S_OK, "got 0x%08x\n", hr);
2291 count = 0;
2292 memset(metrics, 0, sizeof(metrics));
2293 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 4, &count);
2294 ok(hr == S_OK, "got 0x%08x\n", hr);
2295 ok(count == 4, "got %u\n", count);
2297 hr = IDWriteTextLayout_GetLineMetrics(layout, &line, 1, &count);
2298 ok(hr == S_OK, "got 0x%08x\n", hr);
2299 ok(count == 1, "got %u\n", count);
2300 ok(line.length == 4, "got %u\n", line.length);
2301 ok(line.isTrimmed, "got %d\n", line.isTrimmed);
2303 IDWriteTextLayout_Release(layout);
2305 /* NO_WRAP, check cluster wrapping attribute. */
2306 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_NO_WRAP);
2307 ok(hr == S_OK, "got 0x%08x\n", hr);
2309 hr = IDWriteFactory_CreateTextLayout(factory, str6W, lstrlenW(str6W), format, 1000.0f, 200.0f, &layout);
2310 ok(hr == S_OK, "got 0x%08x\n", hr);
2312 count = 0;
2313 memset(metrics, 0, sizeof(metrics));
2314 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2315 ok(hr == S_OK, "got 0x%08x\n", hr);
2316 ok(count == 3, "got %u\n", count);
2318 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
2319 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
2320 ok(metrics[2].canWrapLineAfter == 1, "got %d\n", metrics[2].canWrapLineAfter);
2322 IDWriteTextLayout_Release(layout);
2324 IDWriteInlineObject_Release(trimm);
2325 IDWriteTextFormat_Release(format);
2326 IDWriteFactory_Release(factory);
2329 static void test_SetLocaleName(void)
2331 static const WCHAR eNuSW[] = {'e','N','-','u','S',0};
2332 static const WCHAR strW[] = {'a','b','c','d',0};
2333 WCHAR buffW[LOCALE_NAME_MAX_LENGTH+sizeof(strW)/sizeof(WCHAR)];
2334 IDWriteTextFormat *format, *format2;
2335 IDWriteTextLayout *layout;
2336 DWRITE_TEXT_RANGE range;
2337 IDWriteFactory *factory;
2338 HRESULT hr;
2340 factory = create_factory();
2342 /* create format with mixed case locale name, get it back */
2343 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2344 DWRITE_FONT_STRETCH_NORMAL, 10.0, eNuSW, &format);
2345 ok(hr == S_OK, "got 0x%08x\n", hr);
2347 hr = IDWriteTextFormat_GetLocaleName(format, buffW, sizeof(buffW)/sizeof(buffW[0]));
2348 ok(hr == S_OK, "got 0x%08x\n", hr);
2349 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
2351 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2352 ok(hr == S_OK, "got 0x%08x\n", hr);
2354 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format2);
2355 ok(hr == S_OK, "got 0x%08x\n", hr);
2357 hr = IDWriteTextFormat_GetLocaleName(format2, buffW, sizeof(buffW)/sizeof(buffW[0]));
2358 ok(hr == S_OK, "got 0x%08x\n", hr);
2359 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
2361 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(buffW[0]), NULL);
2362 ok(hr == S_OK, "got 0x%08x\n", hr);
2363 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
2365 IDWriteTextFormat_Release(format2);
2366 IDWriteTextLayout_Release(layout);
2367 IDWriteTextFormat_Release(format);
2369 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2370 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2371 ok(hr == S_OK, "got 0x%08x\n", hr);
2373 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2374 ok(hr == S_OK, "got 0x%08x\n", hr);
2376 range.startPosition = 0;
2377 range.length = 1;
2378 hr = IDWriteTextLayout_SetLocaleName(layout, enusW, range);
2379 ok(hr == S_OK, "got 0x%08x\n", hr);
2381 hr = IDWriteTextLayout_SetLocaleName(layout, NULL, range);
2382 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2384 /* invalid locale name is allowed */
2385 hr = IDWriteTextLayout_SetLocaleName(layout, strW, range);
2386 ok(hr == S_OK, "got 0x%08x\n", hr);
2388 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 0, NULL);
2389 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2391 if (0) /* crashes on native */
2392 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 1, NULL);
2394 buffW[0] = 0;
2395 range.length = 0;
2396 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), &range);
2397 ok(hr == S_OK, "got 0x%08x\n", hr);
2398 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
2399 ok(range.startPosition == 0 && range.length == 1, "got %u,%u\n", range.startPosition, range.length);
2401 /* get with a shorter buffer */
2402 buffW[0] = 0xa;
2403 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, 1, NULL);
2404 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2405 ok(buffW[0] == 0, "got %x\n", buffW[0]);
2407 /* name is too long */
2408 lstrcpyW(buffW, strW);
2409 while (lstrlenW(buffW) <= LOCALE_NAME_MAX_LENGTH)
2410 lstrcatW(buffW, strW);
2412 range.startPosition = 0;
2413 range.length = 1;
2414 hr = IDWriteTextLayout_SetLocaleName(layout, buffW, range);
2415 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2417 buffW[0] = 0;
2418 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), NULL);
2419 ok(hr == S_OK, "got 0x%08x\n", hr);
2420 ok(!lstrcmpW(buffW, strW), "got %s\n", wine_dbgstr_w(buffW));
2422 /* set initial locale name for whole text, except with a different casing */
2423 range.startPosition = 0;
2424 range.length = 4;
2425 hr = IDWriteTextLayout_SetLocaleName(layout, eNuSW, range);
2426 ok(hr == S_OK, "got 0x%08x\n", hr);
2428 buffW[0] = 0;
2429 range.length = 0;
2430 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, sizeof(buffW)/sizeof(WCHAR), &range);
2431 ok(hr == S_OK, "got 0x%08x\n", hr);
2432 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
2433 ok((range.startPosition == 0 && range.length == ~0u) ||
2434 broken(range.startPosition == 0 && range.length == 4) /* vista/win7 */, "got %u,%u\n", range.startPosition, range.length);
2436 /* check what's returned for positions after the text */
2437 buffW[0] = 0;
2438 range.length = 0;
2439 hr = IDWriteTextLayout_GetLocaleName(layout, 100, buffW, sizeof(buffW)/sizeof(WCHAR), &range);
2440 ok(hr == S_OK, "got 0x%08x\n", hr);
2441 ok(!lstrcmpW(buffW, enusW), "got %s\n", wine_dbgstr_w(buffW));
2442 ok((range.startPosition == 0 && range.length == ~0u) ||
2443 broken(range.startPosition == 4 && range.length == ~0u-4) /* vista/win7 */, "got %u,%u\n", range.startPosition, range.length);
2445 IDWriteTextLayout_Release(layout);
2446 IDWriteTextFormat_Release(format);
2447 IDWriteFactory_Release(factory);
2450 static void test_SetPairKerning(void)
2452 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
2453 DWRITE_CLUSTER_METRICS clusters[4];
2454 IDWriteTextLayout1 *layout1;
2455 IDWriteTextFormat *format;
2456 IDWriteTextLayout *layout;
2457 DWRITE_TEXT_RANGE range;
2458 IDWriteFactory *factory;
2459 BOOL kerning;
2460 UINT32 count;
2461 HRESULT hr;
2463 factory = create_factory();
2465 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2466 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2467 ok(hr == S_OK, "got 0x%08x\n", hr);
2469 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2470 ok(hr == S_OK, "got 0x%08x\n", hr);
2471 IDWriteTextFormat_Release(format);
2473 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1);
2474 IDWriteTextLayout_Release(layout);
2476 if (hr != S_OK) {
2477 win_skip("SetPairKerning() is not supported.\n");
2478 IDWriteFactory_Release(factory);
2479 return;
2482 if (0) { /* crashes on native */
2483 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, NULL);
2484 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, &range);
2487 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, NULL);
2488 ok(hr == S_OK, "got 0x%08x\n", hr);
2490 range.startPosition = 0;
2491 range.length = 0;
2492 kerning = TRUE;
2493 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
2494 ok(hr == S_OK, "got 0x%08x\n", hr);
2495 ok(!kerning, "got %d\n", kerning);
2496 ok(range.length == ~0u, "got %u\n", range.length);
2498 count = 0;
2499 hr = IDWriteTextLayout1_GetClusterMetrics(layout1, clusters, 4, &count);
2500 ok(hr == S_OK, "got 0x%08x\n", hr);
2501 todo_wine
2502 ok(count == 3, "got %u\n", count);
2503 if (count == 3) {
2504 ok(clusters[0].length == 1, "got %u\n", clusters[0].length);
2505 ok(clusters[1].length == 2, "got %u\n", clusters[1].length);
2506 ok(clusters[2].length == 1, "got %u\n", clusters[2].length);
2508 /* pair kerning flag participates in itemization - combining characters
2509 breaks */
2510 range.startPosition = 0;
2511 range.length = 2;
2512 hr = IDWriteTextLayout1_SetPairKerning(layout1, 2, range);
2513 ok(hr == S_OK, "got 0x%08x\n", hr);
2515 kerning = FALSE;
2516 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
2517 ok(hr == S_OK, "got 0x%08x\n", hr);
2518 ok(kerning == TRUE, "got %d\n", kerning);
2520 count = 0;
2521 hr = IDWriteTextLayout1_GetClusterMetrics(layout1, clusters, 4, &count);
2522 ok(hr == S_OK, "got 0x%08x\n", hr);
2523 ok(count == 4, "got %u\n", count);
2524 ok(clusters[0].length == 1, "got %u\n", clusters[0].length);
2525 ok(clusters[1].length == 1, "got %u\n", clusters[1].length);
2526 ok(clusters[2].length == 1, "got %u\n", clusters[2].length);
2527 ok(clusters[3].length == 1, "got %u\n", clusters[3].length);
2529 IDWriteTextLayout1_Release(layout1);
2530 IDWriteFactory_Release(factory);
2533 static void test_SetVerticalGlyphOrientation(void)
2535 static const WCHAR strW[] = {'a','b','c','d',0};
2536 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation;
2537 IDWriteTextLayout2 *layout2;
2538 IDWriteTextFormat *format;
2539 IDWriteTextLayout *layout;
2540 IDWriteFactory *factory;
2541 HRESULT hr;
2543 factory = create_factory();
2545 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2546 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2547 ok(hr == S_OK, "got 0x%08x\n", hr);
2549 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2550 ok(hr == S_OK, "got 0x%08x\n", hr);
2551 IDWriteTextFormat_Release(format);
2553 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
2554 IDWriteTextLayout_Release(layout);
2556 if (hr != S_OK) {
2557 win_skip("SetVerticalGlyphOrientation() is not supported.\n");
2558 IDWriteFactory_Release(factory);
2559 return;
2562 orientation = IDWriteTextLayout2_GetVerticalGlyphOrientation(layout2);
2563 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT, "got %d\n", orientation);
2565 hr = IDWriteTextLayout2_SetVerticalGlyphOrientation(layout2, DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED+1);
2566 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2568 IDWriteTextLayout2_Release(layout2);
2569 IDWriteFactory_Release(factory);
2572 static void test_fallback(void)
2574 static const WCHAR strW[] = {'a','b','c','d',0};
2575 IDWriteFontFallback *fallback, *fallback2;
2576 IDWriteTextLayout2 *layout2;
2577 IDWriteTextFormat1 *format1;
2578 IDWriteTextFormat *format;
2579 IDWriteTextLayout *layout;
2580 IDWriteFactory2 *factory2;
2581 IDWriteFactory *factory;
2582 HRESULT hr;
2584 factory = create_factory();
2586 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2587 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2588 ok(hr == S_OK, "got 0x%08x\n", hr);
2590 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2591 ok(hr == S_OK, "got 0x%08x\n", hr);
2592 IDWriteTextFormat_Release(format);
2594 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
2595 IDWriteTextLayout_Release(layout);
2597 if (hr != S_OK) {
2598 win_skip("GetFontFallback() is not supported.\n");
2599 IDWriteFactory_Release(factory);
2600 return;
2603 if (0) /* crashes on native */
2604 hr = IDWriteTextLayout2_GetFontFallback(layout2, NULL);
2606 fallback = (void*)0xdeadbeef;
2607 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback);
2608 ok(hr == S_OK, "got 0x%08x\n", hr);
2609 ok(fallback == NULL, "got %p\n", fallback);
2611 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
2612 ok(hr == S_OK, "got 0x%08x\n", hr);
2614 fallback = (void*)0xdeadbeef;
2615 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback);
2616 ok(hr == S_OK, "got 0x%08x\n", hr);
2617 ok(fallback == NULL, "got %p\n", fallback);
2619 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
2620 ok(hr == S_OK, "got 0x%08x\n", hr);
2622 fallback = NULL;
2623 hr = IDWriteFactory2_GetSystemFontFallback(factory2, &fallback);
2624 ok(hr == S_OK, "got 0x%08x\n", hr);
2625 ok(fallback != NULL, "got %p\n", fallback);
2627 hr = IDWriteTextFormat1_SetFontFallback(format1, fallback);
2628 ok(hr == S_OK, "got 0x%08x\n", hr);
2630 fallback2 = (void*)0xdeadbeef;
2631 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback2);
2632 ok(hr == S_OK, "got 0x%08x\n", hr);
2633 ok(fallback2 == fallback, "got %p\n", fallback2);
2635 hr = IDWriteTextLayout2_SetFontFallback(layout2, NULL);
2636 ok(hr == S_OK, "got 0x%08x\n", hr);
2638 fallback2 = (void*)0xdeadbeef;
2639 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback2);
2640 ok(hr == S_OK, "got 0x%08x\n", hr);
2641 ok(fallback2 == NULL, "got %p\n", fallback2);
2643 IDWriteFontFallback_Release(fallback);
2644 IDWriteTextFormat1_Release(format1);
2645 IDWriteTextLayout2_Release(layout2);
2646 IDWriteFactory_Release(factory);
2649 static void test_DetermineMinWidth(void)
2651 struct minwidth_test {
2652 const WCHAR text[10]; /* text to create a layout for */
2653 const WCHAR mintext[10]; /* text that represents sequence of minimal width */
2654 } minwidth_tests[] = {
2655 { {' ','a','b',' ',0}, {'a','b',0} },
2656 { {'a','\n',' ',' ',0}, {'a',0} },
2657 { {'a','\n',' ',' ','b',0}, {'b',0} },
2658 { {'a','b','c','\n',' ',' ','b',0}, {'a','b','c',0} },
2660 static const WCHAR strW[] = {'a','b','c','d',0};
2661 DWRITE_CLUSTER_METRICS metrics[10];
2662 IDWriteTextFormat *format;
2663 IDWriteTextLayout *layout;
2664 IDWriteFactory *factory;
2665 UINT32 count, i, j;
2666 FLOAT minwidth;
2667 HRESULT hr;
2669 factory = create_factory();
2671 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2672 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2673 ok(hr == S_OK, "got 0x%08x\n", hr);
2675 hr = IDWriteFactory_CreateTextLayout(factory, strW, lstrlenW(strW), format, 1000.0, 1000.0, &layout);
2676 ok(hr == S_OK, "got 0x%08x\n", hr);
2678 hr = IDWriteTextLayout_DetermineMinWidth(layout, NULL);
2679 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2680 IDWriteTextLayout_Release(layout);
2682 /* empty string */
2683 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 100.0f, 100.0f, &layout);
2684 ok(hr == S_OK, "got 0x%08x\n", hr);
2686 minwidth = 1.0f;
2687 hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
2688 ok(hr == S_OK, "got 0x%08x\n", hr);
2689 ok(minwidth == 0.0f, "got %f\n", minwidth);
2690 IDWriteTextLayout_Release(layout);
2692 for (i = 0; i < sizeof(minwidth_tests)/sizeof(minwidth_tests[0]); i++) {
2693 FLOAT width = 0.0f;
2695 /* measure expected width */
2696 hr = IDWriteFactory_CreateTextLayout(factory, minwidth_tests[i].mintext, lstrlenW(minwidth_tests[i].mintext), format, 1000.0f, 1000.0f, &layout);
2697 ok(hr == S_OK, "got 0x%08x\n", hr);
2699 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
2700 ok(hr == S_OK, "got 0x%08x\n", hr);
2702 for (j = 0; j < count; j++)
2703 width += metrics[j].width;
2705 IDWriteTextLayout_Release(layout);
2707 hr = IDWriteFactory_CreateTextLayout(factory, minwidth_tests[i].text, lstrlenW(minwidth_tests[i].text), format, 1000.0f, 1000.0f, &layout);
2708 ok(hr == S_OK, "got 0x%08x\n", hr);
2710 minwidth = 0.0f;
2711 hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
2712 ok(hr == S_OK, "got 0x%08x\n", hr);
2713 ok(minwidth == width, "test %u: expected width %f, got %f\n", i, width, minwidth);
2715 IDWriteTextLayout_Release(layout);
2718 IDWriteTextFormat_Release(format);
2719 IDWriteFactory_Release(factory);
2722 static void test_SetFontSize(void)
2724 static const WCHAR strW[] = {'a','b','c','d',0};
2725 IDWriteTextFormat *format;
2726 IDWriteTextLayout *layout;
2727 IDWriteFactory *factory;
2728 DWRITE_TEXT_RANGE r;
2729 FLOAT size;
2730 HRESULT hr;
2732 factory = create_factory();
2734 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2735 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2736 ok(hr == S_OK, "got 0x%08x\n", hr);
2738 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2739 ok(hr == S_OK, "got 0x%08x\n", hr);
2741 /* negative/zero size */
2742 r.startPosition = 1;
2743 r.length = 1;
2744 hr = IDWriteTextLayout_SetFontSize(layout, -15.0, r);
2745 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2747 hr = IDWriteTextLayout_SetFontSize(layout, 0.0, r);
2748 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2750 r.startPosition = 1;
2751 r.length = 0;
2752 size = 0.0;
2753 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
2754 ok(hr == S_OK, "got 0x%08x\n", hr);
2755 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2756 ok(size == 10.0, "got %.2f\n", size);
2758 r.startPosition = 1;
2759 r.length = 1;
2760 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
2761 ok(hr == S_OK, "got 0x%08x\n", hr);
2763 /* zero length range */
2764 r.startPosition = 1;
2765 r.length = 0;
2766 hr = IDWriteTextLayout_SetFontSize(layout, 123.0, r);
2767 ok(hr == S_OK, "got 0x%08x\n", hr);
2769 size = 0.0;
2770 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
2771 ok(hr == S_OK, "got 0x%08x\n", hr);
2772 ok(size == 15.0, "got %.2f\n", size);
2774 r.startPosition = 0;
2775 r.length = 4;
2776 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
2777 ok(hr == S_OK, "got 0x%08x\n", hr);
2779 size = 0.0;
2780 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
2781 ok(hr == S_OK, "got 0x%08x\n", hr);
2782 ok(size == 15.0, "got %.2f\n", size);
2784 size = 0.0;
2785 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
2786 ok(hr == S_OK, "got 0x%08x\n", hr);
2787 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2788 ok(size == 15.0, "got %.2f\n", size);
2790 size = 15.0;
2791 r.startPosition = r.length = 0;
2792 hr = IDWriteTextLayout_GetFontSize(layout, 20, &size, &r);
2793 ok(hr == S_OK, "got 0x%08x\n", hr);
2794 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2795 ok(size == 10.0, "got %.2f\n", size);
2797 r.startPosition = 100;
2798 r.length = 4;
2799 hr = IDWriteTextLayout_SetFontSize(layout, 25.0, r);
2800 ok(hr == S_OK, "got 0x%08x\n", hr);
2802 size = 15.0;
2803 r.startPosition = r.length = 0;
2804 hr = IDWriteTextLayout_GetFontSize(layout, 100, &size, &r);
2805 ok(hr == S_OK, "got 0x%08x\n", hr);
2806 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2807 ok(size == 25.0, "got %.2f\n", size);
2809 IDWriteTextLayout_Release(layout);
2810 IDWriteTextFormat_Release(format);
2811 IDWriteFactory_Release(factory);
2814 static void test_SetFontFamilyName(void)
2816 static const WCHAR taHomaW[] = {'T','a','H','o','m','a',0};
2817 static const WCHAR arialW[] = {'A','r','i','a','l',0};
2818 static const WCHAR strW[] = {'a','b','c','d',0};
2819 IDWriteTextFormat *format;
2820 IDWriteTextLayout *layout;
2821 IDWriteFactory *factory;
2822 DWRITE_TEXT_RANGE r;
2823 WCHAR nameW[50];
2824 HRESULT hr;
2826 factory = create_factory();
2828 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2829 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2830 ok(hr == S_OK, "got 0x%08x\n", hr);
2832 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2833 ok(hr == S_OK, "got 0x%08x\n", hr);
2835 /* NULL name */
2836 r.startPosition = 1;
2837 r.length = 1;
2838 hr = IDWriteTextLayout_SetFontFamilyName(layout, NULL, r);
2839 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2841 r.startPosition = 1;
2842 r.length = 0;
2843 nameW[0] = 0;
2844 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2845 ok(hr == S_OK, "got 0x%08x\n", hr);
2846 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2848 /* set name only different in casing */
2849 r.startPosition = 1;
2850 r.length = 1;
2851 hr = IDWriteTextLayout_SetFontFamilyName(layout, taHomaW, r);
2852 ok(hr == S_OK, "got 0x%08x\n", hr);
2854 /* zero length range */
2855 r.startPosition = 1;
2856 r.length = 0;
2857 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
2858 ok(hr == S_OK, "got 0x%08x\n", hr);
2860 r.startPosition = 0;
2861 r.length = 0;
2862 nameW[0] = 0;
2863 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2864 ok(hr == S_OK, "got 0x%08x\n", hr);
2865 ok(!lstrcmpW(nameW, taHomaW), "got %s\n", wine_dbgstr_w(nameW));
2866 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2868 r.startPosition = 1;
2869 r.length = 1;
2870 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
2871 ok(hr == S_OK, "got 0x%08x\n", hr);
2873 r.startPosition = 1;
2874 r.length = 0;
2875 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2876 ok(hr == S_OK, "got 0x%08x\n", hr);
2877 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2879 r.startPosition = 0;
2880 r.length = 4;
2881 hr = IDWriteTextLayout_SetFontFamilyName(layout, arialW, r);
2882 ok(hr == S_OK, "got 0x%08x\n", hr);
2884 nameW[0] = 0;
2885 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, sizeof(nameW)/sizeof(WCHAR), &r);
2886 ok(hr == S_OK, "got 0x%08x\n", hr);
2887 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2888 ok(!lstrcmpW(nameW, arialW), "got name %s\n", wine_dbgstr_w(nameW));
2890 IDWriteTextLayout_Release(layout);
2891 IDWriteTextFormat_Release(format);
2892 IDWriteFactory_Release(factory);
2895 static void test_SetFontStyle(void)
2897 static const WCHAR strW[] = {'a','b','c','d',0};
2898 IDWriteTextFormat *format;
2899 IDWriteTextLayout *layout;
2900 IDWriteFactory *factory;
2901 DWRITE_FONT_STYLE style;
2902 DWRITE_TEXT_RANGE r;
2903 HRESULT hr;
2905 factory = create_factory();
2907 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2908 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2909 ok(hr == S_OK, "got 0x%08x\n", hr);
2911 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2912 ok(hr == S_OK, "got 0x%08x\n", hr);
2914 /* invalid style value */
2915 r.startPosition = 1;
2916 r.length = 1;
2917 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC+1, r);
2918 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2920 r.startPosition = 1;
2921 r.length = 0;
2922 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
2923 ok(hr == S_OK, "got 0x%08x\n", hr);
2924 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2925 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
2927 r.startPosition = 1;
2928 r.length = 1;
2929 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC, r);
2930 ok(hr == S_OK, "got 0x%08x\n", hr);
2932 /* zero length range */
2933 r.startPosition = 1;
2934 r.length = 0;
2935 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_NORMAL, r);
2936 ok(hr == S_OK, "got 0x%08x\n", hr);
2938 style = DWRITE_FONT_STYLE_NORMAL;
2939 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
2940 ok(hr == S_OK, "got 0x%08x\n", hr);
2941 ok(style == DWRITE_FONT_STYLE_ITALIC, "got %d\n", style);
2943 r.startPosition = 0;
2944 r.length = 4;
2945 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
2946 ok(hr == S_OK, "got 0x%08x\n", hr);
2948 style = DWRITE_FONT_STYLE_ITALIC;
2949 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
2950 ok(hr == S_OK, "got 0x%08x\n", hr);
2951 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2953 style = DWRITE_FONT_STYLE_ITALIC;
2954 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
2955 ok(hr == S_OK, "got 0x%08x\n", hr);
2956 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2957 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2959 style = DWRITE_FONT_STYLE_ITALIC;
2960 r.startPosition = r.length = 0;
2961 hr = IDWriteTextLayout_GetFontStyle(layout, 20, &style, &r);
2962 ok(hr == S_OK, "got 0x%08x\n", hr);
2963 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2964 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
2966 r.startPosition = 100;
2967 r.length = 4;
2968 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
2969 ok(hr == S_OK, "got 0x%08x\n", hr);
2971 style = DWRITE_FONT_STYLE_NORMAL;
2972 r.startPosition = r.length = 0;
2973 hr = IDWriteTextLayout_GetFontStyle(layout, 100, &style, &r);
2974 ok(hr == S_OK, "got 0x%08x\n", hr);
2975 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2976 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
2978 IDWriteTextLayout_Release(layout);
2979 IDWriteTextFormat_Release(format);
2980 IDWriteFactory_Release(factory);
2983 static void test_SetFontStretch(void)
2985 static const WCHAR strW[] = {'a','b','c','d',0};
2986 DWRITE_FONT_STRETCH stretch;
2987 IDWriteTextFormat *format;
2988 IDWriteTextLayout *layout;
2989 IDWriteFactory *factory;
2990 DWRITE_TEXT_RANGE r;
2991 HRESULT hr;
2993 factory = create_factory();
2995 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2996 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
2997 ok(hr == S_OK, "got 0x%08x\n", hr);
2999 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
3000 ok(hr == S_OK, "got 0x%08x\n", hr);
3002 /* invalid stretch value */
3003 r.startPosition = 1;
3004 r.length = 1;
3005 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_ULTRA_EXPANDED+1, r);
3006 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3008 r.startPosition = 1;
3009 r.length = 0;
3010 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3011 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
3012 ok(hr == S_OK, "got 0x%08x\n", hr);
3013 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
3014 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
3016 r.startPosition = 1;
3017 r.length = 1;
3018 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_CONDENSED, r);
3019 ok(hr == S_OK, "got 0x%08x\n", hr);
3021 /* zero length range */
3022 r.startPosition = 1;
3023 r.length = 0;
3024 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_NORMAL, r);
3025 ok(hr == S_OK, "got 0x%08x\n", hr);
3027 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3028 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
3029 ok(hr == S_OK, "got 0x%08x\n", hr);
3030 ok(stretch == DWRITE_FONT_STRETCH_CONDENSED, "got %d\n", stretch);
3032 r.startPosition = 0;
3033 r.length = 4;
3034 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
3035 ok(hr == S_OK, "got 0x%08x\n", hr);
3037 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3038 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
3039 ok(hr == S_OK, "got 0x%08x\n", hr);
3040 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
3042 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3043 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
3044 ok(hr == S_OK, "got 0x%08x\n", hr);
3045 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
3046 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
3048 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3049 r.startPosition = r.length = 0;
3050 hr = IDWriteTextLayout_GetFontStretch(layout, 20, &stretch, &r);
3051 ok(hr == S_OK, "got 0x%08x\n", hr);
3052 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
3053 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
3055 r.startPosition = 100;
3056 r.length = 4;
3057 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
3058 ok(hr == S_OK, "got 0x%08x\n", hr);
3060 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3061 r.startPosition = r.length = 0;
3062 hr = IDWriteTextLayout_GetFontStretch(layout, 100, &stretch, &r);
3063 ok(hr == S_OK, "got 0x%08x\n", hr);
3064 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
3065 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
3067 /* trying to set undefined value */
3068 r.startPosition = 0;
3069 r.length = 2;
3070 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_UNDEFINED, r);
3071 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3073 IDWriteTextLayout_Release(layout);
3074 IDWriteTextFormat_Release(format);
3075 IDWriteFactory_Release(factory);
3078 static void test_SetStrikethrough(void)
3080 static const WCHAR strW[] = {'a','b','c','d',0};
3081 IDWriteTextFormat *format;
3082 IDWriteTextLayout *layout;
3083 IDWriteFactory *factory;
3084 DWRITE_TEXT_RANGE r;
3085 BOOL value;
3086 HRESULT hr;
3088 factory = create_factory();
3090 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3091 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
3092 ok(hr == S_OK, "got 0x%08x\n", hr);
3094 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
3095 ok(hr == S_OK, "got 0x%08x\n", hr);
3097 r.startPosition = 1;
3098 r.length = 0;
3099 value = TRUE;
3100 hr = IDWriteTextLayout_GetStrikethrough(layout, 0, &value, &r);
3101 ok(hr == S_OK, "got 0x%08x\n", hr);
3102 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
3103 ok(value == FALSE, "got %d\n", value);
3105 r.startPosition = 1;
3106 r.length = 1;
3107 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, r);
3108 ok(hr == S_OK, "got 0x%08x\n", hr);
3110 value = FALSE;
3111 hr = IDWriteTextLayout_GetStrikethrough(layout, 1, &value, &r);
3112 ok(hr == S_OK, "got 0x%08x\n", hr);
3113 ok(value == TRUE, "got %d\n", value);
3114 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
3116 value = TRUE;
3117 r.startPosition = r.length = 0;
3118 hr = IDWriteTextLayout_GetStrikethrough(layout, 20, &value, &r);
3119 ok(hr == S_OK, "got 0x%08x\n", hr);
3120 ok(r.startPosition == 2 && r.length == ~0u-2, "got %u, %u\n", r.startPosition, r.length);
3121 ok(value == FALSE, "got %d\n", value);
3123 r.startPosition = 100;
3124 r.length = 4;
3125 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, r);
3126 ok(hr == S_OK, "got 0x%08x\n", hr);
3128 value = FALSE;
3129 r.startPosition = r.length = 0;
3130 hr = IDWriteTextLayout_GetStrikethrough(layout, 100, &value, &r);
3131 ok(hr == S_OK, "got 0x%08x\n", hr);
3132 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
3133 ok(value == TRUE, "got %d\n", value);
3135 IDWriteTextLayout_Release(layout);
3136 IDWriteTextFormat_Release(format);
3137 IDWriteFactory_Release(factory);
3140 static void test_GetMetrics(void)
3142 static const WCHAR str2W[] = {0x2066,')',')',0x661,'(',0x627,')',0};
3143 static const WCHAR strW[] = {'a','b','c','d',0};
3144 static const WCHAR str3W[] = {'a',0};
3145 DWRITE_CLUSTER_METRICS clusters[4];
3146 DWRITE_TEXT_METRICS metrics;
3147 IDWriteTextFormat *format;
3148 IDWriteTextLayout *layout;
3149 IDWriteFactory *factory;
3150 UINT32 count, i;
3151 FLOAT width;
3152 HRESULT hr;
3154 factory = create_factory();
3156 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3157 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
3158 ok(hr == S_OK, "got 0x%08x\n", hr);
3160 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
3161 ok(hr == S_OK, "got 0x%08x\n", hr);
3163 count = 0;
3164 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count);
3165 ok(hr == S_OK, "got 0x%08x\n", hr);
3166 ok(count == 4, "got %u\n", count);
3167 for (i = 0, width = 0.0; i < count; i++)
3168 width += clusters[i].width;
3170 memset(&metrics, 0xcc, sizeof(metrics));
3171 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3172 ok(hr == S_OK, "got 0x%08x\n", hr);
3173 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
3174 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3175 ok(metrics.width == width, "got %.2f, expected %.2f\n", metrics.width, width);
3176 ok(metrics.widthIncludingTrailingWhitespace == width, "got %.2f, expected %.2f\n",
3177 metrics.widthIncludingTrailingWhitespace, width);
3178 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
3179 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3180 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
3181 ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
3182 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
3184 IDWriteTextLayout_Release(layout);
3186 /* a string with more complex bidi sequence */
3187 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 7, format, 500.0, 1000.0, &layout);
3188 ok(hr == S_OK, "got 0x%08x\n", hr);
3190 memset(&metrics, 0xcc, sizeof(metrics));
3191 metrics.maxBidiReorderingDepth = 0;
3192 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3193 ok(hr == S_OK, "got 0x%08x\n", hr);
3194 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
3195 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3196 ok(metrics.width > 0.0, "got %.2f\n", metrics.width);
3197 ok(metrics.widthIncludingTrailingWhitespace > 0.0, "got %.2f\n", metrics.widthIncludingTrailingWhitespace);
3198 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
3199 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3200 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
3201 todo_wine
3202 ok(metrics.maxBidiReorderingDepth > 1, "got %u\n", metrics.maxBidiReorderingDepth);
3203 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
3205 IDWriteTextLayout_Release(layout);
3207 /* single cluster layout */
3208 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 1, format, 500.0, 1000.0, &layout);
3209 ok(hr == S_OK, "got 0x%08x\n", hr);
3211 count = 0;
3212 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
3213 ok(hr == S_OK, "got 0x%08x\n", hr);
3214 ok(count == 1, "got %u\n", count);
3216 memset(&metrics, 0xcc, sizeof(metrics));
3217 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3218 ok(hr == S_OK, "got 0x%08x\n", hr);
3219 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
3220 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3221 ok(metrics.width == clusters[0].width, "got %.2f, expected %.2f\n", metrics.width, clusters[0].width);
3222 ok(metrics.widthIncludingTrailingWhitespace == clusters[0].width, "got %.2f\n", metrics.widthIncludingTrailingWhitespace);
3223 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
3224 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3225 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
3226 ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
3227 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
3228 IDWriteTextLayout_Release(layout);
3230 IDWriteTextFormat_Release(format);
3231 IDWriteFactory_Release(factory);
3234 static void test_SetFlowDirection(void)
3236 static const WCHAR strW[] = {'a','b','c','d',0};
3237 DWRITE_READING_DIRECTION reading;
3238 DWRITE_FLOW_DIRECTION flow;
3239 IDWriteTextFormat *format;
3240 IDWriteTextLayout *layout;
3241 IDWriteFactory *factory;
3242 HRESULT hr;
3244 factory = create_factory();
3246 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3247 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
3248 ok(hr == S_OK, "got 0x%08x\n", hr);
3250 flow = IDWriteTextFormat_GetFlowDirection(format);
3251 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
3253 reading = IDWriteTextFormat_GetReadingDirection(format);
3254 ok(reading == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", reading);
3256 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
3257 ok(hr == S_OK, "got 0x%08x\n", hr);
3258 IDWriteTextLayout_Release(layout);
3260 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT);
3261 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* vista,win7 */, "got 0x%08x\n", hr);
3262 if (hr == S_OK) {
3263 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
3264 ok(hr == S_OK, "got 0x%08x\n", hr);
3265 IDWriteTextLayout_Release(layout);
3267 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_TOP_TO_BOTTOM);
3268 ok(hr == S_OK, "got 0x%08x\n", hr);
3270 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
3271 ok(hr == S_OK, "got 0x%08x\n", hr);
3273 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
3274 ok(hr == S_OK, "got 0x%08x\n", hr);
3275 IDWriteTextLayout_Release(layout);
3277 else
3278 win_skip("DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT is not supported\n");
3280 IDWriteTextFormat_Release(format);
3281 IDWriteFactory_Release(factory);
3284 static const struct drawcall_entry draweffect_seq[] = {
3285 { DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0x0300,0}, {'e','n','-','u','s',0}, 2 },
3286 { DRAW_GLYPHRUN, {'d',0}, {'e','n','-','u','s',0}, 1 },
3287 { DRAW_LAST_KIND }
3290 static const struct drawcall_entry draweffect2_seq[] = {
3291 { DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0}, {'e','n','-','u','s',0}, 2 },
3292 { DRAW_GLYPHRUN, {'c','d',0}, {'e','n','-','u','s',0}, 2 },
3293 { DRAW_LAST_KIND }
3296 static const struct drawcall_entry draweffect3_seq[] = {
3297 { DRAW_INLINE|DRAW_EFFECT },
3298 { DRAW_LAST_KIND }
3301 static const struct drawcall_entry draweffect4_seq[] = {
3302 { DRAW_INLINE },
3303 { DRAW_LAST_KIND }
3306 static void test_SetDrawingEffect(void)
3308 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
3309 static const WCHAR str2W[] = {'a','e','c','d',0};
3310 IDWriteInlineObject *sign;
3311 IDWriteTextFormat *format;
3312 IDWriteTextLayout *layout;
3313 IDWriteFactory *factory;
3314 IUnknown *unk, *effect;
3315 DWRITE_TEXT_RANGE r;
3316 HRESULT hr;
3317 LONG ref;
3319 factory = create_factory();
3321 effect = create_test_effect();
3323 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3324 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
3325 ok(hr == S_OK, "got 0x%08x\n", hr);
3327 /* string with combining mark */
3328 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
3329 ok(hr == S_OK, "got 0x%08x\n", hr);
3331 /* set effect past the end of text */
3332 r.startPosition = 100;
3333 r.length = 10;
3334 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3335 ok(hr == S_OK, "got 0x%08x\n", hr);
3337 r.startPosition = r.length = 0;
3338 hr = IDWriteTextLayout_GetDrawingEffect(layout, 101, &unk, &r);
3339 ok(hr == S_OK, "got 0x%08x\n", hr);
3340 ok(r.startPosition == 100 && r.length == 10, "got %u, %u\n", r.startPosition, r.length);
3341 IUnknown_Release(unk);
3343 r.startPosition = r.length = 0;
3344 unk = (void*)0xdeadbeef;
3345 hr = IDWriteTextLayout_GetDrawingEffect(layout, 1000, &unk, &r);
3346 ok(hr == S_OK, "got 0x%08x\n", hr);
3347 ok(r.startPosition == 110 && r.length == ~0u-110, "got %u, %u\n", r.startPosition, r.length);
3348 ok(unk == NULL, "got %p\n", unk);
3350 /* effect is applied to clusters, not individual text positions */
3351 r.startPosition = 0;
3352 r.length = 2;
3353 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3354 ok(hr == S_OK, "got 0x%08x\n", hr);
3356 flush_sequence(sequences, RENDERER_ID);
3357 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3358 ok(hr == S_OK, "got 0x%08x\n", hr);
3359 ok_sequence(sequences, RENDERER_ID, draweffect_seq, "effect draw test", TRUE);
3360 IDWriteTextLayout_Release(layout);
3362 /* simple string */
3363 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 1000.0, &layout);
3364 ok(hr == S_OK, "got 0x%08x\n", hr);
3366 r.startPosition = 0;
3367 r.length = 2;
3368 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3369 ok(hr == S_OK, "got 0x%08x\n", hr);
3371 flush_sequence(sequences, RENDERER_ID);
3372 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3373 ok(hr == S_OK, "got 0x%08x\n", hr);
3374 ok_sequence(sequences, RENDERER_ID, draweffect2_seq, "effect draw test 2", FALSE);
3375 IDWriteTextLayout_Release(layout);
3377 /* Inline object - effect set for same range */
3378 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
3379 ok(hr == S_OK, "got 0x%08x\n", hr);
3381 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 1000.0, &layout);
3382 ok(hr == S_OK, "got 0x%08x\n", hr);
3384 r.startPosition = 0;
3385 r.length = 4;
3386 hr = IDWriteTextLayout_SetInlineObject(layout, sign, r);
3387 ok(hr == S_OK, "got 0x%08x\n", hr);
3389 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3390 ok(hr == S_OK, "got 0x%08x\n", hr);
3392 flush_sequence(sequences, RENDERER_ID);
3393 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3394 ok(hr == S_OK, "got 0x%08x\n", hr);
3395 ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 3", FALSE);
3397 /* now set effect somewhere inside a range replaced by inline object */
3398 hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
3399 ok(hr == S_OK, "got 0x%08x\n", hr);
3401 r.startPosition = 1;
3402 r.length = 1;
3403 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3404 ok(hr == S_OK, "got 0x%08x\n", hr);
3406 /* no effect is reported in this case */
3407 flush_sequence(sequences, RENDERER_ID);
3408 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3409 ok(hr == S_OK, "got 0x%08x\n", hr);
3410 ok_sequence(sequences, RENDERER_ID, draweffect4_seq, "effect draw test 4", FALSE);
3412 r.startPosition = 0;
3413 r.length = 4;
3414 hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
3415 ok(hr == S_OK, "got 0x%08x\n", hr);
3417 r.startPosition = 0;
3418 r.length = 1;
3419 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3420 ok(hr == S_OK, "got 0x%08x\n", hr);
3422 /* first range position is all that matters for inline ranges */
3423 flush_sequence(sequences, RENDERER_ID);
3424 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3425 ok(hr == S_OK, "got 0x%08x\n", hr);
3426 ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 5", FALSE);
3428 IDWriteTextLayout_Release(layout);
3430 ref = IUnknown_Release(effect);
3431 ok(ref == 0, "Unexpected effect refcount %u\n", ref);
3432 IDWriteInlineObject_Release(sign);
3433 IDWriteTextFormat_Release(format);
3434 IDWriteFactory_Release(factory);
3437 static BOOL get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, UINT32 size)
3439 UINT32 index;
3440 BOOL exists = FALSE;
3441 HRESULT hr;
3443 hr = IDWriteLocalizedStrings_FindLocaleName(strings, enusW, &index, &exists);
3444 ok(hr == S_OK, "got 0x%08x\n", hr);
3446 if (exists) {
3447 hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
3448 ok(hr == S_OK, "got 0x%08x\n", hr);
3450 else
3451 *buff = 0;
3453 return exists;
3456 static void test_GetLineMetrics(void)
3458 static const WCHAR str3W[] = {'a','\r','b','\n','c','\n','\r','d','\r','\n',0};
3459 static const WCHAR strW[] = {'a','b','c','d',' ',0};
3460 static const WCHAR str2W[] = {'a','b','\r','c','d',0};
3461 static const WCHAR str4W[] = {'a','\r',0};
3462 static const WCHAR emptyW[] = {0};
3463 IDWriteFontCollection *syscollection;
3464 DWRITE_FONT_METRICS fontmetrics;
3465 DWRITE_LINE_METRICS metrics[6];
3466 UINT32 count, i, familycount;
3467 IDWriteTextFormat *format;
3468 IDWriteTextLayout *layout;
3469 IDWriteFontFace *fontface;
3470 IDWriteFactory *factory;
3471 DWRITE_TEXT_RANGE range;
3472 WCHAR nameW[256];
3473 HRESULT hr;
3475 factory = create_factory();
3477 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3478 DWRITE_FONT_STRETCH_NORMAL, 2048.0, enusW, &format);
3479 ok(hr == S_OK, "got 0x%08x\n", hr);
3481 hr = IDWriteFactory_CreateTextLayout(factory, strW, 5, format, 30000.0, 1000.0, &layout);
3482 ok(hr == S_OK, "got 0x%08x\n", hr);
3484 count = 0;
3485 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 0, &count);
3486 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3487 ok(count == 1, "got count %u\n", count);
3489 memset(metrics, 0, sizeof(metrics));
3490 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 1, &count);
3491 ok(hr == S_OK, "got 0x%08x\n", hr);
3492 ok(metrics[0].length == 5, "got %u\n", metrics[0].length);
3493 ok(metrics[0].trailingWhitespaceLength == 1, "got %u\n", metrics[0].trailingWhitespaceLength);
3495 ok(metrics[0].newlineLength == 0, "got %u\n", metrics[0].newlineLength);
3496 ok(metrics[0].isTrimmed == FALSE, "got %d\n", metrics[0].isTrimmed);
3498 IDWriteTextLayout_Release(layout);
3499 IDWriteTextFormat_Release(format);
3501 /* Test line height and baseline calculation */
3502 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
3503 ok(hr == S_OK, "got 0x%08x\n", hr);
3504 familycount = IDWriteFontCollection_GetFontFamilyCount(syscollection);
3506 for (i = 0; i < familycount; i++) {
3507 IDWriteLocalizedStrings *names;
3508 IDWriteFontFamily *family;
3509 IDWriteFont *font;
3510 BOOL exists;
3512 format = NULL;
3513 layout = NULL;
3515 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
3516 ok(hr == S_OK, "got 0x%08x\n", hr);
3518 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
3519 DWRITE_FONT_STYLE_NORMAL, &font);
3520 ok(hr == S_OK, "got 0x%08x\n", hr);
3522 hr = IDWriteFont_CreateFontFace(font, &fontface);
3523 ok(hr == S_OK, "got 0x%08x\n", hr);
3525 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
3526 ok(hr == S_OK, "got 0x%08x\n", hr);
3528 if (!(exists = get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0])))) {
3529 IDWriteLocalFontFileLoader *localloader;
3530 IDWriteFontFileLoader *loader;
3531 IDWriteFontFile *file;
3532 const void *key;
3533 UINT32 keysize;
3534 UINT32 count;
3536 count = 1;
3537 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
3538 ok(hr == S_OK, "got 0x%08x\n", hr);
3540 hr = IDWriteFontFile_GetLoader(file, &loader);
3541 ok(hr == S_OK, "got 0x%08x\n", hr);
3543 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
3544 ok(hr == S_OK, "got 0x%08x\n", hr);
3545 IDWriteFontFileLoader_Release(loader);
3547 hr = IDWriteFontFile_GetReferenceKey(file, &key, &keysize);
3548 ok(hr == S_OK, "got 0x%08x\n", hr);
3550 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, keysize, nameW, sizeof(nameW)/sizeof(*nameW));
3551 ok(hr == S_OK, "got 0x%08x\n", hr);
3553 skip("Failed to get English family name, font file %s\n", wine_dbgstr_w(nameW));
3555 IDWriteLocalFontFileLoader_Release(localloader);
3556 IDWriteFontFile_Release(file);
3559 IDWriteLocalizedStrings_Release(names);
3560 IDWriteFont_Release(font);
3562 if (!exists)
3563 goto cleanup;
3565 IDWriteFontFace_GetMetrics(fontface, &fontmetrics);
3566 hr = IDWriteFactory_CreateTextFormat(factory, nameW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3567 DWRITE_FONT_STRETCH_NORMAL, fontmetrics.designUnitsPerEm, enusW, &format);
3568 ok(hr == S_OK, "got 0x%08x\n", hr);
3570 hr = IDWriteFactory_CreateTextLayout(factory, emptyW, 1, format, 30000.0f, 100.0f, &layout);
3571 ok(hr == S_OK, "got 0x%08x\n", hr);
3573 memset(metrics, 0, sizeof(metrics));
3574 count = 0;
3575 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
3576 ok(hr == S_OK, "got 0x%08x\n", hr);
3577 ok(count == 1, "got %u\n", count);
3579 ok(metrics[0].baseline == fontmetrics.ascent + fontmetrics.lineGap, "%s: got %.2f, expected %d, "
3580 "linegap %d\n", wine_dbgstr_w(nameW), metrics[0].baseline, fontmetrics.ascent + fontmetrics.lineGap,
3581 fontmetrics.lineGap);
3582 ok(metrics[0].height == fontmetrics.ascent + fontmetrics.descent + fontmetrics.lineGap,
3583 "%s: got %.2f, expected %d, linegap %d\n", wine_dbgstr_w(nameW), metrics[0].height,
3584 fontmetrics.ascent + fontmetrics.descent + fontmetrics.lineGap, fontmetrics.lineGap);
3586 cleanup:
3587 if (layout)
3588 IDWriteTextLayout_Release(layout);
3589 if (format)
3590 IDWriteTextFormat_Release(format);
3591 IDWriteFontFace_Release(fontface);
3592 IDWriteFontFamily_Release(family);
3594 IDWriteFontCollection_Release(syscollection);
3596 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3597 DWRITE_FONT_STRETCH_NORMAL, 2048.0f, enusW, &format);
3598 ok(hr == S_OK, "got 0x%08x\n", hr);
3600 fontface = get_fontface_from_format(format);
3601 ok(fontface != NULL, "got %p\n", fontface);
3603 /* force 2 lines */
3604 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 5, format, 10000.0, 1000.0, &layout);
3605 ok(hr == S_OK, "got 0x%08x\n", hr);
3607 memset(metrics, 0, sizeof(metrics));
3608 count = 0;
3609 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, sizeof(metrics)/sizeof(*metrics), &count);
3610 ok(hr == S_OK, "got 0x%08x\n", hr);
3611 ok(count == 2, "got %u\n", count);
3612 /* baseline is relative to a line, and is not accumulated */
3613 ok(metrics[0].baseline == metrics[1].baseline, "got %.2f, %.2f\n", metrics[0].baseline,
3614 metrics[1].baseline);
3616 IDWriteTextLayout_Release(layout);
3617 IDWriteTextFormat_Release(format);
3619 /* line breaks */
3620 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3621 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3622 ok(hr == S_OK, "got 0x%08x\n", hr);
3624 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 10, format, 100.0, 300.0, &layout);
3625 ok(hr == S_OK, "got 0x%08x\n", hr);
3627 memset(metrics, 0xcc, sizeof(metrics));
3628 count = 0;
3629 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, sizeof(metrics)/sizeof(*metrics), &count);
3630 ok(hr == S_OK, "got 0x%08x\n", hr);
3631 ok(count == 6, "got %u\n", count);
3633 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
3634 ok(metrics[1].length == 2, "got %u\n", metrics[1].length);
3635 ok(metrics[2].length == 2, "got %u\n", metrics[2].length);
3636 ok(metrics[3].length == 1, "got %u\n", metrics[3].length);
3637 ok(metrics[4].length == 3, "got %u\n", metrics[4].length);
3638 ok(metrics[5].length == 0, "got %u\n", metrics[5].length);
3640 ok(metrics[0].newlineLength == 1, "got %u\n", metrics[0].newlineLength);
3641 ok(metrics[1].newlineLength == 1, "got %u\n", metrics[1].newlineLength);
3642 ok(metrics[2].newlineLength == 1, "got %u\n", metrics[2].newlineLength);
3643 ok(metrics[3].newlineLength == 1, "got %u\n", metrics[3].newlineLength);
3644 ok(metrics[4].newlineLength == 2, "got %u\n", metrics[4].newlineLength);
3645 ok(metrics[5].newlineLength == 0, "got %u\n", metrics[5].newlineLength);
3647 ok(metrics[0].trailingWhitespaceLength == 1, "got %u\n", metrics[0].newlineLength);
3648 ok(metrics[1].trailingWhitespaceLength == 1, "got %u\n", metrics[1].newlineLength);
3649 ok(metrics[2].trailingWhitespaceLength == 1, "got %u\n", metrics[2].newlineLength);
3650 ok(metrics[3].trailingWhitespaceLength == 1, "got %u\n", metrics[3].newlineLength);
3651 ok(metrics[4].trailingWhitespaceLength == 2, "got %u\n", metrics[4].newlineLength);
3652 ok(metrics[5].trailingWhitespaceLength == 0, "got %u\n", metrics[5].newlineLength);
3654 IDWriteTextLayout_Release(layout);
3656 /* empty text layout */
3657 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 100.0f, 300.0f, &layout);
3658 ok(hr == S_OK, "got 0x%08x\n", hr);
3660 count = 0;
3661 memset(metrics, 0, sizeof(metrics));
3662 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 1, &count);
3663 ok(hr == S_OK, "got 0x%08x\n", hr);
3664 ok(count == 1, "got %u\n", count);
3665 ok(metrics[0].length == 0, "got %u\n", metrics[0].length);
3666 ok(metrics[0].trailingWhitespaceLength == 0, "got %u\n", metrics[0].trailingWhitespaceLength);
3667 ok(metrics[0].newlineLength == 0, "got %u\n", metrics[0].newlineLength);
3668 ok(metrics[0].height > 0.0f, "got %f\n", metrics[0].height);
3669 ok(metrics[0].baseline > 0.0f, "got %f\n", metrics[0].baseline);
3670 ok(!metrics[0].isTrimmed, "got %d\n", metrics[0].isTrimmed);
3672 /* change font size at first position, see if metrics changed */
3673 range.startPosition = 0;
3674 range.length = 1;
3675 hr = IDWriteTextLayout_SetFontSize(layout, 80.0f, range);
3676 ok(hr == S_OK, "got 0x%08x\n", hr);
3678 count = 0;
3679 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count);
3680 ok(hr == S_OK, "got 0x%08x\n", hr);
3681 ok(count == 1, "got %u\n", count);
3682 ok(metrics[1].height > metrics[0].height, "got %f\n", metrics[1].height);
3683 ok(metrics[1].baseline > metrics[0].baseline, "got %f\n", metrics[1].baseline);
3685 /* revert font size back to format value, set different size for position 1 */
3686 hr = IDWriteTextLayout_SetFontSize(layout, 12.0f, range);
3687 ok(hr == S_OK, "got 0x%08x\n", hr);
3689 range.startPosition = 1;
3690 range.length = 1;
3691 hr = IDWriteTextLayout_SetFontSize(layout, 80.0f, range);
3692 ok(hr == S_OK, "got 0x%08x\n", hr);
3694 memset(metrics + 1, 0, sizeof(*metrics));
3695 count = 0;
3696 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count);
3697 ok(hr == S_OK, "got 0x%08x\n", hr);
3698 ok(count == 1, "got %u\n", count);
3699 ok(metrics[1].height == metrics[0].height, "got %f\n", metrics[1].height);
3700 ok(metrics[1].baseline == metrics[0].baseline, "got %f\n", metrics[1].baseline);
3702 IDWriteTextLayout_Release(layout);
3704 /* text is "a\r" */
3705 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 2, format, 100.0f, 300.0f, &layout);
3706 ok(hr == S_OK, "got 0x%08x\n", hr);
3708 count = 0;
3709 memset(metrics, 0, sizeof(metrics));
3710 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, sizeof(metrics)/sizeof(*metrics), &count);
3711 ok(hr == S_OK, "got 0x%08x\n", hr);
3712 ok(count == 2, "got %u\n", count);
3713 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
3714 ok(metrics[0].newlineLength == 1, "got %u\n", metrics[0].newlineLength);
3715 ok(metrics[0].height > 0.0f, "got %f\n", metrics[0].height);
3716 ok(metrics[0].baseline > 0.0f, "got %f\n", metrics[0].baseline);
3717 ok(metrics[1].length == 0, "got %u\n", metrics[1].length);
3718 ok(metrics[1].newlineLength == 0, "got %u\n", metrics[1].newlineLength);
3719 ok(metrics[1].height > 0.0f, "got %f\n", metrics[1].height);
3720 ok(metrics[1].baseline > 0.0f, "got %f\n", metrics[1].baseline);
3722 range.startPosition = 1;
3723 range.length = 1;
3724 hr = IDWriteTextLayout_SetFontSize(layout, 80.0f, range);
3725 ok(hr == S_OK, "got 0x%08x\n", hr);
3727 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 2, 2, &count);
3728 ok(hr == S_OK, "got 0x%08x\n", hr);
3729 ok(count == 2, "got %u\n", count);
3730 ok(metrics[3].height > metrics[1].height, "got %f, old %f\n", metrics[3].height, metrics[1].height);
3731 ok(metrics[3].baseline > metrics[1].baseline, "got %f, old %f\n", metrics[3].baseline, metrics[1].baseline);
3733 /* revert to original format */
3734 hr = IDWriteTextLayout_SetFontSize(layout, 12.0f, range);
3735 ok(hr == S_OK, "got 0x%08x\n", hr);
3736 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 2, 2, &count);
3737 ok(hr == S_OK, "got 0x%08x\n", hr);
3738 ok(count == 2, "got %u\n", count);
3739 ok(metrics[3].height == metrics[1].height, "got %f, old %f\n", metrics[3].height, metrics[1].height);
3740 ok(metrics[3].baseline == metrics[1].baseline, "got %f, old %f\n", metrics[3].baseline, metrics[1].baseline);
3742 /* Switch to uniform spacing */
3743 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_UNIFORM, 456.0f, 123.0f);
3744 ok(hr == S_OK, "got 0x%08x\n", hr);
3746 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, sizeof(metrics)/sizeof(metrics[0]), &count);
3747 ok(hr == S_OK, "got 0x%08x\n", hr);
3748 ok(count == 2, "got %u\n", count);
3750 for (i = 0; i < count; i++) {
3751 ok(metrics[i].height == 456.0f, "%u: got line height %f\n", i, metrics[i].height);
3752 ok(metrics[i].baseline == 123.0f, "%u: got line baseline %f\n", i, metrics[i].baseline);
3755 IDWriteTextLayout_Release(layout);
3757 IDWriteTextFormat_Release(format);
3758 IDWriteFontFace_Release(fontface);
3759 IDWriteFactory_Release(factory);
3762 static void test_SetTextAlignment(void)
3764 static const WCHAR strW[] = {'a',0};
3766 static const WCHAR stringsW[][10] = {
3767 {'a',0},
3771 DWRITE_CLUSTER_METRICS clusters[10];
3772 DWRITE_TEXT_METRICS metrics;
3773 IDWriteTextFormat1 *format1;
3774 IDWriteTextFormat *format;
3775 IDWriteTextLayout *layout;
3776 IDWriteFactory *factory;
3777 DWRITE_TEXT_ALIGNMENT v;
3778 UINT32 count, i;
3779 HRESULT hr;
3781 factory = create_factory();
3783 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3784 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3785 ok(hr == S_OK, "got 0x%08x\n", hr);
3787 v = IDWriteTextFormat_GetTextAlignment(format);
3788 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3790 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3791 ok(hr == S_OK, "got 0x%08x\n", hr);
3793 v = IDWriteTextLayout_GetTextAlignment(layout);
3794 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3796 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
3797 ok(hr == S_OK, "got 0x%08x\n", hr);
3799 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
3800 ok(hr == S_OK, "got 0x%08x\n", hr);
3802 v = IDWriteTextFormat_GetTextAlignment(format);
3803 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3805 v = IDWriteTextLayout_GetTextAlignment(layout);
3806 ok(v == DWRITE_TEXT_ALIGNMENT_TRAILING, "got %d\n", v);
3808 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
3809 if (hr == S_OK) {
3810 hr = IDWriteTextFormat1_SetTextAlignment(format1, DWRITE_TEXT_ALIGNMENT_CENTER);
3811 ok(hr == S_OK, "got 0x%08x\n", hr);
3813 v = IDWriteTextFormat_GetTextAlignment(format);
3814 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3816 v = IDWriteTextLayout_GetTextAlignment(layout);
3817 ok(v == DWRITE_TEXT_ALIGNMENT_CENTER, "got %d\n", v);
3819 v = IDWriteTextFormat1_GetTextAlignment(format1);
3820 ok(v == DWRITE_TEXT_ALIGNMENT_CENTER, "got %d\n", v);
3822 IDWriteTextFormat1_Release(format1);
3824 else
3825 win_skip("IDWriteTextFormat1 is not supported\n");
3827 IDWriteTextLayout_Release(layout);
3829 for (i = 0; i < sizeof(stringsW)/sizeof(stringsW[0]); i++) {
3830 FLOAT text_width;
3832 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING);
3833 ok(hr == S_OK, "got 0x%08x\n", hr);
3835 hr = IDWriteFactory_CreateTextLayout(factory, stringsW[i], lstrlenW(stringsW[i]), format, 500.0f, 100.0f, &layout);
3836 ok(hr == S_OK, "got 0x%08x\n", hr);
3838 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
3839 ok(hr == S_OK, "got 0x%08x\n", hr);
3841 count = 0;
3842 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, sizeof(clusters)/sizeof(*clusters), &count);
3843 ok(hr == S_OK, "got 0x%08x\n", hr);
3844 if (lstrlenW(stringsW[i]))
3845 ok(count > 0, "got %u\n", count);
3846 else
3847 ok(count == 0, "got %u\n", count);
3849 text_width = 0.0f;
3850 while (count)
3851 text_width += clusters[--count].width;
3853 /* maxwidth is 500, leading alignment */
3854 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_LEADING);
3855 ok(hr == S_OK, "got 0x%08x\n", hr);
3857 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3858 ok(hr == S_OK, "got 0x%08x\n", hr);
3860 ok(metrics.left == 0.0f, "got %.2f\n", metrics.left);
3861 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
3862 ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth);
3863 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3865 /* maxwidth is 500, trailing alignment */
3866 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
3867 ok(hr == S_OK, "got 0x%08x\n", hr);
3869 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3870 ok(hr == S_OK, "got 0x%08x\n", hr);
3872 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
3873 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
3874 ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth);
3875 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3876 IDWriteTextLayout_Release(layout);
3878 /* initially created with trailing alignment */
3879 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_TRAILING);
3880 ok(hr == S_OK, "got 0x%08x\n", hr);
3882 hr = IDWriteFactory_CreateTextLayout(factory, stringsW[i], lstrlenW(stringsW[i]), format, 500.0f, 100.0f, &layout);
3883 ok(hr == S_OK, "got 0x%08x\n", hr);
3885 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3886 ok(hr == S_OK, "got 0x%08x\n", hr);
3888 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
3889 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
3890 ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth);
3891 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3892 IDWriteTextLayout_Release(layout);
3894 if (lstrlenW(stringsW[i]) > 0) {
3895 /* max width less than total run width, trailing alignment */
3896 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_NO_WRAP);
3897 ok(hr == S_OK, "got 0x%08x\n", hr);
3899 hr = IDWriteFactory_CreateTextLayout(factory, stringsW[i], lstrlenW(stringsW[i]), format, clusters[0].width, 100.0f, &layout);
3900 ok(hr == S_OK, "got 0x%08x\n", hr);
3901 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3902 ok(hr == S_OK, "got 0x%08x\n", hr);
3903 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
3904 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
3905 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3906 IDWriteTextLayout_Release(layout);
3909 /* maxwidth is 500, centered */
3910 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_CENTER);
3911 ok(hr == S_OK, "got 0x%08x\n", hr);
3913 hr = IDWriteFactory_CreateTextLayout(factory, stringsW[i], lstrlenW(stringsW[i]), format, 500.0f, 100.0f, &layout);
3914 ok(hr == S_OK, "got 0x%08x\n", hr);
3916 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3917 ok(hr == S_OK, "got 0x%08x\n", hr);
3918 ok(metrics.left == (metrics.layoutWidth - metrics.width) / 2.0f, "got %.2f\n", metrics.left);
3919 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
3920 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3922 IDWriteTextLayout_Release(layout);
3925 IDWriteTextFormat_Release(format);
3926 IDWriteFactory_Release(factory);
3929 static void test_SetParagraphAlignment(void)
3931 static const WCHAR strW[] = {'a',0};
3932 DWRITE_TEXT_METRICS metrics;
3933 IDWriteTextFormat *format;
3934 IDWriteTextLayout *layout;
3935 IDWriteFactory *factory;
3936 DWRITE_PARAGRAPH_ALIGNMENT v;
3937 DWRITE_LINE_METRICS lines[1];
3938 UINT32 count;
3939 HRESULT hr;
3941 factory = create_factory();
3943 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3944 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
3945 ok(hr == S_OK, "got 0x%08x\n", hr);
3947 v = IDWriteTextFormat_GetParagraphAlignment(format);
3948 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
3950 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
3951 ok(hr == S_OK, "got 0x%08x\n", hr);
3953 v = IDWriteTextLayout_GetParagraphAlignment(layout);
3954 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
3956 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
3957 ok(hr == S_OK, "got 0x%08x\n", hr);
3959 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
3960 ok(hr == S_OK, "got 0x%08x\n", hr);
3962 v = IDWriteTextFormat_GetParagraphAlignment(format);
3963 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
3965 v = IDWriteTextLayout_GetParagraphAlignment(layout);
3966 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_FAR, "got %d\n", v);
3968 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
3969 ok(hr == S_OK, "got 0x%08x\n", hr);
3971 v = IDWriteTextLayout_GetParagraphAlignment(layout);
3972 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_CENTER, "got %d\n", v);
3974 count = 0;
3975 hr = IDWriteTextLayout_GetLineMetrics(layout, lines, 1, &count);
3976 ok(hr == S_OK, "got 0x%08x\n", hr);
3977 ok(count == 1, "got %u\n", count);
3979 /* maxheight is 100, near alignment */
3980 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
3981 ok(hr == S_OK, "got 0x%08x\n", hr);
3983 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3984 ok(hr == S_OK, "got 0x%08x\n", hr);
3986 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3987 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
3988 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
3989 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
3991 /* maxwidth is 100, far alignment */
3992 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
3993 ok(hr == S_OK, "got 0x%08x\n", hr);
3995 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3996 ok(hr == S_OK, "got 0x%08x\n", hr);
3998 ok(metrics.top == metrics.layoutHeight - metrics.height, "got %.2f\n", metrics.top);
3999 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4000 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
4001 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4002 IDWriteTextLayout_Release(layout);
4004 /* initially created with centered alignment */
4005 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
4006 ok(hr == S_OK, "got 0x%08x\n", hr);
4008 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
4009 ok(hr == S_OK, "got 0x%08x\n", hr);
4011 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4012 ok(hr == S_OK, "got 0x%08x\n", hr);
4014 ok(metrics.top == (metrics.layoutHeight - lines[0].height) / 2, "got %.2f\n", metrics.top);
4015 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4016 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4017 IDWriteTextLayout_Release(layout);
4019 IDWriteTextFormat_Release(format);
4020 IDWriteFactory_Release(factory);
4023 static void test_SetReadingDirection(void)
4025 static const WCHAR strW[] = {'a',0};
4026 DWRITE_CLUSTER_METRICS clusters[1];
4027 DWRITE_TEXT_METRICS metrics;
4028 IDWriteTextFormat *format;
4029 IDWriteTextLayout *layout;
4030 IDWriteFactory *factory;
4031 DWRITE_READING_DIRECTION v;
4032 DWRITE_LINE_METRICS lines[1];
4033 UINT32 count;
4034 HRESULT hr;
4036 factory = create_factory();
4038 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4039 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
4040 ok(hr == S_OK, "got 0x%08x\n", hr);
4042 v = IDWriteTextFormat_GetReadingDirection(format);
4043 ok(v == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", v);
4045 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
4046 ok(hr == S_OK, "got 0x%08x\n", hr);
4048 v = IDWriteTextLayout_GetReadingDirection(layout);
4049 ok(v == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", v);
4051 v = IDWriteTextFormat_GetReadingDirection(format);
4052 ok(v == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", v);
4054 hr = IDWriteTextLayout_SetReadingDirection(layout, DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
4055 ok(hr == S_OK, "got 0x%08x\n", hr);
4057 count = 0;
4058 hr = IDWriteTextLayout_GetLineMetrics(layout, lines, 1, &count);
4059 ok(hr == S_OK, "got 0x%08x\n", hr);
4060 ok(count == 1, "got %u\n", count);
4062 count = 0;
4063 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
4064 ok(hr == S_OK, "got 0x%08x\n", hr);
4065 ok(count == 1, "got %u\n", count);
4067 /* leading alignment, RTL */
4068 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4069 ok(hr == S_OK, "got 0x%08x\n", hr);
4071 ok(metrics.left == metrics.layoutWidth - clusters[0].width, "got %.2f\n", metrics.left);
4072 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
4073 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
4074 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4075 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
4076 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
4077 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4079 /* trailing alignment, RTL */
4080 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
4081 ok(hr == S_OK, "got 0x%08x\n", hr);
4083 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4084 ok(hr == S_OK, "got 0x%08x\n", hr);
4086 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
4087 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
4088 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
4089 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4090 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
4091 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
4092 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4094 /* centered alignment, RTL */
4095 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_CENTER);
4096 ok(hr == S_OK, "got 0x%08x\n", hr);
4098 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4099 ok(hr == S_OK, "got 0x%08x\n", hr);
4101 ok(metrics.left == (metrics.layoutWidth - clusters[0].width) / 2.0, "got %.2f\n", metrics.left);
4102 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
4103 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
4104 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4105 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
4106 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
4107 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4109 IDWriteTextLayout_Release(layout);
4111 IDWriteTextFormat_Release(format);
4112 IDWriteFactory_Release(factory);
4115 static inline FLOAT get_scaled_font_metric(UINT32 metric, FLOAT emSize, const DWRITE_FONT_METRICS *metrics)
4117 return (FLOAT)metric * emSize / (FLOAT)metrics->designUnitsPerEm;
4120 static FLOAT snap_coord(const DWRITE_MATRIX *m, FLOAT ppdip, FLOAT coord)
4122 FLOAT vec[2], det, vec2[2];
4123 BOOL transform;
4125 /* has to be a diagonal matrix */
4126 if ((ppdip <= 0.0) ||
4127 (m->m11 * m->m22 != 0.0 && (m->m12 != 0.0 || m->m21 != 0.0)) ||
4128 (m->m12 * m->m21 != 0.0 && (m->m11 != 0.0 || m->m22 != 0.0)))
4129 return coord;
4131 det = m->m11 * m->m22 - m->m12 * m->m21;
4132 transform = fabsf(det) > 1e-10;
4134 if (transform) {
4135 /* apply transform */
4136 vec[0] = 0.0;
4137 vec[1] = coord * ppdip;
4139 vec2[0] = m->m11 * vec[0] + m->m21 * vec[1] + m->dx;
4140 vec2[1] = m->m12 * vec[0] + m->m22 * vec[1] + m->dy;
4142 /* snap */
4143 vec2[0] = floorf(vec2[0] + 0.5f);
4144 vec2[1] = floorf(vec2[1] + 0.5f);
4146 /* apply inverted transform */
4147 vec[1] = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
4148 vec[1] /= ppdip;
4150 else
4151 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
4152 return vec[1];
4155 static inline BOOL float_eq(FLOAT left, FLOAT right)
4157 int x = *(int *)&left;
4158 int y = *(int *)&right;
4160 if (x < 0)
4161 x = INT_MIN - x;
4162 if (y < 0)
4163 y = INT_MIN - y;
4165 return abs(x - y) <= 16;
4168 struct snapping_test {
4169 DWRITE_MATRIX m;
4170 FLOAT ppdip;
4173 static struct snapping_test snapping_tests[] = {
4174 { { 0.0, 1.0, 2.0, 0.0, 0.2, 0.3 }, 1.0 },
4175 { { 0.0, 1.0, 2.0, 0.0, 0.0, 0.0 }, 1.0 },
4176 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0 }, /* identity transform */
4177 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 0.9 },
4178 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, -1.0 },
4179 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 0.0 },
4180 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.3 }, 1.0 }, /* simple Y shift */
4181 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 10.0 }, /* identity, 10 ppdip */
4182 { { 1.0, 0.0, 0.0, 10.0, 0.0, 0.0 }, 10.0 },
4183 { { 0.0, 1.0, 1.0, 0.0, 0.2, 0.6 }, 1.0 },
4184 { { 0.0, 2.0, 2.0, 0.0, 0.2, 0.6 }, 1.0 },
4185 { { 0.0, 0.5, -0.5, 0.0, 0.2, 0.6 }, 1.0 },
4186 { { 1.0, 2.0, 0.0, 1.0, 0.2, 0.6 }, 1.0 },
4187 { { 1.0, 1.0, 0.0, 1.0, 0.2, 0.6 }, 1.0 },
4188 { { 0.5, 0.5, -0.5, 0.5, 0.2, 0.6 }, 1.0 }, /* 45 degrees rotation */
4189 { { 0.5, 0.5, -0.5, 0.5, 0.0, 0.0 }, 100.0 }, /* 45 degrees rotation */
4190 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 100.0 },
4191 { { 0.0, 1.0, -1.0, 0.0, 0.2, 0.6 }, 1.0 }, /* 90 degrees rotation */
4192 { { -1.0, 0.0, 0.0, -1.0, 0.2, 0.6 }, 1.0 }, /* 180 degrees rotation */
4193 { { 0.0, -1.0, 1.0, 0.0, 0.2, 0.6 }, 1.0 }, /* 270 degrees rotation */
4194 { { 1.0, 0.0, 0.0, 1.0,-0.1, 0.2 }, 1.0 },
4195 { { 0.0, 1.0, -1.0, 0.0,-0.2,-0.3 }, 1.0 }, /* 90 degrees rotation */
4196 { { -1.0, 0.0, 0.0, -1.0,-0.3,-1.6 }, 1.0 }, /* 180 degrees rotation */
4197 { { 0.0, -1.0, 1.0, 0.0,-0.7, 0.6 }, 10.0 }, /* 270 degrees rotation */
4198 { { 0.0, 2.0, 1.0, 0.0, 0.2, 0.6 }, 1.0 },
4199 { { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }, 1.0 },
4200 { { 3.0, 0.0, 0.0, 5.0, 0.2,-0.3 }, 10.0 },
4201 { { 0.0, -3.0, 5.0, 0.0,-0.1, 0.7 }, 10.0 },
4204 static DWRITE_MATRIX compattransforms[] = {
4205 { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
4206 { 1.0, 0.0, 0.0, 1.0, 0.2, 0.3 },
4207 { 2.0, 0.0, 0.0, 2.0, 0.2, 0.3 },
4208 { 2.0, 1.0, 2.0, 2.0, 0.2, 0.3 },
4211 static void test_pixelsnapping(void)
4213 static const WCHAR strW[] = {'a',0};
4214 IDWriteTextLayout *layout, *layout2;
4215 struct renderer_context ctxt;
4216 DWRITE_FONT_METRICS metrics;
4217 IDWriteTextFormat *format;
4218 IDWriteFontFace *fontface;
4219 IDWriteFactory *factory;
4220 FLOAT baseline, originX;
4221 HRESULT hr;
4222 int i, j;
4224 factory = create_factory();
4226 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4227 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
4228 ok(hr == S_OK, "got 0x%08x\n", hr);
4230 fontface = get_fontface_from_format(format);
4231 IDWriteFontFace_GetMetrics(fontface, &metrics);
4233 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 500.0, 100.0, &layout);
4234 ok(hr == S_OK, "got 0x%08x\n", hr);
4236 /* disabled snapping */
4237 ctxt.snapping_disabled = TRUE;
4238 ctxt.gdicompat = FALSE;
4239 ctxt.use_gdi_natural = FALSE;
4240 ctxt.ppdip = 1.0f;
4241 memset(&ctxt.m, 0, sizeof(ctxt.m));
4242 ctxt.m.m11 = ctxt.m.m22 = 1.0;
4243 originX = 0.1;
4245 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, originX, 0.0);
4246 ok(hr == S_OK, "got 0x%08x\n", hr);
4248 baseline = get_scaled_font_metric(metrics.ascent, 12.0, &metrics);
4249 ok(ctxt.originX == originX, "got %f, originX %f\n", ctxt.originX, originX);
4250 ok(ctxt.originY == baseline, "got %f, baseline %f\n", ctxt.originY, baseline);
4251 ok(floor(baseline) != baseline, "got %f\n", baseline);
4253 ctxt.snapping_disabled = FALSE;
4255 for (i = 0; i < sizeof(snapping_tests)/sizeof(snapping_tests[0]); i++) {
4256 struct snapping_test *ptr = &snapping_tests[i];
4257 FLOAT expectedY;
4259 ctxt.m = ptr->m;
4260 ctxt.ppdip = ptr->ppdip;
4261 ctxt.originX = 678.9;
4262 ctxt.originY = 678.9;
4264 expectedY = snap_coord(&ctxt.m, ctxt.ppdip, baseline);
4265 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, originX, 0.0);
4266 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
4267 ok(ctxt.originX == originX, "%d: got %f, originX %f\n", i, ctxt.originX, originX);
4268 ok(float_eq(ctxt.originY, expectedY), "%d: got %f, expected %f, baseline %f\n",
4269 i, ctxt.originY, expectedY, baseline);
4271 /* gdicompat layout transform doesn't affect snapping */
4272 for (j = 0; j < sizeof(compattransforms)/sizeof(compattransforms[0]); j++) {
4273 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, strW, 1, format, 500.0, 100.0,
4274 1.0, &compattransforms[j], FALSE, &layout2);
4275 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
4277 expectedY = snap_coord(&ctxt.m, ctxt.ppdip, baseline);
4278 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, originX, 0.0);
4279 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
4280 ok(ctxt.originX == originX, "%d: got %f, originX %f\n", i, ctxt.originX, originX);
4281 ok(float_eq(ctxt.originY, expectedY), "%d: got %f, expected %f, baseline %f\n",
4282 i, ctxt.originY, expectedY, baseline);
4284 IDWriteTextLayout_Release(layout2);
4288 IDWriteTextLayout_Release(layout);
4289 IDWriteTextFormat_Release(format);
4290 IDWriteFontFace_Release(fontface);
4291 IDWriteFactory_Release(factory);
4294 static void test_SetWordWrapping(void)
4296 static const WCHAR strW[] = {'a',' ','s','o','m','e',' ','t','e','x','t',' ','a','n','d',
4297 ' ','a',' ','b','i','t',' ','m','o','r','e','\n','b'};
4298 IDWriteTextFormat *format;
4299 IDWriteTextLayout *layout;
4300 IDWriteFactory *factory;
4301 DWRITE_WORD_WRAPPING v;
4302 UINT32 count;
4303 HRESULT hr;
4305 factory = create_factory();
4307 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4308 DWRITE_FONT_STRETCH_NORMAL, 12.0, enusW, &format);
4309 ok(hr == S_OK, "got 0x%08x\n", hr);
4311 v = IDWriteTextFormat_GetWordWrapping(format);
4312 ok(v == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", v);
4314 hr = IDWriteFactory_CreateTextLayout(factory, strW, sizeof(strW)/sizeof(WCHAR), format, 10.0f, 100.0f, &layout);
4315 ok(hr == S_OK, "got 0x%08x\n", hr);
4317 v = IDWriteTextLayout_GetWordWrapping(layout);
4318 ok(v == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", v);
4320 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4321 ok(hr == S_OK, "got 0x%08x\n", hr);
4323 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4324 ok(hr == S_OK, "got 0x%08x\n", hr);
4326 v = IDWriteTextFormat_GetWordWrapping(format);
4327 ok(v == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", v);
4329 /* disable wrapping, text has explicit newline */
4330 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4331 ok(hr == S_OK, "got 0x%08x\n", hr);
4333 count = 0;
4334 hr = IDWriteTextLayout_GetLineMetrics(layout, NULL, 0, &count);
4335 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
4336 ok(count == 2, "got %u\n", count);
4338 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_WRAP);
4339 ok(hr == S_OK, "got 0x%08x\n", hr);
4341 count = 0;
4342 hr = IDWriteTextLayout_GetLineMetrics(layout, NULL, 0, &count);
4343 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
4344 ok(count > 2, "got %u\n", count);
4346 IDWriteTextLayout_Release(layout);
4347 IDWriteTextFormat_Release(format);
4348 IDWriteFactory_Release(factory);
4351 /* Collection dedicated to fallback testing */
4353 static const WCHAR g_blahfontW[] = {'B','l','a','h',0};
4354 static HRESULT WINAPI fontcollection_QI(IDWriteFontCollection *iface, REFIID riid, void **obj)
4356 if (IsEqualIID(riid, &IID_IDWriteFontCollection) || IsEqualIID(riid, &IID_IUnknown)) {
4357 *obj = iface;
4358 IDWriteFontCollection_AddRef(iface);
4359 return S_OK;
4362 *obj = NULL;
4363 return E_NOINTERFACE;
4366 static ULONG WINAPI fontcollection_AddRef(IDWriteFontCollection *iface)
4368 return 2;
4371 static ULONG WINAPI fontcollection_Release(IDWriteFontCollection *iface)
4373 return 1;
4376 static UINT32 WINAPI fontcollection_GetFontFamilyCount(IDWriteFontCollection *iface)
4378 ok(0, "unexpected call\n");
4379 return 0;
4382 static HRESULT WINAPI fontcollection_GetFontFamily(IDWriteFontCollection *iface, UINT32 index, IDWriteFontFamily **family)
4384 if (index == 123456) {
4385 IDWriteFactory *factory = create_factory();
4386 IDWriteFontCollection *syscollection;
4387 BOOL exists;
4388 HRESULT hr;
4390 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
4391 ok(hr == S_OK, "got 0x%08x\n", hr);
4393 hr = IDWriteFontCollection_FindFamilyName(syscollection, tahomaW, &index, &exists);
4394 ok(hr == S_OK, "got 0x%08x\n", hr);
4396 hr = IDWriteFontCollection_GetFontFamily(syscollection, index, family);
4397 ok(hr == S_OK, "got 0x%08x\n", hr);
4399 IDWriteFontCollection_Release(syscollection);
4400 IDWriteFactory_Release(factory);
4401 return S_OK;
4403 ok(0, "unexpected call\n");
4404 return E_NOTIMPL;
4407 static HRESULT WINAPI fontcollection_FindFamilyName(IDWriteFontCollection *iface, WCHAR const *name, UINT32 *index, BOOL *exists)
4409 if (!lstrcmpW(name, g_blahfontW)) {
4410 *index = 123456;
4411 *exists = TRUE;
4412 return S_OK;
4414 ok(0, "unexpected call, name %s\n", wine_dbgstr_w(name));
4415 return E_NOTIMPL;
4418 static HRESULT WINAPI fontcollection_GetFontFromFontFace(IDWriteFontCollection *iface, IDWriteFontFace *face, IDWriteFont **font)
4420 ok(0, "unexpected call\n");
4421 return E_NOTIMPL;
4424 static const IDWriteFontCollectionVtbl fallbackcollectionvtbl = {
4425 fontcollection_QI,
4426 fontcollection_AddRef,
4427 fontcollection_Release,
4428 fontcollection_GetFontFamilyCount,
4429 fontcollection_GetFontFamily,
4430 fontcollection_FindFamilyName,
4431 fontcollection_GetFontFromFontFace
4434 static IDWriteFontCollection fallbackcollection = { &fallbackcollectionvtbl };
4436 static void test_MapCharacters(void)
4438 static const WCHAR strW[] = {'a','b','c',0};
4439 static const WCHAR str2W[] = {'a',0x3058,'b',0};
4440 IDWriteLocalizedStrings *strings;
4441 IDWriteFontFallback *fallback;
4442 IDWriteFactory2 *factory2;
4443 IDWriteFactory *factory;
4444 UINT32 mappedlength;
4445 IDWriteFont *font;
4446 WCHAR buffW[50];
4447 BOOL exists;
4448 FLOAT scale;
4449 HRESULT hr;
4451 factory = create_factory();
4453 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
4454 IDWriteFactory_Release(factory);
4455 if (hr != S_OK) {
4456 win_skip("MapCharacters() is not supported\n");
4457 return;
4460 fallback = NULL;
4461 hr = IDWriteFactory2_GetSystemFontFallback(factory2, &fallback);
4462 ok(hr == S_OK, "got 0x%08x\n", hr);
4463 ok(fallback != NULL, "got %p\n", fallback);
4465 mappedlength = 1;
4466 scale = 0.0f;
4467 font = (void*)0xdeadbeef;
4468 hr = IDWriteFontFallback_MapCharacters(fallback, NULL, 0, 0, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4469 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4470 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4471 ok(mappedlength == 0, "got %u\n", mappedlength);
4472 ok(scale == 1.0f, "got %f\n", scale);
4473 ok(font == NULL, "got %p\n", font);
4475 /* zero length source */
4476 g_source = strW;
4477 mappedlength = 1;
4478 scale = 0.0f;
4479 font = (void*)0xdeadbeef;
4480 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 0, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4481 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4482 ok(hr == S_OK, "got 0x%08x\n", hr);
4483 ok(mappedlength == 0, "got %u\n", mappedlength);
4484 ok(scale == 1.0f, "got %f\n", scale);
4485 ok(font == NULL, "got %p\n", font);
4487 g_source = strW;
4488 mappedlength = 0;
4489 scale = 0.0f;
4490 font = NULL;
4491 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4492 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4493 todo_wine {
4494 ok(hr == S_OK, "got 0x%08x\n", hr);
4495 ok(mappedlength == 1, "got %u\n", mappedlength);
4497 ok(scale == 1.0f, "got %f\n", scale);
4498 todo_wine
4499 ok(font != NULL, "got %p\n", font);
4500 if (font) {
4501 IDWriteFont_Release(font);
4503 /* same latin text, full length */
4504 g_source = strW;
4505 mappedlength = 0;
4506 scale = 0.0f;
4507 font = NULL;
4508 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4509 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4510 todo_wine {
4511 ok(hr == S_OK, "got 0x%08x\n", hr);
4512 ok(mappedlength == 3, "got %u\n", mappedlength);
4514 ok(scale == 1.0f, "got %f\n", scale);
4515 todo_wine
4516 ok(font != NULL, "got %p\n", font);
4517 if (font) {
4518 IDWriteFont_Release(font);
4520 /* string 'a\x3058b' */
4521 g_source = str2W;
4522 mappedlength = 0;
4523 scale = 0.0f;
4524 font = NULL;
4525 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4526 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4527 todo_wine {
4528 ok(hr == S_OK, "got 0x%08x\n", hr);
4529 ok(mappedlength == 1, "got %u\n", mappedlength);
4531 ok(scale == 1.0f, "got %f\n", scale);
4532 todo_wine
4533 ok(font != NULL, "got %p\n", font);
4534 if (font) {
4535 IDWriteFont_Release(font);
4537 g_source = str2W;
4538 mappedlength = 0;
4539 scale = 0.0f;
4540 font = NULL;
4541 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 1, 2, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4542 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4543 todo_wine {
4544 ok(hr == S_OK, "got 0x%08x\n", hr);
4545 ok(mappedlength == 1, "got %u\n", mappedlength);
4547 ok(scale == 1.0f, "got %f\n", scale);
4548 todo_wine
4549 ok(font != NULL, "got %p\n", font);
4550 if (font) {
4551 /* font returned for Hiragana character, check if it supports Latin too */
4552 exists = FALSE;
4553 hr = IDWriteFont_HasCharacter(font, 'b', &exists);
4554 ok(hr == S_OK, "got 0x%08x\n", hr);
4555 ok(exists, "got %d\n", exists);
4557 IDWriteFont_Release(font);
4559 /* Try with explicit collection, Tahoma will be forced. */
4560 /* 1. Latin part */
4561 g_source = str2W;
4562 mappedlength = 0;
4563 scale = 0.0f;
4564 font = NULL;
4565 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, &fallbackcollection, g_blahfontW, DWRITE_FONT_WEIGHT_NORMAL,
4566 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4567 ok(hr == S_OK, "got 0x%08x\n", hr);
4568 ok(mappedlength == 1, "got %u\n", mappedlength);
4569 ok(scale == 1.0f, "got %f\n", scale);
4570 ok(font != NULL, "got %p\n", font);
4572 exists = FALSE;
4573 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
4574 ok(hr == S_OK && exists, "got 0x%08x, exists %d\n", hr, exists);
4575 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
4576 ok(hr == S_OK, "got 0x%08x\n", hr);
4577 ok(!lstrcmpW(buffW, tahomaW), "%s\n", wine_dbgstr_w(buffW));
4578 IDWriteLocalizedStrings_Release(strings);
4579 IDWriteFont_Release(font);
4581 /* 2. Hiragana character, force Tahoma font does not support Japanese */
4582 g_source = str2W;
4583 mappedlength = 0;
4584 scale = 0.0f;
4585 font = NULL;
4586 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 1, 1, &fallbackcollection, g_blahfontW, DWRITE_FONT_WEIGHT_NORMAL,
4587 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4588 ok(hr == S_OK, "got 0x%08x\n", hr);
4589 ok(mappedlength == 1, "got %u\n", mappedlength);
4590 ok(scale == 1.0f, "got %f\n", scale);
4591 ok(font != NULL, "got %p\n", font);
4593 exists = FALSE;
4594 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
4595 ok(hr == S_OK && exists, "got 0x%08x, exists %d\n", hr, exists);
4596 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, sizeof(buffW)/sizeof(WCHAR));
4597 ok(hr == S_OK, "got 0x%08x\n", hr);
4598 todo_wine
4599 ok(lstrcmpW(buffW, tahomaW), "%s\n", wine_dbgstr_w(buffW));
4600 IDWriteLocalizedStrings_Release(strings);
4601 IDWriteFont_Release(font);
4603 IDWriteFontFallback_Release(fallback);
4604 IDWriteFactory2_Release(factory2);
4607 static void test_FontFallbackBuilder(void)
4609 static const WCHAR localeW[] = {'l','o','c','a','l','e',0};
4610 static const WCHAR strW[] = {'A',0};
4611 IDWriteFontFallbackBuilder *builder;
4612 IDWriteFontFallback *fallback;
4613 DWRITE_UNICODE_RANGE range;
4614 IDWriteFactory2 *factory2;
4615 IDWriteFactory *factory;
4616 const WCHAR *familyW;
4617 UINT32 mappedlength;
4618 IDWriteFont *font;
4619 FLOAT scale;
4620 HRESULT hr;
4622 factory = create_factory();
4624 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
4625 IDWriteFactory_Release(factory);
4627 if (factory2)
4628 hr = IDWriteFactory2_CreateFontFallbackBuilder(factory2, &builder);
4630 if (hr != S_OK) {
4631 skip("IDWriteFontFallbackBuilder is not supported\n");
4632 return;
4635 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4636 ok(hr == S_OK, "got 0x%08x\n", hr);
4638 hr = IDWriteFontFallbackBuilder_AddMapping(builder, NULL, 0, NULL, 0, NULL, NULL, NULL, 0.0f);
4639 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4641 range.first = 'A';
4642 range.last = 'B';
4643 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 0, NULL, 0, NULL, NULL, NULL, 0.0f);
4644 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4646 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 0, NULL, 0, NULL, NULL, NULL, 1.0f);
4647 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4649 /* negative scaling factor */
4650 range.first = range.last = 0;
4651 familyW = g_blahfontW;
4652 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, -1.0f);
4653 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4655 /* empty range */
4656 range.first = range.last = 0;
4657 familyW = g_blahfontW;
4658 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 1.0f);
4659 ok(hr == S_OK, "got 0x%08x\n", hr);
4661 range.first = range.last = 0;
4662 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 2.0f);
4663 ok(hr == S_OK, "got 0x%08x\n", hr);
4665 range.first = range.last = 'A';
4666 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 3.0f);
4667 ok(hr == S_OK, "got 0x%08x\n", hr);
4669 range.first = 'B';
4670 range.last = 'A';
4671 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 4.0f);
4672 ok(hr == S_OK, "got 0x%08x\n", hr);
4674 if (0) /* crashes on native */
4675 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, NULL);
4677 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4678 ok(hr == S_OK, "got 0x%08x\n", hr);
4680 /* fallback font missing from system collection */
4681 g_source = strW;
4682 mappedlength = 0;
4683 scale = 0.0f;
4684 font = (void*)0xdeadbeef;
4685 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4686 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4687 ok(hr == S_OK, "got 0x%08x\n", hr);
4688 ok(mappedlength == 1, "got %u\n", mappedlength);
4689 ok(scale == 1.0f, "got %f\n", scale);
4690 ok(font == NULL, "got %p\n", font);
4692 IDWriteFontFallback_Release(fallback);
4694 /* remap with custom collection */
4695 range.first = range.last = 'A';
4696 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, NULL, NULL, 5.0f);
4697 ok(hr == S_OK, "got 0x%08x\n", hr);
4699 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4700 ok(hr == S_OK, "got 0x%08x\n", hr);
4702 g_source = strW;
4703 mappedlength = 0;
4704 scale = 0.0f;
4705 font = NULL;
4706 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4707 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4708 ok(hr == S_OK, "got 0x%08x\n", hr);
4709 ok(mappedlength == 1, "got %u\n", mappedlength);
4710 ok(scale == 5.0f, "got %f\n", scale);
4711 ok(font != NULL, "got %p\n", font);
4712 IDWriteFont_Release(font);
4714 IDWriteFontFallback_Release(fallback);
4716 range.first = 'B';
4717 range.last = 'A';
4718 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, NULL, NULL, 6.0f);
4719 ok(hr == S_OK, "got 0x%08x\n", hr);
4721 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4722 ok(hr == S_OK, "got 0x%08x\n", hr);
4724 g_source = strW;
4725 mappedlength = 0;
4726 scale = 0.0f;
4727 font = NULL;
4728 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4729 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4730 ok(hr == S_OK, "got 0x%08x\n", hr);
4731 ok(mappedlength == 1, "got %u\n", mappedlength);
4732 ok(scale == 5.0f, "got %f\n", scale);
4733 ok(font != NULL, "got %p\n", font);
4734 IDWriteFont_Release(font);
4736 IDWriteFontFallback_Release(fallback);
4738 /* explicit locale */
4739 range.first = 'A';
4740 range.last = 'B';
4741 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, localeW, NULL, 6.0f);
4742 ok(hr == S_OK, "got 0x%08x\n", hr);
4744 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4745 ok(hr == S_OK, "got 0x%08x\n", hr);
4747 g_source = strW;
4748 mappedlength = 0;
4749 scale = 0.0f;
4750 font = NULL;
4751 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4752 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4753 ok(hr == S_OK, "got 0x%08x\n", hr);
4754 ok(mappedlength == 1, "got %u\n", mappedlength);
4755 ok(scale == 5.0f, "got %f\n", scale);
4756 ok(font != NULL, "got %p\n", font);
4757 IDWriteFont_Release(font);
4759 IDWriteFontFallbackBuilder_Release(builder);
4760 IDWriteFactory2_Release(factory2);
4763 static void test_SetTypography(void)
4765 static const WCHAR strW[] = {'a','f','i','b',0};
4766 IDWriteTypography *typography, *typography2;
4767 IDWriteTextFormat *format;
4768 IDWriteTextLayout *layout;
4769 DWRITE_TEXT_RANGE range;
4770 IDWriteFactory *factory;
4771 HRESULT hr;
4773 factory = create_factory();
4775 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4776 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
4777 ok(hr == S_OK, "got 0x%08x\n", hr);
4779 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
4780 ok(hr == S_OK, "got 0x%08x\n", hr);
4781 IDWriteTextFormat_Release(format);
4783 hr = IDWriteFactory_CreateTypography(factory, &typography);
4784 ok(hr == S_OK, "got 0x%08x\n", hr);
4786 EXPECT_REF(typography, 1);
4787 range.startPosition = 0;
4788 range.length = 2;
4789 hr = IDWriteTextLayout_SetTypography(layout, typography, range);
4790 ok(hr == S_OK, "got 0x%08x\n", hr);
4791 EXPECT_REF(typography, 2);
4793 hr = IDWriteTextLayout_GetTypography(layout, 0, &typography2, NULL);
4794 ok(hr == S_OK, "got 0x%08x\n", hr);
4795 ok(typography2 == typography, "got %p, expected %p\n", typography2, typography);
4796 IDWriteTypography_Release(typography2);
4797 IDWriteTypography_Release(typography);
4799 hr = IDWriteFactory_CreateTypography(factory, &typography2);
4800 ok(hr == S_OK, "got 0x%08x\n", hr);
4802 range.startPosition = 0;
4803 range.length = 1;
4804 hr = IDWriteTextLayout_SetTypography(layout, typography2, range);
4805 ok(hr == S_OK, "got 0x%08x\n", hr);
4806 EXPECT_REF(typography2, 2);
4807 IDWriteTypography_Release(typography2);
4809 hr = IDWriteTextLayout_GetTypography(layout, 0, &typography, &range);
4810 ok(hr == S_OK, "got 0x%08x\n", hr);
4811 ok(range.length == 1, "got %u\n", range.length);
4813 IDWriteTypography_Release(typography);
4815 IDWriteTextLayout_Release(layout);
4816 IDWriteFactory_Release(factory);
4819 static void test_SetLastLineWrapping(void)
4821 static const WCHAR strW[] = {'a',0};
4822 IDWriteTextLayout2 *layout2;
4823 IDWriteTextFormat1 *format1;
4824 IDWriteTextLayout *layout;
4825 IDWriteTextFormat *format;
4826 IDWriteFactory *factory;
4827 HRESULT hr;
4828 BOOL ret;
4830 factory = create_factory();
4832 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4833 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
4834 ok(hr == S_OK, "got 0x%08x\n", hr);
4836 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4837 IDWriteTextFormat_Release(format);
4838 if (hr != S_OK) {
4839 win_skip("SetLastLineWrapping() is not supported\n");
4840 IDWriteFactory_Release(factory);
4841 return;
4844 ret = IDWriteTextFormat1_GetLastLineWrapping(format1);
4845 ok(ret, "got %d\n", ret);
4847 hr = IDWriteTextFormat1_SetLastLineWrapping(format1, FALSE);
4848 ok(hr == S_OK, "got 0x%08x\n", hr);
4850 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, (IDWriteTextFormat*)format1, 1000.0, 1000.0, &layout);
4851 ok(hr == S_OK, "got 0x%08x\n", hr);
4853 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
4854 ok(hr == S_OK, "got 0x%08x\n", hr);
4855 IDWriteTextLayout_Release(layout);
4857 ret = IDWriteTextLayout2_GetLastLineWrapping(layout2);
4858 ok(!ret, "got %d\n", ret);
4860 hr = IDWriteTextLayout2_SetLastLineWrapping(layout2, TRUE);
4861 ok(hr == S_OK, "got 0x%08x\n", hr);
4863 IDWriteTextLayout2_Release(layout2);
4864 IDWriteTextFormat1_Release(format1);
4865 IDWriteFactory_Release(factory);
4868 static void test_SetOpticalAlignment(void)
4870 static const WCHAR strW[] = {'a',0};
4871 DWRITE_OPTICAL_ALIGNMENT alignment;
4872 IDWriteTextLayout2 *layout2;
4873 IDWriteTextFormat1 *format1;
4874 IDWriteTextLayout *layout;
4875 IDWriteTextFormat *format;
4876 IDWriteFactory *factory;
4877 HRESULT hr;
4879 factory = create_factory();
4881 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4882 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
4883 ok(hr == S_OK, "got 0x%08x\n", hr);
4885 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
4886 IDWriteTextFormat_Release(format);
4887 if (hr != S_OK) {
4888 win_skip("SetOpticalAlignment() is not supported\n");
4889 IDWriteFactory_Release(factory);
4890 return;
4893 alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4894 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
4896 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, (IDWriteTextFormat*)format1, 1000.0, 1000.0, &layout);
4897 ok(hr == S_OK, "got 0x%08x\n", hr);
4899 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
4900 ok(hr == S_OK, "got 0x%08x\n", hr);
4901 IDWriteTextLayout_Release(layout);
4902 IDWriteTextFormat1_Release(format1);
4904 alignment = IDWriteTextLayout2_GetOpticalAlignment(layout2);
4905 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
4907 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
4908 ok(hr == S_OK, "got 0x%08x\n", hr);
4910 alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4911 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
4913 hr = IDWriteTextLayout2_SetOpticalAlignment(layout2, DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS);
4914 ok(hr == S_OK, "got 0x%08x\n", hr);
4916 hr = IDWriteTextLayout2_SetOpticalAlignment(layout2, DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS+1);
4917 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4919 alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
4920 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS, "got %d\n", alignment);
4922 hr = IDWriteTextFormat1_SetOpticalAlignment(format1, DWRITE_OPTICAL_ALIGNMENT_NONE);
4923 ok(hr == S_OK, "got 0x%08x\n", hr);
4925 hr = IDWriteTextFormat1_SetOpticalAlignment(format1, DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS+1);
4926 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4928 alignment = IDWriteTextLayout2_GetOpticalAlignment(layout2);
4929 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
4931 IDWriteTextLayout2_Release(layout2);
4932 IDWriteTextFormat1_Release(format1);
4933 IDWriteFactory_Release(factory);
4936 static const struct drawcall_entry drawunderline_seq[] = {
4937 { DRAW_GLYPHRUN, {'a','e',0x0300,0}, {'e','n','-','u','s',0}, 2 }, /* reported runs can't mix different underline values */
4938 { DRAW_GLYPHRUN, {'d',0}, {'e','n','-','u','s',0}, 1 },
4939 { DRAW_UNDERLINE, {0}, {'e','n','-','u','s',0} },
4940 { DRAW_LAST_KIND }
4943 static const struct drawcall_entry drawunderline2_seq[] = {
4944 { DRAW_GLYPHRUN, {'a',0}, {'e','n','-','u','s',0}, 1 },
4945 { DRAW_GLYPHRUN, {'e',0}, {'e','n','-','u','s',0}, 1 },
4946 { DRAW_UNDERLINE, {0}, {'e','n','-','u','s',0} },
4947 { DRAW_LAST_KIND }
4950 static const struct drawcall_entry drawunderline3_seq[] = {
4951 { DRAW_GLYPHRUN, {'a',0}, {'e','n','-','c','a',0}, 1 },
4952 { DRAW_GLYPHRUN, {'e',0}, {'e','n','-','u','s',0}, 1 },
4953 { DRAW_UNDERLINE, {0}, {'e','n','-','c','a',0} },
4954 { DRAW_UNDERLINE, {0}, {'e','n','-','u','s',0} },
4955 { DRAW_LAST_KIND }
4958 static const struct drawcall_entry drawunderline4_seq[] = {
4959 { DRAW_GLYPHRUN, {'a',0}, {'e','n','-','u','s',0}, 1 },
4960 { DRAW_GLYPHRUN, {'e',0}, {'e','n','-','u','s',0}, 1 },
4961 { DRAW_UNDERLINE, {0}, {'e','n','-','u','s',0} },
4962 { DRAW_STRIKETHROUGH },
4963 { DRAW_LAST_KIND }
4966 static void test_SetUnderline(void)
4968 static const WCHAR encaW[] = {'e','n','-','C','A',0};
4969 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
4970 IDWriteFontCollection *syscollection;
4971 DWRITE_CLUSTER_METRICS clusters[4];
4972 IDWriteTextFormat *format;
4973 IDWriteTextLayout *layout;
4974 DWRITE_TEXT_RANGE range;
4975 IDWriteFactory *factory;
4976 UINT32 count, i;
4977 HRESULT hr;
4979 factory = create_factory();
4981 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4982 DWRITE_FONT_STRETCH_NORMAL, 10.0, enusW, &format);
4983 ok(hr == S_OK, "got 0x%08x\n", hr);
4985 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
4986 ok(hr == S_OK, "got 0x%08x\n", hr);
4988 count = 0;
4989 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, sizeof(clusters)/sizeof(clusters[0]), &count);
4990 ok(hr == S_OK, "got 0x%08x\n", hr);
4991 todo_wine
4992 ok(count == 3, "got %u\n", count);
4994 range.startPosition = 0;
4995 range.length = 2;
4996 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
4997 ok(hr == S_OK, "got 0x%08x\n", hr);
4999 count = 0;
5000 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, sizeof(clusters)/sizeof(clusters[0]), &count);
5001 ok(hr == S_OK, "got 0x%08x\n", hr);
5002 todo_wine
5003 ok(count == 3, "got %u\n", count);
5005 flush_sequence(sequences, RENDERER_ID);
5006 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
5007 ok(hr == S_OK, "got 0x%08x\n", hr);
5008 ok_sequence(sequences, RENDERER_ID, drawunderline_seq, "draw underline test", TRUE);
5010 IDWriteTextLayout_Release(layout);
5012 /* 2 characters, same font, significantly different font size. Set underline for both, see how many
5013 underline drawing calls is there. */
5014 hr = IDWriteFactory_CreateTextLayout(factory, strW, 2, format, 1000.0f, 1000.0f, &layout);
5015 ok(hr == S_OK, "got 0x%08x\n", hr);
5017 range.startPosition = 0;
5018 range.length = 2;
5019 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
5020 ok(hr == S_OK, "got 0x%08x\n", hr);
5022 range.startPosition = 0;
5023 range.length = 1;
5024 hr = IDWriteTextLayout_SetFontSize(layout, 100.0f, range);
5025 ok(hr == S_OK, "got 0x%08x\n", hr);
5027 flush_sequence(sequences, RENDERER_ID);
5028 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0f, 0.0f);
5029 ok(hr == S_OK, "got 0x%08x\n", hr);
5030 ok_sequence(sequences, RENDERER_ID, drawunderline2_seq, "draw underline test 2", FALSE);
5032 /* now set different locale for second char, draw again */
5033 range.startPosition = 0;
5034 range.length = 1;
5035 hr = IDWriteTextLayout_SetLocaleName(layout, encaW, range);
5036 ok(hr == S_OK, "got 0x%08x\n", hr);
5038 flush_sequence(sequences, RENDERER_ID);
5039 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0f, 0.0f);
5040 ok(hr == S_OK, "got 0x%08x\n", hr);
5041 ok_sequence(sequences, RENDERER_ID, drawunderline3_seq, "draw underline test 2", FALSE);
5043 IDWriteTextLayout_Release(layout);
5045 /* 2 characters, same font properties, first with strikethrough, both underlined */
5046 hr = IDWriteFactory_CreateTextLayout(factory, strW, 2, format, 1000.0f, 1000.0f, &layout);
5047 ok(hr == S_OK, "got 0x%08x\n", hr);
5049 range.startPosition = 0;
5050 range.length = 1;
5051 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
5052 ok(hr == S_OK, "got 0x%08x\n", hr);
5054 range.startPosition = 0;
5055 range.length = 2;
5056 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
5057 ok(hr == S_OK, "got 0x%08x\n", hr);
5059 flush_sequence(sequences, RENDERER_ID);
5060 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0f, 0.0f);
5061 ok(hr == S_OK, "got 0x%08x\n", hr);
5062 ok_sequence(sequences, RENDERER_ID, drawunderline4_seq, "draw underline test 4", FALSE);
5064 IDWriteTextLayout_Release(layout);
5066 IDWriteTextFormat_Release(format);
5068 /* Test runHeight value with all available fonts */
5069 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
5070 ok(hr == S_OK, "got 0x%08x\n", hr);
5071 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
5073 for (i = 0; i < count; i++) {
5074 DWRITE_FONT_METRICS fontmetrics;
5075 IDWriteLocalizedStrings *names;
5076 struct renderer_context ctxt;
5077 IDWriteFontFamily *family;
5078 IDWriteFontFace *fontface;
5079 IDWriteFont *font;
5080 WCHAR nameW[256];
5081 BOOL exists;
5083 format = NULL;
5084 layout = NULL;
5086 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
5087 ok(hr == S_OK, "got 0x%08x\n", hr);
5089 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
5090 DWRITE_FONT_STYLE_NORMAL, &font);
5091 ok(hr == S_OK, "got 0x%08x\n", hr);
5093 hr = IDWriteFont_CreateFontFace(font, &fontface);
5094 ok(hr == S_OK, "got 0x%08x\n", hr);
5096 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
5097 ok(hr == S_OK, "got 0x%08x\n", hr);
5099 if (!(exists = get_enus_string(names, nameW, sizeof(nameW)/sizeof(nameW[0])))) {
5100 IDWriteLocalFontFileLoader *localloader;
5101 IDWriteFontFileLoader *loader;
5102 IDWriteFontFile *file;
5103 const void *key;
5104 UINT32 keysize;
5105 UINT32 count;
5107 count = 1;
5108 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
5109 ok(hr == S_OK, "got 0x%08x\n", hr);
5111 hr = IDWriteFontFile_GetLoader(file, &loader);
5112 ok(hr == S_OK, "got 0x%08x\n", hr);
5114 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
5115 ok(hr == S_OK, "got 0x%08x\n", hr);
5116 IDWriteFontFileLoader_Release(loader);
5118 hr = IDWriteFontFile_GetReferenceKey(file, &key, &keysize);
5119 ok(hr == S_OK, "got 0x%08x\n", hr);
5121 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, keysize, nameW, sizeof(nameW)/sizeof(*nameW));
5122 ok(hr == S_OK, "got 0x%08x\n", hr);
5124 skip("Failed to get English family name, font file %s\n", wine_dbgstr_w(nameW));
5126 IDWriteLocalFontFileLoader_Release(localloader);
5127 IDWriteFontFile_Release(file);
5130 IDWriteLocalizedStrings_Release(names);
5131 IDWriteFont_Release(font);
5133 if (!exists)
5134 goto cleanup;
5136 IDWriteFontFace_GetMetrics(fontface, &fontmetrics);
5137 hr = IDWriteFactory_CreateTextFormat(factory, nameW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5138 DWRITE_FONT_STRETCH_NORMAL, fontmetrics.designUnitsPerEm, enusW, &format);
5139 ok(hr == S_OK, "got 0x%08x\n", hr);
5141 hr = IDWriteFactory_CreateTextLayout(factory, strW, 2, format, 30000.0f, 100.0f, &layout);
5142 ok(hr == S_OK, "got 0x%08x\n", hr);
5144 range.startPosition = 0;
5145 range.length = 2;
5146 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
5147 ok(hr == S_OK, "got 0x%08x\n", hr);
5149 memset(&ctxt, 0, sizeof(ctxt));
5150 ctxt.format = format;
5151 ctxt.familyW = nameW;
5152 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0f, 0.0f);
5153 ok(hr == S_OK, "got 0x%08x\n", hr);
5155 cleanup:
5156 if (layout)
5157 IDWriteTextLayout_Release(layout);
5158 if (format)
5159 IDWriteTextFormat_Release(format);
5160 IDWriteFontFace_Release(fontface);
5161 IDWriteFontFamily_Release(family);
5163 IDWriteFontCollection_Release(syscollection);
5165 IDWriteFactory_Release(factory);
5168 static void test_InvalidateLayout(void)
5170 static const WCHAR strW[] = {'a',0};
5171 IDWriteTextLayout3 *layout3;
5172 IDWriteTextLayout *layout;
5173 IDWriteTextFormat *format;
5174 IDWriteFactory *factory;
5175 HRESULT hr;
5177 factory = create_factory();
5179 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5180 DWRITE_FONT_STRETCH_NORMAL, 10.0f, enusW, &format);
5181 ok(hr == S_OK, "got 0x%08x\n", hr);
5183 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 1000.0f, 1000.0f, &layout);
5184 ok(hr == S_OK, "got 0x%08x\n", hr);
5186 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout3, (void**)&layout3);
5187 if (hr == S_OK) {
5188 IDWriteTextFormat1 *format1;
5189 IDWriteTextFormat2 *format2;
5191 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat2, (void**)&format2);
5192 ok(hr == S_OK, "got 0x%08x\n", hr);
5193 IDWriteTextFormat2_Release(format2);
5195 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat2, (void**)&format2);
5196 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
5198 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
5199 ok(hr == S_OK, "got 0x%08x\n", hr);
5201 hr = IDWriteTextFormat1_QueryInterface(format1, &IID_IDWriteTextFormat2, (void**)&format2);
5202 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
5203 IDWriteTextFormat1_Release(format1);
5205 hr = IDWriteTextLayout3_QueryInterface(layout3, &IID_IDWriteTextFormat2, (void**)&format2);
5206 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
5208 hr = IDWriteTextLayout3_InvalidateLayout(layout3);
5209 ok(hr == S_OK, "got 0x%08x\n", hr);
5210 IDWriteTextLayout3_Release(layout3);
5212 else
5213 win_skip("IDWriteTextLayout3::InvalidateLayout() is not supported.\n");
5215 IDWriteTextLayout_Release(layout);
5216 IDWriteTextFormat_Release(format);
5217 IDWriteFactory_Release(factory);
5220 static void test_line_spacing(void)
5222 static const WCHAR strW[] = {'a',0};
5223 IDWriteTextFormat2 *format2;
5224 IDWriteTextLayout *layout;
5225 IDWriteTextFormat *format;
5226 IDWriteFactory *factory;
5227 HRESULT hr;
5229 factory = create_factory();
5231 hr = IDWriteFactory_CreateTextFormat(factory, tahomaW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5232 DWRITE_FONT_STRETCH_NORMAL, 10.0f, enusW, &format);
5233 ok(hr == S_OK, "got 0x%08x\n", hr);
5235 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0f, 0.0f);
5236 ok(hr == S_OK, "got 0x%08x\n", hr);
5238 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0f, -10.0f);
5239 ok(hr == S_OK, "got 0x%08x\n", hr);
5241 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, -10.0f, 0.0f);
5242 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5244 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_PROPORTIONAL+1, 0.0f, 0.0f);
5245 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5247 hr = IDWriteFactory_CreateTextLayout(factory, strW, 1, format, 1000.0f, 1000.0f, &layout);
5248 ok(hr == S_OK, "got 0x%08x\n", hr);
5250 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0f, 0.0f);
5251 ok(hr == S_OK, "got 0x%08x\n", hr);
5253 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0f, -10.0f);
5254 ok(hr == S_OK, "got 0x%08x\n", hr);
5256 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_DEFAULT, -10.0f, 0.0f);
5257 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5259 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_PROPORTIONAL+1, 0.0f, 0.0f);
5260 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5262 if (IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat2, (void**)&format2) == S_OK) {
5263 DWRITE_LINE_SPACING spacing;
5265 hr = IDWriteTextFormat2_GetLineSpacing(format2, &spacing);
5266 ok(hr == S_OK, "got 0x%08x\n", hr);
5268 ok(spacing.method == DWRITE_LINE_SPACING_METHOD_DEFAULT, "got method %d\n", spacing.method);
5269 ok(spacing.height == 0.0f, "got %f\n", spacing.height);
5270 ok(spacing.baseline == -10.0f, "got %f\n", spacing.baseline);
5271 ok(spacing.leadingBefore == 0.0f, "got %f\n", spacing.leadingBefore);
5272 ok(spacing.fontLineGapUsage == DWRITE_FONT_LINE_GAP_USAGE_DEFAULT, "got %f\n", spacing.leadingBefore);
5274 spacing.leadingBefore = -1.0f;
5276 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5277 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5279 spacing.leadingBefore = 1.1f;
5281 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5282 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5284 spacing.leadingBefore = 1.0f;
5286 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5287 ok(hr == S_OK, "got 0x%08x\n", hr);
5289 spacing.method = DWRITE_LINE_SPACING_METHOD_PROPORTIONAL + 1;
5290 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5291 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5293 spacing.method = DWRITE_LINE_SPACING_METHOD_PROPORTIONAL;
5294 spacing.fontLineGapUsage = DWRITE_FONT_LINE_GAP_USAGE_ENABLED + 1;
5295 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5296 ok(hr == S_OK, "got 0x%08x\n", hr);
5298 hr = IDWriteTextFormat2_GetLineSpacing(format2, &spacing);
5299 ok(hr == S_OK, "got 0x%08x\n", hr);
5300 ok(spacing.fontLineGapUsage == DWRITE_FONT_LINE_GAP_USAGE_ENABLED + 1, "got %d\n", spacing.fontLineGapUsage);
5302 IDWriteTextFormat2_Release(format2);
5305 IDWriteTextLayout_Release(layout);
5306 IDWriteTextFormat_Release(format);
5307 IDWriteFactory_Release(factory);
5310 START_TEST(layout)
5312 IDWriteFactory *factory;
5314 if (!(factory = create_factory())) {
5315 win_skip("failed to create factory\n");
5316 return;
5319 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
5320 init_call_sequences(expected_seq, 1);
5322 test_CreateTextLayout();
5323 test_CreateGdiCompatibleTextLayout();
5324 test_CreateTextFormat();
5325 test_GetLocaleName();
5326 test_CreateEllipsisTrimmingSign();
5327 test_fontweight();
5328 test_SetInlineObject();
5329 test_Draw();
5330 test_typography();
5331 test_GetClusterMetrics();
5332 test_SetLocaleName();
5333 test_SetPairKerning();
5334 test_SetVerticalGlyphOrientation();
5335 test_fallback();
5336 test_DetermineMinWidth();
5337 test_SetFontSize();
5338 test_SetFontFamilyName();
5339 test_SetFontStyle();
5340 test_SetFontStretch();
5341 test_SetStrikethrough();
5342 test_GetMetrics();
5343 test_SetFlowDirection();
5344 test_SetDrawingEffect();
5345 test_GetLineMetrics();
5346 test_SetTextAlignment();
5347 test_SetParagraphAlignment();
5348 test_SetReadingDirection();
5349 test_pixelsnapping();
5350 test_SetWordWrapping();
5351 test_MapCharacters();
5352 test_FontFallbackBuilder();
5353 test_SetTypography();
5354 test_SetLastLineWrapping();
5355 test_SetOpticalAlignment();
5356 test_SetUnderline();
5357 test_InvalidateLayout();
5358 test_line_spacing();
5360 IDWriteFactory_Release(factory);