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