Release 6.15.
[wine.git] / dlls / dwrite / tests / layout.c
blob3fe149927cadfb15bf29520898d8cd32b44e6478
1 /*
2 * Text layout/format tests
4 * Copyright 2012, 2014-2020 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 struct testanalysissink
34 IDWriteTextAnalysisSink IDWriteTextAnalysisSink_iface;
35 DWRITE_SCRIPT_ANALYSIS sa; /* last analysis, with SetScriptAnalysis() */
38 static inline struct testanalysissink *impl_from_IDWriteTextAnalysisSink(IDWriteTextAnalysisSink *iface)
40 return CONTAINING_RECORD(iface, struct testanalysissink, IDWriteTextAnalysisSink_iface);
43 /* test IDWriteTextAnalysisSink */
44 static HRESULT WINAPI analysissink_QueryInterface(IDWriteTextAnalysisSink *iface, REFIID riid, void **obj)
46 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown))
48 *obj = iface;
49 return S_OK;
52 *obj = NULL;
53 return E_NOINTERFACE;
56 static ULONG WINAPI analysissink_AddRef(IDWriteTextAnalysisSink *iface)
58 return 2;
61 static ULONG WINAPI analysissink_Release(IDWriteTextAnalysisSink *iface)
63 return 1;
66 static HRESULT WINAPI analysissink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
67 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
69 struct testanalysissink *sink = impl_from_IDWriteTextAnalysisSink(iface);
70 sink->sa = *sa;
71 return S_OK;
74 static HRESULT WINAPI analysissink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
75 UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const* breakpoints)
77 ok(0, "unexpected call\n");
78 return E_NOTIMPL;
81 static HRESULT WINAPI analysissink_SetBidiLevel(IDWriteTextAnalysisSink *iface,
82 UINT32 position, UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
84 ok(0, "unexpected\n");
85 return E_NOTIMPL;
88 static HRESULT WINAPI analysissink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
89 UINT32 position, UINT32 length, IDWriteNumberSubstitution* substitution)
91 ok(0, "unexpected\n");
92 return E_NOTIMPL;
95 static IDWriteTextAnalysisSinkVtbl analysissinkvtbl = {
96 analysissink_QueryInterface,
97 analysissink_AddRef,
98 analysissink_Release,
99 analysissink_SetScriptAnalysis,
100 analysissink_SetLineBreakpoints,
101 analysissink_SetBidiLevel,
102 analysissink_SetNumberSubstitution
105 static struct testanalysissink analysissink = {
106 { &analysissinkvtbl },
107 { 0 }
110 /* test IDWriteTextAnalysisSource */
111 static HRESULT WINAPI analysissource_QueryInterface(IDWriteTextAnalysisSource *iface,
112 REFIID riid, void **obj)
114 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSource) || IsEqualIID(riid, &IID_IUnknown)) {
115 *obj = iface;
116 IDWriteTextAnalysisSource_AddRef(iface);
117 return S_OK;
119 return E_NOINTERFACE;
122 static ULONG WINAPI analysissource_AddRef(IDWriteTextAnalysisSource *iface)
124 return 2;
127 static ULONG WINAPI analysissource_Release(IDWriteTextAnalysisSource *iface)
129 return 1;
132 static const WCHAR *g_source;
134 static HRESULT WINAPI analysissource_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
135 UINT32 position, WCHAR const** text, UINT32* text_len)
137 if (position >= lstrlenW(g_source))
139 *text = NULL;
140 *text_len = 0;
142 else
144 *text = &g_source[position];
145 *text_len = lstrlenW(g_source) - position;
148 return S_OK;
151 static HRESULT WINAPI analysissource_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
152 UINT32 position, WCHAR const** text, UINT32* text_len)
154 ok(0, "unexpected\n");
155 return E_NOTIMPL;
158 static DWRITE_READING_DIRECTION WINAPI analysissource_GetParagraphReadingDirection(
159 IDWriteTextAnalysisSource *iface)
161 ok(0, "unexpected\n");
162 return DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
165 static HRESULT WINAPI analysissource_GetLocaleName(IDWriteTextAnalysisSource *iface,
166 UINT32 position, UINT32* text_len, WCHAR const** locale)
168 *locale = NULL;
169 *text_len = 0;
170 return S_OK;
173 static HRESULT WINAPI analysissource_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
174 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
176 ok(0, "unexpected\n");
177 return E_NOTIMPL;
180 static IDWriteTextAnalysisSourceVtbl analysissourcevtbl = {
181 analysissource_QueryInterface,
182 analysissource_AddRef,
183 analysissource_Release,
184 analysissource_GetTextAtPosition,
185 analysissource_GetTextBeforePosition,
186 analysissource_GetParagraphReadingDirection,
187 analysissource_GetLocaleName,
188 analysissource_GetNumberSubstitution
191 static IDWriteTextAnalysisSource analysissource = { &analysissourcevtbl };
193 static void *create_factory_iid(REFIID riid)
195 IUnknown *factory = NULL;
196 DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, riid, &factory);
197 return factory;
200 static IDWriteFactory *create_factory(void)
202 IDWriteFactory *factory = create_factory_iid(&IID_IDWriteFactory);
203 ok(factory != NULL, "Failed to create factory.\n");
204 return factory;
207 /* obvious limitation is that only last script data is returned, so this
208 helper is suitable for single script strings only */
209 static void get_script_analysis(const WCHAR *str, UINT32 len, DWRITE_SCRIPT_ANALYSIS *sa)
211 IDWriteTextAnalyzer *analyzer;
212 IDWriteFactory *factory;
213 HRESULT hr;
215 g_source = str;
217 factory = create_factory();
218 hr = IDWriteFactory_CreateTextAnalyzer(factory, &analyzer);
219 ok(hr == S_OK, "got 0x%08x\n", hr);
221 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &analysissource, 0, len, &analysissink.IDWriteTextAnalysisSink_iface);
222 ok(hr == S_OK, "got 0x%08x\n", hr);
224 *sa = analysissink.sa;
225 IDWriteFactory_Release(factory);
228 static IDWriteFontFace *get_fontface_from_format(IDWriteTextFormat *format)
230 IDWriteFontCollection *collection;
231 IDWriteFontFamily *family;
232 IDWriteFontFace *fontface;
233 IDWriteFont *font;
234 WCHAR nameW[255];
235 UINT32 index;
236 BOOL exists;
237 HRESULT hr;
239 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
240 ok(hr == S_OK, "got 0x%08x\n", hr);
242 hr = IDWriteTextFormat_GetFontFamilyName(format, nameW, ARRAY_SIZE(nameW));
243 ok(hr == S_OK, "got 0x%08x\n", hr);
245 hr = IDWriteFontCollection_FindFamilyName(collection, nameW, &index, &exists);
246 ok(hr == S_OK, "got 0x%08x\n", hr);
248 hr = IDWriteFontCollection_GetFontFamily(collection, index, &family);
249 ok(hr == S_OK, "got 0x%08x\n", hr);
250 IDWriteFontCollection_Release(collection);
252 hr = IDWriteFontFamily_GetFirstMatchingFont(family,
253 IDWriteTextFormat_GetFontWeight(format),
254 IDWriteTextFormat_GetFontStretch(format),
255 IDWriteTextFormat_GetFontStyle(format),
256 &font);
257 ok(hr == S_OK, "got 0x%08x\n", hr);
259 hr = IDWriteFont_CreateFontFace(font, &fontface);
260 ok(hr == S_OK, "got 0x%08x\n", hr);
262 IDWriteFont_Release(font);
263 IDWriteFontFamily_Release(family);
265 return fontface;
268 #define EXPECT_REF(obj,ref) _expect_ref((IUnknown*)obj, ref, __LINE__)
269 static void _expect_ref(IUnknown* obj, ULONG ref, int line)
271 ULONG rc;
272 IUnknown_AddRef(obj);
273 rc = IUnknown_Release(obj);
274 ok_(__FILE__,line)(rc == ref, "expected refcount %d, got %d\n", ref, rc);
277 enum drawcall_modifiers_kind {
278 DRAW_EFFECT = 0x1000
281 enum drawcall_kind {
282 DRAW_GLYPHRUN = 0,
283 DRAW_UNDERLINE = 1,
284 DRAW_STRIKETHROUGH = 2,
285 DRAW_INLINE = 3,
286 DRAW_LAST_KIND = 4,
287 DRAW_TOTAL_KINDS = 5,
288 DRAW_KINDS_MASK = 0xff
291 static const char *get_draw_kind_name(unsigned short kind)
293 static const char *kind_names[] = {
294 "GLYPH_RUN",
295 "UNDERLINE",
296 "STRIKETHROUGH",
297 "INLINE",
298 "END_OF_SEQ",
300 "GLYPH_RUN|EFFECT",
301 "UNDERLINE|EFFECT",
302 "STRIKETHROUGH|EFFECT",
303 "INLINE|EFFECT",
304 "END_OF_SEQ"
306 if ((kind & DRAW_KINDS_MASK) > DRAW_LAST_KIND)
307 return "unknown";
308 return (kind & DRAW_EFFECT) ? kind_names[(kind & DRAW_KINDS_MASK) + DRAW_TOTAL_KINDS] :
309 kind_names[kind];
312 struct drawcall_entry {
313 enum drawcall_kind kind;
314 WCHAR string[10]; /* only meaningful for DrawGlyphRun() */
315 WCHAR locale[LOCALE_NAME_MAX_LENGTH];
316 UINT32 glyphcount; /* only meaningful for DrawGlyphRun() */
317 UINT32 bidilevel;
320 struct drawcall_sequence
322 int count;
323 int size;
324 struct drawcall_entry *sequence;
327 struct drawtestcontext {
328 unsigned short kind;
329 BOOL todo;
330 int *failcount;
331 const char *file;
332 int line;
335 #define NUM_CALL_SEQUENCES 1
336 #define RENDERER_ID 0
337 static struct drawcall_sequence *sequences[NUM_CALL_SEQUENCES];
338 static struct drawcall_sequence *expected_seq[1];
340 static void add_call(struct drawcall_sequence **seq, int sequence_index, const struct drawcall_entry *call)
342 struct drawcall_sequence *call_seq = seq[sequence_index];
344 if (!call_seq->sequence) {
345 call_seq->size = 10;
346 call_seq->sequence = HeapAlloc(GetProcessHeap(), 0, call_seq->size * sizeof (struct drawcall_entry));
349 if (call_seq->count == call_seq->size) {
350 call_seq->size *= 2;
351 call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
352 call_seq->sequence,
353 call_seq->size * sizeof (struct drawcall_entry));
356 assert(call_seq->sequence);
357 call_seq->sequence[call_seq->count++] = *call;
360 static inline void flush_sequence(struct drawcall_sequence **seg, int sequence_index)
362 struct drawcall_sequence *call_seq = seg[sequence_index];
364 HeapFree(GetProcessHeap(), 0, call_seq->sequence);
365 call_seq->sequence = NULL;
366 call_seq->count = call_seq->size = 0;
369 static void init_call_sequences(struct drawcall_sequence **seq, int n)
371 int i;
373 for (i = 0; i < n; i++)
374 seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct drawcall_sequence));
377 static void ok_sequence_(struct drawcall_sequence **seq, int sequence_index,
378 const struct drawcall_entry *expected, const char *context, BOOL todo,
379 const char *file, int line)
381 static const struct drawcall_entry end_of_sequence = { DRAW_LAST_KIND };
382 struct drawcall_sequence *call_seq = seq[sequence_index];
383 const struct drawcall_entry *actual, *sequence;
384 int failcount = 0;
386 add_call(seq, sequence_index, &end_of_sequence);
388 sequence = call_seq->sequence;
389 actual = sequence;
391 while (expected->kind != DRAW_LAST_KIND && actual->kind != DRAW_LAST_KIND) {
392 if (expected->kind != actual->kind) {
393 if (todo) {
394 failcount++;
395 todo_wine
396 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
397 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
399 flush_sequence(seq, sequence_index);
400 return;
402 else
403 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
404 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
406 else if ((expected->kind & DRAW_KINDS_MASK) == DRAW_GLYPHRUN) {
407 int cmp = lstrcmpW(expected->string, actual->string);
408 if (cmp != 0 && todo) {
409 failcount++;
410 todo_wine
411 ok_(file, line) (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 else
415 ok_(file, line) (cmp == 0, "%s: glyphrun string %s was expected, but got %s instead\n",
416 context, wine_dbgstr_w(expected->string), wine_dbgstr_w(actual->string));
418 cmp = lstrcmpW(expected->locale, actual->locale);
419 if (cmp != 0 && todo) {
420 failcount++;
421 todo_wine
422 ok_(file, line) (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 else
426 ok_(file, line) (cmp == 0, "%s: glyph run locale %s was expected, but got %s instead\n",
427 context, wine_dbgstr_w(expected->locale), wine_dbgstr_w(actual->locale));
429 if (expected->glyphcount != actual->glyphcount && todo) {
430 failcount++;
431 todo_wine
432 ok_(file, line) (0, "%s: wrong glyph count, %u was expected, but got %u instead\n",
433 context, expected->glyphcount, actual->glyphcount);
435 else
436 ok_(file, line) (expected->glyphcount == actual->glyphcount,
437 "%s: wrong glyph count, %u was expected, but got %u instead\n",
438 context, expected->glyphcount, actual->glyphcount);
440 if (expected->bidilevel != actual->bidilevel && todo) {
441 failcount++;
442 todo_wine
443 ok_(file, line) (0, "%s: wrong bidi level, %u was expected, but got %u instead\n",
444 context, expected->bidilevel, actual->bidilevel);
446 else
447 ok_(file, line) (expected->bidilevel == actual->bidilevel,
448 "%s: wrong bidi level, %u was expected, but got %u instead\n",
449 context, expected->bidilevel, actual->bidilevel);
451 else if ((expected->kind & DRAW_KINDS_MASK) == DRAW_UNDERLINE) {
452 int cmp = lstrcmpW(expected->locale, actual->locale);
453 if (cmp != 0 && todo) {
454 failcount++;
455 todo_wine
456 ok_(file, line) (0, "%s: underline locale %s was expected, but got %s instead\n",
457 context, wine_dbgstr_w(expected->locale), wine_dbgstr_w(actual->locale));
459 else
460 ok_(file, line) (cmp == 0, "%s: underline locale %s was expected, but got %s instead\n",
461 context, wine_dbgstr_w(expected->locale), wine_dbgstr_w(actual->locale));
463 expected++;
464 actual++;
467 if (todo) {
468 todo_wine {
469 if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND) {
470 failcount++;
471 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
472 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
476 else if (expected->kind != DRAW_LAST_KIND || actual->kind != DRAW_LAST_KIND)
477 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
478 context, get_draw_kind_name(expected->kind), get_draw_kind_name(actual->kind));
480 if (todo && !failcount) /* succeeded yet marked todo */
481 todo_wine
482 ok_(file, line)(1, "%s: marked \"todo_wine\" but succeeds\n", context);
484 flush_sequence(seq, sequence_index);
487 #define ok_sequence(seq, index, exp, contx, todo) \
488 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
490 static HRESULT WINAPI testrenderer_QI(IDWriteTextRenderer *iface, REFIID riid, void **obj)
492 if (IsEqualIID(riid, &IID_IDWriteTextRenderer) ||
493 IsEqualIID(riid, &IID_IDWritePixelSnapping) ||
494 IsEqualIID(riid, &IID_IUnknown)
496 *obj = iface;
497 return S_OK;
500 *obj = NULL;
502 /* IDWriteTextRenderer1 overrides drawing calls, ignore for now */
503 if (IsEqualIID(riid, &IID_IDWriteTextRenderer1))
504 return E_NOINTERFACE;
506 ok(0, "unexpected QI %s\n", wine_dbgstr_guid(riid));
507 return E_NOINTERFACE;
510 static ULONG WINAPI testrenderer_AddRef(IDWriteTextRenderer *iface)
512 return 2;
515 static ULONG WINAPI testrenderer_Release(IDWriteTextRenderer *iface)
517 return 1;
520 struct renderer_context {
521 BOOL gdicompat;
522 BOOL use_gdi_natural;
523 BOOL snapping_disabled;
524 DWRITE_MATRIX m;
525 FLOAT ppdip;
526 FLOAT originX;
527 FLOAT originY;
528 IDWriteTextFormat *format;
529 const WCHAR *familyW;
532 static HRESULT WINAPI testrenderer_IsPixelSnappingDisabled(IDWriteTextRenderer *iface,
533 void *context, BOOL *disabled)
535 struct renderer_context *ctxt = (struct renderer_context*)context;
536 if (ctxt)
537 *disabled = ctxt->snapping_disabled;
538 else
539 *disabled = TRUE;
540 return S_OK;
543 static HRESULT WINAPI testrenderer_GetCurrentTransform(IDWriteTextRenderer *iface,
544 void *context, DWRITE_MATRIX *m)
546 struct renderer_context *ctxt = (struct renderer_context*)context;
547 ok(!ctxt->snapping_disabled, "expected enabled snapping\n");
548 *m = ctxt->m;
549 return S_OK;
552 static HRESULT WINAPI testrenderer_GetPixelsPerDip(IDWriteTextRenderer *iface,
553 void *context, FLOAT *pixels_per_dip)
555 struct renderer_context *ctxt = (struct renderer_context*)context;
556 *pixels_per_dip = ctxt->ppdip;
557 return S_OK;
560 #define TEST_MEASURING_MODE(ctxt, mode) test_measuring_mode(ctxt, mode, __LINE__)
561 static void test_measuring_mode(const struct renderer_context *ctxt, DWRITE_MEASURING_MODE mode, int line)
563 if (ctxt->gdicompat) {
564 if (ctxt->use_gdi_natural)
565 ok_(__FILE__, line)(mode == DWRITE_MEASURING_MODE_GDI_NATURAL, "got %d\n", mode);
566 else
567 ok_(__FILE__, line)(mode == DWRITE_MEASURING_MODE_GDI_CLASSIC, "got %d\n", mode);
569 else
570 ok_(__FILE__, line)(mode == DWRITE_MEASURING_MODE_NATURAL, "got %d\n", mode);
573 static HRESULT WINAPI testrenderer_DrawGlyphRun(IDWriteTextRenderer *iface,
574 void *context,
575 FLOAT baselineOriginX,
576 FLOAT baselineOriginY,
577 DWRITE_MEASURING_MODE mode,
578 DWRITE_GLYPH_RUN const *run,
579 DWRITE_GLYPH_RUN_DESCRIPTION const *descr,
580 IUnknown *effect)
582 struct renderer_context *ctxt = (struct renderer_context*)context;
583 struct drawcall_entry entry;
584 DWRITE_SCRIPT_ANALYSIS sa;
586 if (ctxt) {
587 TEST_MEASURING_MODE(ctxt, mode);
588 ctxt->originX = baselineOriginX;
589 ctxt->originY = baselineOriginY;
592 ok(descr->stringLength < ARRAY_SIZE(entry.string), "string is too long\n");
593 if (descr->stringLength && descr->stringLength < ARRAY_SIZE(entry.string)) {
594 memcpy(entry.string, descr->string, descr->stringLength*sizeof(WCHAR));
595 entry.string[descr->stringLength] = 0;
597 else
598 entry.string[0] = 0;
600 /* see what's reported for control codes runs */
601 get_script_analysis(descr->string, descr->stringLength, &sa);
602 if (sa.shapes == DWRITE_SCRIPT_SHAPES_NO_VISUAL) {
603 UINT32 i;
605 /* glyphs are not reported at all for control code runs */
606 ok(run->glyphCount == 0, "got %u\n", run->glyphCount);
607 ok(run->glyphAdvances != NULL, "advances array %p\n", run->glyphAdvances);
608 ok(run->glyphOffsets != NULL, "offsets array %p\n", run->glyphOffsets);
609 ok(run->fontFace != NULL, "got %p\n", run->fontFace);
610 /* text positions are still valid */
611 ok(descr->string != NULL, "got string %p\n", descr->string);
612 ok(descr->stringLength > 0, "got string length %u\n", descr->stringLength);
613 ok(descr->clusterMap != NULL, "clustermap %p\n", descr->clusterMap);
614 for (i = 0; i < descr->stringLength; i++)
615 ok(descr->clusterMap[i] == i, "got %u\n", descr->clusterMap[i]);
618 entry.kind = DRAW_GLYPHRUN;
619 if (effect)
620 entry.kind |= DRAW_EFFECT;
621 ok(lstrlenW(descr->localeName) < LOCALE_NAME_MAX_LENGTH, "unexpectedly long locale name\n");
622 lstrcpyW(entry.locale, descr->localeName);
623 entry.glyphcount = run->glyphCount;
624 entry.bidilevel = run->bidiLevel;
625 add_call(sequences, RENDERER_ID, &entry);
626 return S_OK;
629 static HRESULT WINAPI testrenderer_DrawUnderline(IDWriteTextRenderer *iface,
630 void *context,
631 FLOAT baselineOriginX,
632 FLOAT baselineOriginY,
633 DWRITE_UNDERLINE const* underline,
634 IUnknown *effect)
636 struct renderer_context *ctxt = (struct renderer_context*)context;
637 struct drawcall_entry entry = { 0 };
639 if (ctxt)
640 TEST_MEASURING_MODE(ctxt, underline->measuringMode);
642 ok(underline->runHeight > 0.0f, "Expected non-zero run height\n");
643 if (ctxt && ctxt->format) {
644 DWRITE_FONT_METRICS metrics;
645 IDWriteFontFace *fontface;
646 FLOAT emsize;
648 fontface = get_fontface_from_format(ctxt->format);
649 emsize = IDWriteTextFormat_GetFontSize(ctxt->format);
650 IDWriteFontFace_GetMetrics(fontface, &metrics);
652 ok(emsize == metrics.designUnitsPerEm, "Unexpected font size %f\n", emsize);
653 /* Expected height is in design units, allow some absolute difference from it. Seems to only happen on Vista */
654 ok(fabs(metrics.capHeight - underline->runHeight) < 2.0f, "Expected runHeight %u, got %f, family %s\n",
655 metrics.capHeight, underline->runHeight, wine_dbgstr_w(ctxt->familyW));
657 IDWriteFontFace_Release(fontface);
660 entry.kind = DRAW_UNDERLINE;
661 if (effect)
662 entry.kind |= DRAW_EFFECT;
663 lstrcpyW(entry.locale, underline->localeName);
664 add_call(sequences, RENDERER_ID, &entry);
665 return S_OK;
668 static HRESULT WINAPI testrenderer_DrawStrikethrough(IDWriteTextRenderer *iface,
669 void *context,
670 FLOAT baselineOriginX,
671 FLOAT baselineOriginY,
672 DWRITE_STRIKETHROUGH const* strikethrough,
673 IUnknown *effect)
675 struct renderer_context *ctxt = (struct renderer_context*)context;
676 struct drawcall_entry entry = { 0 };
678 if (ctxt)
679 TEST_MEASURING_MODE(ctxt, strikethrough->measuringMode);
681 entry.kind = DRAW_STRIKETHROUGH;
682 if (effect)
683 entry.kind |= DRAW_EFFECT;
684 add_call(sequences, RENDERER_ID, &entry);
685 return S_OK;
688 static HRESULT WINAPI testrenderer_DrawInlineObject(IDWriteTextRenderer *iface,
689 void *context,
690 FLOAT originX,
691 FLOAT originY,
692 IDWriteInlineObject *object,
693 BOOL is_sideways,
694 BOOL is_rtl,
695 IUnknown *effect)
697 struct drawcall_entry entry = { 0 };
698 entry.kind = DRAW_INLINE;
699 if (effect)
700 entry.kind |= DRAW_EFFECT;
701 add_call(sequences, RENDERER_ID, &entry);
702 return S_OK;
705 static const IDWriteTextRendererVtbl testrenderervtbl = {
706 testrenderer_QI,
707 testrenderer_AddRef,
708 testrenderer_Release,
709 testrenderer_IsPixelSnappingDisabled,
710 testrenderer_GetCurrentTransform,
711 testrenderer_GetPixelsPerDip,
712 testrenderer_DrawGlyphRun,
713 testrenderer_DrawUnderline,
714 testrenderer_DrawStrikethrough,
715 testrenderer_DrawInlineObject
718 static IDWriteTextRenderer testrenderer = { &testrenderervtbl };
720 /* test IDWriteInlineObject */
721 static HRESULT WINAPI testinlineobj_QI(IDWriteInlineObject *iface, REFIID riid, void **obj)
723 if (IsEqualIID(riid, &IID_IDWriteInlineObject) || IsEqualIID(riid, &IID_IUnknown)) {
724 *obj = iface;
725 IDWriteInlineObject_AddRef(iface);
726 return S_OK;
729 *obj = NULL;
730 return E_NOINTERFACE;
733 static ULONG WINAPI testinlineobj_AddRef(IDWriteInlineObject *iface)
735 return 2;
738 static ULONG WINAPI testinlineobj_Release(IDWriteInlineObject *iface)
740 return 1;
743 static HRESULT WINAPI testinlineobj_Draw(IDWriteInlineObject *iface,
744 void* client_drawingontext, IDWriteTextRenderer* renderer,
745 FLOAT originX, FLOAT originY, BOOL is_sideways, BOOL is_rtl, IUnknown *drawing_effect)
747 ok(0, "unexpected call\n");
748 return E_NOTIMPL;
751 static HRESULT WINAPI testinlineobj_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
753 metrics->width = 123.0;
754 return 0x8faecafe;
757 static HRESULT WINAPI testinlineobj_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
759 ok(0, "unexpected call\n");
760 return E_NOTIMPL;
763 static HRESULT WINAPI testinlineobj_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
764 DWRITE_BREAK_CONDITION *after)
766 *before = *after = DWRITE_BREAK_CONDITION_MUST_BREAK;
767 return 0x8feacafe;
770 static HRESULT WINAPI testinlineobj2_GetBreakConditions(IDWriteInlineObject *iface, DWRITE_BREAK_CONDITION *before,
771 DWRITE_BREAK_CONDITION *after)
773 *before = *after = DWRITE_BREAK_CONDITION_MAY_NOT_BREAK;
774 return S_OK;
777 static IDWriteInlineObjectVtbl testinlineobjvtbl = {
778 testinlineobj_QI,
779 testinlineobj_AddRef,
780 testinlineobj_Release,
781 testinlineobj_Draw,
782 testinlineobj_GetMetrics,
783 testinlineobj_GetOverhangMetrics,
784 testinlineobj_GetBreakConditions
787 static IDWriteInlineObjectVtbl testinlineobjvtbl2 = {
788 testinlineobj_QI,
789 testinlineobj_AddRef,
790 testinlineobj_Release,
791 testinlineobj_Draw,
792 testinlineobj_GetMetrics,
793 testinlineobj_GetOverhangMetrics,
794 testinlineobj2_GetBreakConditions
797 static IDWriteInlineObject testinlineobj = { &testinlineobjvtbl };
798 static IDWriteInlineObject testinlineobj2 = { &testinlineobjvtbl };
799 static IDWriteInlineObject testinlineobj3 = { &testinlineobjvtbl2 };
801 struct test_inline_obj
803 IDWriteInlineObject IDWriteInlineObject_iface;
804 DWRITE_INLINE_OBJECT_METRICS metrics;
805 DWRITE_OVERHANG_METRICS overhangs;
808 static inline struct test_inline_obj *impl_from_IDWriteInlineObject(IDWriteInlineObject *iface)
810 return CONTAINING_RECORD(iface, struct test_inline_obj, IDWriteInlineObject_iface);
813 static HRESULT WINAPI testinlineobj3_GetMetrics(IDWriteInlineObject *iface, DWRITE_INLINE_OBJECT_METRICS *metrics)
815 struct test_inline_obj *obj = impl_from_IDWriteInlineObject(iface);
816 *metrics = obj->metrics;
817 return S_OK;
820 static HRESULT WINAPI testinlineobj3_GetOverhangMetrics(IDWriteInlineObject *iface, DWRITE_OVERHANG_METRICS *overhangs)
822 struct test_inline_obj *obj = impl_from_IDWriteInlineObject(iface);
823 *overhangs = obj->overhangs;
824 /* Return value is ignored. */
825 return E_NOTIMPL;
828 static const IDWriteInlineObjectVtbl testinlineobjvtbl3 = {
829 testinlineobj_QI,
830 testinlineobj_AddRef,
831 testinlineobj_Release,
832 testinlineobj_Draw,
833 testinlineobj3_GetMetrics,
834 testinlineobj3_GetOverhangMetrics,
835 testinlineobj_GetBreakConditions,
838 static void test_inline_obj_init(struct test_inline_obj *obj, const DWRITE_INLINE_OBJECT_METRICS *metrics,
839 const DWRITE_OVERHANG_METRICS *overhangs)
841 obj->IDWriteInlineObject_iface.lpVtbl = &testinlineobjvtbl3;
842 obj->metrics = *metrics;
843 obj->overhangs = *overhangs;
846 struct test_effect
848 IUnknown IUnknown_iface;
849 LONG ref;
852 static inline struct test_effect *test_effect_from_IUnknown(IUnknown *iface)
854 return CONTAINING_RECORD(iface, struct test_effect, IUnknown_iface);
857 static HRESULT WINAPI testeffect_QI(IUnknown *iface, REFIID riid, void **obj)
859 if (IsEqualIID(riid, &IID_IUnknown)) {
860 *obj = iface;
861 IUnknown_AddRef(iface);
862 return S_OK;
865 ok(0, "Unexpected riid %s.\n", wine_dbgstr_guid(riid));
866 *obj = NULL;
867 return E_NOINTERFACE;
870 static ULONG WINAPI testeffect_AddRef(IUnknown *iface)
872 struct test_effect *effect = test_effect_from_IUnknown(iface);
873 return InterlockedIncrement(&effect->ref);
876 static ULONG WINAPI testeffect_Release(IUnknown *iface)
878 struct test_effect *effect = test_effect_from_IUnknown(iface);
879 LONG ref = InterlockedDecrement(&effect->ref);
881 if (!ref)
882 HeapFree(GetProcessHeap(), 0, effect);
884 return ref;
887 static const IUnknownVtbl testeffectvtbl = {
888 testeffect_QI,
889 testeffect_AddRef,
890 testeffect_Release
893 static IUnknown *create_test_effect(void)
895 struct test_effect *effect;
897 effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*effect));
898 effect->IUnknown_iface.lpVtbl = &testeffectvtbl;
899 effect->ref = 1;
901 return &effect->IUnknown_iface;
904 static void test_CreateTextLayout(void)
906 IDWriteTextLayout4 *layout4;
907 IDWriteTextLayout2 *layout2 = NULL;
908 IDWriteTextLayout *layout;
909 IDWriteTextFormat3 *format3;
910 IDWriteTextFormat *format;
911 IDWriteFactory *factory;
912 HRESULT hr;
914 factory = create_factory();
916 layout = (void*)0xdeadbeef;
917 hr = IDWriteFactory_CreateTextLayout(factory, NULL, 0, NULL, 0.0f, 0.0f, &layout);
918 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
919 ok(layout == NULL, "got %p\n", layout);
921 layout = (void*)0xdeadbeef;
922 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, NULL, 0.0f, 0.0f, &layout);
923 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
924 ok(layout == NULL, "got %p\n", layout);
926 layout = (void*)0xdeadbeef;
927 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, NULL, 1.0f, 0.0f, &layout);
928 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
929 ok(layout == NULL, "got %p\n", layout);
931 layout = (void*)0xdeadbeef;
932 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, NULL, 0.0f, 1.0f, &layout);
933 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
934 ok(layout == NULL, "got %p\n", layout);
936 layout = (void*)0xdeadbeef;
937 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, NULL, 1000.0f, 1000.0f, &layout);
938 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
939 ok(layout == NULL, "got %p\n", layout);
941 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
942 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
943 ok(hr == S_OK, "Failed to create format, hr %#x.\n", hr);
945 layout = (void*)0xdeadbeef;
946 hr = IDWriteFactory_CreateTextLayout(factory, NULL, 0, format, 100.0f, 100.0f, &layout);
947 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
948 ok(layout == NULL, "got %p\n", layout);
950 layout = (void *)0xdeadbeef;
951 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, -100.0f, 100.0f, &layout);
952 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
953 ok(layout == NULL, "Unexpected pointer %p.\n", layout);
955 layout = (void *)0xdeadbeef;
956 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, 100.0f, -100.0f, &layout);
957 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
958 ok(layout == NULL, "Unexpected pointer %p.\n", layout);
960 layout = (void *)0xdeadbeef;
961 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, -100.0f, -100.0f, &layout);
962 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
963 ok(layout == NULL, "Unexpected pointer %p.\n", layout);
965 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 0, format, 0.0f, 0.0f, &layout);
966 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
967 IDWriteTextLayout_Release(layout);
969 EXPECT_REF(format, 1);
970 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, 1000.0f, 1000.0f, &layout);
971 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
972 EXPECT_REF(format, 1);
974 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
975 if (hr == S_OK) {
976 IDWriteTextLayout1 *layout1;
977 IDWriteTextFormat1 *format1;
978 IDWriteTextFormat *format;
980 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextLayout1, (void**)&layout1);
981 ok(hr == S_OK, "got 0x%08x\n", hr);
982 IDWriteTextLayout1_Release(layout1);
984 EXPECT_REF(layout2, 2);
985 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
986 ok(hr == S_OK, "got 0x%08x\n", hr);
987 EXPECT_REF(layout2, 3);
989 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat, (void**)&format);
990 ok(hr == S_OK, "got 0x%08x\n", hr);
991 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
992 ok(format != (IDWriteTextFormat*)layout2, "got %p, %p\n", format, layout2);
993 EXPECT_REF(layout2, 4);
995 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextLayout1, (void**)&layout1);
996 ok(hr == S_OK, "got 0x%08x\n", hr);
997 IDWriteTextLayout1_Release(layout1);
999 IDWriteTextFormat1_Release(format1);
1000 IDWriteTextFormat_Release(format);
1002 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
1003 ok(hr == S_OK, "got 0x%08x\n", hr);
1004 EXPECT_REF(layout2, 3);
1006 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format);
1007 ok(hr == S_OK, "got 0x%08x\n", hr);
1008 ok(format == (IDWriteTextFormat*)format1, "got %p, %p\n", format, format1);
1009 EXPECT_REF(layout2, 4);
1011 IDWriteTextFormat1_Release(format1);
1012 IDWriteTextFormat_Release(format);
1014 else
1015 win_skip("IDWriteTextLayout2 is not supported.\n");
1017 if (layout2 && SUCCEEDED(IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextLayout4, (void **)&layout4)))
1019 hr = IDWriteTextLayout4_QueryInterface(layout4, &IID_IDWriteTextFormat3, (void **)&format3);
1020 ok(hr == S_OK, "Failed to get text format, hr %#x.\n", hr);
1021 IDWriteTextFormat3_Release(format3);
1023 else
1024 win_skip("IDWriteTextLayout4 is not supported.\n");
1026 if (layout2)
1027 IDWriteTextLayout2_Release(layout2);
1028 IDWriteTextLayout_Release(layout);
1029 IDWriteTextFormat_Release(format);
1030 IDWriteFactory_Release(factory);
1033 static DWRITE_MATRIX layoutcreate_transforms[] = {
1034 { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
1035 { 1.0, 0.0, 0.0, 1.0, 0.3, 0.2 },
1036 { 1.0, 0.0, 0.0, 1.0,-0.3,-0.2 },
1038 { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
1039 { 1.0, 0.0, 0.0, 0.0, 0.0, 0.0 },
1040 { 1.0, 2.0, 0.5, 1.0, 0.0, 0.0 },
1043 static void test_CreateGdiCompatibleTextLayout(void)
1045 IDWriteTextLayout *layout;
1046 IDWriteTextFormat *format;
1047 IDWriteFactory *factory;
1048 FLOAT dimension;
1049 HRESULT hr;
1050 int i;
1052 factory = create_factory();
1054 layout = (void*)0xdeadbeef;
1055 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, NULL, 0, NULL, 0.0f, 0.0f, 0.0f, NULL, FALSE, &layout);
1056 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1057 ok(layout == NULL, "got %p\n", layout);
1059 layout = (void*)0xdeadbeef;
1060 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, NULL, 0.0f, 0.0f, 0.0f, NULL,
1061 FALSE, &layout);
1062 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1063 ok(layout == NULL, "got %p\n", layout);
1065 layout = (void*)0xdeadbeef;
1066 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, NULL, 1.0f, 0.0f, 0.0f, NULL,
1067 FALSE, &layout);
1068 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1069 ok(layout == NULL, "got %p\n", layout);
1071 layout = (void*)0xdeadbeef;
1072 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, NULL, 1.0f, 0.0f, 1.0f, NULL,
1073 FALSE, &layout);
1074 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1075 ok(layout == NULL, "got %p\n", layout);
1077 layout = (void*)0xdeadbeef;
1078 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, NULL, 1000.0f, 1000.0f, 1.0f, NULL,
1079 FALSE, &layout);
1080 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1081 ok(layout == NULL, "got %p\n", layout);
1083 /* create with text format */
1084 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1085 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
1086 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
1087 EXPECT_REF(format, 1);
1089 layout = (void*)0xdeadbeef;
1090 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, NULL, 0, format, 100.0f, 100.0f, 1.0f, NULL, FALSE, &layout);
1091 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1092 ok(layout == NULL, "got %p\n", layout);
1094 layout = (void *)0xdeadbeef;
1095 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, -100.0f, 100.0f, 1.0f,
1096 NULL, FALSE, &layout);
1097 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1098 ok(layout == NULL, "Unexpected pointer %p.\n", layout);
1100 layout = (void *)0xdeadbeef;
1101 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, 100.0f, -100.0f, 1.0f,
1102 NULL, FALSE, &layout);
1103 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1104 ok(layout == NULL, "Unexpected pointer %p.\n", layout);
1106 layout = (void *)0xdeadbeef;
1107 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, -100.0f, -100.0f, 1.0f,
1108 NULL, FALSE, &layout);
1109 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1110 ok(layout == NULL, "Unexpected pointer %p.\n", layout);
1112 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, 1.0f, NULL,
1113 FALSE, &layout);
1114 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1115 EXPECT_REF(format, 1);
1116 EXPECT_REF(layout, 1);
1118 IDWriteTextLayout_AddRef(layout);
1119 EXPECT_REF(format, 1);
1120 EXPECT_REF(layout, 2);
1121 IDWriteTextLayout_Release(layout);
1122 IDWriteTextLayout_Release(layout);
1124 /* zero length string is okay */
1125 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 0, format, 100.0f, 100.0f, 1.0f, NULL,
1126 FALSE, &layout);
1127 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1129 dimension = IDWriteTextLayout_GetMaxWidth(layout);
1130 ok(dimension == 100.0, "got %f\n", dimension);
1132 dimension = IDWriteTextLayout_GetMaxHeight(layout);
1133 ok(dimension == 100.0, "got %f\n", dimension);
1135 IDWriteTextLayout_Release(layout);
1137 /* negative, zero ppdip */
1138 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 1, format, 100.0f, 100.0f, -1.0f, NULL,
1139 FALSE, &layout);
1140 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1141 IDWriteTextLayout_Release(layout);
1143 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 1, format, 100.0f, 100.0f, 0.0f, NULL,
1144 FALSE, &layout);
1145 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1146 IDWriteTextLayout_Release(layout);
1148 /* transforms */
1149 for (i = 0; i < ARRAY_SIZE(layoutcreate_transforms); ++i)
1151 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 1, format, 100.0f, 100.0f, 1.0f,
1152 &layoutcreate_transforms[i], FALSE, &layout);
1153 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1154 IDWriteTextLayout_Release(layout);
1157 IDWriteTextFormat_Release(format);
1158 IDWriteFactory_Release(factory);
1161 static void test_CreateTextFormat(void)
1163 IDWriteFontCollection *collection, *syscoll;
1164 DWRITE_PARAGRAPH_ALIGNMENT paralign;
1165 DWRITE_READING_DIRECTION readdir;
1166 DWRITE_WORD_WRAPPING wrapping;
1167 DWRITE_TEXT_ALIGNMENT align;
1168 DWRITE_FLOW_DIRECTION flow;
1169 DWRITE_LINE_SPACING_METHOD method;
1170 DWRITE_TRIMMING trimming;
1171 IDWriteTextFormat *format;
1172 FLOAT spacing, baseline;
1173 IDWriteInlineObject *trimmingsign;
1174 IDWriteFactory *factory;
1175 HRESULT hr;
1177 factory = create_factory();
1179 /* zero/negative font size */
1180 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1181 DWRITE_FONT_STRETCH_NORMAL, 0.0f, L"en-us", &format);
1182 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1184 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1185 DWRITE_FONT_STRETCH_NORMAL, -10.0f, L"en-us", &format);
1186 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1188 /* invalid font properties */
1189 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, 1000, DWRITE_FONT_STYLE_NORMAL,
1190 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
1191 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1193 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL,
1194 DWRITE_FONT_STYLE_ITALIC + 1, DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
1195 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1197 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_ITALIC,
1198 10, 10.0f, L"en-us", &format);
1199 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1201 /* empty family name */
1202 hr = IDWriteFactory_CreateTextFormat(factory, L"", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1203 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
1204 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
1205 IDWriteTextFormat_Release(format);
1207 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1208 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
1209 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
1211 if (0) /* crashes on native */
1212 hr = IDWriteTextFormat_GetFontCollection(format, NULL);
1214 collection = NULL;
1215 hr = IDWriteTextFormat_GetFontCollection(format, &collection);
1216 ok(hr == S_OK, "got 0x%08x\n", hr);
1217 ok(collection != NULL, "got %p\n", collection);
1219 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1220 ok(hr == S_OK, "got 0x%08x\n", hr);
1221 ok(collection == syscoll, "got %p, was %p\n", syscoll, collection);
1222 IDWriteFontCollection_Release(syscoll);
1223 IDWriteFontCollection_Release(collection);
1225 /* default format properties */
1226 align = IDWriteTextFormat_GetTextAlignment(format);
1227 ok(align == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", align);
1229 paralign = IDWriteTextFormat_GetParagraphAlignment(format);
1230 ok(paralign == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", paralign);
1232 wrapping = IDWriteTextFormat_GetWordWrapping(format);
1233 ok(wrapping == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", wrapping);
1235 readdir = IDWriteTextFormat_GetReadingDirection(format);
1236 ok(readdir == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", readdir);
1238 flow = IDWriteTextFormat_GetFlowDirection(format);
1239 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
1241 hr = IDWriteTextFormat_GetLineSpacing(format, &method, &spacing, &baseline);
1242 ok(hr == S_OK, "got 0x%08x\n", hr);
1243 ok(spacing == 0.0, "got %f\n", spacing);
1244 ok(baseline == 0.0, "got %f\n", baseline);
1245 ok(method == DWRITE_LINE_SPACING_METHOD_DEFAULT, "got %d\n", method);
1247 trimming.granularity = DWRITE_TRIMMING_GRANULARITY_WORD;
1248 trimming.delimiter = 10;
1249 trimming.delimiterCount = 10;
1250 trimmingsign = (void*)0xdeadbeef;
1251 hr = IDWriteTextFormat_GetTrimming(format, &trimming, &trimmingsign);
1252 ok(hr == S_OK, "got 0x%08x\n", hr);
1253 ok(trimming.granularity == DWRITE_TRIMMING_GRANULARITY_NONE, "got %d\n", trimming.granularity);
1254 ok(trimming.delimiter == 0, "got %d\n", trimming.delimiter);
1255 ok(trimming.delimiterCount == 0, "got %d\n", trimming.delimiterCount);
1256 ok(trimmingsign == NULL, "got %p\n", trimmingsign);
1258 /* setters */
1259 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING);
1260 ok(hr == S_OK, "got 0x%08x\n", hr);
1262 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_JUSTIFIED+1);
1263 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1265 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
1266 ok(hr == S_OK, "got 0x%08x\n", hr);
1268 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_CENTER+1);
1269 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1271 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_WRAP);
1272 ok(hr == S_OK, "got 0x%08x\n", hr);
1274 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_CHARACTER+1);
1275 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1277 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
1278 ok(hr == S_OK, "got 0x%08x\n", hr);
1280 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
1281 ok(hr == S_OK, "got 0x%08x\n", hr);
1284 hr = IDWriteTextFormat_SetTrimming(format, &trimming, NULL);
1285 ok(hr == S_OK, "got 0x%08x\n", hr);
1287 /* invalid granularity */
1288 trimming.granularity = 10;
1289 trimming.delimiter = 0;
1290 trimming.delimiterCount = 0;
1291 hr = IDWriteTextFormat_SetTrimming(format, &trimming, NULL);
1292 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1294 IDWriteTextFormat_Release(format);
1295 IDWriteFactory_Release(factory);
1298 static void test_GetLocaleName(void)
1300 IDWriteTextFormat *format, *format2;
1301 IDWriteTextLayout *layout;
1302 IDWriteFactory *factory;
1303 WCHAR buff[10];
1304 UINT32 len;
1305 HRESULT hr;
1307 factory = create_factory();
1309 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1310 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"ru", &format);
1311 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
1313 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 0, format, 100.0f, 100.0f, 1.0f, NULL,
1314 FALSE, &layout);
1315 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1317 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format2);
1318 ok(hr == S_OK, "got 0x%08x\n", hr);
1320 len = IDWriteTextFormat_GetLocaleNameLength(format2);
1321 ok(len == 2, "got %u\n", len);
1322 len = IDWriteTextFormat_GetLocaleNameLength(format);
1323 ok(len == 2, "got %u\n", len);
1324 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len);
1325 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1326 hr = IDWriteTextFormat_GetLocaleName(format2, buff, len+1);
1327 ok(hr == S_OK, "got 0x%08x\n", hr);
1328 ok(!lstrcmpW(buff, L"ru"), "Unexpected locale name %s.\n", wine_dbgstr_w(buff));
1329 hr = IDWriteTextFormat_GetLocaleName(format, buff, len);
1330 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
1331 hr = IDWriteTextFormat_GetLocaleName(format, buff, len+1);
1332 ok(hr == S_OK, "got 0x%08x\n", hr);
1333 ok(!lstrcmpW(buff, L"ru"), "Unexpected locale name %s.\n", wine_dbgstr_w(buff));
1335 IDWriteTextLayout_Release(layout);
1336 IDWriteTextFormat_Release(format);
1337 IDWriteTextFormat_Release(format2);
1338 IDWriteFactory_Release(factory);
1341 static const struct drawcall_entry drawellipsis_seq[] = {
1342 { DRAW_GLYPHRUN, {0x2026, 0}, {'e','n','-','g','b',0}, 1 },
1343 { DRAW_LAST_KIND }
1346 static void test_CreateEllipsisTrimmingSign(void)
1348 DWRITE_INLINE_OBJECT_METRICS metrics;
1349 DWRITE_BREAK_CONDITION before, after;
1350 struct renderer_context ctxt;
1351 IDWriteTextFormat *format;
1352 IDWriteInlineObject *sign;
1353 IDWriteFactory *factory;
1354 IUnknown *unk, *effect;
1355 HRESULT hr;
1357 factory = create_factory();
1359 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
1360 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-GB", &format);
1361 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
1363 sign = (void *)0xdeadbeef;
1364 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, NULL, &sign);
1365 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
1366 ok(!sign, "Unexpected pointer %p.\n", sign);
1368 EXPECT_REF(format, 1);
1369 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
1370 ok(hr == S_OK, "got 0x%08x\n", hr);
1371 EXPECT_REF(format, 1);
1373 hr = IDWriteInlineObject_QueryInterface(sign, &IID_IDWriteTextLayout, (void**)&unk);
1374 ok(hr == E_NOINTERFACE, "got 0x%08x\n", hr);
1376 if (0) {/* crashes on native */
1377 hr = IDWriteInlineObject_GetBreakConditions(sign, NULL, NULL);
1378 hr = IDWriteInlineObject_GetMetrics(sign, NULL);
1380 metrics.width = 0.0;
1381 metrics.height = 123.0;
1382 metrics.baseline = 123.0;
1383 metrics.supportsSideways = TRUE;
1384 hr = IDWriteInlineObject_GetMetrics(sign, &metrics);
1385 ok(hr == S_OK, "got 0x%08x\n", hr);
1386 ok(metrics.width > 0.0, "got %.2f\n", metrics.width);
1387 ok(metrics.height == 0.0, "got %.2f\n", metrics.height);
1388 ok(metrics.baseline == 0.0, "got %.2f\n", metrics.baseline);
1389 ok(!metrics.supportsSideways, "got %d\n", metrics.supportsSideways);
1391 before = after = DWRITE_BREAK_CONDITION_CAN_BREAK;
1392 hr = IDWriteInlineObject_GetBreakConditions(sign, &before, &after);
1393 ok(hr == S_OK, "got 0x%08x\n", hr);
1394 ok(before == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", before);
1395 ok(after == DWRITE_BREAK_CONDITION_NEUTRAL, "got %d\n", after);
1397 /* Draw tests */
1398 flush_sequence(sequences, RENDERER_ID);
1399 hr = IDWriteInlineObject_Draw(sign, NULL, &testrenderer, 0.0, 0.0, FALSE, FALSE, NULL);
1400 ok(hr == S_OK, "got 0x%08x\n", hr);
1401 ok_sequence(sequences, RENDERER_ID, drawellipsis_seq, "ellipsis sign draw test", FALSE);
1403 effect = create_test_effect();
1405 EXPECT_REF(effect, 1);
1406 flush_sequence(sequences, RENDERER_ID);
1407 hr = IDWriteInlineObject_Draw(sign, NULL, &testrenderer, 0.0f, 0.0f, FALSE, FALSE, effect);
1408 ok(hr == S_OK, "Failed to draw trimming sign, hr %#x.\n", hr);
1409 ok_sequence(sequences, RENDERER_ID, drawellipsis_seq, "ellipsis sign draw with effect test", FALSE);
1410 EXPECT_REF(effect, 1);
1412 IUnknown_Release(effect);
1414 flush_sequence(sequences, RENDERER_ID);
1415 hr = IDWriteInlineObject_Draw(sign, NULL, &testrenderer, 0.0f, 0.0f, FALSE, FALSE, (void *)0xdeadbeef);
1416 ok(hr == S_OK, "Failed to draw trimming sign, hr %#x.\n", hr);
1417 ok_sequence(sequences, RENDERER_ID, drawellipsis_seq, "ellipsis sign draw with effect test", FALSE);
1419 memset(&ctxt, 0, sizeof(ctxt));
1420 hr = IDWriteInlineObject_Draw(sign, &ctxt, &testrenderer, 123.0f, 456.0f, FALSE, FALSE, NULL);
1421 ok(hr == S_OK, "Failed to draw trimming sign, hr %#x.\n", hr);
1422 ok(ctxt.originX == 123.0f && ctxt.originY == 456.0f, "Unexpected drawing origin\n");
1424 IDWriteInlineObject_Release(sign);
1426 /* Centered format */
1427 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_CENTER);
1428 ok(hr == S_OK, "Failed to set text alignment, hr %#x.\n", hr);
1430 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
1431 ok(hr == S_OK, "got 0x%08x\n", hr);
1433 memset(&ctxt, 0, sizeof(ctxt));
1434 hr = IDWriteInlineObject_Draw(sign, &ctxt, &testrenderer, 123.0f, 456.0f, FALSE, FALSE, NULL);
1435 ok(hr == S_OK, "Failed to draw trimming sign, hr %#x.\n", hr);
1436 ok(ctxt.originX == 123.0f && ctxt.originY == 456.0f, "Unexpected drawing origin\n");
1438 IDWriteInlineObject_Release(sign);
1440 /* non-orthogonal flow/reading combination */
1441 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
1442 ok(hr == S_OK, "got 0x%08x\n", hr);
1444 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT);
1445 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* vista, win7 */, "got 0x%08x\n", hr);
1446 if (hr == S_OK) {
1447 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
1448 ok(hr == DWRITE_E_FLOWDIRECTIONCONFLICTS, "got 0x%08x\n", hr);
1451 IDWriteTextFormat_Release(format);
1452 IDWriteFactory_Release(factory);
1455 static void test_fontweight(void)
1457 IDWriteTextFormat *format, *fmt2;
1458 IDWriteTextLayout *layout;
1459 DWRITE_FONT_WEIGHT weight;
1460 DWRITE_TEXT_RANGE range;
1461 IDWriteFactory *factory;
1462 FLOAT size;
1463 HRESULT hr;
1465 factory = create_factory();
1467 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1468 DWRITE_FONT_STRETCH_NORMAL, 10.0, L"ru", &format);
1469 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
1471 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, 1.0f, NULL,
1472 FALSE, &layout);
1473 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1475 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&fmt2);
1476 ok(hr == S_OK, "got 0x%08x\n", hr);
1478 weight = IDWriteTextFormat_GetFontWeight(fmt2);
1479 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
1481 range.startPosition = range.length = 0;
1482 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1483 ok(hr == S_OK, "got 0x%08x\n", hr);
1484 ok(range.startPosition == 0 && range.length == ~0u, "got %u, %u\n", range.startPosition, range.length);
1486 range.startPosition = 0;
1487 range.length = 6;
1488 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_NORMAL, range);
1489 ok(hr == S_OK, "got 0x%08x\n", hr);
1491 range.startPosition = range.length = 0;
1492 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1493 ok(hr == S_OK, "got 0x%08x\n", hr);
1494 ok(range.startPosition == 0 && range.length == 6, "got %u, %u\n", range.startPosition, range.length);
1496 /* IDWriteTextFormat methods output doesn't reflect layout changes */
1497 weight = IDWriteTextFormat_GetFontWeight(fmt2);
1498 ok(weight == DWRITE_FONT_WEIGHT_BOLD, "got %u\n", weight);
1500 range.length = 0;
1501 weight = DWRITE_FONT_WEIGHT_BOLD;
1502 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
1503 ok(hr == S_OK, "got 0x%08x\n", hr);
1504 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "got %d\n", weight);
1505 ok(range.length == 6, "got %d\n", range.length);
1507 range.startPosition = 0;
1508 range.length = 6;
1509 hr = IDWriteTextLayout_SetFontWeight(layout, 1000, range);
1510 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1512 size = IDWriteTextLayout_GetMaxWidth(layout);
1513 ok(size == 100.0, "got %.2f\n", size);
1515 hr = IDWriteTextLayout_SetMaxWidth(layout, 0.0);
1516 ok(hr == S_OK, "got 0x%08x\n", hr);
1518 size = IDWriteTextLayout_GetMaxWidth(layout);
1519 ok(size == 0.0, "got %.2f\n", size);
1521 hr = IDWriteTextLayout_SetMaxWidth(layout, -1.0);
1522 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1524 size = IDWriteTextLayout_GetMaxWidth(layout);
1525 ok(size == 0.0, "got %.2f\n", size);
1527 hr = IDWriteTextLayout_SetMaxWidth(layout, 100.0);
1528 ok(hr == S_OK, "got 0x%08x\n", hr);
1530 size = IDWriteTextLayout_GetMaxWidth(layout);
1531 ok(size == 100.0, "got %.2f\n", size);
1533 size = IDWriteTextLayout_GetMaxHeight(layout);
1534 ok(size == 100.0, "got %.2f\n", size);
1536 hr = IDWriteTextLayout_SetMaxHeight(layout, 0.0);
1537 ok(hr == S_OK, "got 0x%08x\n", hr);
1539 size = IDWriteTextLayout_GetMaxHeight(layout);
1540 ok(size == 0.0, "got %.2f\n", size);
1542 hr = IDWriteTextLayout_SetMaxHeight(layout, -1.0);
1543 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
1545 size = IDWriteTextLayout_GetMaxHeight(layout);
1546 ok(size == 0.0, "got %.2f\n", size);
1548 hr = IDWriteTextLayout_SetMaxHeight(layout, 100.0);
1549 ok(hr == S_OK, "got 0x%08x\n", hr);
1551 size = IDWriteTextLayout_GetMaxHeight(layout);
1552 ok(size == 100.0, "got %.2f\n", size);
1554 IDWriteTextLayout_Release(layout);
1555 IDWriteTextFormat_Release(fmt2);
1556 IDWriteTextFormat_Release(format);
1557 IDWriteFactory_Release(factory);
1560 static void test_SetInlineObject(void)
1562 IDWriteInlineObject *inlineobj, *inlineobj2, *inlinetest;
1563 DWRITE_TEXT_RANGE range, r2;
1564 IDWriteTextFormat *format;
1565 IDWriteTextLayout *layout;
1566 IDWriteFactory *factory;
1567 HRESULT hr;
1569 factory = create_factory();
1571 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1572 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"ru", &format);
1573 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
1575 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, 1.0f, NULL,
1576 FALSE, &layout);
1577 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1579 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1580 ok(hr == S_OK, "got 0x%08x\n", hr);
1582 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj2);
1583 ok(hr == S_OK, "got 0x%08x\n", hr);
1585 EXPECT_REF(inlineobj, 1);
1586 EXPECT_REF(inlineobj2, 1);
1588 inlinetest = (void*)0x1;
1589 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, NULL);
1590 ok(hr == S_OK, "got 0x%08x\n", hr);
1591 ok(inlinetest == NULL, "got %p\n", inlinetest);
1593 range.startPosition = 0;
1594 range.length = 2;
1595 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1596 ok(hr == S_OK, "got 0x%08x\n", hr);
1598 EXPECT_REF(inlineobj, 2);
1600 inlinetest = (void*)0x1;
1601 hr = IDWriteTextLayout_GetInlineObject(layout, 2, &inlinetest, NULL);
1602 ok(hr == S_OK, "got 0x%08x\n", hr);
1603 ok(inlinetest == NULL, "got %p\n", inlinetest);
1605 inlinetest = NULL;
1606 r2.startPosition = r2.length = 100;
1607 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1608 ok(hr == S_OK, "got 0x%08x\n", hr);
1609 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1610 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1611 IDWriteInlineObject_Release(inlinetest);
1613 EXPECT_REF(inlineobj, 2);
1615 /* get from somewhere inside a range */
1616 inlinetest = NULL;
1617 r2.startPosition = r2.length = 100;
1618 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1619 ok(hr == S_OK, "got 0x%08x\n", hr);
1620 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1621 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1622 IDWriteInlineObject_Release(inlinetest);
1624 EXPECT_REF(inlineobj, 2);
1626 range.startPosition = 1;
1627 range.length = 1;
1628 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj2, range);
1629 ok(hr == S_OK, "got 0x%08x\n", hr);
1631 inlinetest = NULL;
1632 r2.startPosition = r2.length = 100;
1633 hr = IDWriteTextLayout_GetInlineObject(layout, 1, &inlinetest, &r2);
1634 ok(hr == S_OK, "got 0x%08x\n", hr);
1635 ok(inlinetest == inlineobj2, "got %p\n", inlinetest);
1636 ok(r2.startPosition == 1 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1637 IDWriteInlineObject_Release(inlinetest);
1639 EXPECT_REF(inlineobj, 2);
1640 EXPECT_REF(inlineobj2, 2);
1642 inlinetest = NULL;
1643 r2.startPosition = r2.length = 100;
1644 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1645 ok(hr == S_OK, "got 0x%08x\n", hr);
1646 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1647 ok(r2.startPosition == 0 && r2.length == 1, "got %d, %d\n", r2.startPosition, r2.length);
1648 IDWriteInlineObject_Release(inlinetest);
1650 EXPECT_REF(inlineobj, 2);
1652 range.startPosition = 1;
1653 range.length = 1;
1654 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1655 ok(hr == S_OK, "got 0x%08x\n", hr);
1657 r2.startPosition = r2.length = 100;
1658 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1659 ok(hr == S_OK, "got 0x%08x\n", hr);
1660 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1661 ok(r2.startPosition == 0 && r2.length == 2, "got %d, %d\n", r2.startPosition, r2.length);
1662 IDWriteInlineObject_Release(inlinetest);
1664 EXPECT_REF(inlineobj, 2);
1666 range.startPosition = 1;
1667 range.length = 2;
1668 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1669 ok(hr == S_OK, "got 0x%08x\n", hr);
1671 EXPECT_REF(inlineobj, 2);
1673 r2.startPosition = r2.length = 100;
1674 hr = IDWriteTextLayout_GetInlineObject(layout, 0, &inlinetest, &r2);
1675 ok(hr == S_OK, "got 0x%08x\n", hr);
1676 ok(inlinetest == inlineobj, "got %p\n", inlinetest);
1677 ok(r2.startPosition == 0 && r2.length == 3, "got %d, %d\n", r2.startPosition, r2.length);
1678 IDWriteInlineObject_Release(inlinetest);
1680 EXPECT_REF(inlineobj, 2);
1681 EXPECT_REF(inlineobj2, 1);
1683 IDWriteTextLayout_Release(layout);
1685 EXPECT_REF(inlineobj, 1);
1687 IDWriteInlineObject_Release(inlineobj);
1688 IDWriteInlineObject_Release(inlineobj2);
1689 IDWriteTextFormat_Release(format);
1690 IDWriteFactory_Release(factory);
1693 /* drawing calls sequence doesn't depend on run order, instead all runs are
1694 drawn first, inline objects next and then underline/strikes */
1695 static const struct drawcall_entry draw_seq[] = {
1696 { DRAW_GLYPHRUN, {'s',0}, {'r','u',0}, 1 },
1697 { DRAW_GLYPHRUN, {'r','i',0}, {'r','u',0}, 2 },
1698 { DRAW_GLYPHRUN|DRAW_EFFECT, {'n',0}, {'r','u',0}, 1 },
1699 { DRAW_GLYPHRUN, {'g',0}, {'r','u',0}, 1 },
1700 { DRAW_INLINE },
1701 { DRAW_UNDERLINE, {0}, {'r','u',0} },
1702 { DRAW_STRIKETHROUGH },
1703 { DRAW_LAST_KIND }
1706 static const struct drawcall_entry draw_trimmed_seq[] = {
1707 { DRAW_GLYPHRUN, {'a',0}, {'e','n','-','u','s',0}, 1 },
1708 { DRAW_LAST_KIND }
1711 static const struct drawcall_entry draw_seq2[] = {
1712 { DRAW_GLYPHRUN, {'s',0}, {'r','u',0}, 1 },
1713 { DRAW_GLYPHRUN, {'t',0}, {'r','u',0}, 1 },
1714 { DRAW_GLYPHRUN, {'r',0}, {'r','u',0}, 1 },
1715 { DRAW_GLYPHRUN, {'i',0}, {'r','u',0}, 1 },
1716 { DRAW_GLYPHRUN, {'n',0}, {'r','u',0}, 1 },
1717 { DRAW_GLYPHRUN, {'g',0}, {'r','u',0}, 1 },
1718 { DRAW_LAST_KIND }
1721 static const struct drawcall_entry draw_seq3[] = {
1722 { DRAW_GLYPHRUN, {0x202a,0x202c,0}, {'r','u',0}, 0 },
1723 { DRAW_GLYPHRUN, {'a','b',0}, {'r','u',0}, 2 },
1724 { DRAW_LAST_KIND }
1727 static const struct drawcall_entry draw_seq4[] = {
1728 { DRAW_GLYPHRUN, {'s','t','r',0}, {'r','u',0}, 3 },
1729 { DRAW_GLYPHRUN, {'i','n','g',0}, {'r','u',0}, 3 },
1730 { DRAW_STRIKETHROUGH },
1731 { DRAW_LAST_KIND }
1734 static const struct drawcall_entry draw_seq5[] = {
1735 { DRAW_GLYPHRUN, {'s','t',0}, {'r','u',0}, 2 },
1736 { DRAW_GLYPHRUN, {'r','i',0}, {'r','u',0}, 2 },
1737 { DRAW_GLYPHRUN, {'n','g',0}, {'r','u',0}, 2 },
1738 { DRAW_STRIKETHROUGH },
1739 { DRAW_LAST_KIND }
1742 static const struct drawcall_entry empty_seq[] = {
1743 { DRAW_LAST_KIND }
1746 static const struct drawcall_entry draw_single_run_seq[] = {
1747 { DRAW_GLYPHRUN, {'s','t','r','i','n','g',0}, {'r','u',0}, 6 },
1748 { DRAW_LAST_KIND }
1751 static const struct drawcall_entry draw_ltr_reordered_run_seq[] = {
1752 { DRAW_GLYPHRUN, {'1','2','3','-','5','2',0}, {'r','u',0}, 6 },
1753 { DRAW_GLYPHRUN, {0x64a,0x64f,0x633,0x627,0x648,0x650,0x64a,0}, {'r','u',0}, 7, 1 },
1754 { DRAW_GLYPHRUN, {'7','1',0}, {'r','u',0}, 2, 2 },
1755 { DRAW_GLYPHRUN, {'.',0}, {'r','u',0}, 1 },
1756 { DRAW_LAST_KIND }
1759 static void test_Draw(void)
1761 static const WCHAR str3W[] = {'1','2','3','-','5','2',0x64a,0x64f,0x633,0x627,0x648,0x650,
1762 0x64a,'7','1','.',0};
1763 static const WCHAR str2W[] = {0x202a,0x202c,'a','b',0};
1764 IDWriteInlineObject *inlineobj;
1765 struct renderer_context ctxt;
1766 IDWriteTextFormat *format;
1767 IDWriteTextLayout *layout;
1768 DWRITE_TEXT_RANGE range;
1769 IDWriteFactory *factory;
1770 DWRITE_TEXT_METRICS tm;
1771 DWRITE_MATRIX m;
1772 HRESULT hr;
1774 factory = create_factory();
1776 memset(&ctxt, 0, sizeof(ctxt));
1777 ctxt.snapping_disabled = TRUE;
1779 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_NORMAL,
1780 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"ru", &format);
1781 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
1783 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, &layout);
1784 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1786 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
1787 ok(hr == S_OK, "got 0x%08x\n", hr);
1789 range.startPosition = 5;
1790 range.length = 1;
1791 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1792 ok(hr == S_OK, "got 0x%08x\n", hr);
1794 range.startPosition = 1;
1795 range.length = 1;
1796 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
1797 ok(hr == S_OK, "got 0x%08x\n", hr);
1799 range.startPosition = 4;
1800 range.length = 1;
1801 hr = IDWriteTextLayout_SetDrawingEffect(layout, (IUnknown*)inlineobj, range);
1802 ok(hr == S_OK, "got 0x%08x\n", hr);
1804 range.startPosition = 0;
1805 range.length = 1;
1806 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
1807 ok(hr == S_OK, "got 0x%08x\n", hr);
1809 flush_sequence(sequences, RENDERER_ID);
1810 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1811 ok(hr == S_OK, "got 0x%08x\n", hr);
1812 ok_sequence(sequences, RENDERER_ID, draw_seq, "draw test", FALSE);
1813 IDWriteTextLayout_Release(layout);
1815 /* with reduced width DrawGlyphRun() is called for every line */
1816 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, 5.0f, 100.0f, &layout);
1817 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1818 flush_sequence(sequences, RENDERER_ID);
1819 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1820 ok(hr == S_OK, "got 0x%08x\n", hr);
1821 ok_sequence(sequences, RENDERER_ID, draw_seq2, "draw test 2", TRUE);
1822 hr = IDWriteTextLayout_GetMetrics(layout, &tm);
1823 ok(hr == S_OK, "got 0x%08x\n", hr);
1824 todo_wine
1825 ok(tm.lineCount == 6, "got %u\n", tm.lineCount);
1826 IDWriteTextLayout_Release(layout);
1828 /* string with control characters */
1829 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 4, format, 500.0, 100.0, &layout);
1830 ok(hr == S_OK, "got 0x%08x\n", hr);
1831 flush_sequence(sequences, RENDERER_ID);
1832 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1833 ok(hr == S_OK, "got 0x%08x\n", hr);
1834 ok_sequence(sequences, RENDERER_ID, draw_seq3, "draw test 3", FALSE);
1835 IDWriteTextLayout_Release(layout);
1837 /* strikethrough splits ranges from renderer point of view, but doesn't break
1838 shaping */
1839 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, 500.0f, 100.0f, &layout);
1840 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1841 flush_sequence(sequences, RENDERER_ID);
1843 range.startPosition = 0;
1844 range.length = 3;
1845 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1846 ok(hr == S_OK, "got 0x%08x\n", hr);
1848 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1849 ok(hr == S_OK, "got 0x%08x\n", hr);
1850 ok_sequence(sequences, RENDERER_ID, draw_seq4, "draw test 4", FALSE);
1851 IDWriteTextLayout_Release(layout);
1853 /* Strike through somewhere in the middle */
1854 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, 500.0f, 100.0f, &layout);
1855 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1856 flush_sequence(sequences, RENDERER_ID);
1858 range.startPosition = 2;
1859 range.length = 2;
1860 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
1861 ok(hr == S_OK, "got 0x%08x\n", hr);
1863 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1864 ok(hr == S_OK, "got 0x%08x\n", hr);
1865 ok_sequence(sequences, RENDERER_ID, draw_seq5, "draw test 5", FALSE);
1866 IDWriteTextLayout_Release(layout);
1868 /* empty string */
1869 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 0, format, 500.0f, 100.0f, &layout);
1870 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1872 flush_sequence(sequences, RENDERER_ID);
1873 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1874 ok(hr == S_OK, "got 0x%08x\n", hr);
1875 ok_sequence(sequences, RENDERER_ID, empty_seq, "draw test 6", FALSE);
1876 IDWriteTextLayout_Release(layout);
1878 ctxt.gdicompat = TRUE;
1879 ctxt.use_gdi_natural = TRUE;
1881 /* different parameter combinations with gdi-compatible layout */
1882 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, 1.0f, NULL,
1883 TRUE, &layout);
1884 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1885 flush_sequence(sequences, RENDERER_ID);
1886 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1887 ok(hr == S_OK, "got 0x%08x\n", hr);
1888 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 7", FALSE);
1890 /* text alignment keeps pixel-aligned origin */
1891 hr = IDWriteTextLayout_GetMetrics(layout, &tm);
1892 ok(hr == S_OK, "got 0x%08x\n", hr);
1893 ok(tm.width == floorf(tm.width), "got %f\n", tm.width);
1895 hr = IDWriteTextLayout_SetMaxWidth(layout, tm.width + 3.0);
1896 ok(hr == S_OK, "got 0x%08x\n", hr);
1897 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_CENTER);
1898 ok(hr == S_OK, "got 0x%08x\n", hr);
1900 ctxt.originX = ctxt.originY = 0.0;
1901 flush_sequence(sequences, RENDERER_ID);
1902 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1903 ok(hr == S_OK, "got 0x%08x\n", hr);
1904 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 7", FALSE);
1905 ok(ctxt.originX != 0.0 && ctxt.originX == floorf(ctxt.originX), "got %f\n", ctxt.originX);
1907 IDWriteTextLayout_Release(layout);
1909 ctxt.gdicompat = TRUE;
1910 ctxt.use_gdi_natural = FALSE;
1912 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, 1.0f, NULL,
1913 FALSE, &layout);
1914 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1915 flush_sequence(sequences, RENDERER_ID);
1916 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1917 ok(hr == S_OK, "got 0x%08x\n", hr);
1918 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 8", FALSE);
1919 IDWriteTextLayout_Release(layout);
1921 ctxt.gdicompat = TRUE;
1922 ctxt.use_gdi_natural = TRUE;
1924 m.m11 = m.m22 = 2.0;
1925 m.m12 = m.m21 = m.dx = m.dy = 0.0;
1926 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, 1.0f, &m,
1927 TRUE, &layout);
1928 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1929 flush_sequence(sequences, RENDERER_ID);
1930 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1931 ok(hr == S_OK, "got 0x%08x\n", hr);
1932 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 9", FALSE);
1933 IDWriteTextLayout_Release(layout);
1935 ctxt.gdicompat = TRUE;
1936 ctxt.use_gdi_natural = FALSE;
1938 m.m11 = m.m22 = 2.0;
1939 m.m12 = m.m21 = m.dx = m.dy = 0.0;
1940 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, 1.0f, &m,
1941 FALSE, &layout);
1942 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
1943 flush_sequence(sequences, RENDERER_ID);
1944 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0, 0.0);
1945 ok(hr == S_OK, "got 0x%08x\n", hr);
1946 ok_sequence(sequences, RENDERER_ID, draw_single_run_seq, "draw test 10", FALSE);
1947 IDWriteTextLayout_Release(layout);
1949 IDWriteInlineObject_Release(inlineobj);
1951 /* text that triggers bidi run reordering */
1952 hr = IDWriteFactory_CreateTextLayout(factory, str3W, lstrlenW(str3W), format, 1000.0f, 100.0f, &layout);
1953 ok(hr == S_OK, "got 0x%08x\n", hr);
1955 ctxt.gdicompat = FALSE;
1956 ctxt.use_gdi_natural = FALSE;
1957 ctxt.snapping_disabled = TRUE;
1959 hr = IDWriteTextLayout_SetReadingDirection(layout, DWRITE_READING_DIRECTION_LEFT_TO_RIGHT);
1960 ok(hr == S_OK, "Failed to set reading direction, hr %#x.\n", hr);
1962 flush_sequence(sequences, RENDERER_ID);
1963 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0f, 0.0f);
1964 ok(hr == S_OK, "got 0x%08x\n", hr);
1965 ok_sequence(sequences, RENDERER_ID, draw_ltr_reordered_run_seq, "draw test 11", FALSE);
1967 IDWriteTextLayout_Release(layout);
1969 IDWriteTextFormat_Release(format);
1970 IDWriteFactory_Release(factory);
1973 static void test_typography(void)
1975 DWRITE_FONT_FEATURE feature;
1976 IDWriteTypography *typography;
1977 IDWriteFactory *factory;
1978 UINT32 count;
1979 HRESULT hr;
1981 factory = create_factory();
1983 hr = IDWriteFactory_CreateTypography(factory, &typography);
1984 ok(hr == S_OK, "got 0x%08x\n", hr);
1986 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1987 feature.parameter = 1;
1988 hr = IDWriteTypography_AddFontFeature(typography, feature);
1989 ok(hr == S_OK, "got 0x%08x\n", hr);
1991 count = IDWriteTypography_GetFontFeatureCount(typography);
1992 ok(count == 1, "got %u\n", count);
1994 /* duplicated features work just fine */
1995 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
1996 feature.parameter = 0;
1997 hr = IDWriteTypography_AddFontFeature(typography, feature);
1998 ok(hr == S_OK, "got 0x%08x\n", hr);
2000 count = IDWriteTypography_GetFontFeatureCount(typography);
2001 ok(count == 2, "got %u\n", count);
2003 memset(&feature, 0xcc, sizeof(feature));
2004 hr = IDWriteTypography_GetFontFeature(typography, 0, &feature);
2005 ok(hr == S_OK, "got 0x%08x\n", hr);
2006 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
2007 ok(feature.parameter == 1, "got %u\n", feature.parameter);
2009 memset(&feature, 0xcc, sizeof(feature));
2010 hr = IDWriteTypography_GetFontFeature(typography, 1, &feature);
2011 ok(hr == S_OK, "got 0x%08x\n", hr);
2012 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
2013 ok(feature.parameter == 0, "got %u\n", feature.parameter);
2015 hr = IDWriteTypography_GetFontFeature(typography, 2, &feature);
2016 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2018 /* duplicated with same parameter value */
2019 feature.nameTag = DWRITE_FONT_FEATURE_TAG_KERNING;
2020 feature.parameter = 0;
2021 hr = IDWriteTypography_AddFontFeature(typography, feature);
2022 ok(hr == S_OK, "got 0x%08x\n", hr);
2024 count = IDWriteTypography_GetFontFeatureCount(typography);
2025 ok(count == 3, "got %u\n", count);
2027 memset(&feature, 0xcc, sizeof(feature));
2028 hr = IDWriteTypography_GetFontFeature(typography, 2, &feature);
2029 ok(hr == S_OK, "got 0x%08x\n", hr);
2030 ok(feature.nameTag == DWRITE_FONT_FEATURE_TAG_KERNING, "got tag %x\n", feature.nameTag);
2031 ok(feature.parameter == 0, "got %u\n", feature.parameter);
2033 IDWriteTypography_Release(typography);
2034 IDWriteFactory_Release(factory);
2037 static void test_GetClusterMetrics(void)
2039 static const WCHAR str_white_spaceW[] = {
2040 /* BK - FORM FEED, LINE TABULATION, LINE SEP, PARA SEP */ 0xc, 0xb, 0x2028, 0x2029,
2041 /* ZW - ZERO WIDTH SPACE */ 0x200b,
2042 /* SP - SPACE */ 0x20
2044 static const WCHAR str5W[] = {'a','\r','b','\n','c','\n','\r','d','\r','\n','e',0xb,'f',0xc,
2045 'g',0x0085,'h',0x2028,'i',0x2029,0xad,0xa,0};
2046 static const WCHAR str3W[] = {0x2066,')',')',0x661,'(',0x627,')',0};
2047 static const WCHAR str2W[] = {0x202a,0x202c,'a',0};
2048 DWRITE_INLINE_OBJECT_METRICS inline_metrics;
2049 DWRITE_CLUSTER_METRICS metrics[22];
2050 DWRITE_TEXT_METRICS text_metrics;
2051 DWRITE_TRIMMING trimming_options;
2052 IDWriteTextLayout1 *layout1;
2053 IDWriteInlineObject *trimm;
2054 IDWriteTextFormat *format;
2055 IDWriteTextLayout *layout;
2056 DWRITE_LINE_METRICS line;
2057 DWRITE_TEXT_RANGE range;
2058 IDWriteFactory *factory;
2059 UINT32 count, i;
2060 FLOAT width;
2061 HRESULT hr;
2063 factory = create_factory();
2065 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2066 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
2067 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
2069 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 7, format, 1000.0, 1000.0, &layout);
2070 ok(hr == S_OK, "got 0x%08x\n", hr);
2071 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
2072 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2073 ok(count == 7, "got %u\n", count);
2074 IDWriteTextLayout_Release(layout);
2076 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
2077 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2079 count = 0;
2080 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
2081 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2082 ok(count == 4, "got %u\n", count);
2084 /* check every cluster width */
2085 count = 0;
2086 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, ARRAY_SIZE(metrics), &count);
2087 ok(hr == S_OK, "got 0x%08x\n", hr);
2088 ok(count == 4, "got %u\n", count);
2089 for (i = 0; i < count; i++) {
2090 ok(metrics[i].width > 0.0, "%u: got width %.2f\n", i, metrics[i].width);
2091 ok(metrics[i].length == 1, "%u: got length %u\n", i, metrics[i].length);
2094 /* apply spacing and check widths again */
2095 if (IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1) == S_OK) {
2096 DWRITE_CLUSTER_METRICS metrics2[4];
2097 FLOAT leading, trailing, min_advance;
2098 DWRITE_TEXT_RANGE r;
2100 leading = trailing = min_advance = 2.0;
2101 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 500, &leading, &trailing,
2102 &min_advance, &r);
2103 ok(hr == S_OK, "got 0x%08x\n", hr);
2104 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
2105 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
2106 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2108 leading = trailing = min_advance = 2.0;
2109 hr = IDWriteTextLayout1_GetCharacterSpacing(layout1, 0, &leading, &trailing,
2110 &min_advance, NULL);
2111 ok(hr == S_OK, "got 0x%08x\n", hr);
2112 ok(leading == 0.0 && trailing == 0.0 && min_advance == 0.0,
2113 "got %.2f, %.2f, %.2f\n", leading, trailing, min_advance);
2115 r.startPosition = 0;
2116 r.length = 4;
2117 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 10.0, 15.0, 0.0, r);
2118 ok(hr == S_OK, "got 0x%08x\n", hr);
2120 count = 0;
2121 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics2, ARRAY_SIZE(metrics2), &count);
2122 ok(hr == S_OK, "got 0x%08x\n", hr);
2123 ok(count == 4, "got %u\n", count);
2124 for (i = 0; i < count; ++i)
2126 ok(metrics2[i].width > metrics[i].width, "%u: got width %.2f, was %.2f\n", i, metrics2[i].width,
2127 metrics[i].width);
2128 ok(metrics2[i].length == 1, "%u: got length %u\n", i, metrics2[i].length);
2131 /* back to defaults */
2132 r.startPosition = 0;
2133 r.length = 4;
2134 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, 0.0, r);
2135 ok(hr == S_OK, "got 0x%08x\n", hr);
2137 /* negative advance limit */
2138 r.startPosition = 0;
2139 r.length = 4;
2140 hr = IDWriteTextLayout1_SetCharacterSpacing(layout1, 0.0, 0.0, -10.0, r);
2141 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2143 IDWriteTextLayout1_Release(layout1);
2145 else
2146 win_skip("IDWriteTextLayout1 is not supported, cluster spacing test skipped.\n");
2148 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &trimm);
2149 ok(hr == S_OK, "got 0x%08x\n", hr);
2151 range.startPosition = 0;
2152 range.length = 2;
2153 hr = IDWriteTextLayout_SetInlineObject(layout, trimm, range);
2154 ok(hr == S_OK, "got 0x%08x\n", hr);
2156 /* inline object takes a separate cluster, replaced codepoints number doesn't matter */
2157 count = 0;
2158 hr = IDWriteTextLayout_GetClusterMetrics(layout, NULL, 0, &count);
2159 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2160 ok(count == 3, "got %u\n", count);
2162 count = 0;
2163 memset(&metrics, 0, sizeof(metrics));
2164 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
2165 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2166 ok(count == 3, "got %u\n", count);
2167 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
2169 hr = IDWriteInlineObject_GetMetrics(trimm, &inline_metrics);
2170 ok(hr == S_OK, "got 0x%08x\n", hr);
2171 ok(inline_metrics.width > 0.0 && inline_metrics.width == metrics[0].width, "got %.2f, expected %.2f\n",
2172 inline_metrics.width, metrics[0].width);
2174 IDWriteTextLayout_Release(layout);
2176 /* text with non-visual control codes */
2177 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 3, format, 1000.0, 1000.0, &layout);
2178 ok(hr == S_OK, "got 0x%08x\n", hr);
2180 /* bidi control codes take a separate cluster */
2181 count = 0;
2182 memset(metrics, 0, sizeof(metrics));
2183 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2184 ok(hr == S_OK, "got 0x%08x\n", hr);
2185 ok(count == 3, "got %u\n", count);
2187 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
2188 ok(metrics[0].length == 1, "got %d\n", metrics[0].length);
2189 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
2190 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
2191 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
2192 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
2193 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
2195 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
2196 ok(metrics[1].length == 1, "got %d\n", metrics[1].length);
2197 ok(metrics[1].canWrapLineAfter == 0, "got %d\n", metrics[1].canWrapLineAfter);
2198 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
2199 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
2200 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
2201 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
2203 ok(metrics[2].width > 0.0, "got %.2f\n", metrics[2].width);
2204 ok(metrics[2].length == 1, "got %d\n", metrics[2].length);
2205 ok(metrics[2].canWrapLineAfter == 1, "got %d\n", metrics[2].canWrapLineAfter);
2206 ok(metrics[2].isWhitespace == 0, "got %d\n", metrics[2].isWhitespace);
2207 ok(metrics[2].isNewline == 0, "got %d\n", metrics[2].isNewline);
2208 ok(metrics[2].isSoftHyphen == 0, "got %d\n", metrics[2].isSoftHyphen);
2209 ok(metrics[2].isRightToLeft == 0, "got %d\n", metrics[2].isRightToLeft);
2211 IDWriteTextLayout_Release(layout);
2213 /* single inline object that fails to report its metrics */
2214 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
2215 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2217 range.startPosition = 0;
2218 range.length = 4;
2219 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj, range);
2220 ok(hr == S_OK, "got 0x%08x\n", hr);
2222 count = 0;
2223 memset(metrics, 0, sizeof(metrics));
2224 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2225 ok(hr == S_OK, "got 0x%08x\n", hr);
2226 ok(count == 1, "got %u\n", count);
2228 /* object sets a width to 123.0, but returns failure from GetMetrics() */
2229 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
2230 ok(metrics[0].length == 4, "got %d\n", metrics[0].length);
2231 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
2232 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
2233 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
2234 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
2235 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
2237 /* now set two inline object for [0,1] and [2,3], both fail to report break conditions */
2238 range.startPosition = 2;
2239 range.length = 2;
2240 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj2, range);
2241 ok(hr == S_OK, "got 0x%08x\n", hr);
2243 count = 0;
2244 memset(metrics, 0, sizeof(metrics));
2245 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2246 ok(hr == S_OK, "got 0x%08x\n", hr);
2247 ok(count == 2, "got %u\n", count);
2249 ok(metrics[0].width == 0.0, "got %.2f\n", metrics[0].width);
2250 ok(metrics[0].length == 2, "got %d\n", metrics[0].length);
2251 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
2252 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
2253 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
2254 ok(metrics[0].isSoftHyphen == 0, "got %d\n", metrics[0].isSoftHyphen);
2255 ok(metrics[0].isRightToLeft == 0, "got %d\n", metrics[0].isRightToLeft);
2257 ok(metrics[1].width == 0.0, "got %.2f\n", metrics[1].width);
2258 ok(metrics[1].length == 2, "got %d\n", metrics[1].length);
2259 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
2260 ok(metrics[1].isWhitespace == 0, "got %d\n", metrics[1].isWhitespace);
2261 ok(metrics[1].isNewline == 0, "got %d\n", metrics[1].isNewline);
2262 ok(metrics[1].isSoftHyphen == 0, "got %d\n", metrics[1].isSoftHyphen);
2263 ok(metrics[1].isRightToLeft == 0, "got %d\n", metrics[1].isRightToLeft);
2265 IDWriteTextLayout_Release(layout);
2267 /* zero length string */
2268 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 0, format, 1000.0f, 1000.0f, &layout);
2269 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2271 count = 1;
2272 memset(metrics, 0, sizeof(metrics));
2273 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2274 ok(hr == S_OK, "got 0x%08x\n", hr);
2275 ok(count == 0, "got %u\n", count);
2276 IDWriteTextLayout_Release(layout);
2278 /* Whitespace */
2279 hr = IDWriteFactory_CreateTextLayout(factory, L"a ", 2, format, 1000.0f, 1000.0f, &layout);
2280 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2282 count = 0;
2283 memset(metrics, 0, sizeof(metrics));
2284 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 2, &count);
2285 ok(hr == S_OK, "got 0x%08x\n", hr);
2286 ok(count == 2, "got %u\n", count);
2287 ok(metrics[0].isWhitespace == 0, "got %d\n", metrics[0].isWhitespace);
2288 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
2289 ok(metrics[1].isWhitespace == 1, "got %d\n", metrics[1].isWhitespace);
2290 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
2291 IDWriteTextLayout_Release(layout);
2293 /* Layout is fully covered by inline object with after condition DWRITE_BREAK_CONDITION_MAY_NOT_BREAK. */
2294 hr = IDWriteFactory_CreateTextLayout(factory, L"a ", 2, format, 1000.0f, 1000.0f, &layout);
2295 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2297 range.startPosition = 0;
2298 range.length = ~0u;
2299 hr = IDWriteTextLayout_SetInlineObject(layout, &testinlineobj3, range);
2300 ok(hr == S_OK, "got 0x%08x\n", hr);
2302 count = 0;
2303 memset(metrics, 0, sizeof(metrics));
2304 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 2, &count);
2305 ok(hr == S_OK, "got 0x%08x\n", hr);
2306 ok(count == 1, "got %u\n", count);
2307 ok(metrics[0].canWrapLineAfter == 1, "got %d\n", metrics[0].canWrapLineAfter);
2309 IDWriteTextLayout_Release(layout);
2311 /* compare natural cluster width with gdi layout */
2312 hr = IDWriteFactory_CreateTextLayout(factory, L"a ", 1, format, 100.0f, 100.0f, &layout);
2313 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2315 count = 0;
2316 memset(metrics, 0, sizeof(metrics));
2317 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
2318 ok(hr == S_OK, "got 0x%08x\n", hr);
2319 ok(count == 1, "got %u\n", count);
2320 ok(metrics[0].width != floorf(metrics[0].width), "got %f\n", metrics[0].width);
2322 IDWriteTextLayout_Release(layout);
2324 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"a ", 1, format, 100.0f, 100.0f, 1.0f, NULL,
2325 FALSE, &layout);
2326 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2328 count = 0;
2329 memset(metrics, 0, sizeof(metrics));
2330 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
2331 ok(hr == S_OK, "got 0x%08x\n", hr);
2332 ok(count == 1, "got %u\n", count);
2333 ok(metrics[0].width == floorf(metrics[0].width), "got %f\n", metrics[0].width);
2335 IDWriteTextLayout_Release(layout);
2337 /* isNewline tests */
2338 hr = IDWriteFactory_CreateTextLayout(factory, str5W, lstrlenW(str5W), format, 100.0f, 200.0f, &layout);
2339 ok(hr == S_OK, "got 0x%08x\n", hr);
2341 count = 0;
2342 memset(metrics, 0, sizeof(metrics));
2343 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, ARRAY_SIZE(metrics), &count);
2344 ok(hr == S_OK, "got 0x%08x\n", hr);
2345 ok(count == 22, "got %u\n", count);
2347 ok(metrics[1].isNewline == 1, "got %d\n", metrics[1].isNewline);
2348 ok(metrics[3].isNewline == 1, "got %d\n", metrics[3].isNewline);
2349 ok(metrics[5].isNewline == 1, "got %d\n", metrics[5].isNewline);
2350 ok(metrics[6].isNewline == 1, "got %d\n", metrics[6].isNewline);
2351 ok(metrics[9].isNewline == 1, "got %d\n", metrics[9].isNewline);
2352 ok(metrics[11].isNewline == 1, "got %d\n", metrics[11].isNewline);
2353 ok(metrics[13].isNewline == 1, "got %d\n", metrics[13].isNewline);
2354 ok(metrics[15].isNewline == 1, "got %d\n", metrics[15].isNewline);
2355 ok(metrics[17].isNewline == 1, "got %d\n", metrics[17].isNewline);
2356 ok(metrics[19].isNewline == 1, "got %d\n", metrics[19].isNewline);
2357 ok(metrics[21].isNewline == 1, "got %d\n", metrics[21].isNewline);
2359 ok(metrics[0].isNewline == 0, "got %d\n", metrics[0].isNewline);
2360 ok(metrics[2].isNewline == 0, "got %d\n", metrics[2].isNewline);
2361 ok(metrics[4].isNewline == 0, "got %d\n", metrics[4].isNewline);
2362 ok(metrics[7].isNewline == 0, "got %d\n", metrics[7].isNewline);
2363 ok(metrics[8].isNewline == 0, "got %d\n", metrics[8].isNewline);
2364 ok(metrics[10].isNewline == 0, "got %d\n", metrics[10].isNewline);
2365 ok(metrics[12].isNewline == 0, "got %d\n", metrics[12].isNewline);
2366 ok(metrics[14].isNewline == 0, "got %d\n", metrics[14].isNewline);
2367 ok(metrics[16].isNewline == 0, "got %d\n", metrics[16].isNewline);
2368 ok(metrics[18].isNewline == 0, "got %d\n", metrics[18].isNewline);
2369 ok(metrics[20].isNewline == 0, "got %d\n", metrics[20].isNewline);
2371 for (i = 0; i < count; i++) {
2372 ok(metrics[i].length == 1, "%d: got %d\n", i, metrics[i].length);
2373 ok(metrics[i].isSoftHyphen == (i == count - 2), "%d: got %d\n", i, metrics[i].isSoftHyphen);
2374 if (metrics[i].isSoftHyphen)
2375 ok(!metrics[i].isWhitespace, "%u: got %d\n", i, metrics[i].isWhitespace);
2376 if (metrics[i].isNewline) {
2377 ok(metrics[i].width == 0.0f, "%u: got width %f\n", i, metrics[i].width);
2378 ok(metrics[i].isWhitespace == 1, "%u: got %d\n", i, metrics[i].isWhitespace);
2379 ok(metrics[i].canWrapLineAfter == 1, "%u: got %d\n", i, metrics[i].canWrapLineAfter);
2383 IDWriteTextLayout_Release(layout);
2385 /* Test whitespace resolution from linebreaking classes BK, ZW, and SP */
2386 hr = IDWriteFactory_CreateTextLayout(factory, str_white_spaceW, ARRAY_SIZE(str_white_spaceW), format,
2387 100.0f, 200.0f, &layout);
2388 ok(hr == S_OK, "got 0x%08x\n", hr);
2390 count = 0;
2391 memset(metrics, 0, sizeof(metrics));
2392 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 20, &count);
2393 ok(hr == S_OK, "got 0x%08x\n", hr);
2394 ok(count == 6, "got %u\n", count);
2396 ok(metrics[0].isWhitespace == 1, "got %d\n", metrics[0].isWhitespace);
2397 ok(metrics[1].isWhitespace == 1, "got %d\n", metrics[1].isWhitespace);
2398 ok(metrics[2].isWhitespace == 1, "got %d\n", metrics[2].isWhitespace);
2399 ok(metrics[3].isWhitespace == 1, "got %d\n", metrics[3].isWhitespace);
2400 ok(metrics[4].isWhitespace == 0, "got %d\n", metrics[4].isWhitespace);
2401 ok(metrics[5].isWhitespace == 1, "got %d\n", metrics[5].isWhitespace);
2403 IDWriteTextLayout_Release(layout);
2405 /* Trigger line trimming. */
2406 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 100.0f, 200.0f, &layout);
2407 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2409 count = 0;
2410 memset(metrics, 0, sizeof(metrics));
2411 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 4, &count);
2412 ok(hr == S_OK, "got 0x%08x\n", hr);
2413 ok(count == 4, "got %u\n", count);
2415 hr = IDWriteTextLayout_GetMetrics(layout, &text_metrics);
2416 ok(hr == S_OK, "got 0x%08x\n", hr);
2418 width = metrics[0].width + inline_metrics.width;
2419 ok(width < text_metrics.width, "unexpected trimming sign width\n");
2421 /* enable trimming, reduce layout width so only first cluster and trimming sign fits */
2422 trimming_options.granularity = DWRITE_TRIMMING_GRANULARITY_CHARACTER;
2423 trimming_options.delimiter = 0;
2424 trimming_options.delimiterCount = 0;
2425 hr = IDWriteTextLayout_SetTrimming(layout, &trimming_options, trimm);
2426 ok(hr == S_OK, "got 0x%08x\n", hr);
2428 hr = IDWriteTextLayout_SetMaxWidth(layout, width);
2429 ok(hr == S_OK, "got 0x%08x\n", hr);
2431 count = 0;
2432 memset(metrics, 0, sizeof(metrics));
2433 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 4, &count);
2434 ok(hr == S_OK, "got 0x%08x\n", hr);
2435 ok(count == 4, "got %u\n", count);
2437 hr = IDWriteTextLayout_GetLineMetrics(layout, &line, 1, &count);
2438 ok(hr == S_OK, "got 0x%08x\n", hr);
2439 ok(count == 1, "got %u\n", count);
2440 ok(line.length == 4, "got %u\n", line.length);
2441 ok(line.isTrimmed, "got %d\n", line.isTrimmed);
2443 IDWriteTextLayout_Release(layout);
2445 /* NO_WRAP, check cluster wrapping attribute. */
2446 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_NO_WRAP);
2447 ok(hr == S_OK, "got 0x%08x\n", hr);
2449 hr = IDWriteFactory_CreateTextLayout(factory, L"a b", 3, format, 1000.0f, 200.0f, &layout);
2450 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2452 count = 0;
2453 memset(metrics, 0, sizeof(metrics));
2454 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 3, &count);
2455 ok(hr == S_OK, "got 0x%08x\n", hr);
2456 ok(count == 3, "got %u\n", count);
2458 ok(metrics[0].canWrapLineAfter == 0, "got %d\n", metrics[0].canWrapLineAfter);
2459 ok(metrics[1].canWrapLineAfter == 1, "got %d\n", metrics[1].canWrapLineAfter);
2460 ok(metrics[2].canWrapLineAfter == 1, "got %d\n", metrics[2].canWrapLineAfter);
2462 IDWriteTextLayout_Release(layout);
2464 /* Single cluster layout, trigger trimming. */
2465 hr = IDWriteFactory_CreateTextLayout(factory, L"a b", 1, format, 1000.0f, 200.0f, &layout);
2466 ok(hr == S_OK, "Failed to create layout, hr %#x.\n", hr);
2468 count = 0;
2469 memset(metrics, 0, sizeof(metrics));
2470 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
2471 ok(hr == S_OK, "Failed to get cluster metrics, hr %#x.\n", hr);
2472 ok(count == 1, "Unexpected cluster count %u.\n", count);
2474 hr = IDWriteTextLayout_SetMaxWidth(layout, metrics[0].width / 2.0f);
2475 ok(hr == S_OK, "Failed to set layout width, hr %#x.\n", hr);
2477 trimming_options.granularity = DWRITE_TRIMMING_GRANULARITY_CHARACTER;
2478 trimming_options.delimiter = 0;
2479 trimming_options.delimiterCount = 0;
2480 hr = IDWriteTextLayout_SetTrimming(layout, &trimming_options, trimm);
2481 ok(hr == S_OK, "Failed to set trimming options, hr %#x.\n", hr);
2483 count = 0;
2484 memset(metrics, 0, sizeof(metrics));
2485 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, 1, &count);
2486 ok(hr == S_OK, "Failed to get cluster metrics, hr %#x.\n", hr);
2487 ok(count == 1, "Unexpected cluster count %u.\n", count);
2489 hr = IDWriteTextLayout_GetLineMetrics(layout, &line, 1, &count);
2490 ok(hr == S_OK, "Failed to get line metrics, hr %#x.\n", hr);
2491 ok(count == 1, "Unexpected line count %u.\n", count);
2492 ok(line.length == 1, "Unexpected line length %u.\n", line.length);
2493 ok(line.isTrimmed, "Unexpected trimming flag %x.\n", line.isTrimmed);
2495 flush_sequence(sequences, RENDERER_ID);
2496 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0f, 0.0f);
2497 ok(hr == S_OK, "Draw() failed, hr %#x.\n", hr);
2498 ok_sequence(sequences, RENDERER_ID, draw_trimmed_seq, "Trimmed draw test", FALSE);
2500 IDWriteTextLayout_Release(layout);
2502 IDWriteInlineObject_Release(trimm);
2503 IDWriteTextFormat_Release(format);
2504 IDWriteFactory_Release(factory);
2507 static void test_SetLocaleName(void)
2509 WCHAR buffW[LOCALE_NAME_MAX_LENGTH + 5];
2510 IDWriteTextFormat *format, *format2;
2511 IDWriteTextLayout *layout;
2512 DWRITE_TEXT_RANGE range;
2513 IDWriteFactory *factory;
2514 HRESULT hr;
2516 factory = create_factory();
2518 /* create format with mixed case locale name, get it back */
2519 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2520 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"eN-uS", &format);
2521 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
2523 hr = IDWriteTextFormat_GetLocaleName(format, buffW, ARRAY_SIZE(buffW));
2524 ok(hr == S_OK, "got 0x%08x\n", hr);
2525 ok(!lstrcmpW(buffW, L"en-us"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
2527 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
2528 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2530 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat, (void**)&format2);
2531 ok(hr == S_OK, "got 0x%08x\n", hr);
2533 hr = IDWriteTextFormat_GetLocaleName(format2, buffW, ARRAY_SIZE(buffW));
2534 ok(hr == S_OK, "got 0x%08x\n", hr);
2535 ok(!lstrcmpW(buffW, L"en-us"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
2537 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, ARRAY_SIZE(buffW), NULL);
2538 ok(hr == S_OK, "got 0x%08x\n", hr);
2539 ok(!lstrcmpW(buffW, L"en-us"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
2541 IDWriteTextFormat_Release(format2);
2542 IDWriteTextLayout_Release(layout);
2543 IDWriteTextFormat_Release(format);
2545 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2546 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
2547 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
2549 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
2550 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2552 range.startPosition = 0;
2553 range.length = 1;
2554 hr = IDWriteTextLayout_SetLocaleName(layout, L"en-us", range);
2555 ok(hr == S_OK, "Failed to set locale name, hr %#x.\n", hr);
2557 hr = IDWriteTextLayout_SetLocaleName(layout, NULL, range);
2558 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2560 /* invalid locale name is allowed */
2561 hr = IDWriteTextLayout_SetLocaleName(layout, L"abcd", range);
2562 ok(hr == S_OK, "Failed to set locale name, hr %#x.\n", hr);
2564 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 0, NULL);
2565 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2567 if (0) /* crashes on native */
2568 hr = IDWriteTextLayout_GetLocaleName(layout, 0, NULL, 1, NULL);
2570 buffW[0] = 0;
2571 range.length = 0;
2572 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, ARRAY_SIZE(buffW), &range);
2573 ok(hr == S_OK, "got 0x%08x\n", hr);
2574 ok(!lstrcmpW(buffW, L"abcd"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
2575 ok(range.startPosition == 0 && range.length == 1, "got %u,%u\n", range.startPosition, range.length);
2577 /* get with a shorter buffer */
2578 buffW[0] = 0xa;
2579 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, 1, NULL);
2580 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
2581 ok(buffW[0] == 0, "got %x\n", buffW[0]);
2583 /* name is too long */
2584 lstrcpyW(buffW, L"abcd");
2585 while (lstrlenW(buffW) <= LOCALE_NAME_MAX_LENGTH)
2586 lstrcatW(buffW, L"abcd");
2588 range.startPosition = 0;
2589 range.length = 1;
2590 hr = IDWriteTextLayout_SetLocaleName(layout, buffW, range);
2591 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2593 buffW[0] = 0;
2594 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, ARRAY_SIZE(buffW), NULL);
2595 ok(hr == S_OK, "got 0x%08x\n", hr);
2596 ok(!lstrcmpW(buffW, L"abcd"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
2598 /* set initial locale name for whole text, except with a different casing */
2599 range.startPosition = 0;
2600 range.length = 4;
2601 hr = IDWriteTextLayout_SetLocaleName(layout, L"eN-uS", range);
2602 ok(hr == S_OK, "Failed to set locale name, hr %#x.\n", hr);
2604 buffW[0] = 0;
2605 range.length = 0;
2606 hr = IDWriteTextLayout_GetLocaleName(layout, 0, buffW, ARRAY_SIZE(buffW), &range);
2607 ok(hr == S_OK, "got 0x%08x\n", hr);
2608 ok(!lstrcmpW(buffW, L"en-us"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
2609 ok((range.startPosition == 0 && range.length == ~0u) ||
2610 broken(range.startPosition == 0 && range.length == 4) /* vista/win7 */, "got %u,%u\n", range.startPosition, range.length);
2612 /* check what's returned for positions after the text */
2613 buffW[0] = 0;
2614 range.length = 0;
2615 hr = IDWriteTextLayout_GetLocaleName(layout, 100, buffW, ARRAY_SIZE(buffW), &range);
2616 ok(hr == S_OK, "got 0x%08x\n", hr);
2617 ok(!lstrcmpW(buffW, L"en-us"), "Unexpected locale name %s.\n", wine_dbgstr_w(buffW));
2618 ok((range.startPosition == 0 && range.length == ~0u) ||
2619 broken(range.startPosition == 4 && range.length == ~0u-4) /* vista/win7 */, "got %u,%u\n", range.startPosition, range.length);
2621 IDWriteTextLayout_Release(layout);
2622 IDWriteTextFormat_Release(format);
2623 IDWriteFactory_Release(factory);
2626 static void test_SetPairKerning(void)
2628 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
2629 DWRITE_CLUSTER_METRICS clusters[4];
2630 IDWriteTextLayout1 *layout1;
2631 IDWriteTextFormat *format;
2632 IDWriteTextLayout *layout;
2633 DWRITE_TEXT_RANGE range;
2634 IDWriteFactory *factory;
2635 BOOL kerning;
2636 UINT32 count;
2637 HRESULT hr;
2639 factory = create_factory();
2641 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2642 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
2643 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
2645 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
2646 ok(hr == S_OK, "got 0x%08x\n", hr);
2647 IDWriteTextFormat_Release(format);
2649 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void**)&layout1);
2650 IDWriteTextLayout_Release(layout);
2652 if (hr != S_OK) {
2653 win_skip("SetPairKerning() is not supported.\n");
2654 IDWriteFactory_Release(factory);
2655 return;
2658 if (0) { /* crashes on native */
2659 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, NULL);
2660 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, NULL, &range);
2663 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, NULL);
2664 ok(hr == S_OK, "got 0x%08x\n", hr);
2666 range.startPosition = 0;
2667 range.length = 0;
2668 kerning = TRUE;
2669 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
2670 ok(hr == S_OK, "got 0x%08x\n", hr);
2671 ok(!kerning, "got %d\n", kerning);
2672 ok(range.length == ~0u, "got %u\n", range.length);
2674 count = 0;
2675 hr = IDWriteTextLayout1_GetClusterMetrics(layout1, clusters, 4, &count);
2676 ok(hr == S_OK, "got 0x%08x\n", hr);
2677 ok(count == 3, "Unexpected cluster count %u.\n", count);
2678 ok(clusters[0].length == 1, "got %u\n", clusters[0].length);
2679 ok(clusters[1].length == 2, "got %u\n", clusters[1].length);
2680 ok(clusters[2].length == 1, "got %u\n", clusters[2].length);
2682 /* pair kerning flag participates in itemization - combining characters
2683 breaks */
2684 range.startPosition = 0;
2685 range.length = 2;
2686 hr = IDWriteTextLayout1_SetPairKerning(layout1, 2, range);
2687 ok(hr == S_OK, "got 0x%08x\n", hr);
2689 kerning = FALSE;
2690 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &kerning, &range);
2691 ok(hr == S_OK, "got 0x%08x\n", hr);
2692 ok(kerning == TRUE, "got %d\n", kerning);
2694 count = 0;
2695 hr = IDWriteTextLayout1_GetClusterMetrics(layout1, clusters, 4, &count);
2696 ok(hr == S_OK, "got 0x%08x\n", hr);
2697 ok(count == 4, "got %u\n", count);
2698 ok(clusters[0].length == 1, "got %u\n", clusters[0].length);
2699 ok(clusters[1].length == 1, "got %u\n", clusters[1].length);
2700 ok(clusters[2].length == 1, "got %u\n", clusters[2].length);
2701 ok(clusters[3].length == 1, "got %u\n", clusters[3].length);
2703 IDWriteTextLayout1_Release(layout1);
2704 IDWriteFactory_Release(factory);
2707 static void test_SetVerticalGlyphOrientation(void)
2709 DWRITE_VERTICAL_GLYPH_ORIENTATION orientation;
2710 IDWriteTextLayout2 *layout2;
2711 IDWriteTextFormat1 *format1;
2712 IDWriteTextFormat *format;
2713 IDWriteTextLayout *layout;
2714 IDWriteFactory *factory;
2715 HRESULT hr;
2717 factory = create_factory();
2719 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2720 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
2721 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
2723 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
2724 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2725 IDWriteTextFormat_Release(format);
2727 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
2728 IDWriteTextLayout_Release(layout);
2730 if (hr != S_OK) {
2731 win_skip("SetVerticalGlyphOrientation() is not supported.\n");
2732 IDWriteFactory_Release(factory);
2733 return;
2736 orientation = IDWriteTextLayout2_GetVerticalGlyphOrientation(layout2);
2737 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT, "got %d\n", orientation);
2739 hr = IDWriteTextLayout2_SetVerticalGlyphOrientation(layout2, DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED+1);
2740 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2742 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void **)&format1);
2743 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
2745 orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
2746 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT, "Unexpected orientation %d.\n", orientation);
2748 hr = IDWriteTextLayout2_SetVerticalGlyphOrientation(layout2, DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED);
2749 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
2751 orientation = IDWriteTextLayout2_GetVerticalGlyphOrientation(layout2);
2752 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED, "Unexpected orientation %d.\n", orientation);
2754 orientation = IDWriteTextFormat1_GetVerticalGlyphOrientation(format1);
2755 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_STACKED, "Unexpected orientation %d.\n", orientation);
2757 hr = IDWriteTextFormat1_SetVerticalGlyphOrientation(format1, DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT);
2758 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
2760 orientation = IDWriteTextLayout2_GetVerticalGlyphOrientation(layout2);
2761 ok(orientation == DWRITE_VERTICAL_GLYPH_ORIENTATION_DEFAULT, "Unexpected orientation %d.\n", orientation);
2763 IDWriteTextFormat1_Release(format1);
2765 IDWriteTextLayout2_Release(layout2);
2766 IDWriteFactory_Release(factory);
2769 static void test_DetermineMinWidth(void)
2771 struct minwidth_test {
2772 const WCHAR text[10]; /* text to create a layout for */
2773 const WCHAR mintext[10]; /* text that represents sequence of minimal width */
2774 } minwidth_tests[] = {
2775 { {' ','a','b',' ',0}, {'a','b',0} },
2776 { {'a','\n',' ',' ',0}, {'a',0} },
2777 { {'a','\n',' ',' ','b',0}, {'b',0} },
2778 { {'a','b','c','\n',' ',' ','b',0}, {'a','b','c',0} },
2780 DWRITE_CLUSTER_METRICS metrics[10];
2781 IDWriteTextFormat *format;
2782 IDWriteTextLayout *layout;
2783 IDWriteFactory *factory;
2784 UINT32 count, i, j;
2785 FLOAT minwidth;
2786 HRESULT hr;
2788 factory = create_factory();
2790 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2791 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
2792 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
2794 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
2795 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2797 hr = IDWriteTextLayout_DetermineMinWidth(layout, NULL);
2798 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2799 IDWriteTextLayout_Release(layout);
2801 /* empty string */
2802 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 0, format, 100.0f, 100.0f, &layout);
2803 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2805 minwidth = 1.0f;
2806 hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
2807 ok(hr == S_OK, "got 0x%08x\n", hr);
2808 ok(minwidth == 0.0f, "got %f\n", minwidth);
2809 IDWriteTextLayout_Release(layout);
2811 for (i = 0; i < ARRAY_SIZE(minwidth_tests); i++) {
2812 FLOAT width = 0.0f;
2814 /* measure expected width */
2815 hr = IDWriteFactory_CreateTextLayout(factory, minwidth_tests[i].mintext, lstrlenW(minwidth_tests[i].mintext), format, 1000.0f, 1000.0f, &layout);
2816 ok(hr == S_OK, "got 0x%08x\n", hr);
2818 hr = IDWriteTextLayout_GetClusterMetrics(layout, metrics, ARRAY_SIZE(metrics), &count);
2819 ok(hr == S_OK, "got 0x%08x\n", hr);
2821 for (j = 0; j < count; j++)
2822 width += metrics[j].width;
2824 IDWriteTextLayout_Release(layout);
2826 hr = IDWriteFactory_CreateTextLayout(factory, minwidth_tests[i].text, lstrlenW(minwidth_tests[i].text), format, 1000.0f, 1000.0f, &layout);
2827 ok(hr == S_OK, "got 0x%08x\n", hr);
2829 minwidth = 0.0f;
2830 hr = IDWriteTextLayout_DetermineMinWidth(layout, &minwidth);
2831 ok(hr == S_OK, "got 0x%08x\n", hr);
2832 ok(minwidth == width, "test %u: expected width %f, got %f\n", i, width, minwidth);
2834 IDWriteTextLayout_Release(layout);
2837 IDWriteTextFormat_Release(format);
2838 IDWriteFactory_Release(factory);
2841 static void test_SetFontSize(void)
2843 IDWriteTextFormat *format;
2844 IDWriteTextLayout *layout;
2845 IDWriteFactory *factory;
2846 DWRITE_TEXT_RANGE r;
2847 FLOAT size;
2848 HRESULT hr;
2850 factory = create_factory();
2852 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2853 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
2854 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
2856 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
2857 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2859 /* negative/zero size */
2860 r.startPosition = 1;
2861 r.length = 1;
2862 hr = IDWriteTextLayout_SetFontSize(layout, -15.0, r);
2863 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2865 hr = IDWriteTextLayout_SetFontSize(layout, 0.0, r);
2866 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2868 r.startPosition = 1;
2869 r.length = 0;
2870 size = 0.0;
2871 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
2872 ok(hr == S_OK, "got 0x%08x\n", hr);
2873 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2874 ok(size == 10.0, "got %.2f\n", size);
2876 r.startPosition = 1;
2877 r.length = 1;
2878 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
2879 ok(hr == S_OK, "got 0x%08x\n", hr);
2881 /* zero length range */
2882 r.startPosition = 1;
2883 r.length = 0;
2884 hr = IDWriteTextLayout_SetFontSize(layout, 123.0, r);
2885 ok(hr == S_OK, "got 0x%08x\n", hr);
2887 size = 0.0;
2888 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
2889 ok(hr == S_OK, "got 0x%08x\n", hr);
2890 ok(size == 15.0, "got %.2f\n", size);
2892 r.startPosition = 0;
2893 r.length = 4;
2894 hr = IDWriteTextLayout_SetFontSize(layout, 15.0, r);
2895 ok(hr == S_OK, "got 0x%08x\n", hr);
2897 size = 0.0;
2898 hr = IDWriteTextLayout_GetFontSize(layout, 1, &size, &r);
2899 ok(hr == S_OK, "got 0x%08x\n", hr);
2900 ok(size == 15.0, "got %.2f\n", size);
2902 size = 0.0;
2903 hr = IDWriteTextLayout_GetFontSize(layout, 0, &size, &r);
2904 ok(hr == S_OK, "got 0x%08x\n", hr);
2905 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2906 ok(size == 15.0, "got %.2f\n", size);
2908 size = 15.0;
2909 r.startPosition = r.length = 0;
2910 hr = IDWriteTextLayout_GetFontSize(layout, 20, &size, &r);
2911 ok(hr == S_OK, "got 0x%08x\n", hr);
2912 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
2913 ok(size == 10.0, "got %.2f\n", size);
2915 r.startPosition = 100;
2916 r.length = 4;
2917 hr = IDWriteTextLayout_SetFontSize(layout, 25.0, r);
2918 ok(hr == S_OK, "got 0x%08x\n", hr);
2920 size = 15.0;
2921 r.startPosition = r.length = 0;
2922 hr = IDWriteTextLayout_GetFontSize(layout, 100, &size, &r);
2923 ok(hr == S_OK, "got 0x%08x\n", hr);
2924 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
2925 ok(size == 25.0, "got %.2f\n", size);
2927 IDWriteTextLayout_Release(layout);
2928 IDWriteTextFormat_Release(format);
2929 IDWriteFactory_Release(factory);
2932 static void test_SetFontFamilyName(void)
2934 IDWriteTextFormat *format;
2935 IDWriteTextLayout *layout;
2936 IDWriteFactory *factory;
2937 DWRITE_TEXT_RANGE r;
2938 WCHAR nameW[50];
2939 HRESULT hr;
2941 factory = create_factory();
2943 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
2944 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
2945 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
2947 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
2948 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
2950 /* NULL name */
2951 r.startPosition = 1;
2952 r.length = 1;
2953 hr = IDWriteTextLayout_SetFontFamilyName(layout, NULL, r);
2954 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
2956 r.startPosition = 1;
2957 r.length = 0;
2958 nameW[0] = 0;
2959 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, ARRAY_SIZE(nameW), &r);
2960 ok(hr == S_OK, "got 0x%08x\n", hr);
2961 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
2963 /* set name only different in casing */
2964 r.startPosition = 1;
2965 r.length = 1;
2966 hr = IDWriteTextLayout_SetFontFamilyName(layout, L"TaHoma", r);
2967 ok(hr == S_OK, "got 0x%08x\n", hr);
2969 /* zero length range */
2970 r.startPosition = 1;
2971 r.length = 0;
2972 hr = IDWriteTextLayout_SetFontFamilyName(layout, L"Arial", r);
2973 ok(hr == S_OK, "got 0x%08x\n", hr);
2975 r.startPosition = 0;
2976 r.length = 0;
2977 nameW[0] = 0;
2978 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, ARRAY_SIZE(nameW), &r);
2979 ok(hr == S_OK, "got 0x%08x\n", hr);
2980 ok(!lstrcmpW(nameW, L"TaHoma"), "Unexpected family name %s.\n", wine_dbgstr_w(nameW));
2981 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2983 r.startPosition = 1;
2984 r.length = 1;
2985 hr = IDWriteTextLayout_SetFontFamilyName(layout, L"Arial", r);
2986 ok(hr == S_OK, "got 0x%08x\n", hr);
2988 r.startPosition = 1;
2989 r.length = 0;
2990 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, ARRAY_SIZE(nameW), &r);
2991 ok(hr == S_OK, "got 0x%08x\n", hr);
2992 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
2994 r.startPosition = 0;
2995 r.length = 4;
2996 hr = IDWriteTextLayout_SetFontFamilyName(layout, L"Arial", r);
2997 ok(hr == S_OK, "got 0x%08x\n", hr);
2999 nameW[0] = 0;
3000 hr = IDWriteTextLayout_GetFontFamilyName(layout, 1, nameW, ARRAY_SIZE(nameW), &r);
3001 ok(hr == S_OK, "got 0x%08x\n", hr);
3002 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
3003 ok(!lstrcmpW(nameW, L"Arial"), "Unexpected family name %s.\n", wine_dbgstr_w(nameW));
3005 IDWriteTextLayout_Release(layout);
3006 IDWriteTextFormat_Release(format);
3007 IDWriteFactory_Release(factory);
3010 static void test_SetFontStyle(void)
3012 IDWriteTextFormat *format;
3013 IDWriteTextLayout *layout;
3014 IDWriteFactory *factory;
3015 DWRITE_FONT_STYLE style;
3016 DWRITE_TEXT_RANGE r;
3017 HRESULT hr;
3019 factory = create_factory();
3021 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3022 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
3023 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3025 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
3026 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3028 /* invalid style value */
3029 r.startPosition = 1;
3030 r.length = 1;
3031 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC+1, r);
3032 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3034 r.startPosition = 1;
3035 r.length = 0;
3036 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
3037 ok(hr == S_OK, "got 0x%08x\n", hr);
3038 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
3039 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
3041 r.startPosition = 1;
3042 r.length = 1;
3043 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC, r);
3044 ok(hr == S_OK, "got 0x%08x\n", hr);
3046 /* zero length range */
3047 r.startPosition = 1;
3048 r.length = 0;
3049 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_NORMAL, r);
3050 ok(hr == S_OK, "got 0x%08x\n", hr);
3052 style = DWRITE_FONT_STYLE_NORMAL;
3053 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
3054 ok(hr == S_OK, "got 0x%08x\n", hr);
3055 ok(style == DWRITE_FONT_STYLE_ITALIC, "got %d\n", style);
3057 r.startPosition = 0;
3058 r.length = 4;
3059 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
3060 ok(hr == S_OK, "got 0x%08x\n", hr);
3062 style = DWRITE_FONT_STYLE_ITALIC;
3063 hr = IDWriteTextLayout_GetFontStyle(layout, 1, &style, &r);
3064 ok(hr == S_OK, "got 0x%08x\n", hr);
3065 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
3067 style = DWRITE_FONT_STYLE_ITALIC;
3068 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &r);
3069 ok(hr == S_OK, "got 0x%08x\n", hr);
3070 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
3071 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
3073 style = DWRITE_FONT_STYLE_ITALIC;
3074 r.startPosition = r.length = 0;
3075 hr = IDWriteTextLayout_GetFontStyle(layout, 20, &style, &r);
3076 ok(hr == S_OK, "got 0x%08x\n", hr);
3077 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
3078 ok(style == DWRITE_FONT_STYLE_NORMAL, "got %d\n", style);
3080 r.startPosition = 100;
3081 r.length = 4;
3082 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_OBLIQUE, r);
3083 ok(hr == S_OK, "got 0x%08x\n", hr);
3085 style = DWRITE_FONT_STYLE_NORMAL;
3086 r.startPosition = r.length = 0;
3087 hr = IDWriteTextLayout_GetFontStyle(layout, 100, &style, &r);
3088 ok(hr == S_OK, "got 0x%08x\n", hr);
3089 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
3090 ok(style == DWRITE_FONT_STYLE_OBLIQUE, "got %d\n", style);
3092 IDWriteTextLayout_Release(layout);
3093 IDWriteTextFormat_Release(format);
3094 IDWriteFactory_Release(factory);
3097 static void test_SetFontStretch(void)
3099 DWRITE_FONT_STRETCH stretch;
3100 IDWriteTextFormat *format;
3101 IDWriteTextLayout *layout;
3102 IDWriteFactory *factory;
3103 DWRITE_TEXT_RANGE r;
3104 HRESULT hr;
3106 factory = create_factory();
3108 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3109 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
3110 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3112 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
3113 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3115 /* invalid stretch value */
3116 r.startPosition = 1;
3117 r.length = 1;
3118 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_ULTRA_EXPANDED+1, r);
3119 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3121 r.startPosition = 1;
3122 r.length = 0;
3123 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3124 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
3125 ok(hr == S_OK, "got 0x%08x\n", hr);
3126 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
3127 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
3129 r.startPosition = 1;
3130 r.length = 1;
3131 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_CONDENSED, r);
3132 ok(hr == S_OK, "got 0x%08x\n", hr);
3134 /* zero length range */
3135 r.startPosition = 1;
3136 r.length = 0;
3137 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_NORMAL, r);
3138 ok(hr == S_OK, "got 0x%08x\n", hr);
3140 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3141 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
3142 ok(hr == S_OK, "got 0x%08x\n", hr);
3143 ok(stretch == DWRITE_FONT_STRETCH_CONDENSED, "got %d\n", stretch);
3145 r.startPosition = 0;
3146 r.length = 4;
3147 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
3148 ok(hr == S_OK, "got 0x%08x\n", hr);
3150 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3151 hr = IDWriteTextLayout_GetFontStretch(layout, 1, &stretch, &r);
3152 ok(hr == S_OK, "got 0x%08x\n", hr);
3153 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
3155 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3156 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &r);
3157 ok(hr == S_OK, "got 0x%08x\n", hr);
3158 ok(r.startPosition == 0 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
3159 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
3161 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3162 r.startPosition = r.length = 0;
3163 hr = IDWriteTextLayout_GetFontStretch(layout, 20, &stretch, &r);
3164 ok(hr == S_OK, "got 0x%08x\n", hr);
3165 ok(r.startPosition == 4 && r.length == ~0u-4, "got %u, %u\n", r.startPosition, r.length);
3166 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "got %d\n", stretch);
3168 r.startPosition = 100;
3169 r.length = 4;
3170 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_EXPANDED, r);
3171 ok(hr == S_OK, "got 0x%08x\n", hr);
3173 stretch = DWRITE_FONT_STRETCH_UNDEFINED;
3174 r.startPosition = r.length = 0;
3175 hr = IDWriteTextLayout_GetFontStretch(layout, 100, &stretch, &r);
3176 ok(hr == S_OK, "got 0x%08x\n", hr);
3177 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
3178 ok(stretch == DWRITE_FONT_STRETCH_EXPANDED, "got %d\n", stretch);
3180 /* trying to set undefined value */
3181 r.startPosition = 0;
3182 r.length = 2;
3183 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_UNDEFINED, r);
3184 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
3186 IDWriteTextLayout_Release(layout);
3187 IDWriteTextFormat_Release(format);
3188 IDWriteFactory_Release(factory);
3191 static void test_SetStrikethrough(void)
3193 IDWriteTextFormat *format;
3194 IDWriteTextLayout *layout;
3195 IDWriteFactory *factory;
3196 DWRITE_TEXT_RANGE r;
3197 BOOL value;
3198 HRESULT hr;
3200 factory = create_factory();
3202 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3203 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
3204 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3206 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
3207 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3209 r.startPosition = 1;
3210 r.length = 0;
3211 value = TRUE;
3212 hr = IDWriteTextLayout_GetStrikethrough(layout, 0, &value, &r);
3213 ok(hr == S_OK, "got 0x%08x\n", hr);
3214 ok(r.startPosition == 0 && r.length == ~0u, "got %u, %u\n", r.startPosition, r.length);
3215 ok(value == FALSE, "got %d\n", value);
3217 r.startPosition = 1;
3218 r.length = 1;
3219 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, r);
3220 ok(hr == S_OK, "got 0x%08x\n", hr);
3222 value = FALSE;
3223 hr = IDWriteTextLayout_GetStrikethrough(layout, 1, &value, &r);
3224 ok(hr == S_OK, "got 0x%08x\n", hr);
3225 ok(value == TRUE, "got %d\n", value);
3226 ok(r.startPosition == 1 && r.length == 1, "got %u, %u\n", r.startPosition, r.length);
3228 value = TRUE;
3229 r.startPosition = r.length = 0;
3230 hr = IDWriteTextLayout_GetStrikethrough(layout, 20, &value, &r);
3231 ok(hr == S_OK, "got 0x%08x\n", hr);
3232 ok(r.startPosition == 2 && r.length == ~0u-2, "got %u, %u\n", r.startPosition, r.length);
3233 ok(value == FALSE, "got %d\n", value);
3235 r.startPosition = 100;
3236 r.length = 4;
3237 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, r);
3238 ok(hr == S_OK, "got 0x%08x\n", hr);
3240 value = FALSE;
3241 r.startPosition = r.length = 0;
3242 hr = IDWriteTextLayout_GetStrikethrough(layout, 100, &value, &r);
3243 ok(hr == S_OK, "got 0x%08x\n", hr);
3244 ok(r.startPosition == 100 && r.length == 4, "got %u, %u\n", r.startPosition, r.length);
3245 ok(value == TRUE, "got %d\n", value);
3247 IDWriteTextLayout_Release(layout);
3248 IDWriteTextFormat_Release(format);
3249 IDWriteFactory_Release(factory);
3252 static void test_GetMetrics(void)
3254 static const WCHAR str2W[] = {0x2066,')',')',0x661,'(',0x627,')',0};
3255 DWRITE_CLUSTER_METRICS clusters[4];
3256 DWRITE_TEXT_METRICS metrics;
3257 IDWriteTextFormat *format;
3258 IDWriteTextLayout *layout;
3259 IDWriteFactory *factory;
3260 UINT32 count, i;
3261 FLOAT width;
3262 HRESULT hr;
3264 factory = create_factory();
3266 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3267 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
3268 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3270 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 500.0f, 1000.0f, &layout);
3271 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3273 count = 0;
3274 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count);
3275 ok(hr == S_OK, "got 0x%08x\n", hr);
3276 ok(count == 4, "got %u\n", count);
3277 for (i = 0, width = 0.0; i < count; i++)
3278 width += clusters[i].width;
3280 memset(&metrics, 0xcc, sizeof(metrics));
3281 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3282 ok(hr == S_OK, "got 0x%08x\n", hr);
3283 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
3284 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3285 ok(metrics.width == width, "got %.2f, expected %.2f\n", metrics.width, width);
3286 ok(metrics.widthIncludingTrailingWhitespace == width, "got %.2f, expected %.2f\n",
3287 metrics.widthIncludingTrailingWhitespace, width);
3288 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
3289 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3290 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
3291 ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
3292 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
3294 IDWriteTextLayout_Release(layout);
3296 /* a string with more complex bidi sequence */
3297 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 7, format, 500.0, 1000.0, &layout);
3298 ok(hr == S_OK, "got 0x%08x\n", hr);
3300 memset(&metrics, 0xcc, sizeof(metrics));
3301 metrics.maxBidiReorderingDepth = 0;
3302 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3303 ok(hr == S_OK, "got 0x%08x\n", hr);
3304 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
3305 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3306 ok(metrics.width > 0.0, "got %.2f\n", metrics.width);
3307 ok(metrics.widthIncludingTrailingWhitespace > 0.0, "got %.2f\n", metrics.widthIncludingTrailingWhitespace);
3308 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
3309 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3310 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
3311 todo_wine
3312 ok(metrics.maxBidiReorderingDepth > 1, "got %u\n", metrics.maxBidiReorderingDepth);
3313 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
3315 IDWriteTextLayout_Release(layout);
3317 /* single cluster layout */
3318 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 500.0f, 1000.0f, &layout);
3319 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3321 count = 0;
3322 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
3323 ok(hr == S_OK, "got 0x%08x\n", hr);
3324 ok(count == 1, "got %u\n", count);
3326 memset(&metrics, 0xcc, sizeof(metrics));
3327 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3328 ok(hr == S_OK, "got 0x%08x\n", hr);
3329 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
3330 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
3331 ok(metrics.width == clusters[0].width, "got %.2f, expected %.2f\n", metrics.width, clusters[0].width);
3332 ok(metrics.widthIncludingTrailingWhitespace == clusters[0].width, "got %.2f\n", metrics.widthIncludingTrailingWhitespace);
3333 ok(metrics.height > 0.0, "got %.2f\n", metrics.height);
3334 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
3335 ok(metrics.layoutHeight == 1000.0, "got %.2f\n", metrics.layoutHeight);
3336 ok(metrics.maxBidiReorderingDepth == 1, "got %u\n", metrics.maxBidiReorderingDepth);
3337 ok(metrics.lineCount == 1, "got %u\n", metrics.lineCount);
3338 IDWriteTextLayout_Release(layout);
3340 /* Whitespace only. */
3341 hr = IDWriteFactory_CreateTextLayout(factory, L" ", 1, format, 500.0f, 1000.0f, &layout);
3342 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3344 memset(&metrics, 0xcc, sizeof(metrics));
3345 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
3346 ok(hr == S_OK, "Failed to get layout metrics, hr %#x.\n", hr);
3347 ok(metrics.left == 0.0f, "Unexpected value for left %f.\n", metrics.left);
3348 ok(metrics.top == 0.0f, "Unexpected value for top %f.\n", metrics.top);
3349 ok(metrics.width == 0.0f, "Unexpected width %f.\n", metrics.width);
3350 ok(metrics.widthIncludingTrailingWhitespace > 0.0f, "Unexpected full width %f.\n",
3351 metrics.widthIncludingTrailingWhitespace);
3352 ok(metrics.height > 0.0, "Unexpected height %f.\n", metrics.height);
3353 ok(metrics.layoutWidth == 500.0, "Unexpected box width %f.\n", metrics.layoutWidth);
3354 ok(metrics.layoutHeight == 1000.0, "Unexpected box height %f.\n", metrics.layoutHeight);
3355 ok(metrics.maxBidiReorderingDepth == 1, "Unexpected reordering depth %u.\n", metrics.maxBidiReorderingDepth);
3356 ok(metrics.lineCount == 1, "Unexpected line count %u.\n", metrics.lineCount);
3357 IDWriteTextLayout_Release(layout);
3359 IDWriteTextFormat_Release(format);
3360 IDWriteFactory_Release(factory);
3363 static void test_SetFlowDirection(void)
3365 DWRITE_READING_DIRECTION reading;
3366 DWRITE_FLOW_DIRECTION flow;
3367 IDWriteTextFormat *format;
3368 IDWriteTextLayout *layout;
3369 IDWriteFactory *factory;
3370 HRESULT hr;
3372 factory = create_factory();
3374 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3375 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
3376 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3378 flow = IDWriteTextFormat_GetFlowDirection(format);
3379 ok(flow == DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM, "got %d\n", flow);
3381 reading = IDWriteTextFormat_GetReadingDirection(format);
3382 ok(reading == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", reading);
3384 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 500.0f, 1000.0f, &layout);
3385 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3386 IDWriteTextLayout_Release(layout);
3388 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT);
3389 ok(hr == S_OK || broken(hr == E_INVALIDARG) /* vista,win7 */, "got 0x%08x\n", hr);
3390 if (hr == S_OK)
3392 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 500.0f, 1000.0f, &layout);
3393 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3394 IDWriteTextLayout_Release(layout);
3396 hr = IDWriteTextFormat_SetReadingDirection(format, DWRITE_READING_DIRECTION_TOP_TO_BOTTOM);
3397 ok(hr == S_OK, "got 0x%08x\n", hr);
3399 hr = IDWriteTextFormat_SetFlowDirection(format, DWRITE_FLOW_DIRECTION_TOP_TO_BOTTOM);
3400 ok(hr == S_OK, "got 0x%08x\n", hr);
3402 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 500.0f, 1000.0f, &layout);
3403 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3404 IDWriteTextLayout_Release(layout);
3406 else
3407 win_skip("DWRITE_FLOW_DIRECTION_LEFT_TO_RIGHT is not supported\n");
3409 IDWriteTextFormat_Release(format);
3410 IDWriteFactory_Release(factory);
3413 static const struct drawcall_entry draweffect_seq[] = {
3414 { DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0x0300,0}, {'e','n','-','u','s',0}, 2 },
3415 { DRAW_GLYPHRUN, {'d',0}, {'e','n','-','u','s',0}, 1 },
3416 { DRAW_LAST_KIND }
3419 static const struct drawcall_entry draweffect2_seq[] = {
3420 { DRAW_GLYPHRUN|DRAW_EFFECT, {'a','e',0}, {'e','n','-','u','s',0}, 2 },
3421 { DRAW_GLYPHRUN, {'c','d',0}, {'e','n','-','u','s',0}, 2 },
3422 { DRAW_LAST_KIND }
3425 static const struct drawcall_entry draweffect3_seq[] = {
3426 { DRAW_INLINE|DRAW_EFFECT },
3427 { DRAW_LAST_KIND }
3430 static const struct drawcall_entry draweffect4_seq[] = {
3431 { DRAW_INLINE },
3432 { DRAW_LAST_KIND }
3435 static void test_SetDrawingEffect(void)
3437 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
3438 IDWriteInlineObject *sign;
3439 IDWriteTextFormat *format;
3440 IDWriteTextLayout *layout;
3441 IDWriteFactory *factory;
3442 IUnknown *unk, *effect;
3443 DWRITE_TEXT_RANGE r;
3444 HRESULT hr;
3445 LONG ref;
3447 factory = create_factory();
3449 effect = create_test_effect();
3451 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3452 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
3453 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3455 /* string with combining mark */
3456 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 500.0, 1000.0, &layout);
3457 ok(hr == S_OK, "got 0x%08x\n", hr);
3459 /* set effect past the end of text */
3460 r.startPosition = 100;
3461 r.length = 10;
3462 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3463 ok(hr == S_OK, "got 0x%08x\n", hr);
3465 r.startPosition = r.length = 0;
3466 hr = IDWriteTextLayout_GetDrawingEffect(layout, 101, &unk, &r);
3467 ok(hr == S_OK, "got 0x%08x\n", hr);
3468 ok(r.startPosition == 100 && r.length == 10, "got %u, %u\n", r.startPosition, r.length);
3469 IUnknown_Release(unk);
3471 r.startPosition = r.length = 0;
3472 unk = (void*)0xdeadbeef;
3473 hr = IDWriteTextLayout_GetDrawingEffect(layout, 1000, &unk, &r);
3474 ok(hr == S_OK, "got 0x%08x\n", hr);
3475 ok(r.startPosition == 110 && r.length == ~0u-110, "got %u, %u\n", r.startPosition, r.length);
3476 ok(unk == NULL, "got %p\n", unk);
3478 /* effect is applied to clusters, not individual text positions */
3479 r.startPosition = 0;
3480 r.length = 2;
3481 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3482 ok(hr == S_OK, "got 0x%08x\n", hr);
3484 flush_sequence(sequences, RENDERER_ID);
3485 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3486 ok(hr == S_OK, "got 0x%08x\n", hr);
3487 ok_sequence(sequences, RENDERER_ID, draweffect_seq, "effect draw test", TRUE);
3488 IDWriteTextLayout_Release(layout);
3490 /* simple string */
3491 hr = IDWriteFactory_CreateTextLayout(factory, L"aecd", 4, format, 500.0f, 1000.0f, &layout);
3492 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3494 r.startPosition = 0;
3495 r.length = 2;
3496 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3497 ok(hr == S_OK, "got 0x%08x\n", hr);
3499 flush_sequence(sequences, RENDERER_ID);
3500 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3501 ok(hr == S_OK, "got 0x%08x\n", hr);
3502 ok_sequence(sequences, RENDERER_ID, draweffect2_seq, "effect draw test 2", FALSE);
3503 IDWriteTextLayout_Release(layout);
3505 /* Inline object - effect set for same range */
3506 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
3507 ok(hr == S_OK, "got 0x%08x\n", hr);
3509 hr = IDWriteFactory_CreateTextLayout(factory, L"aecd", 4, format, 500.0f, 1000.0f, &layout);
3510 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3512 r.startPosition = 0;
3513 r.length = 4;
3514 hr = IDWriteTextLayout_SetInlineObject(layout, sign, r);
3515 ok(hr == S_OK, "got 0x%08x\n", hr);
3517 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3518 ok(hr == S_OK, "got 0x%08x\n", hr);
3520 flush_sequence(sequences, RENDERER_ID);
3521 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3522 ok(hr == S_OK, "got 0x%08x\n", hr);
3523 ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 3", FALSE);
3525 /* now set effect somewhere inside a range replaced by inline object */
3526 hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
3527 ok(hr == S_OK, "got 0x%08x\n", hr);
3529 r.startPosition = 1;
3530 r.length = 1;
3531 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3532 ok(hr == S_OK, "got 0x%08x\n", hr);
3534 /* no effect is reported in this case */
3535 flush_sequence(sequences, RENDERER_ID);
3536 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3537 ok(hr == S_OK, "got 0x%08x\n", hr);
3538 ok_sequence(sequences, RENDERER_ID, draweffect4_seq, "effect draw test 4", FALSE);
3540 r.startPosition = 0;
3541 r.length = 4;
3542 hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, r);
3543 ok(hr == S_OK, "got 0x%08x\n", hr);
3545 r.startPosition = 0;
3546 r.length = 1;
3547 hr = IDWriteTextLayout_SetDrawingEffect(layout, effect, r);
3548 ok(hr == S_OK, "got 0x%08x\n", hr);
3550 /* first range position is all that matters for inline ranges */
3551 flush_sequence(sequences, RENDERER_ID);
3552 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
3553 ok(hr == S_OK, "got 0x%08x\n", hr);
3554 ok_sequence(sequences, RENDERER_ID, draweffect3_seq, "effect draw test 5", FALSE);
3556 IDWriteTextLayout_Release(layout);
3558 ref = IUnknown_Release(effect);
3559 ok(ref == 0, "Unexpected effect refcount %u\n", ref);
3560 IDWriteInlineObject_Release(sign);
3561 IDWriteTextFormat_Release(format);
3562 IDWriteFactory_Release(factory);
3565 static BOOL get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, UINT32 size)
3567 UINT32 index;
3568 BOOL exists = FALSE;
3569 HRESULT hr;
3571 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-us", &index, &exists);
3572 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
3574 if (exists) {
3575 hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
3576 ok(hr == S_OK, "got 0x%08x\n", hr);
3578 else
3579 *buff = 0;
3581 return exists;
3584 static void test_GetLineMetrics(void)
3586 static const WCHAR str3W[] = {'a','\r','b','\n','c','\n','\r','d','\r','\n',0};
3587 static const WCHAR strW[] = {'a','b','c','d',' ',0};
3588 static const WCHAR str2W[] = {'a','b','\r','c','d',0};
3589 static const WCHAR str4W[] = {'a','\r',0};
3590 IDWriteFontCollection *syscollection;
3591 DWRITE_FONT_METRICS fontmetrics;
3592 DWRITE_LINE_METRICS metrics[6];
3593 UINT32 count, i, familycount;
3594 IDWriteTextFormat *format;
3595 IDWriteTextLayout *layout;
3596 IDWriteFontFace *fontface;
3597 IDWriteFactory *factory;
3598 DWRITE_TEXT_RANGE range;
3599 WCHAR nameW[256];
3600 HRESULT hr;
3602 factory = create_factory();
3604 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3605 DWRITE_FONT_STRETCH_NORMAL, 2048.0f, L"en-us", &format);
3606 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3608 hr = IDWriteFactory_CreateTextLayout(factory, strW, 5, format, 30000.0, 1000.0, &layout);
3609 ok(hr == S_OK, "got 0x%08x\n", hr);
3611 count = 0;
3612 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 0, &count);
3613 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
3614 ok(count == 1, "got count %u\n", count);
3616 memset(metrics, 0, sizeof(metrics));
3617 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 1, &count);
3618 ok(hr == S_OK, "got 0x%08x\n", hr);
3619 ok(metrics[0].length == 5, "got %u\n", metrics[0].length);
3620 ok(metrics[0].trailingWhitespaceLength == 1, "got %u\n", metrics[0].trailingWhitespaceLength);
3622 ok(metrics[0].newlineLength == 0, "got %u\n", metrics[0].newlineLength);
3623 ok(metrics[0].isTrimmed == FALSE, "got %d\n", metrics[0].isTrimmed);
3625 IDWriteTextLayout_Release(layout);
3626 IDWriteTextFormat_Release(format);
3628 /* Test line height and baseline calculation */
3629 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
3630 ok(hr == S_OK, "got 0x%08x\n", hr);
3631 familycount = IDWriteFontCollection_GetFontFamilyCount(syscollection);
3633 for (i = 0; i < familycount; i++) {
3634 IDWriteLocalizedStrings *names;
3635 IDWriteFontFamily *family;
3636 IDWriteFont *font;
3637 BOOL exists;
3639 format = NULL;
3640 layout = NULL;
3642 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
3643 ok(hr == S_OK, "got 0x%08x\n", hr);
3645 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
3646 DWRITE_FONT_STYLE_NORMAL, &font);
3647 ok(hr == S_OK, "got 0x%08x\n", hr);
3649 hr = IDWriteFont_CreateFontFace(font, &fontface);
3650 ok(hr == S_OK, "got 0x%08x\n", hr);
3652 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
3653 ok(hr == S_OK, "got 0x%08x\n", hr);
3655 if (!(exists = get_enus_string(names, nameW, ARRAY_SIZE(nameW)))) {
3656 IDWriteLocalFontFileLoader *localloader;
3657 IDWriteFontFileLoader *loader;
3658 IDWriteFontFile *file;
3659 const void *key;
3660 UINT32 keysize;
3661 UINT32 count;
3663 count = 1;
3664 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
3665 ok(hr == S_OK, "got 0x%08x\n", hr);
3667 hr = IDWriteFontFile_GetLoader(file, &loader);
3668 ok(hr == S_OK, "got 0x%08x\n", hr);
3670 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
3671 ok(hr == S_OK, "got 0x%08x\n", hr);
3672 IDWriteFontFileLoader_Release(loader);
3674 hr = IDWriteFontFile_GetReferenceKey(file, &key, &keysize);
3675 ok(hr == S_OK, "got 0x%08x\n", hr);
3677 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, keysize, nameW, ARRAY_SIZE(nameW));
3678 ok(hr == S_OK, "got 0x%08x\n", hr);
3680 skip("Failed to get English family name, font file %s\n", wine_dbgstr_w(nameW));
3682 IDWriteLocalFontFileLoader_Release(localloader);
3683 IDWriteFontFile_Release(file);
3686 IDWriteLocalizedStrings_Release(names);
3687 IDWriteFont_Release(font);
3689 if (!exists)
3690 goto cleanup;
3692 IDWriteFontFace_GetMetrics(fontface, &fontmetrics);
3693 hr = IDWriteFactory_CreateTextFormat(factory, nameW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3694 DWRITE_FONT_STRETCH_NORMAL, fontmetrics.designUnitsPerEm, L"en-us", &format);
3695 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3697 hr = IDWriteFactory_CreateTextLayout(factory, L"", 1, format, 30000.0f, 100.0f, &layout);
3698 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3700 memset(metrics, 0, sizeof(metrics));
3701 count = 0;
3702 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, ARRAY_SIZE(metrics), &count);
3703 ok(hr == S_OK, "got 0x%08x\n", hr);
3704 ok(count == 1, "got %u\n", count);
3706 ok(metrics[0].baseline == fontmetrics.ascent + fontmetrics.lineGap, "%s: got %.2f, expected %d, "
3707 "linegap %d\n", wine_dbgstr_w(nameW), metrics[0].baseline, fontmetrics.ascent + fontmetrics.lineGap,
3708 fontmetrics.lineGap);
3709 ok(metrics[0].height == fontmetrics.ascent + fontmetrics.descent + fontmetrics.lineGap,
3710 "%s: got %.2f, expected %d, linegap %d\n", wine_dbgstr_w(nameW), metrics[0].height,
3711 fontmetrics.ascent + fontmetrics.descent + fontmetrics.lineGap, fontmetrics.lineGap);
3713 cleanup:
3714 if (layout)
3715 IDWriteTextLayout_Release(layout);
3716 if (format)
3717 IDWriteTextFormat_Release(format);
3718 IDWriteFontFace_Release(fontface);
3719 IDWriteFontFamily_Release(family);
3721 IDWriteFontCollection_Release(syscollection);
3723 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3724 DWRITE_FONT_STRETCH_NORMAL, 2048.0f, L"en-us", &format);
3725 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3727 fontface = get_fontface_from_format(format);
3728 ok(fontface != NULL, "got %p\n", fontface);
3730 /* force 2 lines */
3731 hr = IDWriteFactory_CreateTextLayout(factory, str2W, 5, format, 10000.0, 1000.0, &layout);
3732 ok(hr == S_OK, "got 0x%08x\n", hr);
3734 memset(metrics, 0, sizeof(metrics));
3735 count = 0;
3736 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, ARRAY_SIZE(metrics), &count);
3737 ok(hr == S_OK, "got 0x%08x\n", hr);
3738 ok(count == 2, "got %u\n", count);
3739 /* baseline is relative to a line, and is not accumulated */
3740 ok(metrics[0].baseline == metrics[1].baseline, "got %.2f, %.2f\n", metrics[0].baseline,
3741 metrics[1].baseline);
3743 IDWriteTextLayout_Release(layout);
3744 IDWriteTextFormat_Release(format);
3746 /* line breaks */
3747 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3748 DWRITE_FONT_STRETCH_NORMAL, 12.0f, L"en-us", &format);
3749 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3751 hr = IDWriteFactory_CreateTextLayout(factory, str3W, 10, format, 100.0, 300.0, &layout);
3752 ok(hr == S_OK, "got 0x%08x\n", hr);
3754 memset(metrics, 0xcc, sizeof(metrics));
3755 count = 0;
3756 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, ARRAY_SIZE(metrics), &count);
3757 ok(hr == S_OK, "got 0x%08x\n", hr);
3758 ok(count == 6, "got %u\n", count);
3760 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
3761 ok(metrics[1].length == 2, "got %u\n", metrics[1].length);
3762 ok(metrics[2].length == 2, "got %u\n", metrics[2].length);
3763 ok(metrics[3].length == 1, "got %u\n", metrics[3].length);
3764 ok(metrics[4].length == 3, "got %u\n", metrics[4].length);
3765 ok(metrics[5].length == 0, "got %u\n", metrics[5].length);
3767 ok(metrics[0].newlineLength == 1, "got %u\n", metrics[0].newlineLength);
3768 ok(metrics[1].newlineLength == 1, "got %u\n", metrics[1].newlineLength);
3769 ok(metrics[2].newlineLength == 1, "got %u\n", metrics[2].newlineLength);
3770 ok(metrics[3].newlineLength == 1, "got %u\n", metrics[3].newlineLength);
3771 ok(metrics[4].newlineLength == 2, "got %u\n", metrics[4].newlineLength);
3772 ok(metrics[5].newlineLength == 0, "got %u\n", metrics[5].newlineLength);
3774 ok(metrics[0].trailingWhitespaceLength == 1, "got %u\n", metrics[0].newlineLength);
3775 ok(metrics[1].trailingWhitespaceLength == 1, "got %u\n", metrics[1].newlineLength);
3776 ok(metrics[2].trailingWhitespaceLength == 1, "got %u\n", metrics[2].newlineLength);
3777 ok(metrics[3].trailingWhitespaceLength == 1, "got %u\n", metrics[3].newlineLength);
3778 ok(metrics[4].trailingWhitespaceLength == 2, "got %u\n", metrics[4].newlineLength);
3779 ok(metrics[5].trailingWhitespaceLength == 0, "got %u\n", metrics[5].newlineLength);
3781 IDWriteTextLayout_Release(layout);
3783 /* empty text layout */
3784 hr = IDWriteFactory_CreateTextLayout(factory, strW, 0, format, 100.0f, 300.0f, &layout);
3785 ok(hr == S_OK, "got 0x%08x\n", hr);
3787 count = 0;
3788 memset(metrics, 0, sizeof(metrics));
3789 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, 1, &count);
3790 ok(hr == S_OK, "got 0x%08x\n", hr);
3791 ok(count == 1, "got %u\n", count);
3792 ok(metrics[0].length == 0, "got %u\n", metrics[0].length);
3793 ok(metrics[0].trailingWhitespaceLength == 0, "got %u\n", metrics[0].trailingWhitespaceLength);
3794 ok(metrics[0].newlineLength == 0, "got %u\n", metrics[0].newlineLength);
3795 ok(metrics[0].height > 0.0f, "got %f\n", metrics[0].height);
3796 ok(metrics[0].baseline > 0.0f, "got %f\n", metrics[0].baseline);
3797 ok(!metrics[0].isTrimmed, "got %d\n", metrics[0].isTrimmed);
3799 /* change font size at first position, see if metrics changed */
3800 range.startPosition = 0;
3801 range.length = 1;
3802 hr = IDWriteTextLayout_SetFontSize(layout, 80.0f, range);
3803 ok(hr == S_OK, "got 0x%08x\n", hr);
3805 count = 0;
3806 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count);
3807 ok(hr == S_OK, "got 0x%08x\n", hr);
3808 ok(count == 1, "got %u\n", count);
3809 ok(metrics[1].height > metrics[0].height, "got %f\n", metrics[1].height);
3810 ok(metrics[1].baseline > metrics[0].baseline, "got %f\n", metrics[1].baseline);
3812 /* revert font size back to format value, set different size for position 1 */
3813 hr = IDWriteTextLayout_SetFontSize(layout, 12.0f, range);
3814 ok(hr == S_OK, "got 0x%08x\n", hr);
3816 range.startPosition = 1;
3817 range.length = 1;
3818 hr = IDWriteTextLayout_SetFontSize(layout, 80.0f, range);
3819 ok(hr == S_OK, "got 0x%08x\n", hr);
3821 memset(metrics + 1, 0, sizeof(*metrics));
3822 count = 0;
3823 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count);
3824 ok(hr == S_OK, "got 0x%08x\n", hr);
3825 ok(count == 1, "got %u\n", count);
3826 ok(metrics[1].height == metrics[0].height, "got %f\n", metrics[1].height);
3827 ok(metrics[1].baseline == metrics[0].baseline, "got %f\n", metrics[1].baseline);
3829 IDWriteTextLayout_Release(layout);
3831 /* text is "a\r" */
3832 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 2, format, 100.0f, 300.0f, &layout);
3833 ok(hr == S_OK, "got 0x%08x\n", hr);
3835 count = 0;
3836 memset(metrics, 0, sizeof(metrics));
3837 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, ARRAY_SIZE(metrics), &count);
3838 ok(hr == S_OK, "got 0x%08x\n", hr);
3839 ok(count == 2, "got %u\n", count);
3840 ok(metrics[0].length == 2, "got %u\n", metrics[0].length);
3841 ok(metrics[0].newlineLength == 1, "got %u\n", metrics[0].newlineLength);
3842 ok(metrics[0].height > 0.0f, "got %f\n", metrics[0].height);
3843 ok(metrics[0].baseline > 0.0f, "got %f\n", metrics[0].baseline);
3844 ok(metrics[1].length == 0, "got %u\n", metrics[1].length);
3845 ok(metrics[1].newlineLength == 0, "got %u\n", metrics[1].newlineLength);
3846 ok(metrics[1].height > 0.0f, "got %f\n", metrics[1].height);
3847 ok(metrics[1].baseline > 0.0f, "got %f\n", metrics[1].baseline);
3849 range.startPosition = 1;
3850 range.length = 1;
3851 hr = IDWriteTextLayout_SetFontSize(layout, 80.0f, range);
3852 ok(hr == S_OK, "got 0x%08x\n", hr);
3854 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 2, 2, &count);
3855 ok(hr == S_OK, "got 0x%08x\n", hr);
3856 ok(count == 2, "got %u\n", count);
3857 ok(metrics[3].height > metrics[1].height, "got %f, old %f\n", metrics[3].height, metrics[1].height);
3858 ok(metrics[3].baseline > metrics[1].baseline, "got %f, old %f\n", metrics[3].baseline, metrics[1].baseline);
3860 /* revert to original format */
3861 hr = IDWriteTextLayout_SetFontSize(layout, 12.0f, range);
3862 ok(hr == S_OK, "got 0x%08x\n", hr);
3863 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 2, 2, &count);
3864 ok(hr == S_OK, "got 0x%08x\n", hr);
3865 ok(count == 2, "got %u\n", count);
3866 ok(metrics[3].height == metrics[1].height, "got %f, old %f\n", metrics[3].height, metrics[1].height);
3867 ok(metrics[3].baseline == metrics[1].baseline, "got %f, old %f\n", metrics[3].baseline, metrics[1].baseline);
3869 /* Switch to uniform spacing */
3870 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_UNIFORM, 456.0f, 123.0f);
3871 ok(hr == S_OK, "got 0x%08x\n", hr);
3873 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, ARRAY_SIZE(metrics), &count);
3874 ok(hr == S_OK, "got 0x%08x\n", hr);
3875 ok(count == 2, "got %u\n", count);
3877 for (i = 0; i < count; i++) {
3878 ok(metrics[i].height == 456.0f, "%u: got line height %f\n", i, metrics[i].height);
3879 ok(metrics[i].baseline == 123.0f, "%u: got line baseline %f\n", i, metrics[i].baseline);
3882 IDWriteTextLayout_Release(layout);
3884 /* Switch to proportional */
3885 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_PROPORTIONAL, 2.0f, 4.0f);
3886 if (hr == S_OK) {
3887 hr = IDWriteFactory_CreateTextLayout(factory, str4W, 1, format, 100.0f, 300.0f, &layout);
3888 ok(hr == S_OK, "Failed to create layout, hr %#x.\n", hr);
3890 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics, ARRAY_SIZE(metrics), &count);
3891 ok(hr == S_OK, "Failed to get line metrics, hr %#x.\n", hr);
3892 ok(count == 1, "Unexpected line count %u\n", count);
3894 /* Back to default mode. */
3895 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0f, 0.0f);
3896 ok(hr == S_OK, "Failed to set spacing method, hr %#x.\n", hr);
3898 hr = IDWriteTextLayout_GetLineMetrics(layout, metrics + 1, 1, &count);
3899 ok(hr == S_OK, "Failed to get line metrics, hr %#x.\n", hr);
3900 ok(count == 1, "Unexpected line count %u\n", count);
3902 /* Proportional spacing applies multipliers to default, content based spacing. */
3903 ok(metrics[0].height == 2.0f * metrics[1].height, "Unexpected line height %f.\n", metrics[0].height);
3904 ok(metrics[0].baseline == 4.0f * metrics[1].baseline, "Unexpected line baseline %f.\n", metrics[0].baseline);
3906 IDWriteTextLayout_Release(layout);
3908 else
3909 win_skip("Proportional spacing is not supported.\n");
3911 IDWriteTextFormat_Release(format);
3912 IDWriteFontFace_Release(fontface);
3913 IDWriteFactory_Release(factory);
3916 static void test_SetTextAlignment(void)
3918 static const WCHAR stringsW[][10] = {
3919 {'a',0},
3923 DWRITE_CLUSTER_METRICS clusters[10];
3924 DWRITE_TEXT_METRICS metrics;
3925 IDWriteTextFormat1 *format1;
3926 IDWriteTextFormat *format;
3927 IDWriteTextLayout *layout;
3928 IDWriteFactory *factory;
3929 DWRITE_TEXT_ALIGNMENT v;
3930 UINT32 count, i;
3931 HRESULT hr;
3933 factory = create_factory();
3935 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
3936 DWRITE_FONT_STRETCH_NORMAL, 12.0f, L"en-us", &format);
3937 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
3939 v = IDWriteTextFormat_GetTextAlignment(format);
3940 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3942 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 500.0f, 100.0f, &layout);
3943 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
3945 v = IDWriteTextLayout_GetTextAlignment(layout);
3946 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3948 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
3949 ok(hr == S_OK, "got 0x%08x\n", hr);
3951 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
3952 ok(hr == S_OK, "got 0x%08x\n", hr);
3954 v = IDWriteTextFormat_GetTextAlignment(format);
3955 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3957 v = IDWriteTextLayout_GetTextAlignment(layout);
3958 ok(v == DWRITE_TEXT_ALIGNMENT_TRAILING, "got %d\n", v);
3960 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
3961 if (hr == S_OK) {
3962 hr = IDWriteTextFormat1_SetTextAlignment(format1, DWRITE_TEXT_ALIGNMENT_CENTER);
3963 ok(hr == S_OK, "got 0x%08x\n", hr);
3965 v = IDWriteTextFormat_GetTextAlignment(format);
3966 ok(v == DWRITE_TEXT_ALIGNMENT_LEADING, "got %d\n", v);
3968 v = IDWriteTextLayout_GetTextAlignment(layout);
3969 ok(v == DWRITE_TEXT_ALIGNMENT_CENTER, "got %d\n", v);
3971 v = IDWriteTextFormat1_GetTextAlignment(format1);
3972 ok(v == DWRITE_TEXT_ALIGNMENT_CENTER, "got %d\n", v);
3974 IDWriteTextFormat1_Release(format1);
3976 else
3977 win_skip("IDWriteTextFormat1 is not supported\n");
3979 IDWriteTextLayout_Release(layout);
3981 for (i = 0; i < ARRAY_SIZE(stringsW); i++) {
3982 FLOAT text_width;
3984 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_LEADING);
3985 ok(hr == S_OK, "got 0x%08x\n", hr);
3987 hr = IDWriteFactory_CreateTextLayout(factory, stringsW[i], lstrlenW(stringsW[i]), format, 500.0f, 100.0f, &layout);
3988 ok(hr == S_OK, "got 0x%08x\n", hr);
3990 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
3991 ok(hr == S_OK, "got 0x%08x\n", hr);
3993 count = 0;
3994 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, ARRAY_SIZE(clusters), &count);
3995 ok(hr == S_OK, "got 0x%08x\n", hr);
3996 if (stringsW[i][0])
3997 ok(count > 0, "got %u\n", count);
3998 else
3999 ok(count == 0, "got %u\n", count);
4001 text_width = 0.0f;
4002 while (count)
4003 text_width += clusters[--count].width;
4005 /* maxwidth is 500, leading alignment */
4006 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_LEADING);
4007 ok(hr == S_OK, "got 0x%08x\n", hr);
4009 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4010 ok(hr == S_OK, "got 0x%08x\n", hr);
4012 ok(metrics.left == 0.0f, "got %.2f\n", metrics.left);
4013 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
4014 ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth);
4015 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4017 /* maxwidth is 500, trailing alignment */
4018 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
4019 ok(hr == S_OK, "got 0x%08x\n", hr);
4021 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4022 ok(hr == S_OK, "got 0x%08x\n", hr);
4024 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
4025 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
4026 ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth);
4027 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4028 IDWriteTextLayout_Release(layout);
4030 /* initially created with trailing alignment */
4031 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_TRAILING);
4032 ok(hr == S_OK, "got 0x%08x\n", hr);
4034 hr = IDWriteFactory_CreateTextLayout(factory, stringsW[i], lstrlenW(stringsW[i]), format, 500.0f, 100.0f, &layout);
4035 ok(hr == S_OK, "got 0x%08x\n", hr);
4037 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4038 ok(hr == S_OK, "got 0x%08x\n", hr);
4040 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
4041 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
4042 ok(metrics.layoutWidth == 500.0f, "got %.2f\n", metrics.layoutWidth);
4043 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4044 IDWriteTextLayout_Release(layout);
4046 if (stringsW[i][0]) {
4047 /* max width less than total run width, trailing alignment */
4048 hr = IDWriteTextFormat_SetWordWrapping(format, DWRITE_WORD_WRAPPING_NO_WRAP);
4049 ok(hr == S_OK, "got 0x%08x\n", hr);
4051 hr = IDWriteFactory_CreateTextLayout(factory, stringsW[i], lstrlenW(stringsW[i]), format, clusters[0].width, 100.0f, &layout);
4052 ok(hr == S_OK, "got 0x%08x\n", hr);
4053 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4054 ok(hr == S_OK, "got 0x%08x\n", hr);
4055 ok(metrics.left == metrics.layoutWidth - metrics.width, "got %.2f\n", metrics.left);
4056 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
4057 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4058 IDWriteTextLayout_Release(layout);
4061 /* maxwidth is 500, centered */
4062 hr = IDWriteTextFormat_SetTextAlignment(format, DWRITE_TEXT_ALIGNMENT_CENTER);
4063 ok(hr == S_OK, "got 0x%08x\n", hr);
4065 hr = IDWriteFactory_CreateTextLayout(factory, stringsW[i], lstrlenW(stringsW[i]), format, 500.0f, 100.0f, &layout);
4066 ok(hr == S_OK, "got 0x%08x\n", hr);
4068 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4069 ok(hr == S_OK, "got 0x%08x\n", hr);
4070 ok(metrics.left == (metrics.layoutWidth - metrics.width) / 2.0f, "got %.2f\n", metrics.left);
4071 ok(metrics.width == text_width, "got %.2f\n", metrics.width);
4072 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4074 IDWriteTextLayout_Release(layout);
4077 IDWriteTextFormat_Release(format);
4078 IDWriteFactory_Release(factory);
4081 static void test_SetParagraphAlignment(void)
4083 DWRITE_TEXT_METRICS metrics;
4084 IDWriteTextFormat *format;
4085 IDWriteTextLayout *layout;
4086 IDWriteFactory *factory;
4087 DWRITE_PARAGRAPH_ALIGNMENT v;
4088 DWRITE_LINE_METRICS lines[1];
4089 UINT32 count;
4090 HRESULT hr;
4092 factory = create_factory();
4094 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4095 DWRITE_FONT_STRETCH_NORMAL, 12.0f, L"en-us", &format);
4096 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
4098 v = IDWriteTextFormat_GetParagraphAlignment(format);
4099 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
4101 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 500.0f, 100.0f, &layout);
4102 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
4104 v = IDWriteTextLayout_GetParagraphAlignment(layout);
4105 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
4107 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
4108 ok(hr == S_OK, "got 0x%08x\n", hr);
4110 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
4111 ok(hr == S_OK, "got 0x%08x\n", hr);
4113 v = IDWriteTextFormat_GetParagraphAlignment(format);
4114 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_NEAR, "got %d\n", v);
4116 v = IDWriteTextLayout_GetParagraphAlignment(layout);
4117 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_FAR, "got %d\n", v);
4119 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
4120 ok(hr == S_OK, "got 0x%08x\n", hr);
4122 v = IDWriteTextLayout_GetParagraphAlignment(layout);
4123 ok(v == DWRITE_PARAGRAPH_ALIGNMENT_CENTER, "got %d\n", v);
4125 count = 0;
4126 hr = IDWriteTextLayout_GetLineMetrics(layout, lines, 1, &count);
4127 ok(hr == S_OK, "got 0x%08x\n", hr);
4128 ok(count == 1, "got %u\n", count);
4130 /* maxheight is 100, near alignment */
4131 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_NEAR);
4132 ok(hr == S_OK, "got 0x%08x\n", hr);
4134 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4135 ok(hr == S_OK, "got 0x%08x\n", hr);
4137 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
4138 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4139 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
4140 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4142 /* maxwidth is 100, far alignment */
4143 hr = IDWriteTextLayout_SetParagraphAlignment(layout, DWRITE_PARAGRAPH_ALIGNMENT_FAR);
4144 ok(hr == S_OK, "got 0x%08x\n", hr);
4146 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4147 ok(hr == S_OK, "got 0x%08x\n", hr);
4149 ok(metrics.top == metrics.layoutHeight - metrics.height, "got %.2f\n", metrics.top);
4150 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4151 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
4152 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4153 IDWriteTextLayout_Release(layout);
4155 /* initially created with centered alignment */
4156 hr = IDWriteTextFormat_SetParagraphAlignment(format, DWRITE_PARAGRAPH_ALIGNMENT_CENTER);
4157 ok(hr == S_OK, "got 0x%08x\n", hr);
4159 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 500.0f, 100.0f, &layout);
4160 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
4162 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4163 ok(hr == S_OK, "got 0x%08x\n", hr);
4165 ok(metrics.top == (metrics.layoutHeight - lines[0].height) / 2, "got %.2f\n", metrics.top);
4166 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4167 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4168 IDWriteTextLayout_Release(layout);
4170 IDWriteTextFormat_Release(format);
4171 IDWriteFactory_Release(factory);
4174 static void test_SetReadingDirection(void)
4176 DWRITE_CLUSTER_METRICS clusters[1];
4177 DWRITE_TEXT_METRICS metrics;
4178 IDWriteTextFormat *format;
4179 IDWriteTextLayout *layout;
4180 IDWriteFactory *factory;
4181 DWRITE_READING_DIRECTION v;
4182 DWRITE_LINE_METRICS lines[1];
4183 UINT32 count;
4184 HRESULT hr;
4186 factory = create_factory();
4188 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4189 DWRITE_FONT_STRETCH_NORMAL, 12.0f, L"en-us", &format);
4190 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
4192 v = IDWriteTextFormat_GetReadingDirection(format);
4193 ok(v == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", v);
4195 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 500.0f, 100.0f, &layout);
4196 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
4198 v = IDWriteTextLayout_GetReadingDirection(layout);
4199 ok(v == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", v);
4201 v = IDWriteTextFormat_GetReadingDirection(format);
4202 ok(v == DWRITE_READING_DIRECTION_LEFT_TO_RIGHT, "got %d\n", v);
4204 hr = IDWriteTextLayout_SetReadingDirection(layout, DWRITE_READING_DIRECTION_RIGHT_TO_LEFT);
4205 ok(hr == S_OK, "got 0x%08x\n", hr);
4207 count = 0;
4208 hr = IDWriteTextLayout_GetLineMetrics(layout, lines, 1, &count);
4209 ok(hr == S_OK, "got 0x%08x\n", hr);
4210 ok(count == 1, "got %u\n", count);
4212 count = 0;
4213 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 1, &count);
4214 ok(hr == S_OK, "got 0x%08x\n", hr);
4215 ok(count == 1, "got %u\n", count);
4217 /* leading alignment, RTL */
4218 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4219 ok(hr == S_OK, "got 0x%08x\n", hr);
4221 ok(metrics.left == metrics.layoutWidth - clusters[0].width, "got %.2f\n", metrics.left);
4222 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
4223 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
4224 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4225 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
4226 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
4227 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4229 /* trailing alignment, RTL */
4230 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_TRAILING);
4231 ok(hr == S_OK, "got 0x%08x\n", hr);
4233 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4234 ok(hr == S_OK, "got 0x%08x\n", hr);
4236 ok(metrics.left == 0.0, "got %.2f\n", metrics.left);
4237 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
4238 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
4239 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4240 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
4241 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
4242 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4244 /* centered alignment, RTL */
4245 hr = IDWriteTextLayout_SetTextAlignment(layout, DWRITE_TEXT_ALIGNMENT_CENTER);
4246 ok(hr == S_OK, "got 0x%08x\n", hr);
4248 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4249 ok(hr == S_OK, "got 0x%08x\n", hr);
4251 ok(metrics.left == (metrics.layoutWidth - clusters[0].width) / 2.0, "got %.2f\n", metrics.left);
4252 ok(metrics.top == 0.0, "got %.2f\n", metrics.top);
4253 ok(metrics.width == clusters[0].width, "got %.2f\n", metrics.width);
4254 ok(metrics.height == lines[0].height, "got %.2f\n", metrics.height);
4255 ok(metrics.layoutWidth == 500.0, "got %.2f\n", metrics.layoutWidth);
4256 ok(metrics.layoutHeight == 100.0, "got %.2f\n", metrics.layoutHeight);
4257 ok(metrics.lineCount == 1, "got %d\n", metrics.lineCount);
4259 IDWriteTextLayout_Release(layout);
4261 IDWriteTextFormat_Release(format);
4262 IDWriteFactory_Release(factory);
4265 static inline FLOAT get_scaled_font_metric(UINT32 metric, FLOAT emSize, const DWRITE_FONT_METRICS *metrics)
4267 return (FLOAT)metric * emSize / (FLOAT)metrics->designUnitsPerEm;
4270 static FLOAT snap_coord(const DWRITE_MATRIX *m, FLOAT ppdip, FLOAT coord)
4272 FLOAT vec[2], det, vec2[2];
4273 BOOL transform;
4275 /* has to be a diagonal matrix */
4276 if ((ppdip <= 0.0) ||
4277 (m->m11 * m->m22 != 0.0 && (m->m12 != 0.0 || m->m21 != 0.0)) ||
4278 (m->m12 * m->m21 != 0.0 && (m->m11 != 0.0 || m->m22 != 0.0)))
4279 return coord;
4281 det = m->m11 * m->m22 - m->m12 * m->m21;
4282 transform = fabsf(det) > 1e-10;
4284 if (transform) {
4285 /* apply transform */
4286 vec[0] = 0.0;
4287 vec[1] = coord * ppdip;
4289 vec2[0] = m->m11 * vec[0] + m->m21 * vec[1] + m->dx;
4290 vec2[1] = m->m12 * vec[0] + m->m22 * vec[1] + m->dy;
4292 /* snap */
4293 vec2[0] = floorf(vec2[0] + 0.5f);
4294 vec2[1] = floorf(vec2[1] + 0.5f);
4296 /* apply inverted transform */
4297 vec[1] = (-m->m12 * vec2[0] + m->m11 * vec2[1] - (m->m11 * m->dy - m->m12 * m->dx)) / det;
4298 vec[1] /= ppdip;
4300 else
4301 vec[1] = floorf(coord * ppdip + 0.5f) / ppdip;
4302 return vec[1];
4305 static inline BOOL float_eq(FLOAT left, FLOAT right)
4307 int x = *(int *)&left;
4308 int y = *(int *)&right;
4310 if (x < 0)
4311 x = INT_MIN - x;
4312 if (y < 0)
4313 y = INT_MIN - y;
4315 return abs(x - y) <= 16;
4318 struct snapping_test {
4319 DWRITE_MATRIX m;
4320 FLOAT ppdip;
4323 static struct snapping_test snapping_tests[] = {
4324 { { 0.0, 1.0, 2.0, 0.0, 0.2, 0.3 }, 1.0 },
4325 { { 0.0, 1.0, 2.0, 0.0, 0.0, 0.0 }, 1.0 },
4326 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 1.0 }, /* identity transform */
4327 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 0.9 },
4328 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, -1.0 },
4329 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 0.0 },
4330 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.3 }, 1.0 }, /* simple Y shift */
4331 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 10.0 }, /* identity, 10 ppdip */
4332 { { 1.0, 0.0, 0.0, 10.0, 0.0, 0.0 }, 10.0 },
4333 { { 0.0, 1.0, 1.0, 0.0, 0.2, 0.6 }, 1.0 },
4334 { { 0.0, 2.0, 2.0, 0.0, 0.2, 0.6 }, 1.0 },
4335 { { 0.0, 0.5, -0.5, 0.0, 0.2, 0.6 }, 1.0 },
4336 { { 1.0, 2.0, 0.0, 1.0, 0.2, 0.6 }, 1.0 },
4337 { { 1.0, 1.0, 0.0, 1.0, 0.2, 0.6 }, 1.0 },
4338 { { 0.5, 0.5, -0.5, 0.5, 0.2, 0.6 }, 1.0 }, /* 45 degrees rotation */
4339 { { 0.5, 0.5, -0.5, 0.5, 0.0, 0.0 }, 100.0 }, /* 45 degrees rotation */
4340 { { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 }, 100.0 },
4341 { { 0.0, 1.0, -1.0, 0.0, 0.2, 0.6 }, 1.0 }, /* 90 degrees rotation */
4342 { { -1.0, 0.0, 0.0, -1.0, 0.2, 0.6 }, 1.0 }, /* 180 degrees rotation */
4343 { { 0.0, -1.0, 1.0, 0.0, 0.2, 0.6 }, 1.0 }, /* 270 degrees rotation */
4344 { { 1.0, 0.0, 0.0, 1.0,-0.1, 0.2 }, 1.0 },
4345 { { 0.0, 1.0, -1.0, 0.0,-0.2,-0.3 }, 1.0 }, /* 90 degrees rotation */
4346 { { -1.0, 0.0, 0.0, -1.0,-0.3,-1.6 }, 1.0 }, /* 180 degrees rotation */
4347 { { 0.0, -1.0, 1.0, 0.0,-0.7, 0.6 }, 10.0 }, /* 270 degrees rotation */
4348 { { 0.0, 2.0, 1.0, 0.0, 0.2, 0.6 }, 1.0 },
4349 { { 0.0, 0.0, 1.0, 0.0, 0.0, 0.0 }, 1.0 },
4350 { { 3.0, 0.0, 0.0, 5.0, 0.2,-0.3 }, 10.0 },
4351 { { 0.0, -3.0, 5.0, 0.0,-0.1, 0.7 }, 10.0 },
4354 static DWRITE_MATRIX compattransforms[] = {
4355 { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 },
4356 { 1.0, 0.0, 0.0, 1.0, 0.2, 0.3 },
4357 { 2.0, 0.0, 0.0, 2.0, 0.2, 0.3 },
4358 { 2.0, 1.0, 2.0, 2.0, 0.2, 0.3 },
4361 static void test_pixelsnapping(void)
4363 IDWriteTextLayout *layout, *layout2;
4364 struct renderer_context ctxt;
4365 DWRITE_FONT_METRICS metrics;
4366 IDWriteTextFormat *format;
4367 IDWriteFontFace *fontface;
4368 IDWriteFactory *factory;
4369 FLOAT baseline, originX;
4370 HRESULT hr;
4371 int i, j;
4373 factory = create_factory();
4375 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4376 DWRITE_FONT_STRETCH_NORMAL, 12.0f, L"en-us", &format);
4377 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
4379 fontface = get_fontface_from_format(format);
4380 IDWriteFontFace_GetMetrics(fontface, &metrics);
4382 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 500.0f, 100.0f, &layout);
4383 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
4385 /* disabled snapping */
4386 ctxt.snapping_disabled = TRUE;
4387 ctxt.gdicompat = FALSE;
4388 ctxt.use_gdi_natural = FALSE;
4389 ctxt.ppdip = 1.0f;
4390 memset(&ctxt.m, 0, sizeof(ctxt.m));
4391 ctxt.m.m11 = ctxt.m.m22 = 1.0;
4392 originX = 0.1;
4394 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, originX, 0.0);
4395 ok(hr == S_OK, "got 0x%08x\n", hr);
4397 baseline = get_scaled_font_metric(metrics.ascent, 12.0, &metrics);
4398 ok(ctxt.originX == originX, "got %f, originX %f\n", ctxt.originX, originX);
4399 ok(ctxt.originY == baseline, "got %f, baseline %f\n", ctxt.originY, baseline);
4400 ok(floor(baseline) != baseline, "got %f\n", baseline);
4402 ctxt.snapping_disabled = FALSE;
4404 for (i = 0; i < ARRAY_SIZE(snapping_tests); i++) {
4405 struct snapping_test *ptr = &snapping_tests[i];
4406 FLOAT expectedY;
4408 ctxt.m = ptr->m;
4409 ctxt.ppdip = ptr->ppdip;
4410 ctxt.originX = 678.9;
4411 ctxt.originY = 678.9;
4413 expectedY = snap_coord(&ctxt.m, ctxt.ppdip, baseline);
4414 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, originX, 0.0);
4415 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
4416 ok(ctxt.originX == originX, "%d: got %f, originX %f\n", i, ctxt.originX, originX);
4417 ok(float_eq(ctxt.originY, expectedY), "%d: got %f, expected %f, baseline %f\n",
4418 i, ctxt.originY, expectedY, baseline);
4420 /* gdicompat layout transform doesn't affect snapping */
4421 for (j = 0; j < ARRAY_SIZE(compattransforms); ++j)
4423 hr = IDWriteFactory_CreateGdiCompatibleTextLayout(factory, L"a", 1, format, 500.0f, 100.0f,
4424 1.0f, &compattransforms[j], FALSE, &layout2);
4425 ok(hr == S_OK, "%d: failed to create text layout, hr %#x.\n", i, hr);
4427 expectedY = snap_coord(&ctxt.m, ctxt.ppdip, baseline);
4428 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, originX, 0.0);
4429 ok(hr == S_OK, "%d: got 0x%08x\n", i, hr);
4430 ok(ctxt.originX == originX, "%d: got %f, originX %f\n", i, ctxt.originX, originX);
4431 ok(float_eq(ctxt.originY, expectedY), "%d: got %f, expected %f, baseline %f\n",
4432 i, ctxt.originY, expectedY, baseline);
4434 IDWriteTextLayout_Release(layout2);
4438 IDWriteTextLayout_Release(layout);
4439 IDWriteTextFormat_Release(format);
4440 IDWriteFontFace_Release(fontface);
4441 IDWriteFactory_Release(factory);
4444 static void test_SetWordWrapping(void)
4446 static const WCHAR strW[] = {'a',' ','s','o','m','e',' ','t','e','x','t',' ','a','n','d',
4447 ' ','a',' ','b','i','t',' ','m','o','r','e','\n','b'};
4448 IDWriteTextFormat *format;
4449 IDWriteTextLayout *layout;
4450 IDWriteFactory *factory;
4451 DWRITE_WORD_WRAPPING v;
4452 UINT32 count;
4453 HRESULT hr;
4455 factory = create_factory();
4457 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4458 DWRITE_FONT_STRETCH_NORMAL, 12.0f, L"en-us", &format);
4459 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
4461 v = IDWriteTextFormat_GetWordWrapping(format);
4462 ok(v == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", v);
4464 hr = IDWriteFactory_CreateTextLayout(factory, strW, ARRAY_SIZE(strW), format, 10.0f, 100.0f, &layout);
4465 ok(hr == S_OK, "got 0x%08x\n", hr);
4467 v = IDWriteTextLayout_GetWordWrapping(layout);
4468 ok(v == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", v);
4470 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4471 ok(hr == S_OK, "got 0x%08x\n", hr);
4473 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4474 ok(hr == S_OK, "got 0x%08x\n", hr);
4476 v = IDWriteTextFormat_GetWordWrapping(format);
4477 ok(v == DWRITE_WORD_WRAPPING_WRAP, "got %d\n", v);
4479 /* disable wrapping, text has explicit newline */
4480 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_NO_WRAP);
4481 ok(hr == S_OK, "got 0x%08x\n", hr);
4483 count = 0;
4484 hr = IDWriteTextLayout_GetLineMetrics(layout, NULL, 0, &count);
4485 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
4486 ok(count == 2, "got %u\n", count);
4488 hr = IDWriteTextLayout_SetWordWrapping(layout, DWRITE_WORD_WRAPPING_WRAP);
4489 ok(hr == S_OK, "got 0x%08x\n", hr);
4491 count = 0;
4492 hr = IDWriteTextLayout_GetLineMetrics(layout, NULL, 0, &count);
4493 ok(hr == E_NOT_SUFFICIENT_BUFFER, "got 0x%08x\n", hr);
4494 ok(count > 2, "got %u\n", count);
4496 IDWriteTextLayout_Release(layout);
4497 IDWriteTextFormat_Release(format);
4498 IDWriteFactory_Release(factory);
4501 /* Collection dedicated to fallback testing */
4503 static const WCHAR g_blahfontW[] = {'B','l','a','h',0};
4504 static HRESULT WINAPI fontcollection_QI(IDWriteFontCollection *iface, REFIID riid, void **obj)
4506 if (IsEqualIID(riid, &IID_IDWriteFontCollection) || IsEqualIID(riid, &IID_IUnknown)) {
4507 *obj = iface;
4508 IDWriteFontCollection_AddRef(iface);
4509 return S_OK;
4512 *obj = NULL;
4513 return E_NOINTERFACE;
4516 static ULONG WINAPI fontcollection_AddRef(IDWriteFontCollection *iface)
4518 return 2;
4521 static ULONG WINAPI fontcollection_Release(IDWriteFontCollection *iface)
4523 return 1;
4526 static UINT32 WINAPI fontcollection_GetFontFamilyCount(IDWriteFontCollection *iface)
4528 ok(0, "unexpected call\n");
4529 return 0;
4532 static HRESULT WINAPI fontcollection_GetFontFamily(IDWriteFontCollection *iface, UINT32 index, IDWriteFontFamily **family)
4534 if (index == 123456)
4536 IDWriteFactory *factory = create_factory();
4537 IDWriteFontCollection *syscollection;
4538 BOOL exists;
4539 HRESULT hr;
4541 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
4542 ok(hr == S_OK, "got 0x%08x\n", hr);
4544 hr = IDWriteFontCollection_FindFamilyName(syscollection, L"Tahoma", &index, &exists);
4545 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
4547 hr = IDWriteFontCollection_GetFontFamily(syscollection, index, family);
4548 ok(hr == S_OK, "got 0x%08x\n", hr);
4550 IDWriteFontCollection_Release(syscollection);
4551 IDWriteFactory_Release(factory);
4552 return S_OK;
4555 ok(0, "unexpected call\n");
4556 return E_NOTIMPL;
4559 static HRESULT WINAPI fontcollection_FindFamilyName(IDWriteFontCollection *iface, WCHAR const *name, UINT32 *index, BOOL *exists)
4561 if (!lstrcmpW(name, g_blahfontW)) {
4562 *index = 123456;
4563 *exists = TRUE;
4564 return S_OK;
4566 ok(0, "unexpected call, name %s\n", wine_dbgstr_w(name));
4567 return E_NOTIMPL;
4570 static HRESULT WINAPI fontcollection_GetFontFromFontFace(IDWriteFontCollection *iface, IDWriteFontFace *face, IDWriteFont **font)
4572 ok(0, "unexpected call\n");
4573 return E_NOTIMPL;
4576 static const IDWriteFontCollectionVtbl fallbackcollectionvtbl = {
4577 fontcollection_QI,
4578 fontcollection_AddRef,
4579 fontcollection_Release,
4580 fontcollection_GetFontFamilyCount,
4581 fontcollection_GetFontFamily,
4582 fontcollection_FindFamilyName,
4583 fontcollection_GetFontFromFontFace
4586 static IDWriteFontCollection fallbackcollection = { &fallbackcollectionvtbl };
4588 static void test_MapCharacters(void)
4590 static const WCHAR str2W[] = {'a',0x3058,'b',0};
4591 IDWriteLocalizedStrings *strings;
4592 IDWriteFontFallback *fallback;
4593 IDWriteFactory2 *factory2;
4594 IDWriteFactory *factory;
4595 UINT32 mappedlength;
4596 IDWriteFont *font;
4597 WCHAR buffW[50];
4598 BOOL exists;
4599 FLOAT scale;
4600 HRESULT hr;
4602 factory = create_factory();
4604 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
4605 IDWriteFactory_Release(factory);
4606 if (hr != S_OK) {
4607 win_skip("MapCharacters() is not supported\n");
4608 return;
4611 fallback = NULL;
4612 hr = IDWriteFactory2_GetSystemFontFallback(factory2, &fallback);
4613 ok(hr == S_OK, "got 0x%08x\n", hr);
4614 ok(fallback != NULL, "got %p\n", fallback);
4616 mappedlength = 1;
4617 scale = 0.0f;
4618 font = (void*)0xdeadbeef;
4619 hr = IDWriteFontFallback_MapCharacters(fallback, NULL, 0, 0, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4620 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4621 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4622 ok(mappedlength == 0, "got %u\n", mappedlength);
4623 ok(scale == 1.0f, "got %f\n", scale);
4624 ok(font == NULL, "got %p\n", font);
4626 /* zero length source */
4627 g_source = L"abc";
4628 mappedlength = 1;
4629 scale = 0.0f;
4630 font = (void*)0xdeadbeef;
4631 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 0, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4632 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4633 ok(hr == S_OK, "got 0x%08x\n", hr);
4634 ok(mappedlength == 0, "got %u\n", mappedlength);
4635 ok(scale == 1.0f, "got %f\n", scale);
4636 ok(font == NULL, "got %p\n", font);
4638 g_source = L"abc";
4639 mappedlength = 0;
4640 scale = 0.0f;
4641 font = NULL;
4642 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4643 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4644 todo_wine {
4645 ok(hr == S_OK, "got 0x%08x\n", hr);
4646 ok(mappedlength == 1, "got %u\n", mappedlength);
4648 ok(scale == 1.0f, "got %f\n", scale);
4649 todo_wine
4650 ok(font != NULL, "got %p\n", font);
4651 if (font) {
4652 IDWriteFont_Release(font);
4654 /* same Latin text, full length */
4655 g_source = L"abc";
4656 mappedlength = 0;
4657 scale = 0.0f;
4658 font = NULL;
4659 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4660 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4661 todo_wine {
4662 ok(hr == S_OK, "got 0x%08x\n", hr);
4663 ok(mappedlength == 3, "got %u\n", mappedlength);
4665 ok(scale == 1.0f, "got %f\n", scale);
4666 todo_wine
4667 ok(font != NULL, "got %p\n", font);
4668 if (font) {
4669 IDWriteFont_Release(font);
4671 /* string 'a\x3058b' */
4672 g_source = str2W;
4673 mappedlength = 0;
4674 scale = 0.0f;
4675 font = NULL;
4676 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4677 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4678 todo_wine {
4679 ok(hr == S_OK, "got 0x%08x\n", hr);
4680 ok(mappedlength == 1, "got %u\n", mappedlength);
4682 ok(scale == 1.0f, "got %f\n", scale);
4683 todo_wine
4684 ok(font != NULL, "got %p\n", font);
4685 if (font) {
4686 IDWriteFont_Release(font);
4688 g_source = str2W;
4689 mappedlength = 0;
4690 scale = 0.0f;
4691 font = NULL;
4692 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 1, 2, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4693 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4694 todo_wine {
4695 ok(hr == S_OK, "got 0x%08x\n", hr);
4696 ok(mappedlength == 1, "got %u\n", mappedlength);
4698 ok(scale == 1.0f, "got %f\n", scale);
4699 todo_wine
4700 ok(font != NULL, "got %p\n", font);
4701 if (font) {
4702 IDWriteFont_Release(font);
4704 /* Try with explicit collection, Tahoma will be forced. */
4705 /* 1. Latin part */
4706 g_source = str2W;
4707 mappedlength = 0;
4708 scale = 0.0f;
4709 font = NULL;
4710 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 3, &fallbackcollection, g_blahfontW, DWRITE_FONT_WEIGHT_NORMAL,
4711 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4712 ok(hr == S_OK, "got 0x%08x\n", hr);
4713 ok(mappedlength == 1, "got %u\n", mappedlength);
4714 ok(scale == 1.0f, "got %f\n", scale);
4715 ok(font != NULL, "got %p\n", font);
4717 exists = FALSE;
4718 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
4719 ok(hr == S_OK && exists, "got 0x%08x, exists %d\n", hr, exists);
4720 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW));
4721 ok(hr == S_OK, "got 0x%08x\n", hr);
4722 ok(!lstrcmpW(buffW, L"Tahoma"), "Unexpected string %s.\n", wine_dbgstr_w(buffW));
4723 IDWriteLocalizedStrings_Release(strings);
4724 IDWriteFont_Release(font);
4726 /* 2. Hiragana character, force Tahoma font does not support Japanese */
4727 g_source = str2W;
4728 mappedlength = 0;
4729 scale = 0.0f;
4730 font = NULL;
4731 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 1, 1, &fallbackcollection, g_blahfontW, DWRITE_FONT_WEIGHT_NORMAL,
4732 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4733 ok(hr == S_OK, "got 0x%08x\n", hr);
4734 ok(mappedlength == 1, "got %u\n", mappedlength);
4735 ok(scale == 1.0f, "got %f\n", scale);
4736 ok(font != NULL, "got %p\n", font);
4738 exists = FALSE;
4739 hr = IDWriteFont_GetInformationalStrings(font, DWRITE_INFORMATIONAL_STRING_WIN32_FAMILY_NAMES, &strings, &exists);
4740 ok(hr == S_OK && exists, "got 0x%08x, exists %d\n", hr, exists);
4741 hr = IDWriteLocalizedStrings_GetString(strings, 0, buffW, ARRAY_SIZE(buffW));
4742 ok(hr == S_OK, "got 0x%08x\n", hr);
4743 todo_wine
4744 ok(lstrcmpW(buffW, L"Tahoma"), "Unexpected string %s.\n", wine_dbgstr_w(buffW));
4745 IDWriteLocalizedStrings_Release(strings);
4746 IDWriteFont_Release(font);
4748 IDWriteFontFallback_Release(fallback);
4749 IDWriteFactory2_Release(factory2);
4752 static void test_FontFallbackBuilder(void)
4754 IDWriteFontFallback *fallback, *fallback2;
4755 IDWriteFontFallbackBuilder *builder;
4756 IDWriteFontFallback1 *fallback1;
4757 DWRITE_UNICODE_RANGE range;
4758 IDWriteFactory2 *factory2;
4759 IDWriteFactory *factory;
4760 const WCHAR *familyW;
4761 UINT32 mappedlength;
4762 IDWriteFont *font;
4763 FLOAT scale;
4764 HRESULT hr;
4765 ULONG ref;
4767 factory = create_factory();
4769 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
4770 IDWriteFactory_Release(factory);
4772 if (hr != S_OK) {
4773 win_skip("IDWriteFontFallbackBuilder is not supported\n");
4774 return;
4777 EXPECT_REF(factory2, 1);
4778 hr = IDWriteFactory2_CreateFontFallbackBuilder(factory2, &builder);
4779 EXPECT_REF(factory2, 2);
4781 fallback = NULL;
4782 EXPECT_REF(factory2, 2);
4783 EXPECT_REF(builder, 1);
4784 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4785 ok(hr == S_OK, "got 0x%08x\n", hr);
4786 EXPECT_REF(factory2, 3);
4787 EXPECT_REF(fallback, 1);
4788 EXPECT_REF(builder, 1);
4790 IDWriteFontFallback_AddRef(fallback);
4791 EXPECT_REF(builder, 1);
4792 EXPECT_REF(fallback, 2);
4793 EXPECT_REF(factory2, 3);
4794 IDWriteFontFallback_Release(fallback);
4796 /* New instance is created every time, even if mappings have not changed. */
4797 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback2);
4798 ok(hr == S_OK, "Failed to create fallback object, hr %#x.\n", hr);
4799 ok(fallback != fallback2, "Unexpected fallback instance.\n");
4800 IDWriteFontFallback_Release(fallback2);
4802 hr = IDWriteFontFallbackBuilder_AddMapping(builder, NULL, 0, NULL, 0, NULL, NULL, NULL, 0.0f);
4803 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4805 range.first = 'A';
4806 range.last = 'B';
4807 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 0, NULL, 0, NULL, NULL, NULL, 0.0f);
4808 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4810 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 0, NULL, 0, NULL, NULL, NULL, 1.0f);
4811 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4813 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 0, &familyW, 1, NULL, NULL, NULL, 1.0f);
4814 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4816 hr = IDWriteFontFallbackBuilder_AddMapping(builder, NULL, 0, &familyW, 1, NULL, NULL, NULL, 1.0f);
4817 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4819 /* negative scaling factor */
4820 range.first = range.last = 0;
4821 familyW = g_blahfontW;
4822 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, -1.0f);
4823 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
4825 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 0.0f);
4826 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
4828 /* empty range */
4829 range.first = range.last = 0;
4830 familyW = g_blahfontW;
4831 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 1.0f);
4832 ok(hr == S_OK, "got 0x%08x\n", hr);
4834 range.first = range.last = 0;
4835 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 2.0f);
4836 ok(hr == S_OK, "got 0x%08x\n", hr);
4838 range.first = range.last = 'A';
4839 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 3.0f);
4840 ok(hr == S_OK, "got 0x%08x\n", hr);
4842 range.first = 'B';
4843 range.last = 'A';
4844 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, NULL, NULL, NULL, 4.0f);
4845 ok(hr == S_OK, "got 0x%08x\n", hr);
4847 IDWriteFontFallback_Release(fallback);
4849 if (0) /* crashes on native */
4850 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, NULL);
4852 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4853 ok(hr == S_OK, "got 0x%08x\n", hr);
4855 /* fallback font missing from system collection */
4856 g_source = L"A";
4857 mappedlength = 0;
4858 scale = 0.0f;
4859 font = (void*)0xdeadbeef;
4860 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4861 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4862 todo_wine {
4863 ok(hr == S_OK, "got 0x%08x\n", hr);
4864 ok(mappedlength == 1, "got %u\n", mappedlength);
4865 ok(scale == 1.0f, "got %f\n", scale);
4866 ok(font == NULL, "got %p\n", font);
4868 IDWriteFontFallback_Release(fallback);
4870 /* remap with custom collection */
4871 range.first = range.last = 'A';
4872 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, NULL, NULL, 5.0f);
4873 ok(hr == S_OK, "got 0x%08x\n", hr);
4875 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4876 ok(hr == S_OK, "got 0x%08x\n", hr);
4878 g_source = L"A";
4879 mappedlength = 0;
4880 scale = 0.0f;
4881 font = NULL;
4882 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4883 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4884 todo_wine {
4885 ok(hr == S_OK, "got 0x%08x\n", hr);
4886 ok(mappedlength == 1, "got %u\n", mappedlength);
4887 ok(scale == 5.0f, "got %f\n", scale);
4888 ok(font != NULL, "got %p\n", font);
4890 if (font)
4891 IDWriteFont_Release(font);
4893 IDWriteFontFallback_Release(fallback);
4895 range.first = 'B';
4896 range.last = 'A';
4897 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, NULL, NULL, 6.0f);
4898 ok(hr == S_OK, "got 0x%08x\n", hr);
4900 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4901 ok(hr == S_OK, "got 0x%08x\n", hr);
4903 g_source = L"A";
4904 mappedlength = 0;
4905 scale = 0.0f;
4906 font = NULL;
4907 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4908 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4909 todo_wine {
4910 ok(hr == S_OK, "got 0x%08x\n", hr);
4911 ok(mappedlength == 1, "got %u\n", mappedlength);
4912 ok(scale == 5.0f, "got %f\n", scale);
4913 ok(font != NULL, "got %p\n", font);
4915 if (font)
4916 IDWriteFont_Release(font);
4918 IDWriteFontFallback_Release(fallback);
4920 /* explicit locale */
4921 range.first = 'A';
4922 range.last = 'B';
4923 hr = IDWriteFontFallbackBuilder_AddMapping(builder, &range, 1, &familyW, 1, &fallbackcollection, L"locale", NULL, 6.0f);
4924 ok(hr == S_OK, "Failed to add mapping, hr %#x.\n", hr);
4926 hr = IDWriteFontFallbackBuilder_CreateFontFallback(builder, &fallback);
4927 ok(hr == S_OK, "got 0x%08x\n", hr);
4929 g_source = L"A";
4930 mappedlength = 0;
4931 scale = 0.0f;
4932 font = NULL;
4933 hr = IDWriteFontFallback_MapCharacters(fallback, &analysissource, 0, 1, NULL, NULL, DWRITE_FONT_WEIGHT_NORMAL,
4934 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, &mappedlength, &font, &scale);
4935 todo_wine {
4936 ok(hr == S_OK, "got 0x%08x\n", hr);
4937 ok(mappedlength == 1, "got %u\n", mappedlength);
4938 ok(scale == 5.0f, "got %f\n", scale);
4939 ok(font != NULL, "got %p\n", font);
4941 if (font)
4942 IDWriteFont_Release(font);
4944 if (SUCCEEDED(IDWriteFontFallback_QueryInterface(fallback, &IID_IDWriteFontFallback1, (void **)&fallback1)))
4946 IDWriteFontFallback1_Release(fallback1);
4948 else
4949 win_skip("IDWriteFontFallback1 is not supported.\n");
4951 IDWriteFontFallback_Release(fallback);
4953 IDWriteFontFallbackBuilder_Release(builder);
4954 ref = IDWriteFactory2_Release(factory2);
4955 ok(ref == 0, "Factory is not released, ref %u.\n", ref);
4958 static void test_fallback(void)
4960 IDWriteFontFallback *fallback, *fallback2;
4961 IDWriteFontFallback1 *fallback1;
4962 DWRITE_CLUSTER_METRICS clusters[4];
4963 DWRITE_TEXT_METRICS metrics;
4964 IDWriteTextLayout2 *layout2;
4965 IDWriteTextFormat1 *format1;
4966 IDWriteTextFormat *format;
4967 IDWriteTextLayout *layout;
4968 IDWriteFactory2 *factory2;
4969 IDWriteFactory *factory;
4970 UINT32 count, i;
4971 FLOAT width;
4972 HRESULT hr;
4974 factory = create_factory();
4976 /* Font does not exist in system collection. */
4977 hr = IDWriteFactory_CreateTextFormat(factory, g_blahfontW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
4978 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
4979 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
4981 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
4982 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
4984 count = 0;
4985 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count);
4986 todo_wine {
4987 ok(hr == S_OK, "Failed to get cluster metrics, hr %#x.\n", hr);
4988 ok(count == 4, "Unexpected count %u.\n", count);
4990 for (i = 0, width = 0.0; i < count; i++)
4991 width += clusters[i].width;
4993 memset(&metrics, 0xcc, sizeof(metrics));
4994 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
4995 ok(hr == S_OK, "Failed to get layout metrics, hr %#x.\n", hr);
4996 todo_wine {
4997 ok(metrics.width > 0.0 && metrics.width == width, "Unexpected width %.2f, expected %.2f.\n", metrics.width, width);
4998 ok(metrics.height > 0.0, "Unexpected height %.2f.\n", metrics.height);
4999 ok(metrics.lineCount == 1, "Unexpected line count %u.\n", metrics.lineCount);
5001 IDWriteTextLayout_Release(layout);
5002 IDWriteTextFormat_Release(format);
5004 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5005 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
5006 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5008 /* Existing font. */
5009 hr = IDWriteFactory_CreateTextLayout(factory, L"abcd", 4, format, 1000.0f, 1000.0f, &layout);
5010 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
5011 IDWriteTextFormat_Release(format);
5013 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
5014 IDWriteTextLayout_Release(layout);
5016 if (hr != S_OK) {
5017 win_skip("GetFontFallback() is not supported.\n");
5018 IDWriteFactory_Release(factory);
5019 return;
5022 if (0) /* crashes on native */
5023 hr = IDWriteTextLayout2_GetFontFallback(layout2, NULL);
5025 fallback = (void*)0xdeadbeef;
5026 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback);
5027 ok(hr == S_OK, "got 0x%08x\n", hr);
5028 ok(fallback == NULL, "got %p\n", fallback);
5030 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
5031 ok(hr == S_OK, "got 0x%08x\n", hr);
5033 fallback = (void*)0xdeadbeef;
5034 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback);
5035 ok(hr == S_OK, "got 0x%08x\n", hr);
5036 ok(fallback == NULL, "got %p\n", fallback);
5038 hr = IDWriteFactory_QueryInterface(factory, &IID_IDWriteFactory2, (void**)&factory2);
5039 ok(hr == S_OK, "got 0x%08x\n", hr);
5041 fallback = NULL;
5042 hr = IDWriteFactory2_GetSystemFontFallback(factory2, &fallback);
5043 ok(hr == S_OK, "got 0x%08x\n", hr);
5044 ok(fallback != NULL, "got %p\n", fallback);
5046 hr = IDWriteTextFormat1_SetFontFallback(format1, fallback);
5047 ok(hr == S_OK, "got 0x%08x\n", hr);
5049 fallback2 = (void*)0xdeadbeef;
5050 hr = IDWriteTextLayout2_GetFontFallback(layout2, &fallback2);
5051 ok(hr == S_OK, "got 0x%08x\n", hr);
5052 ok(fallback2 == fallback, "got %p\n", fallback2);
5054 hr = IDWriteTextLayout2_SetFontFallback(layout2, NULL);
5055 ok(hr == S_OK, "got 0x%08x\n", hr);
5057 fallback2 = (void*)0xdeadbeef;
5058 hr = IDWriteTextFormat1_GetFontFallback(format1, &fallback2);
5059 ok(hr == S_OK, "got 0x%08x\n", hr);
5060 ok(fallback2 == NULL, "got %p\n", fallback2);
5062 if (SUCCEEDED(IDWriteFontFallback_QueryInterface(fallback, &IID_IDWriteFontFallback1, (void **)&fallback1)))
5064 IDWriteFontFallback1_Release(fallback1);
5066 else
5067 win_skip("IDWriteFontFallback1 is not supported.\n");
5069 IDWriteFontFallback_Release(fallback);
5070 IDWriteTextFormat1_Release(format1);
5071 IDWriteTextLayout2_Release(layout2);
5072 IDWriteFactory_Release(factory);
5075 static void test_SetTypography(void)
5077 IDWriteTypography *typography, *typography2;
5078 IDWriteTextFormat *format;
5079 IDWriteTextLayout *layout;
5080 DWRITE_TEXT_RANGE range;
5081 IDWriteFactory *factory;
5082 HRESULT hr;
5084 factory = create_factory();
5086 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5087 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
5088 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5090 hr = IDWriteFactory_CreateTextLayout(factory, L"afib", 4, format, 1000.0f, 1000.0f, &layout);
5091 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
5092 IDWriteTextFormat_Release(format);
5094 hr = IDWriteFactory_CreateTypography(factory, &typography);
5095 ok(hr == S_OK, "got 0x%08x\n", hr);
5097 EXPECT_REF(typography, 1);
5098 range.startPosition = 0;
5099 range.length = 2;
5100 hr = IDWriteTextLayout_SetTypography(layout, typography, range);
5101 ok(hr == S_OK, "got 0x%08x\n", hr);
5102 EXPECT_REF(typography, 2);
5104 hr = IDWriteTextLayout_GetTypography(layout, 0, &typography2, NULL);
5105 ok(hr == S_OK, "got 0x%08x\n", hr);
5106 ok(typography2 == typography, "got %p, expected %p\n", typography2, typography);
5107 IDWriteTypography_Release(typography2);
5108 IDWriteTypography_Release(typography);
5110 hr = IDWriteFactory_CreateTypography(factory, &typography2);
5111 ok(hr == S_OK, "got 0x%08x\n", hr);
5113 range.startPosition = 0;
5114 range.length = 1;
5115 hr = IDWriteTextLayout_SetTypography(layout, typography2, range);
5116 ok(hr == S_OK, "got 0x%08x\n", hr);
5117 EXPECT_REF(typography2, 2);
5118 IDWriteTypography_Release(typography2);
5120 hr = IDWriteTextLayout_GetTypography(layout, 0, &typography, &range);
5121 ok(hr == S_OK, "got 0x%08x\n", hr);
5122 ok(range.length == 1, "got %u\n", range.length);
5124 IDWriteTypography_Release(typography);
5126 IDWriteTextLayout_Release(layout);
5127 IDWriteFactory_Release(factory);
5130 static void test_SetLastLineWrapping(void)
5132 IDWriteTextLayout2 *layout2;
5133 IDWriteTextFormat1 *format1;
5134 IDWriteTextLayout *layout;
5135 IDWriteTextFormat *format;
5136 IDWriteFactory *factory;
5137 HRESULT hr;
5138 BOOL ret;
5140 factory = create_factory();
5142 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5143 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
5144 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5146 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
5147 IDWriteTextFormat_Release(format);
5148 if (hr != S_OK) {
5149 win_skip("SetLastLineWrapping() is not supported\n");
5150 IDWriteFactory_Release(factory);
5151 return;
5154 ret = IDWriteTextFormat1_GetLastLineWrapping(format1);
5155 ok(ret, "got %d\n", ret);
5157 hr = IDWriteTextFormat1_SetLastLineWrapping(format1, FALSE);
5158 ok(hr == S_OK, "got 0x%08x\n", hr);
5160 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, (IDWriteTextFormat *)format1, 1000.0f, 1000.0f, &layout);
5161 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
5163 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
5164 ok(hr == S_OK, "got 0x%08x\n", hr);
5165 IDWriteTextLayout_Release(layout);
5167 ret = IDWriteTextLayout2_GetLastLineWrapping(layout2);
5168 ok(!ret, "got %d\n", ret);
5170 hr = IDWriteTextLayout2_SetLastLineWrapping(layout2, TRUE);
5171 ok(hr == S_OK, "got 0x%08x\n", hr);
5173 IDWriteTextLayout2_Release(layout2);
5174 IDWriteTextFormat1_Release(format1);
5175 IDWriteFactory_Release(factory);
5178 static void test_SetOpticalAlignment(void)
5180 DWRITE_OPTICAL_ALIGNMENT alignment;
5181 IDWriteTextLayout2 *layout2;
5182 IDWriteTextFormat1 *format1;
5183 IDWriteTextLayout *layout;
5184 IDWriteTextFormat *format;
5185 IDWriteFactory *factory;
5186 HRESULT hr;
5188 factory = create_factory();
5190 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5191 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
5192 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5194 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat1, (void**)&format1);
5195 IDWriteTextFormat_Release(format);
5196 if (hr != S_OK) {
5197 win_skip("SetOpticalAlignment() is not supported\n");
5198 IDWriteFactory_Release(factory);
5199 return;
5202 alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
5203 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
5205 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, (IDWriteTextFormat *)format1, 1000.0f, 1000.0f, &layout);
5206 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
5208 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout2, (void**)&layout2);
5209 ok(hr == S_OK, "got 0x%08x\n", hr);
5210 IDWriteTextLayout_Release(layout);
5211 IDWriteTextFormat1_Release(format1);
5213 alignment = IDWriteTextLayout2_GetOpticalAlignment(layout2);
5214 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
5216 hr = IDWriteTextLayout2_QueryInterface(layout2, &IID_IDWriteTextFormat1, (void**)&format1);
5217 ok(hr == S_OK, "got 0x%08x\n", hr);
5219 alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
5220 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
5222 hr = IDWriteTextLayout2_SetOpticalAlignment(layout2, DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS);
5223 ok(hr == S_OK, "got 0x%08x\n", hr);
5225 hr = IDWriteTextLayout2_SetOpticalAlignment(layout2, DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS+1);
5226 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5228 alignment = IDWriteTextFormat1_GetOpticalAlignment(format1);
5229 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS, "got %d\n", alignment);
5231 hr = IDWriteTextFormat1_SetOpticalAlignment(format1, DWRITE_OPTICAL_ALIGNMENT_NONE);
5232 ok(hr == S_OK, "got 0x%08x\n", hr);
5234 hr = IDWriteTextFormat1_SetOpticalAlignment(format1, DWRITE_OPTICAL_ALIGNMENT_NO_SIDE_BEARINGS+1);
5235 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5237 alignment = IDWriteTextLayout2_GetOpticalAlignment(layout2);
5238 ok(alignment == DWRITE_OPTICAL_ALIGNMENT_NONE, "got %d\n", alignment);
5240 IDWriteTextLayout2_Release(layout2);
5241 IDWriteTextFormat1_Release(format1);
5242 IDWriteFactory_Release(factory);
5245 static const struct drawcall_entry drawunderline_seq[] = {
5246 { DRAW_GLYPHRUN, {'a','e',0x0300,0}, {'e','n','-','u','s',0}, 2 }, /* reported runs can't mix different underline values */
5247 { DRAW_GLYPHRUN, {'d',0}, {'e','n','-','u','s',0}, 1 },
5248 { DRAW_UNDERLINE, {0}, {'e','n','-','u','s',0} },
5249 { DRAW_LAST_KIND }
5252 static const struct drawcall_entry drawunderline2_seq[] = {
5253 { DRAW_GLYPHRUN, {'a',0}, {'e','n','-','u','s',0}, 1 },
5254 { DRAW_GLYPHRUN, {'e',0}, {'e','n','-','u','s',0}, 1 },
5255 { DRAW_UNDERLINE, {0}, {'e','n','-','u','s',0} },
5256 { DRAW_LAST_KIND }
5259 static const struct drawcall_entry drawunderline3_seq[] = {
5260 { DRAW_GLYPHRUN, {'a',0}, {'e','n','-','c','a',0}, 1 },
5261 { DRAW_GLYPHRUN, {'e',0}, {'e','n','-','u','s',0}, 1 },
5262 { DRAW_UNDERLINE, {0}, {'e','n','-','c','a',0} },
5263 { DRAW_UNDERLINE, {0}, {'e','n','-','u','s',0} },
5264 { DRAW_LAST_KIND }
5267 static const struct drawcall_entry drawunderline4_seq[] = {
5268 { DRAW_GLYPHRUN, {'a',0}, {'e','n','-','u','s',0}, 1 },
5269 { DRAW_GLYPHRUN, {'e',0}, {'e','n','-','u','s',0}, 1 },
5270 { DRAW_UNDERLINE, {0}, {'e','n','-','u','s',0} },
5271 { DRAW_STRIKETHROUGH },
5272 { DRAW_LAST_KIND }
5275 static void test_SetUnderline(void)
5277 static const WCHAR strW[] = {'a','e',0x0300,'d',0}; /* accent grave */
5278 IDWriteFontCollection *syscollection;
5279 DWRITE_CLUSTER_METRICS clusters[4];
5280 IDWriteTextFormat *format;
5281 IDWriteTextLayout *layout;
5282 DWRITE_TEXT_RANGE range;
5283 IDWriteFactory *factory;
5284 UINT32 count, i;
5285 HRESULT hr;
5287 factory = create_factory();
5289 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5290 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
5291 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5293 hr = IDWriteFactory_CreateTextLayout(factory, strW, 4, format, 1000.0, 1000.0, &layout);
5294 ok(hr == S_OK, "got 0x%08x\n", hr);
5296 count = 0;
5297 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, ARRAY_SIZE(clusters), &count);
5298 ok(hr == S_OK, "Failed to get cluster metrics, hr %#x.\n", hr);
5299 ok(count == 3, "Unexpected cluster count %u.\n", count);
5301 range.startPosition = 0;
5302 range.length = 2;
5303 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
5304 ok(hr == S_OK, "got 0x%08x\n", hr);
5306 count = 0;
5307 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, ARRAY_SIZE(clusters), &count);
5308 ok(hr == S_OK, "Failed to get cluster metrics, hr %#x.\n", hr);
5309 ok(count == 3, "Unexpected cluster count %u.\n", count);
5311 flush_sequence(sequences, RENDERER_ID);
5312 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0, 0.0);
5313 ok(hr == S_OK, "got 0x%08x\n", hr);
5314 ok_sequence(sequences, RENDERER_ID, drawunderline_seq, "draw underline test", TRUE);
5316 IDWriteTextLayout_Release(layout);
5318 /* 2 characters, same font, significantly different font size. Set underline for both, see how many
5319 underline drawing calls is there. */
5320 hr = IDWriteFactory_CreateTextLayout(factory, strW, 2, format, 1000.0f, 1000.0f, &layout);
5321 ok(hr == S_OK, "got 0x%08x\n", hr);
5323 range.startPosition = 0;
5324 range.length = 2;
5325 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
5326 ok(hr == S_OK, "got 0x%08x\n", hr);
5328 range.startPosition = 0;
5329 range.length = 1;
5330 hr = IDWriteTextLayout_SetFontSize(layout, 100.0f, range);
5331 ok(hr == S_OK, "got 0x%08x\n", hr);
5333 flush_sequence(sequences, RENDERER_ID);
5334 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0f, 0.0f);
5335 ok(hr == S_OK, "got 0x%08x\n", hr);
5336 ok_sequence(sequences, RENDERER_ID, drawunderline2_seq, "draw underline test 2", FALSE);
5338 /* now set different locale for second char, draw again */
5339 range.startPosition = 0;
5340 range.length = 1;
5341 hr = IDWriteTextLayout_SetLocaleName(layout, L"en-CA", range);
5342 ok(hr == S_OK, "got 0x%08x\n", hr);
5344 flush_sequence(sequences, RENDERER_ID);
5345 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0f, 0.0f);
5346 ok(hr == S_OK, "got 0x%08x\n", hr);
5347 ok_sequence(sequences, RENDERER_ID, drawunderline3_seq, "draw underline test 2", FALSE);
5349 IDWriteTextLayout_Release(layout);
5351 /* 2 characters, same font properties, first with strikethrough, both underlined */
5352 hr = IDWriteFactory_CreateTextLayout(factory, strW, 2, format, 1000.0f, 1000.0f, &layout);
5353 ok(hr == S_OK, "got 0x%08x\n", hr);
5355 range.startPosition = 0;
5356 range.length = 1;
5357 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
5358 ok(hr == S_OK, "got 0x%08x\n", hr);
5360 range.startPosition = 0;
5361 range.length = 2;
5362 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
5363 ok(hr == S_OK, "got 0x%08x\n", hr);
5365 flush_sequence(sequences, RENDERER_ID);
5366 hr = IDWriteTextLayout_Draw(layout, NULL, &testrenderer, 0.0f, 0.0f);
5367 ok(hr == S_OK, "got 0x%08x\n", hr);
5368 ok_sequence(sequences, RENDERER_ID, drawunderline4_seq, "draw underline test 4", FALSE);
5370 IDWriteTextLayout_Release(layout);
5372 IDWriteTextFormat_Release(format);
5374 /* Test runHeight value with all available fonts */
5375 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscollection, FALSE);
5376 ok(hr == S_OK, "got 0x%08x\n", hr);
5377 count = IDWriteFontCollection_GetFontFamilyCount(syscollection);
5379 for (i = 0; i < count; ++i)
5381 DWRITE_FONT_METRICS fontmetrics;
5382 IDWriteLocalizedStrings *names;
5383 struct renderer_context ctxt;
5384 IDWriteFontFamily *family;
5385 IDWriteFontFace *fontface;
5386 WCHAR nameW[256], str[1];
5387 IDWriteFont *font;
5388 UINT32 codepoint;
5389 UINT16 glyph;
5390 BOOL exists;
5392 format = NULL;
5393 layout = NULL;
5395 hr = IDWriteFontCollection_GetFontFamily(syscollection, i, &family);
5396 ok(hr == S_OK, "got 0x%08x\n", hr);
5398 hr = IDWriteFontFamily_GetFirstMatchingFont(family, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STRETCH_NORMAL,
5399 DWRITE_FONT_STYLE_NORMAL, &font);
5400 ok(hr == S_OK, "got 0x%08x\n", hr);
5402 hr = IDWriteFont_CreateFontFace(font, &fontface);
5403 ok(hr == S_OK, "got 0x%08x\n", hr);
5405 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
5406 ok(hr == S_OK, "got 0x%08x\n", hr);
5408 if (!(exists = get_enus_string(names, nameW, ARRAY_SIZE(nameW)))) {
5409 IDWriteLocalFontFileLoader *localloader;
5410 IDWriteFontFileLoader *loader;
5411 IDWriteFontFile *file;
5412 const void *key;
5413 UINT32 keysize;
5414 UINT32 count;
5416 count = 1;
5417 hr = IDWriteFontFace_GetFiles(fontface, &count, &file);
5418 ok(hr == S_OK, "got 0x%08x\n", hr);
5420 hr = IDWriteFontFile_GetLoader(file, &loader);
5421 ok(hr == S_OK, "got 0x%08x\n", hr);
5423 hr = IDWriteFontFileLoader_QueryInterface(loader, &IID_IDWriteLocalFontFileLoader, (void**)&localloader);
5424 ok(hr == S_OK, "got 0x%08x\n", hr);
5425 IDWriteFontFileLoader_Release(loader);
5427 hr = IDWriteFontFile_GetReferenceKey(file, &key, &keysize);
5428 ok(hr == S_OK, "got 0x%08x\n", hr);
5430 hr = IDWriteLocalFontFileLoader_GetFilePathFromKey(localloader, key, keysize, nameW, ARRAY_SIZE(nameW));
5431 ok(hr == S_OK, "got 0x%08x\n", hr);
5433 skip("Failed to get English family name, font file %s\n", wine_dbgstr_w(nameW));
5435 IDWriteLocalFontFileLoader_Release(localloader);
5436 IDWriteFontFile_Release(file);
5439 IDWriteLocalizedStrings_Release(names);
5440 IDWriteFont_Release(font);
5442 if (!exists)
5443 goto cleanup;
5445 IDWriteFontFace_GetMetrics(fontface, &fontmetrics);
5446 hr = IDWriteFactory_CreateTextFormat(factory, nameW, NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5447 DWRITE_FONT_STRETCH_NORMAL, fontmetrics.designUnitsPerEm, L"en-us", &format);
5448 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5450 /* Look for first supported character to avoid triggering fallback path. With fallback it's harder to test
5451 DrawUnderline() metrics, because actual resolved fontface is not passed to it. Grabbing fontface instance
5452 from corresponding DrawGlyphRun() call is not straightforward. */
5453 for (codepoint = ' '; codepoint < 0xffff; ++codepoint)
5455 glyph = 0;
5456 hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, &glyph);
5457 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5458 if (glyph)
5459 break;
5462 if (!glyph)
5464 skip("Couldn't find reasonable test string.\n");
5465 goto cleanup;
5468 str[0] = codepoint;
5469 hr = IDWriteFactory_CreateTextLayout(factory, str, 1, format, 30000.0f, 100.0f, &layout);
5470 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5472 range.startPosition = 0;
5473 range.length = 2;
5474 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
5475 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5477 memset(&ctxt, 0, sizeof(ctxt));
5478 ctxt.format = format;
5479 ctxt.familyW = nameW;
5480 hr = IDWriteTextLayout_Draw(layout, &ctxt, &testrenderer, 0.0f, 0.0f);
5481 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5483 cleanup:
5484 if (layout)
5485 IDWriteTextLayout_Release(layout);
5486 if (format)
5487 IDWriteTextFormat_Release(format);
5488 IDWriteFontFace_Release(fontface);
5489 IDWriteFontFamily_Release(family);
5491 IDWriteFontCollection_Release(syscollection);
5493 IDWriteFactory_Release(factory);
5496 static void test_InvalidateLayout(void)
5498 IDWriteTextLayout3 *layout3;
5499 IDWriteTextLayout *layout;
5500 IDWriteTextFormat *format;
5501 IDWriteFactory *factory;
5502 HRESULT hr;
5504 factory = create_factory();
5506 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5507 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
5508 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5510 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 1000.0f, 1000.0f, &layout);
5511 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
5513 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout3, (void**)&layout3);
5514 if (hr == S_OK) {
5515 IDWriteTextFormat1 *format1;
5516 IDWriteTextFormat2 *format2;
5518 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat2, (void**)&format2);
5519 ok(hr == S_OK, "got 0x%08x\n", hr);
5520 IDWriteTextFormat2_Release(format2);
5522 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat2, (void**)&format2);
5523 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Unexpected hr %#x.\n", hr);
5524 if (hr == S_OK) {
5525 ok(format != (IDWriteTextFormat *)format2, "Unexpected interface pointer.\n");
5526 IDWriteTextFormat2_Release(format2);
5529 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextFormat1, (void**)&format1);
5530 ok(hr == S_OK, "got 0x%08x\n", hr);
5532 hr = IDWriteTextFormat1_QueryInterface(format1, &IID_IDWriteTextFormat2, (void**)&format2);
5533 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "Unexpected hr %#x.\n", hr);
5534 if (hr == S_OK)
5535 IDWriteTextFormat2_Release(format2);
5536 IDWriteTextFormat1_Release(format1);
5538 hr = IDWriteTextLayout3_QueryInterface(layout3, &IID_IDWriteTextFormat2, (void**)&format2);
5539 ok(hr == S_OK || broken(hr == E_NOINTERFACE), "got 0x%08x\n", hr);
5540 if (hr == S_OK)
5541 IDWriteTextFormat2_Release(format2);
5543 hr = IDWriteTextLayout3_InvalidateLayout(layout3);
5544 ok(hr == S_OK, "got 0x%08x\n", hr);
5545 IDWriteTextLayout3_Release(layout3);
5547 else
5548 win_skip("IDWriteTextLayout3::InvalidateLayout() is not supported.\n");
5550 IDWriteTextLayout_Release(layout);
5551 IDWriteTextFormat_Release(format);
5552 IDWriteFactory_Release(factory);
5555 static void test_line_spacing(void)
5557 IDWriteTextFormat2 *format2;
5558 IDWriteTextLayout *layout;
5559 IDWriteTextFormat *format;
5560 IDWriteFactory *factory;
5561 HRESULT hr;
5563 factory = create_factory();
5565 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5566 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
5567 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5569 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0f, 0.0f);
5570 ok(hr == S_OK, "got 0x%08x\n", hr);
5572 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0f, -10.0f);
5573 ok(hr == S_OK, "got 0x%08x\n", hr);
5575 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_DEFAULT, -10.0f, 0.0f);
5576 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5578 hr = IDWriteTextFormat_SetLineSpacing(format, DWRITE_LINE_SPACING_METHOD_PROPORTIONAL+1, 0.0f, 0.0f);
5579 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5581 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 1000.0f, 1000.0f, &layout);
5582 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
5584 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0f, 0.0f);
5585 ok(hr == S_OK, "got 0x%08x\n", hr);
5587 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_DEFAULT, 0.0f, -10.0f);
5588 ok(hr == S_OK, "got 0x%08x\n", hr);
5590 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_DEFAULT, -10.0f, 0.0f);
5591 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5593 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_PROPORTIONAL+1, 0.0f, 0.0f);
5594 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5596 if (IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat2, (void**)&format2) == S_OK) {
5597 DWRITE_LINE_SPACING spacing;
5599 hr = IDWriteTextFormat2_GetLineSpacing(format2, &spacing);
5600 ok(hr == S_OK, "got 0x%08x\n", hr);
5602 ok(spacing.method == DWRITE_LINE_SPACING_METHOD_DEFAULT, "got method %d\n", spacing.method);
5603 ok(spacing.height == 0.0f, "got %f\n", spacing.height);
5604 ok(spacing.baseline == -10.0f, "got %f\n", spacing.baseline);
5605 ok(spacing.leadingBefore == 0.0f, "got %f\n", spacing.leadingBefore);
5606 ok(spacing.fontLineGapUsage == DWRITE_FONT_LINE_GAP_USAGE_DEFAULT, "got %f\n", spacing.leadingBefore);
5608 spacing.leadingBefore = -1.0f;
5610 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5611 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5613 spacing.leadingBefore = 1.1f;
5615 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5616 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5618 spacing.leadingBefore = 1.0f;
5620 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5621 ok(hr == S_OK, "got 0x%08x\n", hr);
5623 spacing.method = DWRITE_LINE_SPACING_METHOD_PROPORTIONAL + 1;
5624 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5625 ok(hr == E_INVALIDARG, "got 0x%08x\n", hr);
5627 spacing.method = DWRITE_LINE_SPACING_METHOD_PROPORTIONAL;
5628 spacing.fontLineGapUsage = DWRITE_FONT_LINE_GAP_USAGE_ENABLED + 1;
5629 hr = IDWriteTextFormat2_SetLineSpacing(format2, &spacing);
5630 ok(hr == S_OK, "got 0x%08x\n", hr);
5632 hr = IDWriteTextFormat2_GetLineSpacing(format2, &spacing);
5633 ok(hr == S_OK, "got 0x%08x\n", hr);
5634 ok(spacing.fontLineGapUsage == DWRITE_FONT_LINE_GAP_USAGE_ENABLED + 1, "got %d\n", spacing.fontLineGapUsage);
5636 IDWriteTextFormat2_Release(format2);
5639 IDWriteTextLayout_Release(layout);
5640 IDWriteTextFormat_Release(format);
5641 IDWriteFactory_Release(factory);
5644 static void test_GetOverhangMetrics(void)
5646 static const struct overhangs_test
5648 FLOAT uniform_baseline;
5649 DWRITE_INLINE_OBJECT_METRICS metrics;
5650 DWRITE_OVERHANG_METRICS overhang_metrics;
5651 DWRITE_OVERHANG_METRICS expected;
5652 } overhangs_tests[] = {
5653 { 16.0f, { 10.0f, 50.0f, 20.0f }, { 1.0f, 2.0f, 3.0f, 4.0f }, { 1.0f, 6.0f, 3.0f, 0.0f } },
5654 { 15.0f, { 10.0f, 50.0f, 20.0f }, { 1.0f, 2.0f, 3.0f, 4.0f }, { 1.0f, 7.0f, 3.0f, -1.0f } },
5655 { 16.0f, { 10.0f, 50.0f, 20.0f }, { -1.0f, 0.0f, -3.0f, 4.0f }, { -1.0f, 4.0f, -3.0f, 0.0f } },
5656 { 15.0f, { 10.0f, 50.0f, 20.0f }, { -1.0f, 10.0f, 3.0f, -4.0f }, { -1.0f, 15.0f, 3.0f, -9.0f } },
5658 IDWriteFactory *factory;
5659 IDWriteTextFormat *format;
5660 IDWriteTextLayout *layout;
5661 HRESULT hr;
5662 UINT32 i;
5664 factory = create_factory();
5666 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
5667 DWRITE_FONT_STRETCH_NORMAL, 100.0f, L"en-us", &format);
5668 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5670 hr = IDWriteFactory_CreateTextLayout(factory, L"A", 1, format, 1000.0f, 1000.0f, &layout);
5671 ok(hr == S_OK, "Failed to create text layout, hr %x.\n", hr);
5673 for (i = 0; i < ARRAY_SIZE(overhangs_tests); i++) {
5674 const struct overhangs_test *test = &overhangs_tests[i];
5675 DWRITE_OVERHANG_METRICS overhang_metrics;
5676 DWRITE_TEXT_RANGE range = { 0, 1 };
5677 DWRITE_TEXT_METRICS metrics;
5678 struct test_inline_obj obj;
5680 test_inline_obj_init(&obj, &test->metrics, &test->overhang_metrics);
5682 hr = IDWriteTextLayout_SetLineSpacing(layout, DWRITE_LINE_SPACING_METHOD_UNIFORM, test->metrics.height * 2.0f,
5683 test->uniform_baseline);
5684 ok(hr == S_OK, "Failed to set line spacing, hr %#x.\n", hr);
5686 hr = IDWriteTextLayout_SetInlineObject(layout, NULL, range);
5687 ok(hr == S_OK, "Failed to reset inline object, hr %#x.\n", hr);
5689 hr = IDWriteTextLayout_SetInlineObject(layout, &obj.IDWriteInlineObject_iface, range);
5690 ok(hr == S_OK, "Failed to set inline object, hr %#x.\n", hr);
5692 hr = IDWriteTextLayout_GetMetrics(layout, &metrics);
5693 ok(hr == S_OK, "Failed to get layout metrics, hr %#x.\n", hr);
5695 ok(metrics.width == test->metrics.width, "%u: unexpected formatted width.\n", i);
5696 ok(metrics.height == test->metrics.height * 2.0f, "%u: unexpected formatted height.\n", i);
5698 hr = IDWriteTextLayout_SetMaxWidth(layout, metrics.width);
5699 hr = IDWriteTextLayout_SetMaxHeight(layout, test->metrics.height);
5701 hr = IDWriteTextLayout_GetOverhangMetrics(layout, &overhang_metrics);
5702 ok(hr == S_OK, "Failed to get overhang metrics, hr %#x.\n", hr);
5704 ok(!memcmp(&overhang_metrics, &test->expected, sizeof(overhang_metrics)),
5705 "%u: unexpected overhang metrics (%f, %f, %f, %f).\n", i, overhang_metrics.left, overhang_metrics.top,
5706 overhang_metrics.right, overhang_metrics.bottom);
5709 IDWriteTextLayout_Release(layout);
5710 IDWriteTextFormat_Release(format);
5711 IDWriteFactory_Release(factory);
5714 static void test_tab_stops(void)
5716 DWRITE_CLUSTER_METRICS clusters[4];
5717 IDWriteTextLayout *layout;
5718 IDWriteTextFormat *format;
5719 IDWriteFactory *factory;
5720 DWRITE_TEXT_RANGE range;
5721 FLOAT tabstop, size;
5722 ULONG count;
5723 HRESULT hr;
5725 factory = create_factory();
5727 /* Default tab stop value. */
5728 for (size = 1.0f; size < 25.0f; size += 5.0f)
5730 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL,
5731 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, size, L"en-us", &format);
5732 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5734 tabstop = IDWriteTextFormat_GetIncrementalTabStop(format);
5735 ok(tabstop == 4.0f * size, "Unexpected tab stop %f.\n", tabstop);
5737 IDWriteTextFormat_Release(format);
5740 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL,
5741 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"en-us", &format);
5742 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5744 hr = IDWriteTextFormat_SetIncrementalTabStop(format, 0.0f);
5745 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5747 hr = IDWriteTextFormat_SetIncrementalTabStop(format, -10.0f);
5748 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5750 tabstop = IDWriteTextFormat_GetIncrementalTabStop(format);
5751 ok(tabstop == 40.0f, "Unexpected tab stop %f.\n", tabstop);
5753 hr = IDWriteTextFormat_SetIncrementalTabStop(format, 100.0f);
5754 ok(hr == S_OK, "Failed to set tab stop value, hr %#x.\n", hr);
5756 tabstop = IDWriteTextFormat_GetIncrementalTabStop(format);
5757 ok(tabstop == 100.0f, "Unexpected tab stop %f.\n", tabstop);
5759 hr = IDWriteFactory_CreateTextLayout(factory, L"\ta\tb", 4, format, 1000.0f, 1000.0f, &layout);
5760 ok(hr == S_OK, "Failed to create text layout, hr %x.\n", hr);
5762 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count);
5763 ok(hr == S_OK, "Failed to get cluster metrics, hr %#x.\n", hr);
5764 ok(clusters[0].isWhitespace, "Unexpected isWhitespace.\n");
5765 ok(!clusters[1].isWhitespace, "Unexpected isWhitespace.\n");
5766 ok(clusters[2].isWhitespace, "Unexpected isWhitespace.\n");
5767 ok(!clusters[3].isWhitespace, "Unexpected isWhitespace.\n");
5768 todo_wine {
5769 ok(clusters[0].width == tabstop, "Unexpected tab width.\n");
5770 ok(clusters[1].width + clusters[2].width == tabstop, "Unexpected tab width.\n");
5772 range.startPosition = 0;
5773 range.length = ~0u;
5774 hr = IDWriteTextLayout_SetFontSize(layout, 20.0f, range);
5775 ok(hr == S_OK, "Failed to set font size, hr %#x.\n", hr);
5777 tabstop = IDWriteTextLayout_GetIncrementalTabStop(layout);
5778 ok(tabstop == 100.0f, "Unexpected tab stop %f.\n", tabstop);
5780 hr = IDWriteTextLayout_GetClusterMetrics(layout, clusters, 4, &count);
5781 ok(hr == S_OK, "Failed to get cluster metrics, hr %#x.\n", hr);
5782 ok(clusters[0].isWhitespace, "Unexpected isWhitespace.\n");
5783 ok(!clusters[1].isWhitespace, "Unexpected isWhitespace.\n");
5784 ok(clusters[2].isWhitespace, "Unexpected isWhitespace.\n");
5785 ok(!clusters[3].isWhitespace, "Unexpected isWhitespace.\n");
5786 todo_wine {
5787 ok(clusters[0].width == tabstop, "Unexpected tab width.\n");
5788 ok(clusters[1].width + clusters[2].width == tabstop, "Unexpected tab width.\n");
5790 IDWriteTextLayout_Release(layout);
5792 IDWriteTextFormat_Release(format);
5794 IDWriteFactory_Release(factory);
5797 static void test_automatic_font_axes(void)
5799 DWRITE_AUTOMATIC_FONT_AXES axes;
5800 IDWriteTextLayout4 *layout4 = NULL;
5801 IDWriteTextFormat3 *format3;
5802 IDWriteTextLayout *layout;
5803 IDWriteTextFormat *format;
5804 IDWriteFactory *factory;
5805 HRESULT hr;
5807 factory = create_factory();
5809 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL,
5810 DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 16.0f, L"en-us", &format);
5811 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
5813 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 1000.0f, 1000.0f, &layout);
5814 ok(hr == S_OK, "Failed to create text layout, hr %x.\n", hr);
5816 IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout4, (void **)&layout4);
5818 IDWriteTextLayout_Release(layout);
5820 if (!layout4)
5822 win_skip("Text layout does not support variable fonts.\n");
5823 IDWriteFactory_Release(factory);
5824 IDWriteTextFormat_Release(format);
5825 return;
5828 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat3, (void **)&format3);
5829 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5831 axes = IDWriteTextFormat3_GetAutomaticFontAxes(format3);
5832 ok(axes == DWRITE_AUTOMATIC_FONT_AXES_NONE, "Unexpected automatic axes %u.\n", axes);
5834 hr = IDWriteTextFormat3_SetAutomaticFontAxes(format3, DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE);
5835 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5837 hr = IDWriteTextFormat3_SetAutomaticFontAxes(format3, DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE + 1);
5838 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5840 IDWriteTextFormat3_Release(format3);
5842 axes = IDWriteTextLayout4_GetAutomaticFontAxes(layout4);
5843 ok(axes == DWRITE_AUTOMATIC_FONT_AXES_NONE, "Unexpected automatic axes %u.\n", axes);
5845 hr = IDWriteTextLayout4_SetAutomaticFontAxes(layout4, DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE + 1);
5846 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5848 hr = IDWriteTextLayout4_SetAutomaticFontAxes(layout4, DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE);
5849 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5851 IDWriteTextLayout4_Release(layout4);
5853 /* Out of range values allow for formats, but not for layouts. */
5854 hr = IDWriteFactory_CreateTextLayout(factory, L"a", 1, format, 1000.0f, 1000.0f, &layout);
5855 ok(hr == S_OK, "Failed to create text layout, hr %x.\n", hr);
5857 hr = IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout4, (void **)&layout4);
5858 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5860 axes = IDWriteTextLayout4_GetAutomaticFontAxes(layout4);
5861 ok(axes == DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE + 1, "Unexpected automatic axes %u.\n", axes);
5863 hr = IDWriteTextLayout4_QueryInterface(layout4, &IID_IDWriteTextFormat3, (void **)&format3);
5864 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5866 axes = IDWriteTextFormat3_GetAutomaticFontAxes(format3);
5867 ok(axes == DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE + 1, "Unexpected automatic axes %u.\n", axes);
5869 hr = IDWriteTextLayout4_SetAutomaticFontAxes(layout4, DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE);
5870 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5872 axes = IDWriteTextFormat3_GetAutomaticFontAxes(format3);
5873 ok(axes == DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE, "Unexpected automatic axes %u.\n", axes);
5875 hr = IDWriteTextFormat3_SetAutomaticFontAxes(format3, DWRITE_AUTOMATIC_FONT_AXES_OPTICAL_SIZE + 1);
5876 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
5878 IDWriteTextFormat3_Release(format3);
5880 IDWriteTextLayout_Release(layout);
5882 IDWriteTextLayout4_Release(layout4);
5883 IDWriteTextFormat_Release(format);
5884 IDWriteFactory_Release(factory);
5887 static void test_text_format_axes(void)
5889 IDWriteFontCollection *collection;
5890 IDWriteFontCollection2 *collection2;
5891 DWRITE_FONT_AXIS_VALUE axes[2];
5892 IDWriteTextFormat3 *format3;
5893 DWRITE_FONT_STRETCH stretch;
5894 DWRITE_FONT_WEIGHT weight;
5895 IDWriteTextFormat *format;
5896 IDWriteFactory6 *factory;
5897 DWRITE_FONT_STYLE style;
5898 DWRITE_FONT_FAMILY_MODEL model;
5899 unsigned int count;
5900 HRESULT hr;
5902 factory = create_factory_iid(&IID_IDWriteFactory6);
5904 if (!factory)
5906 win_skip("Text format does not support variations.\n");
5907 return;
5910 hr = IDWriteFactory6_CreateTextFormat(factory, L"test_family", NULL, NULL, 0, 10.0f, L"en-us", &format3);
5911 todo_wine
5912 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5914 if (SUCCEEDED(hr))
5916 hr = IDWriteTextFormat3_GetFontCollection(format3, &collection);
5917 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5919 hr = IDWriteFontCollection_QueryInterface(collection, &IID_IDWriteFontCollection2, (void **)&collection2);
5920 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5922 model = IDWriteFontCollection2_GetFontFamilyModel(collection2);
5923 ok(model == DWRITE_FONT_FAMILY_MODEL_TYPOGRAPHIC, "Unexpected model %d.\n", model);
5925 IDWriteFontCollection_Release(collection);
5926 IDWriteFontCollection2_Release(collection2);
5928 count = IDWriteTextFormat3_GetFontAxisValueCount(format3);
5929 ok(!count, "Unexpected axis count %u.\n", count);
5931 stretch = IDWriteTextFormat3_GetFontStretch(format3);
5932 ok(stretch == DWRITE_FONT_STRETCH_NORMAL, "Unexpected font stretch %d.\n", stretch);
5934 style = IDWriteTextFormat3_GetFontStyle(format3);
5935 ok(style == DWRITE_FONT_STYLE_NORMAL, "Unexpected font style %d.\n", style);
5937 weight = IDWriteTextFormat3_GetFontWeight(format3);
5938 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "Unexpected font weight %d.\n", weight);
5940 /* Regular properties are not set from axis values. */
5941 axes[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
5942 axes[0].value = 200.0f;
5943 hr = IDWriteTextFormat3_SetFontAxisValues(format3, axes, 1);
5944 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5946 weight = IDWriteTextFormat3_GetFontWeight(format3);
5947 ok(weight == DWRITE_FONT_WEIGHT_NORMAL, "Unexpected font weight %d.\n", weight);
5949 IDWriteTextFormat3_Release(format3);
5951 hr = IDWriteFactory_CreateTextFormat((IDWriteFactory *)factory, L"test_family", NULL,
5952 DWRITE_FONT_WEIGHT_BOLD, DWRITE_FONT_STYLE_ITALIC, DWRITE_FONT_STRETCH_EXPANDED,
5953 10.0f, L"en-us", &format);
5954 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5956 hr = IDWriteTextFormat_QueryInterface(format, &IID_IDWriteTextFormat3, (void **)&format3);
5957 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5959 count = IDWriteTextFormat3_GetFontAxisValueCount(format3);
5960 ok(!count, "Unexpected axis count %u.\n", count);
5962 axes[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
5963 hr = IDWriteTextFormat3_GetFontAxisValues(format3, axes, 1);
5964 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5965 ok(axes[0].axisTag == 0 && axes[0].value == 0.0f, "Unexpected value.\n");
5967 axes[0].axisTag = DWRITE_FONT_AXIS_TAG_WEIGHT;
5968 axes[0].value = 200.0f;
5969 axes[1].axisTag = DWRITE_FONT_AXIS_TAG_WIDTH;
5970 axes[1].value = 2.0f;
5971 hr = IDWriteTextFormat3_SetFontAxisValues(format3, axes, 2);
5972 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5974 count = IDWriteTextFormat3_GetFontAxisValueCount(format3);
5975 ok(count == 2, "Unexpected axis count %u.\n", count);
5977 hr = IDWriteTextFormat3_GetFontAxisValues(format3, axes, 1);
5978 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
5980 hr = IDWriteTextFormat3_GetFontAxisValues(format3, axes, 0);
5981 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
5983 hr = IDWriteTextFormat3_GetFontAxisValues(format3, axes, 2);
5984 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5986 hr = IDWriteTextFormat3_SetFontAxisValues(format3, axes, 0);
5987 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
5989 count = IDWriteTextFormat3_GetFontAxisValueCount(format3);
5990 ok(!count, "Unexpected axis count %u.\n", count);
5992 IDWriteTextFormat3_Release(format3);
5993 IDWriteTextFormat_Release(format);
5995 IDWriteFactory6_Release(factory);
5998 static void test_layout_range_length(void)
6000 IDWriteFontCollection *collection, *collection2;
6001 IDWriteInlineObject *sign, *object;
6002 IDWriteTypography *typography;
6003 DWRITE_FONT_STRETCH stretch;
6004 IDWriteTextLayout1 *layout1;
6005 IDWriteTextFormat *format;
6006 IDWriteTextLayout *layout;
6007 DWRITE_FONT_WEIGHT weight;
6008 DWRITE_FONT_STYLE style;
6009 DWRITE_TEXT_RANGE range;
6010 IDWriteFactory *factory;
6011 HRESULT hr;
6012 BOOL value;
6014 factory = create_factory();
6016 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
6017 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"ru", &format);
6018 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
6020 /* Range length is validated when setting properties. */
6022 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, &layout);
6023 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
6025 /* Weight */
6026 range.startPosition = 10;
6027 range.length = ~0u;
6028 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_NORMAL, range);
6029 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6031 range.startPosition = 10;
6032 range.length = ~0u - 9;
6033 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_NORMAL, range);
6034 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6036 range.startPosition = 10;
6037 range.length = ~0u - 10;
6038 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_HEAVY, range);
6039 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6041 range.startPosition = range.length = 0;
6042 hr = IDWriteTextLayout_GetFontWeight(layout, 0, &weight, &range);
6043 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6044 ok(range.startPosition == 0 && range.length == 10, "Unexpected range (%u, %u).\n", range.startPosition, range.length);
6046 range.startPosition = range.length = 0;
6047 hr = IDWriteTextLayout_GetFontWeight(layout, 10, &weight, &range);
6048 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6049 ok(range.startPosition == 10 && range.length == ~0u - 10, "Unexpected range (%u, %u).\n",
6050 range.startPosition, range.length);
6052 range.startPosition = 0;
6053 range.length = ~0u;
6054 hr = IDWriteTextLayout_SetFontWeight(layout, DWRITE_FONT_WEIGHT_NORMAL, range);
6055 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6057 /* Family name */
6058 range.startPosition = 10;
6059 range.length = ~0u;
6060 hr = IDWriteTextLayout_SetFontFamilyName(layout, L"family", range);
6061 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6063 range.startPosition = 10;
6064 range.length = ~0u - 9;
6065 hr = IDWriteTextLayout_SetFontFamilyName(layout, L"family", range);
6066 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6068 range.startPosition = 10;
6069 range.length = ~0u - 10;
6070 hr = IDWriteTextLayout_SetFontFamilyName(layout, L"family", range);
6071 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6073 range.startPosition = 0;
6074 range.length = ~0u;
6075 hr = IDWriteTextLayout_SetFontFamilyName(layout, L"Tahoma", range);
6076 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6078 /* Style */
6079 range.startPosition = 10;
6080 range.length = ~0u;
6081 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC, range);
6082 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6084 range.startPosition = 10;
6085 range.length = ~0u - 9;
6086 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC, range);
6087 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6089 range.startPosition = 10;
6090 range.length = ~0u - 10;
6091 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_ITALIC, range);
6092 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6094 range.startPosition = range.length = 0;
6095 hr = IDWriteTextLayout_GetFontStyle(layout, 0, &style, &range);
6096 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6097 ok(range.startPosition == 0 && range.length == 10, "Unexpected range (%u, %u).\n", range.startPosition, range.length);
6099 range.startPosition = range.length = 0;
6100 hr = IDWriteTextLayout_GetFontStyle(layout, 10, &style, &range);
6101 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6102 ok(range.startPosition == 10 && range.length == ~0u - 10, "Unexpected range (%u, %u).\n",
6103 range.startPosition, range.length);
6105 range.startPosition = 0;
6106 range.length = ~0u;
6107 hr = IDWriteTextLayout_SetFontStyle(layout, DWRITE_FONT_STYLE_NORMAL, range);
6108 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6110 /* Stretch */
6111 range.startPosition = 10;
6112 range.length = ~0u;
6113 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_CONDENSED, range);
6114 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6116 range.startPosition = 10;
6117 range.length = ~0u - 9;
6118 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_CONDENSED, range);
6119 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6121 range.startPosition = 10;
6122 range.length = ~0u - 10;
6123 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_CONDENSED, range);
6124 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6126 range.startPosition = range.length = 0;
6127 hr = IDWriteTextLayout_GetFontStretch(layout, 0, &stretch, &range);
6128 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6129 ok(range.startPosition == 0 && range.length == 10, "Unexpected range (%u, %u).\n", range.startPosition, range.length);
6131 range.startPosition = range.length = 0;
6132 hr = IDWriteTextLayout_GetFontStretch(layout, 10, &stretch, &range);
6133 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6134 ok(range.startPosition == 10 && range.length == ~0u - 10, "Unexpected range (%u, %u).\n",
6135 range.startPosition, range.length);
6137 range.startPosition = 0;
6138 range.length = ~0u;
6139 hr = IDWriteTextLayout_SetFontStretch(layout, DWRITE_FONT_STRETCH_NORMAL, range);
6140 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6142 /* Underline */
6143 range.startPosition = 10;
6144 range.length = ~0u;
6145 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
6146 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6148 range.startPosition = 10;
6149 range.length = ~0u - 9;
6150 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
6151 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6153 range.startPosition = 10;
6154 range.length = ~0u - 10;
6155 hr = IDWriteTextLayout_SetUnderline(layout, TRUE, range);
6156 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6158 range.startPosition = range.length = 0;
6159 hr = IDWriteTextLayout_GetUnderline(layout, 0, &value, &range);
6160 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6161 ok(range.startPosition == 0 && range.length == 10, "Unexpected range (%u, %u).\n", range.startPosition, range.length);
6163 range.startPosition = range.length = 0;
6164 hr = IDWriteTextLayout_GetUnderline(layout, 10, &value, &range);
6165 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6166 ok(range.startPosition == 10 && range.length == ~0u - 10, "Unexpected range (%u, %u).\n",
6167 range.startPosition, range.length);
6169 range.startPosition = 0;
6170 range.length = ~0u;
6171 hr = IDWriteTextLayout_SetUnderline(layout, FALSE, range);
6172 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6174 /* Strikethrough */
6175 range.startPosition = 10;
6176 range.length = ~0u;
6177 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
6178 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6180 range.startPosition = 10;
6181 range.length = ~0u - 9;
6182 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
6183 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6185 range.startPosition = 10;
6186 range.length = ~0u - 10;
6187 hr = IDWriteTextLayout_SetStrikethrough(layout, TRUE, range);
6188 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6190 range.startPosition = range.length = 0;
6191 hr = IDWriteTextLayout_GetStrikethrough(layout, 0, &value, &range);
6192 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6193 ok(range.startPosition == 0 && range.length == 10, "Unexpected range (%u, %u).\n", range.startPosition, range.length);
6195 range.startPosition = range.length = 0;
6196 hr = IDWriteTextLayout_GetStrikethrough(layout, 10, &value, &range);
6197 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6198 ok(range.startPosition == 10 && range.length == ~0u - 10, "Unexpected range (%u, %u).\n",
6199 range.startPosition, range.length);
6201 range.startPosition = 0;
6202 range.length = ~0u;
6203 hr = IDWriteTextLayout_SetStrikethrough(layout, FALSE, range);
6204 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6206 /* Locale name */
6207 range.startPosition = 10;
6208 range.length = ~0u;
6209 hr = IDWriteTextLayout_SetLocaleName(layout, L"locale", range);
6210 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6212 range.startPosition = 10;
6213 range.length = ~0u - 9;
6214 hr = IDWriteTextLayout_SetLocaleName(layout, L"locale", range);
6215 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6217 range.startPosition = 10;
6218 range.length = ~0u - 10;
6219 hr = IDWriteTextLayout_SetLocaleName(layout, L"locale", range);
6220 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6222 range.startPosition = 0;
6223 range.length = ~0u;
6224 hr = IDWriteTextLayout_SetLocaleName(layout, L"ru", range);
6225 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6227 /* Inline object */
6228 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &sign);
6229 ok(hr == S_OK, "got 0x%08x\n", hr);
6231 range.startPosition = 10;
6232 range.length = ~0u;
6233 hr = IDWriteTextLayout_SetInlineObject(layout, sign, range);
6234 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6236 range.startPosition = 10;
6237 range.length = ~0u - 9;
6238 hr = IDWriteTextLayout_SetInlineObject(layout, sign, range);
6239 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6241 range.startPosition = 10;
6242 range.length = ~0u - 10;
6243 hr = IDWriteTextLayout_SetInlineObject(layout, sign, range);
6244 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6246 range.startPosition = range.length = 0;
6247 object = NULL;
6248 hr = IDWriteTextLayout_GetInlineObject(layout, 10, &object, &range);
6249 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6250 ok(range.startPosition == 10 && range.length == ~0u - 10, "Unexpected range (%u, %u).\n",
6251 range.startPosition, range.length);
6252 IDWriteInlineObject_Release(object);
6254 range.startPosition = 0;
6255 range.length = ~0u;
6256 hr = IDWriteTextLayout_SetInlineObject(layout, NULL, range);
6257 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6259 /* Drawing effect */
6260 range.startPosition = 10;
6261 range.length = ~0u;
6262 hr = IDWriteTextLayout_SetDrawingEffect(layout, (IUnknown *)sign, range);
6263 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6265 range.startPosition = 10;
6266 range.length = ~0u - 9;
6267 hr = IDWriteTextLayout_SetDrawingEffect(layout, (IUnknown *)sign, range);
6268 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6270 range.startPosition = 10;
6271 range.length = ~0u - 10;
6272 hr = IDWriteTextLayout_SetDrawingEffect(layout, (IUnknown *)sign, range);
6273 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6275 range.startPosition = 0;
6276 range.length = ~0u;
6277 hr = IDWriteTextLayout_SetDrawingEffect(layout, NULL, range);
6278 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6280 IDWriteInlineObject_Release(sign);
6282 /* Typography */
6283 hr = IDWriteFactory_CreateTypography(factory, &typography);
6284 ok(hr == S_OK, "got 0x%08x\n", hr);
6286 range.startPosition = 10;
6287 range.length = ~0u;
6288 hr = IDWriteTextLayout_SetTypography(layout, typography, range);
6289 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6291 range.startPosition = 10;
6292 range.length = ~0u - 9;
6293 hr = IDWriteTextLayout_SetTypography(layout, typography, range);
6294 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6296 range.startPosition = 10;
6297 range.length = ~0u - 10;
6298 hr = IDWriteTextLayout_SetTypography(layout, typography, range);
6299 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6301 range.startPosition = 0;
6302 range.length = ~0u;
6303 hr = IDWriteTextLayout_SetTypography(layout, NULL, range);
6304 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6306 IDWriteTypography_Release(typography);
6308 /* Font collection */
6309 hr = IDWriteFactory_GetSystemFontCollection(factory, &collection, FALSE);
6310 ok(hr == S_OK, "Failed to get system collection, hr %#x.\n", hr);
6312 range.startPosition = 10;
6313 range.length = ~0u;
6314 hr = IDWriteTextLayout_SetFontCollection(layout, collection, range);
6315 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6317 range.startPosition = 10;
6318 range.length = ~0u - 9;
6319 hr = IDWriteTextLayout_SetFontCollection(layout, collection, range);
6320 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6322 range.startPosition = 10;
6323 range.length = ~0u - 10;
6324 hr = IDWriteTextLayout_SetFontCollection(layout, collection, range);
6325 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6327 range.startPosition = 0;
6328 range.length = ~0u;
6329 hr = IDWriteTextLayout_SetFontCollection(layout, NULL, range);
6330 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6332 range.startPosition = range.length = 0;
6333 collection2 = NULL;
6334 hr = IDWriteTextLayout_GetFontCollection(layout, 10, &collection2, &range);
6335 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6336 ok(range.length == ~0u, "Unexpected range length %u.\n", range.length);
6337 if (collection2)
6338 IDWriteFontCollection_Release(collection2);
6340 IDWriteFontCollection_Release(collection);
6342 if (SUCCEEDED(IDWriteTextLayout_QueryInterface(layout, &IID_IDWriteTextLayout1, (void **)&layout1)))
6344 /* Pair kerning */
6345 range.startPosition = 10;
6346 range.length = ~0u;
6347 hr = IDWriteTextLayout1_SetPairKerning(layout1, TRUE, range);
6348 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6350 range.startPosition = 10;
6351 range.length = ~0u - 9;
6352 hr = IDWriteTextLayout1_SetPairKerning(layout1, TRUE, range);
6353 ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
6355 range.startPosition = 10;
6356 range.length = ~0u - 10;
6357 hr = IDWriteTextLayout1_SetPairKerning(layout1, TRUE, range);
6358 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6360 range.startPosition = range.length = 0;
6361 hr = IDWriteTextLayout1_GetPairKerning(layout1, 0, &value, &range);
6362 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6363 ok(range.startPosition == 0 && range.length == 10, "Unexpected range (%u, %u).\n", range.startPosition, range.length);
6365 range.startPosition = range.length = 0;
6366 value = FALSE;
6367 hr = IDWriteTextLayout1_GetPairKerning(layout1, 10, &value, &range);
6368 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6369 ok(range.startPosition == 10 && range.length == ~0u - 10, "Unexpected range (%u, %u).\n",
6370 range.startPosition, range.length);
6371 ok(!!value, "Unexpected value %d.\n", value);
6373 range.startPosition = 0;
6374 range.length = ~0u;
6375 hr = IDWriteTextLayout1_SetPairKerning(layout1, FALSE, range);
6376 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6378 IDWriteTextLayout1_Release(layout1);
6381 IDWriteTextLayout_Release(layout);
6383 IDWriteTextFormat_Release(format);
6384 IDWriteFactory_Release(factory);
6387 static void test_HitTestTextRange(void)
6389 DWRITE_HIT_TEST_METRICS metrics[10];
6390 IDWriteInlineObject *inlineobj;
6391 DWRITE_LINE_METRICS line;
6392 IDWriteTextFormat *format;
6393 IDWriteTextLayout *layout;
6394 DWRITE_TEXT_RANGE range;
6395 IDWriteFactory *factory;
6396 unsigned int count;
6397 HRESULT hr;
6399 factory = create_factory();
6401 hr = IDWriteFactory_CreateTextFormat(factory, L"Tahoma", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL,
6402 DWRITE_FONT_STRETCH_NORMAL, 10.0f, L"ru", &format);
6403 ok(hr == S_OK, "Failed to create text format, hr %#x.\n", hr);
6405 hr = IDWriteFactory_CreateTextLayout(factory, L"string", 6, format, 100.0f, 100.0f, &layout);
6406 ok(hr == S_OK, "Failed to create text layout, hr %#x.\n", hr);
6408 /* Start index exceeding layout text length, dummy range returned. */
6409 count = 0;
6410 hr = IDWriteTextLayout_HitTestTextRange(layout, 7, 10, 0.0f, 0.0f, metrics, ARRAY_SIZE(metrics), &count);
6411 todo_wine
6412 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6413 if (SUCCEEDED(hr))
6415 ok(count == 1, "Unexpected metrics count %u.\n", count);
6416 ok(metrics[0].textPosition == 6 && metrics[0].length == 0, "Unexpected metrics range %u, %u.\n",
6417 metrics[0].textPosition, metrics[0].length);
6418 ok(!!metrics[0].isText, "Expected text range.\n");
6420 /* Length exceeding layout text length, trimmed. */
6421 count = 0;
6422 hr = IDWriteTextLayout_HitTestTextRange(layout, 0, 10, 0.0f, 0.0f, metrics, ARRAY_SIZE(metrics), &count);
6423 todo_wine
6424 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6425 if (SUCCEEDED(hr))
6427 ok(count == 1, "Unexpected metrics count %u.\n", count);
6428 ok(metrics[0].textPosition == 0 && metrics[0].length == 6, "Unexpected metrics range %u, %u.\n",
6429 metrics[0].textPosition, metrics[0].length);
6430 ok(!!metrics[0].isText, "Expected text range.\n");
6432 /* Change font size for second half. */
6433 range.startPosition = 3;
6434 range.length = 3;
6435 hr = IDWriteTextLayout_SetFontSize(layout, 20.0f, range);
6436 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6438 count = 0;
6439 hr = IDWriteTextLayout_HitTestTextRange(layout, 0, 6, 0.0f, 0.0f, metrics, ARRAY_SIZE(metrics), &count);
6440 todo_wine
6441 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6442 if (SUCCEEDED(hr))
6444 ok(count == 1, "Unexpected metrics count %u.\n", count);
6445 ok(metrics[0].textPosition == 0 && metrics[0].length == 6, "Unexpected metrics range %u, %u.\n",
6446 metrics[0].textPosition, metrics[0].length);
6447 ok(!!metrics[0].isText, "Expected text range.\n");
6449 hr = IDWriteTextLayout_GetLineMetrics(layout, &line, 1, &count);
6450 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6451 ok(line.height == metrics[0].height, "Unexpected range height.\n");
6453 /* With inline object. */
6454 hr = IDWriteFactory_CreateEllipsisTrimmingSign(factory, format, &inlineobj);
6455 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6457 hr = IDWriteTextLayout_SetInlineObject(layout, inlineobj, range);
6458 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6460 count = 0;
6461 hr = IDWriteTextLayout_HitTestTextRange(layout, 0, 6, 0.0f, 0.0f, metrics, ARRAY_SIZE(metrics), &count);
6462 todo_wine
6463 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6464 if (SUCCEEDED(hr))
6466 ok(count == 2, "Unexpected metrics count %u.\n", count);
6467 ok(metrics[0].textPosition == 0 && metrics[0].length == 3, "Unexpected metrics range %u, %u.\n",
6468 metrics[0].textPosition, metrics[0].length);
6469 ok(!!metrics[0].isText, "Expected text range.\n");
6470 ok(metrics[1].textPosition == 3 && metrics[1].length == 3, "Unexpected metrics range %u, %u.\n",
6471 metrics[1].textPosition, metrics[1].length);
6472 ok(!metrics[1].isText, "Unexpected text range.\n");
6474 count = 0;
6475 hr = IDWriteTextLayout_HitTestTextRange(layout, 7, 10, 0.0f, 0.0f, metrics, ARRAY_SIZE(metrics), &count);
6476 todo_wine
6477 ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
6478 if (SUCCEEDED(hr))
6480 ok(count == 1, "Unexpected metrics count %u.\n", count);
6481 ok(metrics[0].textPosition == 6 && metrics[0].length == 0, "Unexpected metrics range %u, %u.\n",
6482 metrics[0].textPosition, metrics[0].length);
6483 ok(!metrics[0].isText, "Unexpected text range.\n");
6485 IDWriteInlineObject_Release(inlineobj);
6486 IDWriteTextLayout_Release(layout);
6487 IDWriteTextFormat_Release(format);
6489 IDWriteFactory_Release(factory);
6492 START_TEST(layout)
6494 IDWriteFactory *factory;
6496 if (!(factory = create_factory())) {
6497 win_skip("failed to create factory\n");
6498 return;
6501 init_call_sequences(sequences, NUM_CALL_SEQUENCES);
6502 init_call_sequences(expected_seq, 1);
6504 test_CreateTextLayout();
6505 test_CreateGdiCompatibleTextLayout();
6506 test_CreateTextFormat();
6507 test_GetLocaleName();
6508 test_CreateEllipsisTrimmingSign();
6509 test_fontweight();
6510 test_SetInlineObject();
6511 test_Draw();
6512 test_typography();
6513 test_GetClusterMetrics();
6514 test_SetLocaleName();
6515 test_SetPairKerning();
6516 test_SetVerticalGlyphOrientation();
6517 test_fallback();
6518 test_DetermineMinWidth();
6519 test_SetFontSize();
6520 test_SetFontFamilyName();
6521 test_SetFontStyle();
6522 test_SetFontStretch();
6523 test_SetStrikethrough();
6524 test_GetMetrics();
6525 test_SetFlowDirection();
6526 test_SetDrawingEffect();
6527 test_GetLineMetrics();
6528 test_SetTextAlignment();
6529 test_SetParagraphAlignment();
6530 test_SetReadingDirection();
6531 test_pixelsnapping();
6532 test_SetWordWrapping();
6533 test_MapCharacters();
6534 test_FontFallbackBuilder();
6535 test_SetTypography();
6536 test_SetLastLineWrapping();
6537 test_SetOpticalAlignment();
6538 test_SetUnderline();
6539 test_InvalidateLayout();
6540 test_line_spacing();
6541 test_GetOverhangMetrics();
6542 test_tab_stops();
6543 test_automatic_font_axes();
6544 test_text_format_axes();
6545 test_layout_range_length();
6546 test_HitTestTextRange();
6548 IDWriteFactory_Release(factory);