ReactOS 0.4.17-dev-970-gcf0f1a6
analyzer.c
Go to the documentation of this file.
1/*
2 * Text analyzing tests
3 *
4 * Copyright 2012-2020 Nikolay Sivov for CodeWeavers
5 *
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.
10 *
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.
15 *
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
19 */
20
21#define COBJMACROS
22
23#include <assert.h>
24#include <stdio.h>
25#include <limits.h>
26#include <math.h>
27
28#include "initguid.h"
29#include "windows.h"
30#include "winternl.h"
31#include "dwrite_3.h"
32#include "usp10.h"
33
34#include "wine/test.h"
35
37
39{
40 IDWriteTextAnalyzer *analyzer;
41 void *ret = NULL;
42
43 if (SUCCEEDED(IDWriteFactory_CreateTextAnalyzer(factory, &analyzer)))
44 {
45 IDWriteTextAnalyzer_QueryInterface(analyzer, riid, &ret);
46 IDWriteTextAnalyzer_Release(analyzer);
47 }
48
49 return ret;
50}
51
52#define LRE 0x202a
53#define RLE 0x202b
54#define PDF 0x202c
55#define LRO 0x202d
56#define RLO 0x202e
57#define LRI 0x2066
58#define RLI 0x2067
59#define FSI 0x2068
60#define PDI 0x2069
61
62#define MS_GDEF_TAG DWRITE_MAKE_OPENTYPE_TAG('G','D','E','F')
63
64#ifdef WORDS_BIGENDIAN
65#define GET_BE_WORD(x) (x)
66#define GET_BE_DWORD(x) (x)
67#define GET_LE_WORD(x) RtlUshortByteSwap(x)
68#define GET_LE_DWORD(x) RtlUlongByteSwap(x)
69#else
70#define GET_BE_WORD(x) RtlUshortByteSwap(x)
71#define GET_BE_DWORD(x) RtlUlongByteSwap(x)
72#define GET_LE_WORD(x) (x)
73#define GET_LE_DWORD(x) (x)
74#endif
75
77{
82};
83
85{
89};
90
92{
96};
97
102
103static const char *get_analysis_kind_name(enum analysis_kind kind)
104{
105 switch (kind)
106 {
107 case ScriptAnalysis:
108 return "ScriptAnalysis";
109 default:
110 return "unknown";
111 }
112}
113
118};
119
123};
124
129 const char *file;
130 int line;
131};
132
134{
135 int count;
136 int size;
138};
139
140#define NUM_CALL_SEQUENCES 1
141#define ANALYZER_ID 0
143static struct call_sequence *expected_seq[1];
144
145static void add_call(struct call_sequence **seq, int sequence_index, const struct call_entry *call)
146{
147 struct call_sequence *call_seq = seq[sequence_index];
148
149 if (!call_seq->sequence)
150 {
151 call_seq->size = 10;
152 call_seq->sequence = malloc(call_seq->size * sizeof(*call_seq->sequence));
153 }
154
155 if (call_seq->count == call_seq->size)
156 {
157 call_seq->size *= 2;
158 call_seq->sequence = realloc(call_seq->sequence, call_seq->size * sizeof(*call_seq->sequence));
159 }
160
161 assert(call_seq->sequence);
162
163 call_seq->sequence[call_seq->count++] = *call;
164}
165
166static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
167{
168 struct call_sequence *call_seq = seg[sequence_index];
169
170 free(call_seq->sequence);
171 call_seq->sequence = NULL;
172 call_seq->count = call_seq->size = 0;
173}
174
175static void init_call_sequences(struct call_sequence **seq, int n)
176{
177 int i;
178
179 for (i = 0; i < n; i++)
180 seq[i] = calloc(1, sizeof(*seq[i]));
181}
182
183static void test_uint(UINT32 actual, UINT32 expected, const char *name, const struct testcontext *ctxt)
184{
185 if (expected != actual && ctxt->todo)
186 {
187 (*ctxt->failcount)++;
188 ok_(ctxt->file, ctxt->line) (0, "%s: \"%s\" expecting %u, got %u\n", get_analysis_kind_name(ctxt->kind), name, expected, actual);
189 }
190 else
191 ok_(ctxt->file, ctxt->line) (expected == actual, "%s: \"%s\" expecting %u, got %u\n", get_analysis_kind_name(ctxt->kind), name,
192 expected, actual);
193}
194
195static void ok_sequence_(struct call_sequence **seq, int sequence_index,
196 const struct call_entry *expected, const char *context, BOOL todo,
197 const char *file, int line)
198{
199 struct call_sequence *call_seq = seq[sequence_index];
200 static const struct call_entry end_of_sequence = { LastKind };
201 const struct call_entry *actual, *sequence;
202 int failcount = 0;
203 struct testcontext ctxt;
204
205 add_call(seq, sequence_index, &end_of_sequence);
206
207 sequence = call_seq->sequence;
208 actual = sequence;
209
210 ctxt.failcount = &failcount;
211 ctxt.todo = todo;
212 ctxt.file = file;
213 ctxt.line = line;
214
215 while (expected->kind != LastKind && actual->kind != LastKind)
216 {
217 if (expected->kind == actual->kind)
218 {
219 ctxt.kind = expected->kind;
220
221 switch (actual->kind)
222 {
223 case ScriptAnalysis:
224 test_uint(actual->sa.pos, expected->sa.pos, "position", &ctxt);
225 test_uint(actual->sa.len, expected->sa.len, "length", &ctxt);
226 test_uint(actual->sa.shapes, expected->sa.shapes, "shapes", &ctxt);
227 break;
228 default:
229 ok(0, "%s: callback not handled, %s\n", context, get_analysis_kind_name(actual->kind));
230 }
231 expected++;
232 actual++;
233 }
234 else if (todo)
235 {
236 failcount++;
238 {
239 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
241 }
242
243 flush_sequence(seq, sequence_index);
244 return;
245 }
246 else
247 {
248 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
250 expected++;
251 actual++;
252 }
253 }
254
255 if (todo)
256 {
258 {
259 if (expected->kind != LastKind || actual->kind != LastKind)
260 {
261 failcount++;
262 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
264 }
265 }
266 }
267 else if (expected->kind != LastKind || actual->kind != LastKind)
268 {
269 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
271 }
272
273 if (todo && !failcount) /* succeeded yet marked todo */
274 {
276 {
277 ok_(file, line)(1, "%s: marked \"todo_wine\" but succeeds\n", context);
278 }
279 }
280
281 flush_sequence(seq, sequence_index);
282}
283
284#define ok_sequence(seq, index, exp, contx, todo) \
285 ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
286
288{
289 if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown))
290 {
291 *obj = iface;
292 return S_OK;
293 }
294
295 *obj = NULL;
296 return E_NOINTERFACE;
297}
298
300{
301 return 2;
302}
303
305{
306 return 1;
307}
308
310 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
311{
312 struct call_entry entry;
313 entry.kind = ScriptAnalysis;
314 entry.sa.pos = position;
315 entry.sa.len = length;
316 entry.sa.shapes = sa->shapes;
318 return S_OK;
319}
320
323 UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* sa)
324{
325 g_sa = *sa;
326 return S_OK;
327}
328
329#define BREAKPOINT_COUNT 20
331
333 UINT32 position,
335 DWRITE_LINE_BREAKPOINT const* breakpoints)
336{
337 if (position + length > BREAKPOINT_COUNT) {
338 ok(0, "SetLineBreakpoints: reported pos=%u, len=%u overflows expected length %d\n", position, length, BREAKPOINT_COUNT);
339 return E_FAIL;
340 }
341 memcpy(&g_actual_bp[position], breakpoints, length*sizeof(DWRITE_LINE_BREAKPOINT));
342 return S_OK;
343}
344
345#define BIDI_LEVELS_COUNT 10
349 UINT32 position,
351 UINT8 explicitLevel,
352 UINT8 resolvedLevel)
353{
354 if (position + length > BIDI_LEVELS_COUNT) {
355 ok(0, "SetBidiLevel: reported pos=%u, len=%u overflows expected length %d\n", position, length, BIDI_LEVELS_COUNT);
356 return E_FAIL;
357 }
358 memset(g_explicit_levels + position, explicitLevel, length);
359 memset(g_resolved_levels + position, resolvedLevel, length);
360 return S_OK;
361}
362
364 UINT32 position,
366 IDWriteNumberSubstitution* substitution)
367{
368 ok(0, "unexpected\n");
369 return E_NOTIMPL;
370}
371
372static IDWriteTextAnalysisSinkVtbl analysissinkvtbl = {
380};
381
382static IDWriteTextAnalysisSinkVtbl analysissinkvtbl2 = {
390};
391
394
396 REFIID riid, void **obj)
397{
398 ok(0, "QueryInterface not expected\n");
399 return E_NOTIMPL;
400}
401
403{
404 ok(0, "AddRef not expected\n");
405 return 2;
406}
407
409{
410 ok(0, "Release not expected\n");
411 return 1;
412}
413
415{
417 const WCHAR *text;
420};
421
424{
425 source->text = text;
426 source->text_length = text_length == -1 ? lstrlenW(text) : text_length;
427 source->direction = direction;
428};
429
431{
433}
434
436 UINT32 position, WCHAR const** text, UINT32* text_len)
437{
439
440 if (position >= source->text_length)
441 {
442 *text = NULL;
443 *text_len = 0;
444 }
445 else
446 {
447 *text = source->text + position;
448 *text_len = source->text_length - position;
449 }
450
451 return S_OK;
452}
453
455 UINT32 position, WCHAR const** text, UINT32* text_len)
456{
457 ok(0, "unexpected\n");
458 return E_NOTIMPL;
459}
460
463{
465 return source->direction;
466}
467
469 UINT32 position, UINT32* text_len, WCHAR const** locale)
470{
471 *locale = NULL;
472 *text_len = 0;
473 return S_OK;
474}
475
477 UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
478{
479 ok(0, "unexpected\n");
480 return E_NOTIMPL;
481}
482
483static IDWriteTextAnalysisSourceVtbl analysissourcevtbl = {
492};
493
495
497{
498 IDWriteGdiInterop *interop;
499 IDWriteFontFace *fontface;
501 LOGFONTW logfont;
502 HRESULT hr;
503
504 hr = IDWriteFactory_GetGdiInterop(factory, &interop);
505 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
506
507 memset(&logfont, 0, sizeof(logfont));
508 logfont.lfHeight = 12;
509 logfont.lfWidth = 12;
510 logfont.lfWeight = FW_NORMAL;
511 logfont.lfItalic = 1;
512 lstrcpyW(logfont.lfFaceName, L"Tahoma");
513
514 hr = IDWriteGdiInterop_CreateFontFromLOGFONT(interop, &logfont, &font);
515 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
516
517 hr = IDWriteFont_CreateFontFace(font, &fontface);
518 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
519
520 IDWriteFont_Release(font);
521 IDWriteGdiInterop_Release(interop);
522
523 return fontface;
524}
525
527{
528 static WCHAR pathW[MAX_PATH];
529 DWORD written;
530 HANDLE file;
531 HRSRC res;
532 void *ptr;
533
536
538 ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %ld\n", wine_dbgstr_w(pathW),
539 GetLastError());
540
542 ok(res != 0, "couldn't find resource\n");
545 ok(written == SizeofResource(GetModuleHandleA(NULL), res), "couldn't write resource\n");
547
548 return pathW;
549}
550
551#define DELETE_FONTFILE(filename) _delete_testfontfile(filename, __LINE__)
552static void _delete_testfontfile(const WCHAR *filename, int line)
553{
555 ok_(__FILE__,line)(ret, "failed to delete file %s, error %ld\n", wine_dbgstr_w(filename), GetLastError());
556}
557
559{
562 HRESULT hr;
563
564 hr = IDWriteFactory_CreateFontFileReference(factory, filename, NULL, &file);
565 ok(hr == S_OK, "Unexpected hr %#lx.\n",hr);
566
567 hr = IDWriteFactory_CreateFontFace(factory, DWRITE_FONT_FACE_TYPE_TRUETYPE, 1, &file, 0,
569 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
570 IDWriteFontFile_Release(file);
571
572 return face;
573}
574
575struct sa_test {
576 const WCHAR string[50];
579 struct script_analysis sa[10];
580};
581
582static struct sa_test sa_tests[] = {
583 {
584 /* just 1 char string */
585 {'t',0}, -1, 1,
587 },
588 {
589 {'t','e','s','t',0}, -1, 1,
591 },
592 {
593 {' ',' ',' ',' ','!','$','[','^','{','~',0}, -1, 1,
594 { { 0, 10, DWRITE_SCRIPT_SHAPES_DEFAULT }}
595 },
596 {
597 {' ',' ',' ','1','2',' ',0}, -1, 1,
599 },
600 {
601 /* digits only */
602 {'1','2',0}, -1, 1,
604 },
605 {
606 /* Arabic */
607 {0x064a,0x064f,0x0633,0x0627,0x0648,0x0650,0x064a,0x0661,0}, -1, 1,
609 },
610 {
611 /* Arabic */
612 {0x0627,0x0644,0x0635,0x0651,0x0650,0x062d,0x0629,0x064f,' ',0x062a,0x064e,
613 0x0627,0x062c,0x064c,' ',0x0639,0x064e,0x0644,0x0649,' ',
614 0x0631,0x064f,0x0624,0x0648,0x0633,0x0650,' ',0x0627,0x0644,
615 0x0623,0x0635,0x0650,0x062d,0x0651,0x064e,0x0627,0x0621,0x0650,0x06f0,0x06f5,0}, -1, 1,
616 { { 0, 40, DWRITE_SCRIPT_SHAPES_DEFAULT }}
617 },
618 {
619 /* Arabic, Latin */
620 {'1','2','3','-','5','2',0x064a,0x064f,0x0633,0x0627,0x0648,0x0650,0x064a,'7','1','.',0}, -1, 1,
621 { { 0, 16, DWRITE_SCRIPT_SHAPES_DEFAULT }}
622 },
623 {
624 /* Arabic, English */
625 {'A','B','C','-','D','E','F',' ',0x0621,0x0623,0x0624,0}, -1, 2,
628 }
629 },
630 {
631 /* leading space, Arabic, English */
632 {' ',0x0621,0x0623,0x0624,'A','B','C','-','D','E','F',0}, -1, 2,
635 }
636 },
637 {
638 /* English, Arabic, trailing space */
639 {'A','B','C','-','D','E','F',0x0621,0x0623,0x0624,' ',0}, -1, 2,
642 }
643 },
644 {
645 /* C1 Controls, Latin-1 Supplement */
646 {0x80,0x90,0x9f,0xa0,0xc0,0xb8,0xbf,0xc0,0xff,0}, -1, 2,
649 }
650 },
651 {
652 /* Latin Extended-A */
653 {0x100,0x120,0x130,0x140,0x150,0x160,0x170,0x17f,0}, -1, 1,
655 },
656 {
657 /* Latin Extended-B */
658 {0x180,0x190,0x1bf,0x1c0,0x1c3,0x1c4,0x1cc,0x1dc,0x1ff,0x217,0x21b,0x24f,0}, -1, 1,
659 { { 0, 12, DWRITE_SCRIPT_SHAPES_DEFAULT }}
660 },
661 {
662 /* IPA Extensions */
663 {0x250,0x260,0x270,0x290,0x2af,0}, -1, 1,
665 },
666 {
667 /* Spacing Modifier Letters */
668 {0x2b0,0x2ba,0x2d7,0x2dd,0x2ef,0x2ff,0}, -1, 1,
670 },
671 {
672 /* Combining Diacritical Marks */
673 {0x300,0x320,0x340,0x345,0x350,0x36f,0}, -1, 1,
675 },
676 {
677 /* Greek and Coptic */
678 {0x370,0x388,0x3d8,0x3e1,0x3e2,0x3fa,0x3ff,0}, -1, 3,
682 }
683 },
684 {
685 /* Cyrillic and Cyrillic Supplement */
686 {0x400,0x40f,0x410,0x44f,0x450,0x45f,0x460,0x481,0x48a,0x4f0,0x4fa,0x4ff,0x500,0x510,0x520,0}, -1, 1,
687 { { 0, 15, DWRITE_SCRIPT_SHAPES_DEFAULT }}
688 },
689 {
690 /* Armenian */
691 {0x531,0x540,0x559,0x55f,0x570,0x589,0x58a,0}, -1, 1,
693 },
694 {
695 /* Hebrew */
696 {0x5e9,0x5dc,0x5d5,0x5dd,0}, -1, 1,
698 },
699 {
700 /* Latin, Hebrew, Latin */
701 {'p','a','r','t',' ','o','n','e',' ',0x5d7,0x5dc,0x5e7,' ',0x5e9,0x5ea,0x5d9,0x5d9,0x5dd,' ','p','a','r','t',' ','t','h','r','e','e',0}, -1, 3,
705 },
706 {
707 /* Syriac */
708 {0x710,0x712,0x712,0x714,'.',0}, -1, 1,
710 },
711 {
712 /* Arabic Supplement */
713 {0x750,0x760,0x76d,'.',0}, -1, 1,
715 },
716 {
717 /* Thaana */
718 {0x780,0x78e,0x798,0x7a6,0x7b0,'.',0}, -1, 1,
720 },
721 {
722 /* N'Ko */
723 {0x7c0,0x7ca,0x7e8,0x7eb,0x7f6,'.',0}, -1, 1,
725 },
726 {
727 /* Thaana */
728 {0x780,0x798,0x7a5,0x7a6,0x7b0,'.',0}, -1, 1,
730 },
731 {
732 /* Devanagari */
733 {0x926,0x947,0x935,0x928,0x93e,0x917,0x930,0x940,'.',0}, -1, 1,
735 },
736 {
737 /* Bengali */
738 {0x9ac,0x9be,0x982,0x9b2,0x9be,'.',0}, -1, 1,
740 },
741 {
742 /* Gurmukhi */
743 {0xa17,0xa41,0xa30,0xa2e,0xa41,0xa16,0xa40,'.',0}, -1, 1,
745 },
746 {
747 /* Gujarati */
748 {0xa97,0xac1,0xa9c,0xab0,0xabe,0xaa4,0xac0,'.',0}, -1, 1,
750 },
751 {
752 /* Oriya */
753 {0xb13,0xb21,0xb3c,0xb3f,0xb06,'.',0}, -1, 1,
755 },
756 {
757 /* Tamil */
758 {0xba4,0xbae,0xbbf,0xbb4,0xbcd,'.',0}, -1, 1,
760 },
761 {
762 /* Telugu */
763 {0xc24,0xc46,0xc32,0xc41,0xc17,0xc41,'.',0}, -1, 1,
765 },
766 {
767 /* Kannada */
768 {0xc95,0xca8,0xccd,0xca8,0xca1,'.',0}, -1, 1,
770 },
771 {
772 /* Malayalam */
773 {0xd2e,0xd32,0xd2f,0xd3e,0xd33,0xd02,'.',0}, -1, 1,
775 },
776 {
777 /* Sinhala */
778 {0xd82,0xd85,0xd9a,0xdcf,'.',0}, -1, 1,
780 },
781 {
782 /* Thai */
783 {0x0e04,0x0e27,0x0e32,0x0e21,0x0e1e,0x0e22,0x0e32,0x0e22,0x0e32,0x0e21,
784 0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e44,0x0e2b,0x0e19,
785 0x0e04,0x0e27,0x0e32,0x0e21,0x0e2a, 0x0e33,0x0e40,0x0e23,0x0e47,0x0e08,
786 0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e19,0x0e31,0x0e48,0x0e19,'.',0}, -1, 1,
787 { { 0, 42, DWRITE_SCRIPT_SHAPES_DEFAULT }}
788 },
789 {
790 /* Lao */
791 {0xead,0xeb1,0xe81,0xeaa,0xead,0xe99,0xea5,0xeb2,0xea7,'.',0}, -1, 1,
792 { { 0, 10, DWRITE_SCRIPT_SHAPES_DEFAULT }}
793 },
794 {
795 /* Tibetan */
796 {0xf04,0xf05,0xf0e,0x020,0xf51,0xf7c,0xf53,0xf0b,0xf5a,0xf53,0xf0b,
797 0xf51,0xf44,0xf0b,0xf54,0xf7c,0xf0d,'.',0}, -1, 1,
798 { { 0, 18, DWRITE_SCRIPT_SHAPES_DEFAULT }}
799 },
800 {
801 /* Myanmar */
802 {0x1019,0x103c,0x1014,0x103a,0x1019,0x102c,0x1021,0x1000,0x1039,0x1001,0x101b,0x102c,'.',0}, -1, 1,
803 { { 0, 13, DWRITE_SCRIPT_SHAPES_DEFAULT }}
804 },
805 {
806 /* Georgian */
807 {0x10a0,0x10d0,0x10da,0x10f1,0x10fb,0x2d00,'.',0}, -1, 1,
809 },
810 {
811 /* Hangul */
812 {0x1100,0x1110,0x1160,0x1170,0x11a8,'.',0}, -1, 1,
814 },
815 {
816 /* Ethiopic */
817 {0x130d,0x12d5,0x12dd,0}, -1, 1,
819 },
820 {
821 /* Cherokee */
822 {0x13e3,0x13b3,0x13a9,0x0020,0x13a6,0x13ec,0x13c2,0x13af,0x13cd,0x13d7,0}, -1, 1,
823 { { 0, 10, DWRITE_SCRIPT_SHAPES_DEFAULT }}
824 },
825 {
826 /* Canadian */
827 {0x1403,0x14c4,0x1483,0x144e,0x1450,0x1466,0}, -1, 1,
829 },
830 {
831 /* Ogham */
832 {0x169b,0x1691,0x168c,0x1690,0x168b,0x169c,0}, -1, 1,
834 },
835 {
836 /* Runic */
837 {0x16a0,0x16a1,0x16a2,0x16a3,0x16a4,0x16a5,0}, -1, 1,
839 },
840 {
841 /* Khmer */
842 {0x1781,0x17c1,0x1798,0x179a,0x1797,0x17b6,0x179f,0x17b6,0x19e0,0}, -1, 1,
844 },
845 {
846 /* Mongolian */
847 {0x182e,0x1823,0x1829,0x182d,0x1823,0x182f,0x0020,0x182a,0x1822,0x1834,0x1822,0x182d,0x180c,0}, -1, 1,
848 { { 0, 13, DWRITE_SCRIPT_SHAPES_DEFAULT }}
849 },
850 {
851 /* Limbu */
852 {0x1900,0x1910,0x1920,0x1930,0}, -1, 1,
854 },
855 {
856 /* Tai Le */
857 {0x1956,0x196d,0x1970,0x1956,0x196c,0x1973,0x1951,0x1968,0x1952,0x1970,0}, -1, 1,
858 { { 0, 10, DWRITE_SCRIPT_SHAPES_DEFAULT }}
859 },
860 {
861 /* New Tai Lue */
862 {0x1992,0x19c4,0}, -1, 1,
864 },
865 {
866 /* Buginese */
867 {0x1a00,0x1a10,0}, -1, 1,
869 },
870 {
871 /* Tai Tham */
872 {0x1a20,0x1a40,0x1a50,0}, -1, 1,
874 },
875 {
876 /* Balinese */
877 {0x1b00,0x1b05,0x1b20,0}, -1, 1,
879 },
880 {
881 /* Sundanese */
882 {0x1b80,0x1b85,0x1ba0,0}, -1, 1,
884 },
885 {
886 /* Batak */
887 {0x1bc0,0x1be5,0x1bfc,0}, -1, 1,
889 },
890 {
891 /* Lepcha */
892 {0x1c00,0x1c20,0x1c40,0}, -1, 1,
894 },
895 {
896 /* Ol Chiki */
897 {0x1c50,0x1c5a,0x1c77,0}, -1, 1,
899 },
900 {
901 /* Sundanese Supplement */
902 {0x1cc0,0x1cc5,0x1cc7,0}, -1, 1,
904 },
905 {
906 /* Phonetic Extensions */
907 {0x1d00,0x1d40,0x1d70,0}, -1, 1,
909 },
910 {
911 /* Combining diacritical marks */
912 {0x1dc0,0x300,0x1ddf,0}, -1, 1,
914 },
915 {
916 /* Latin Extended Additional, Extended-C */
917 {0x1e00,0x1d00,0x2c60,0}, -1, 1,
919 },
920 {
921 /* Greek Extended */
922 {0x3f0,0x1f00,0}, -1, 1,
924 },
925 {
926 /* General Punctuation */
927 {0x1dc0,0x2000,0}, -1, 1,
929 },
930 {
931 /* Superscripts and Subscripts */
932 {0x2070,0x2086,0x2000,0}, -1, 1,
934 },
935 {
936 /* Currency, Combining Diacritical Marks for Symbols. Letterlike Symbols.. */
937 {0x20a0,0x20b8,0x2000,0x20d0,0x2100,0x2150,0x2190,0x2200,0x2300,0x2400,0x2440,0x2460,0x2500,0x2580,0x25a0,0x2600,
938 0x2700,0x27c0,0x27f0,0x2900,0x2980,0x2a00,0x2b00,0}, -1, 1,
939 { { 0, 23, DWRITE_SCRIPT_SHAPES_DEFAULT }}
940 },
941 {
942 /* Braille */
943 {0x2800,0x2070,0x2000,0}, -1, 1,
945 },
946 {
947 /* Glagolitic */
948 {0x2c00,0x2c12,0}, -1, 1,
950 },
951 {
952 /* Coptic */
953 {0x2c80,0x3e2,0x1f00,0}, -1, 2,
956 },
957 {
958 /* Tifinagh */
959 {0x2d30,0x2d4a,0}, -1, 1,
961 },
962 {
963 /* LRE/PDF */
964 {LRE,PDF,'a','b','c','\r',0}, -1, 3,
968 },
969 {
970 /* LRE/PDF and other visual and non-visual codes from Common script range */
971 {LRE,PDF,'r','!',0x200b,'\r',0}, -1, 3,
975 },
976 {
977 /* Inherited on its own */
978 {0x300,0x300,0}, -1, 1,
979 { { 0, 2, DWRITE_SCRIPT_SHAPES_DEFAULT } }
980 },
981 {
982 /* Inherited followed by Latin */
983 {0x300,0x300,'a',0}, -1, 1,
984 { { 0, 3, DWRITE_SCRIPT_SHAPES_DEFAULT } }
985 },
986 {
987 /* Inherited mixed with Arabic and Latin */
988 {0x300,'+',0x627,0x300,'a',0}, -1, 2,
991 },
992 {
993 {'a',0x300,'+',0x627,0x300,')','a',0}, -1, 3,
997 },
998 /* Paired punctuation */
999 {
1000 {0x627,'(','a',')','a',0}, -1, 2,
1001 { { 0, 2, DWRITE_SCRIPT_SHAPES_DEFAULT },
1003 },
1004 {
1005 {0x627,'[','a',']',0x627,0}, -1, 3,
1006 { { 0, 2, DWRITE_SCRIPT_SHAPES_DEFAULT },
1009 },
1010 /* Combining marks */
1011 {
1012 /* dotted circle - Common, followed by accent - Inherited */
1013 {0x25cc,0x300,0}, -1, 1,
1014 { { 0, 2, DWRITE_SCRIPT_SHAPES_DEFAULT } }
1015 },
1016 {
1017 /* combining mark with explicit script value */
1018 {0x25cc,0x300,0x5c4,0}, -1, 1,
1019 { { 0, 3, DWRITE_SCRIPT_SHAPES_DEFAULT } }
1020 },
1021 {
1022 /* inherited merges with following explicit script */
1023 {0x25cc,0x300,'a',0}, -1, 1,
1024 { { 0, 3, DWRITE_SCRIPT_SHAPES_DEFAULT } }
1025 },
1026 {
1027 /* TAKRI LETTER A U+11680 */
1028 {0xd805,0xde80,0}, -1, 1,
1029 { { 0, 2, DWRITE_SCRIPT_SHAPES_DEFAULT } }
1030 },
1031 {
1032 /* Musical symbols, U+1D173 */
1033 {0xd834,0xdd73,0}, -1, 1,
1034 { { 0, 2, DWRITE_SCRIPT_SHAPES_NO_VISUAL } }
1035 },
1036 {
1037 /* Tags, U+E0020 */
1038 {0xdb40,0xdc20,0}, -1, 1,
1039 { { 0, 2, DWRITE_SCRIPT_SHAPES_NO_VISUAL } }
1040 },
1041 {
1042 /* Null at start of string */
1043 L"\0test", 5, 2,
1046 },
1047 {
1048 /* Null embedded in string */
1049 L"te\0st", 5, 3,
1050 { { 0, 2, DWRITE_SCRIPT_SHAPES_DEFAULT },
1053 },
1054 {
1055 /* Null at end of string */
1056 L"test\0", 5, 2,
1057 { { 0, 4, DWRITE_SCRIPT_SHAPES_DEFAULT },
1059 },
1060};
1061
1062static void init_expected_sa(struct call_sequence **seq, const struct sa_test *test)
1063{
1064 static const struct call_entry end_of_sequence = { LastKind };
1065 int i;
1066
1068
1069 /* add expected calls */
1070 for (i = 0; i < test->item_count; i++)
1071 {
1072 struct call_entry call;
1073
1074 call.kind = ScriptAnalysis;
1075 call.sa.pos = test->sa[i].pos;
1076 call.sa.len = test->sa[i].len;
1077 call.sa.shapes = test->sa[i].shapes;
1078 add_call(seq, 0, &call);
1079 }
1080
1081 /* and stop marker */
1082 add_call(seq, 0, &end_of_sequence);
1083}
1084
1086{
1087 IDWriteTextAnalyzer *analyzer;
1088 HRESULT hr;
1089
1091
1092 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer);
1093 ok(!!analyzer, "Failed to create analyzer instance.\n");
1094
1095 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &analysissource.IDWriteTextAnalysisSource_iface, 0,
1097 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1098
1099 *sa = g_sa;
1100
1101 IDWriteTextAnalyzer_Release(analyzer);
1102}
1103
1104static void test_AnalyzeScript(void)
1105{
1106 IDWriteTextAnalyzer *analyzer;
1107 HRESULT hr;
1108 UINT i;
1109
1110 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer);
1111 ok(!!analyzer, "Failed to create analyzer instance.\n");
1112
1113 for (i = 0; i < ARRAY_SIZE(sa_tests); i++)
1114 {
1117
1119
1121 hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &analysissource.IDWriteTextAnalysisSource_iface, 0,
1122 sa_tests[i].str_len == -1 ? lstrlenW(sa_tests[i].string) : sa_tests[i].str_len, &analysissink);
1123 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1126
1128 }
1129
1130 IDWriteTextAnalyzer_Release(analyzer);
1131}
1132
1136};
1137
1138static const struct linebreaks_test linebreaks_tests[] =
1139{
1140 { {'A','-','B',' ','C',0x58a,'D',0x2010,'E',0x2012,'F',0x2013,'\t',0xc,0xb,0x2028,0x2029,0x200b,0},
1141 {
1160 }
1161 },
1162 /* Soft hyphen, visible word dividers */
1163 { {'A',0xad,'B',0x5be,'C',0xf0b,'D',0x1361,'E',0x17d8,'F',0x17da,'G',0},
1164 {
1178 }
1179 },
1180 /* LB30 changes in Unicode 13 regarding East Asian parentheses */
1181 { {0x5f35,'G',0x300c,0},
1182 {
1186 }
1187 },
1188 { { 0 } }
1189};
1190
1192{
1193 static const char *conditions[] = {"N","CB","NB","B"};
1194 const WCHAR *text = test->text;
1195 int cmp = memcmp(test->bp, actual, sizeof(*actual)*BREAKPOINT_COUNT);
1196 ok(!cmp, "%s: got wrong breakpoint data\n", wine_dbgstr_w(test->text));
1197 if (cmp) {
1198 int i = 0;
1199 while (*text) {
1200 ok(!memcmp(&test->bp[i], &actual[i], sizeof(*actual)),
1201 "%s: got [%s, %s] (%s, %s), expected [%s, %s] (%s, %s)\n",
1202 wine_dbgstr_wn(&test->text[i], 1),
1203 conditions[g_actual_bp[i].breakConditionBefore],
1204 conditions[g_actual_bp[i].breakConditionAfter],
1205 g_actual_bp[i].isWhitespace ? "WS" : "0",
1206 g_actual_bp[i].isSoftHyphen ? "SHY" : "0",
1207 conditions[test->bp[i].breakConditionBefore],
1208 conditions[test->bp[i].breakConditionAfter],
1209 test->bp[i].isWhitespace ? "WS" : "0",
1210 test->bp[i].isSoftHyphen ? "SHY" : "0");
1211 if (g_actual_bp[i].isSoftHyphen)
1212 ok(!g_actual_bp[i].isWhitespace, "%s: soft hyphen marked as a whitespace\n",
1213 wine_dbgstr_wn(&test->text[i], 1));
1214 text++;
1215 i++;
1216 }
1217 }
1218}
1219
1221{
1222 const struct linebreaks_test *ptr = linebreaks_tests;
1223 IDWriteTextAnalyzer *analyzer;
1224 UINT32 i = 0;
1225 HRESULT hr;
1226
1227 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer);
1228 ok(!!analyzer, "Failed to create analyzer instance.\n");
1229
1231 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &analysissource.IDWriteTextAnalysisSource_iface, 0, 0,
1232 &analysissink);
1233 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1234
1235 while (*ptr->text)
1236 {
1237 UINT32 len;
1238
1240
1241 len = lstrlenW(ptr->text);
1242 if (len > BREAKPOINT_COUNT) {
1243 ok(0, "test %u: increase BREAKPOINT_COUNT to at least %u\n", i, len);
1244 i++;
1245 ptr++;
1246 continue;
1247 }
1248
1249 memset(g_actual_bp, 0, sizeof(g_actual_bp));
1250 hr = IDWriteTextAnalyzer_AnalyzeLineBreakpoints(analyzer, &analysissource.IDWriteTextAnalysisSource_iface,
1251 0, len, &analysissink);
1252 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1254
1255 i++;
1256 ptr++;
1257 }
1258
1259 IDWriteTextAnalyzer_Release(analyzer);
1260}
1261
1263{
1264 IDWriteTextAnalyzer1 *analyzer;
1267 HRESULT hr;
1268
1269 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer1);
1270 if (!analyzer)
1271 {
1272 win_skip("GetScriptProperties() is not supported.\n");
1273 return;
1274 }
1275
1276 sa.script = 1000;
1277 hr = IDWriteTextAnalyzer1_GetScriptProperties(analyzer, sa, &props);
1278 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1279
1280 if (0) /* Crashes on Windows */
1281 hr = IDWriteTextAnalyzer1_GetScriptProperties(analyzer, sa, NULL);
1282
1283 sa.script = 0;
1284 hr = IDWriteTextAnalyzer1_GetScriptProperties(analyzer, sa, &props);
1285 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1286
1287 IDWriteTextAnalyzer1_Release(analyzer);
1288}
1289
1291 const WCHAR text[5];
1295};
1296
1298 { {0}, 1, FALSE, 1 },
1299 { {0}, 0, TRUE, 0 },
1300 { {0x610,0}, 0, TRUE, 0 },
1301 { {'A','B','C','D',0}, 3, TRUE, 3 },
1302 { {'A','B','C','D',0}, 5, TRUE, 4 },
1303 { {'A','B','C','D',0}, 10, TRUE, 4 },
1304 { {'A',0x610,'C','D',0}, 1, TRUE, 1 },
1305 { {'A',0x610,'C','D',0}, 2, FALSE, 2 },
1306 { {0x610,'A','C','D',0}, 1, FALSE, 1 },
1307 { {0x610,'A','C','D',0}, 2, FALSE, 1 },
1308 { {0x610,0x610,'C','D',0}, 2, FALSE, 2 },
1309 { {0xd800,'A','B',0}, 1, FALSE, 1 },
1310 { {0xd800,'A','B',0}, 2, FALSE, 1 },
1311 { {0xdc00,'A','B',0}, 2, FALSE, 1 },
1312 { {0x202a,'A',0x202c,0}, 3, FALSE, 1 },
1313 { {0x200e,'A',0}, 2, FALSE, 1 },
1314 { {0x200f,'A',0}, 2, FALSE, 1 },
1315 { {0x202d,'A',0}, 2, FALSE, 1 },
1316 { {0x202e,'A',0}, 2, FALSE, 1 },
1317
1318};
1319
1320static void test_GetTextComplexity(void)
1321{
1322 IDWriteTextAnalyzer1 *analyzer;
1323 IDWriteFontFace *fontface;
1324 UINT16 indices[10];
1325 BOOL simple;
1326 HRESULT hr;
1327 UINT32 len;
1328 int i;
1329
1330 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer1);
1331 if (!analyzer)
1332 {
1333 win_skip("GetTextComplexity() is not supported.\n");
1334 return;
1335 }
1336
1337if (0) { /* crashes on native */
1338 hr = IDWriteTextAnalyzer1_GetTextComplexity(analyzer, NULL, 0, NULL, NULL, NULL, NULL);
1339 hr = IDWriteTextAnalyzer1_GetTextComplexity(analyzer, NULL, 0, NULL, NULL, &len, NULL);
1340 hr = IDWriteTextAnalyzer1_GetTextComplexity(analyzer, L"ABC", 3, NULL, NULL, NULL, NULL);
1341 hr = IDWriteTextAnalyzer1_GetTextComplexity(analyzer, L"ABC", 3, NULL, NULL, &len, NULL);
1342 hr = IDWriteTextAnalyzer1_GetTextComplexity(analyzer, L"ABC", 3, NULL, &simple, NULL, NULL);
1343}
1344
1345 len = 1;
1346 simple = TRUE;
1347 hr = IDWriteTextAnalyzer1_GetTextComplexity(analyzer, NULL, 0, NULL, &simple, &len, NULL);
1348 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1349 ok(len == 0, "got %d\n", len);
1350 ok(simple == FALSE, "got %d\n", simple);
1351
1352 len = 1;
1353 simple = TRUE;
1354 indices[0] = 1;
1355 hr = IDWriteTextAnalyzer1_GetTextComplexity(analyzer, L"ABC", 3, NULL, &simple, &len, NULL);
1356 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1357 ok(len == 0, "got %d\n", len);
1358 ok(simple == FALSE, "got %d\n", simple);
1359 ok(indices[0] == 1, "got %d\n", indices[0]);
1360
1361 fontface = create_fontface();
1362
1363 for (i = 0; i < ARRAY_SIZE(textcomplexity_tests); ++i)
1364 {
1366 len = 1;
1367 simple = !ptr->simple;
1368 indices[0] = 0;
1369 hr = IDWriteTextAnalyzer1_GetTextComplexity(analyzer, ptr->text, ptr->length, fontface, &simple, &len, indices);
1370 ok(hr == S_OK, "%d: Unexpected hr %#lx.\n", i, hr);
1371 ok(len == ptr->len_read, "%d: read length: got %d, expected %d\n", i, len, ptr->len_read);
1372 ok(simple == ptr->simple, "%d: simple: got %d, expected %d\n", i, simple, ptr->simple);
1373 if (simple && ptr->length)
1374 ok(indices[0] > 0, "%d: got %d\n", i, indices[0]);
1375 else
1376 ok(indices[0] == 0, "%d: got %d\n", i, indices[0]);
1377 }
1378
1379 IDWriteFontFace_Release(fontface);
1380 IDWriteTextAnalyzer1_Release(analyzer);
1381}
1382
1384{
1385 IDWriteNumberSubstitution *substitution;
1386 HRESULT hr;
1387
1388 /* locale is not specified, method does not require it */
1389 hr = IDWriteFactory_CreateNumberSubstitution(factory, DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, NULL, FALSE, &substitution);
1390 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1391 IDWriteNumberSubstitution_Release(substitution);
1392
1393 /* invalid locale name, method does not require it */
1394 hr = IDWriteFactory_CreateNumberSubstitution(factory, DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, L"dummy",
1395 FALSE, &substitution);
1396 ok(hr == S_OK, "Failed to create number substitution, hr %#lx.\n", hr);
1397 IDWriteNumberSubstitution_Release(substitution);
1398
1399 /* invalid method */
1400 hr = IDWriteFactory_CreateNumberSubstitution(factory, DWRITE_NUMBER_SUBSTITUTION_METHOD_TRADITIONAL+1, NULL, FALSE, &substitution);
1401 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1402
1403 /* invalid method */
1404 hr = IDWriteFactory_CreateNumberSubstitution(factory, -1, NULL, FALSE, &substitution);
1405 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1406
1407 /* invalid locale */
1408 hr = IDWriteFactory_CreateNumberSubstitution(factory, DWRITE_NUMBER_SUBSTITUTION_METHOD_TRADITIONAL, NULL, FALSE, &substitution);
1409 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1410
1411 hr = IDWriteFactory_CreateNumberSubstitution(factory, DWRITE_NUMBER_SUBSTITUTION_METHOD_TRADITIONAL, L"dummy",
1412 FALSE, &substitution);
1413 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1414
1415 hr = IDWriteFactory_CreateNumberSubstitution(factory, DWRITE_NUMBER_SUBSTITUTION_METHOD_CONTEXTUAL, L"dummy",
1416 FALSE, &substitution);
1417 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1418
1419 hr = IDWriteFactory_CreateNumberSubstitution(factory, DWRITE_NUMBER_SUBSTITUTION_METHOD_NATIONAL, L"dummy",
1420 FALSE, &substitution);
1421 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
1422
1423 /* invalid locale, but it's not needed for this method */
1424 hr = IDWriteFactory_CreateNumberSubstitution(factory, DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE, L"dummy", FALSE,
1425 &substitution);
1426 ok(hr == S_OK, "Failed to create number substitution, hr %#lx.\n", hr);
1427 IDWriteNumberSubstitution_Release(substitution);
1428}
1429
1430static void get_fontface_glyphs(IDWriteFontFace *fontface, const WCHAR *str, UINT16 *glyphs)
1431{
1432 while (*str) {
1433 UINT32 codepoint = *str;
1434 HRESULT hr;
1435
1436 hr = IDWriteFontFace_GetGlyphIndices(fontface, &codepoint, 1, glyphs++);
1437 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1438 str++;
1439 }
1440}
1441
1442static void get_fontface_advances(IDWriteFontFace *fontface, FLOAT emsize, const UINT16 *glyphs, FLOAT *advances, UINT32 count)
1443{
1444 DWRITE_FONT_METRICS fontmetrics;
1445 UINT32 i;
1446
1447 IDWriteFontFace_GetMetrics(fontface, &fontmetrics);
1448 for (i = 0; i < count; i++) {
1450 HRESULT hr;
1451
1452 hr = IDWriteFontFace_GetDesignGlyphMetrics(fontface, glyphs + i, 1, &metrics, FALSE);
1453 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1454
1455 advances[i] = (FLOAT)metrics.advanceWidth * emsize / (FLOAT)fontmetrics.designUnitsPerEm;
1456 }
1457}
1458
1460{
1467};
1468
1469struct dwrite_fonttable
1470{
1472 void *context;
1473 unsigned int size;
1474};
1475
1476static const void *table_read_ensure(const struct dwrite_fonttable *table, unsigned int offset, unsigned int size)
1477{
1478 if (size > table->size || offset > table->size - size)
1479 return NULL;
1480
1481 return table->data + offset;
1482}
1483
1484static WORD table_read_be_word(const struct dwrite_fonttable *table, unsigned int offset)
1485{
1486 const WORD *ptr = table_read_ensure(table, offset, sizeof(*ptr));
1487 return ptr ? GET_BE_WORD(*ptr) : 0;
1488}
1489
1490static int gdef_class_compare_format2(const void *g, const void *r)
1491{
1492 const struct ot_gdef_class_range *range = r;
1493 UINT16 glyph = *(UINT16 *)g;
1494
1495 if (glyph < GET_BE_WORD(range->start_glyph))
1496 return -1;
1497 else if (glyph > GET_BE_WORD(range->end_glyph))
1498 return 1;
1499 else
1500 return 0;
1501}
1502
1503static unsigned int get_glyph_class(const struct dwrite_fonttable *table, UINT16 glyph)
1504{
1506 WORD format, count;
1507
1509
1511
1512 if (format == 1)
1513 {
1514 const struct ot_gdef_classdef_format1 *format1;
1515
1518 if (format1)
1519 {
1521 if (glyph >= start_glyph && (glyph - start_glyph) < count)
1522 {
1523 glyph_class = GET_BE_WORD(format1->classes[glyph - start_glyph]);
1524 if (glyph_class > GDEF_CLASS_MAX)
1525 glyph_class = GDEF_CLASS_UNCLASSIFIED;
1526 }
1527 }
1528 }
1529 else if (format == 2)
1530 {
1531 const struct ot_gdef_classdef_format2 *format2;
1532
1535 if (format2)
1536 {
1537 const struct ot_gdef_class_range *range = bsearch(&glyph, format2->ranges, count,
1539 glyph_class = range && glyph <= GET_BE_WORD(range->end_glyph) ?
1543 }
1544 }
1545
1546 return glyph_class;
1547}
1548
1550{
1551 BOOL exists = FALSE;
1552 unsigned int index;
1553 HRESULT hr;
1554
1555 hr = IDWriteLocalizedStrings_FindLocaleName(strings, L"en-us", &index, &exists);
1556 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1557
1558 /* Not all fonts have an en-us name! */
1559 if (!exists)
1560 index = 0;
1561
1562 hr = IDWriteLocalizedStrings_GetString(strings, index, buff, size);
1563 ok(hr == S_OK, "Failed to get name string, hr %#lx.\n", hr);
1564}
1565
1566static void test_glyph_props(IDWriteTextAnalyzer *analyzer, const WCHAR *family, const WCHAR *face,
1567 IDWriteFontFace *fontface)
1568{
1569 unsigned int i, ch, count, offset;
1570 struct dwrite_fonttable gdef;
1571 DWRITE_UNICODE_RANGE *ranges;
1572 IDWriteFontFace1 *fontface1;
1573 BOOL exists = FALSE;
1574 HRESULT hr;
1575
1576 hr = IDWriteFontFace_TryGetFontTable(fontface, MS_GDEF_TAG, (const void **)&gdef.data, &gdef.size,
1577 &gdef.context, &exists);
1578 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1579
1580 if (!exists)
1581 return;
1582
1583 offset = table_read_be_word(&gdef, 4);
1584 if (!offset)
1585 {
1586 IDWriteFontFace_ReleaseFontTable(fontface, gdef.context);
1587 return;
1588 }
1589
1590 if (FAILED(IDWriteFontFace_QueryInterface(fontface, &IID_IDWriteFontFace1, (void **)&fontface1)))
1591 {
1592 IDWriteFontFace_ReleaseFontTable(fontface, gdef.context);
1593 return;
1594 }
1595
1596 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, 0, NULL, &count);
1597 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1598
1599 ranges = malloc(count * sizeof(*ranges));
1600
1601 hr = IDWriteFontFace1_GetUnicodeRanges(fontface1, count, ranges, &count);
1602 ok(hr == S_OK, "Failed to get ranges, hr %#lx.\n", hr);
1603
1604 for (i = 0; i < count; ++i)
1605 {
1606 if (ranges[i].first > 0xffff)
1607 break;
1608
1609 for (ch = ranges[i].first; ch <= ranges[i].last; ch++)
1610 {
1611 DWRITE_SHAPING_TEXT_PROPERTIES text_props[10];
1612 DWRITE_SHAPING_GLYPH_PROPERTIES glyph_props[10];
1613 UINT16 glyphs[10], clustermap[10], glyph;
1614 unsigned int actual_count, glyph_class;
1616 WCHAR text[1];
1617
1618 hr = IDWriteFontFace1_GetGlyphIndices(fontface1, &ch, 1, &glyph);
1619 ok(hr == S_OK, "Failed to get glyph index, hr %#lx.\n", hr);
1620
1621 if (!glyph)
1622 continue;
1623
1624 sa.script = 999;
1626 text[0] = (WCHAR)ch;
1627 memset(glyph_props, 0, sizeof(glyph_props));
1628 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, text, 1, fontface, FALSE, FALSE, &sa, NULL,
1629 NULL, NULL, NULL, 0, ARRAY_SIZE(glyphs), clustermap, text_props, glyphs, glyph_props, &actual_count);
1630 ok(hr == S_OK, "Failed to shape, hr %#lx.\n", hr);
1631 if (actual_count > 1)
1632 continue;
1633
1634 glyph_class = get_glyph_class(&gdef, glyphs[0]);
1635
1636 switch (glyph_class)
1637 {
1638 case GDEF_CLASS_MARK:
1639 ok(glyph_props[0].isDiacritic && glyph_props[0].isZeroWidthSpace,
1640 "%#x -> %u: unexpected glyph properties %u/%u. Class %u. Font %s - %s.\n",
1641 text[0], glyphs[0], glyph_props[0].isDiacritic, glyph_props[0].isZeroWidthSpace,
1642 glyph_class, wine_dbgstr_w(family), wine_dbgstr_w(face));
1643 break;
1644 default:
1645 break;
1646 }
1647
1648 if (glyph_props[0].isDiacritic)
1649 ok(glyph_props[0].isZeroWidthSpace,
1650 "%#x -> %u: unexpected glyph properties %u/%u. Class %u. Font %s - %s.\n", text[0], glyphs[0],
1651 glyph_props[0].isDiacritic, glyph_props[0].isZeroWidthSpace, glyph_class,
1652 wine_dbgstr_w(family), wine_dbgstr_w(face));
1653 }
1654 }
1655
1656 free(ranges);
1657
1658 IDWriteFontFace_ReleaseFontTable(fontface, gdef.context);
1659 IDWriteFontFace1_Release(fontface1);
1660}
1661
1662static void test_GetGlyphs(void)
1663{
1664 static const WCHAR test1W[] = {'<','B',' ','C',0};
1665 static const WCHAR test2W[] = {'<','B','\t','C',0};
1666 static const WCHAR test3W[] = {0x202a,0x202c,0};
1667 DWRITE_SHAPING_GLYPH_PROPERTIES shapingprops[20];
1669 UINT32 maxglyphcount, actual_count;
1670 FLOAT advances[10], advances2[10];
1671 IDWriteFontCollection *syscoll;
1672 IDWriteTextAnalyzer *analyzer;
1673 IDWriteFontFace *fontface;
1676 UINT16 clustermap[10];
1677 UINT16 glyphs1[10];
1678 UINT16 glyphs2[10];
1679 unsigned int i, j;
1680 HRESULT hr;
1681
1682 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer);
1683 ok(!!analyzer, "Failed to create analyzer instance.\n");
1684
1685 fontface = create_fontface();
1686
1687 maxglyphcount = 1;
1688 sa.script = 0;
1690 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test1W, lstrlenW(test1W), fontface, FALSE, FALSE, &sa, NULL,
1691 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs1, shapingprops, &actual_count);
1692 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1693
1694if (0) {
1695 /* NULL fontface - crashes on Windows */
1696 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test1W, lstrlenW(test1W), NULL, FALSE, FALSE, &sa, NULL,
1697 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs1, shapingprops, &actual_count);
1698}
1699
1700 /* invalid script id */
1701 maxglyphcount = 10;
1702 actual_count = 0;
1703 sa.script = 999;
1705 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test1W, lstrlenW(test1W), fontface, FALSE, FALSE, &sa, NULL,
1706 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs1, shapingprops, &actual_count);
1707 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1708 ok(actual_count == 4, "got %d\n", actual_count);
1709 ok(sa.script == 999, "got %u\n", sa.script);
1710
1711 /* no '\t' -> ' ' replacement */
1712 maxglyphcount = 10;
1713 actual_count = 0;
1714 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test1W, lstrlenW(test1W), fontface, FALSE, FALSE, &sa, NULL,
1715 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs1, shapingprops, &actual_count);
1716 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1717 ok(actual_count == 4, "got %d\n", actual_count);
1718
1719 actual_count = 0;
1720 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test2W, lstrlenW(test2W), fontface, FALSE, FALSE, &sa, NULL,
1721 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs2, shapingprops, &actual_count);
1722 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1723 ok(actual_count == 4, "got %d\n", actual_count);
1724 ok(glyphs1[2] != glyphs2[2], "got %d\n", glyphs1[2]);
1725
1726 /* check that mirroring works */
1727 maxglyphcount = 10;
1728 actual_count = 0;
1729 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test1W, lstrlenW(test1W), fontface, FALSE, FALSE, &sa, NULL,
1730 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs1, shapingprops, &actual_count);
1731 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1732 ok(actual_count == 4, "got %d\n", actual_count);
1733
1734 actual_count = 0;
1735 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test1W, lstrlenW(test1W), fontface, FALSE, TRUE, &sa, NULL,
1736 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs2, shapingprops, &actual_count);
1737 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1738 ok(actual_count == 4, "got %d\n", actual_count);
1739 ok(glyphs1[0] != glyphs2[0], "got %d\n", glyphs1[0]);
1740
1741 /* embedded control codes, with unknown script id 0 */
1742 get_fontface_glyphs(fontface, test3W, glyphs2);
1743 get_fontface_advances(fontface, 10.0, glyphs2, advances2, 2);
1744
1745 actual_count = 0;
1746 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test3W, lstrlenW(test3W), fontface, FALSE, TRUE, &sa, NULL,
1747 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs1, shapingprops, &actual_count);
1748 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1749 ok(actual_count == 2, "got %d\n", actual_count);
1750 ok(glyphs1[0] == glyphs2[0], "got %u, expected %u\n", glyphs1[0], glyphs2[0]);
1751 ok(glyphs1[1] == glyphs2[1], "got %u, expected %u\n", glyphs1[1], glyphs2[1]);
1752 ok(shapingprops[0].isClusterStart == 1, "got %d\n", shapingprops[0].isClusterStart);
1753 ok(shapingprops[0].isZeroWidthSpace == 0, "got %d\n", shapingprops[0].isZeroWidthSpace);
1754 ok(shapingprops[1].isClusterStart == 1, "got %d\n", shapingprops[1].isClusterStart);
1755 ok(shapingprops[1].isZeroWidthSpace == 0, "got %d\n", shapingprops[1].isZeroWidthSpace);
1756 ok(clustermap[0] == 0, "got %d\n", clustermap[0]);
1757 ok(clustermap[1] == 1, "got %d\n", clustermap[1]);
1758
1759 memset(advances, 0, sizeof(advances));
1760 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, test3W, clustermap, props, lstrlenW(test3W),
1761 glyphs1, shapingprops, actual_count, fontface, 10.0, FALSE, FALSE, &sa, NULL, NULL,
1762 NULL, 0, advances, offsets);
1763 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1764 ok(advances[0] == advances2[0], "got %.2f, expected %.2f\n", advances[0], advances2[0]);
1765 ok(advances[1] == advances2[1], "got %.2f, expected %.2f\n", advances[1], advances2[1]);
1766
1767 /* embedded control codes with proper script */
1768 sa.script = 0;
1769 get_script_analysis(test3W, &sa);
1770 ok(sa.script != 0, "got %d\n", sa.script);
1771 actual_count = 0;
1772 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test3W, lstrlenW(test3W), fontface, FALSE, FALSE, &sa, NULL,
1773 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs1, shapingprops, &actual_count);
1774 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1775 ok(actual_count == 2, "got %d\n", actual_count);
1776 ok(glyphs1[0] == glyphs2[0], "got %u, expected %u\n", glyphs1[0], glyphs2[0]);
1777 ok(glyphs1[1] == glyphs2[1], "got %u, expected %u\n", glyphs1[1], glyphs2[1]);
1778 ok(shapingprops[0].isClusterStart == 1, "got %d\n", shapingprops[0].isClusterStart);
1779 ok(shapingprops[0].isZeroWidthSpace == 0, "got %d\n", shapingprops[0].isZeroWidthSpace);
1780 ok(shapingprops[1].isClusterStart == 1, "got %d\n", shapingprops[1].isClusterStart);
1781 ok(shapingprops[1].isZeroWidthSpace == 0, "got %d\n", shapingprops[1].isZeroWidthSpace);
1782 ok(clustermap[0] == 0, "got %d\n", clustermap[0]);
1783 ok(clustermap[1] == 1, "got %d\n", clustermap[1]);
1784
1785 memset(advances, 0, sizeof(advances));
1786 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, test3W, clustermap, props, lstrlenW(test3W),
1787 glyphs1, shapingprops, actual_count, fontface, 10.0, FALSE, FALSE, &sa, NULL, NULL,
1788 NULL, 0, advances, offsets);
1789 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1790 ok(advances[0] == advances2[0], "got %.2f, expected %.2f\n", advances[0], advances2[0]);
1791 ok(advances[1] == advances2[1], "got %.2f, expected %.2f\n", advances[1], advances2[1]);
1792
1793 /* DWRITE_SCRIPT_SHAPES_NO_VISUAL run */
1794 maxglyphcount = 10;
1795 actual_count = 0;
1796 sa.script = 0;
1798 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, test1W, lstrlenW(test1W), fontface, FALSE, FALSE, &sa, NULL,
1799 NULL, NULL, NULL, 0, maxglyphcount, clustermap, props, glyphs1, shapingprops, &actual_count);
1800 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1801 ok(actual_count == 4, "got %d\n", actual_count);
1802 ok(sa.script == 0, "got %u\n", sa.script);
1803 ok(!shapingprops[0].isZeroWidthSpace, "got %d\n", shapingprops[0].isZeroWidthSpace);
1804
1805 IDWriteFontFace_Release(fontface);
1806
1807 /* Test setting glyph properties from GDEF. */
1808 hr = IDWriteFactory_GetSystemFontCollection(factory, &syscoll, FALSE);
1809 ok(hr == S_OK, "Failed to get system collection, hr %#lx.\n", hr);
1810
1811 for (i = 0; i < IDWriteFontCollection_GetFontFamilyCount(syscoll); ++i)
1812 {
1814 IDWriteFontFamily *family;
1815 WCHAR familyW[256];
1816
1817 hr = IDWriteFontCollection_GetFontFamily(syscoll, i, &family);
1818 ok(hr == S_OK, "Failed to get font family, hr %#lx.\n", hr);
1819
1820 hr = IDWriteFontFamily_GetFamilyNames(family, &names);
1821 ok(hr == S_OK, "Failed to get family names, hr %#lx.\n", hr);
1822 get_enus_string(names, familyW, ARRAY_SIZE(familyW));
1823 IDWriteLocalizedStrings_Release(names);
1824
1825 for (j = 0; j < IDWriteFontFamily_GetFontCount(family); ++j)
1826 {
1828 WCHAR faceW[256];
1829
1830 hr = IDWriteFontFamily_GetFont(family, j, &font);
1831 ok(hr == S_OK, "Failed to get font instance, hr %#lx.\n", hr);
1832
1833 hr = IDWriteFont_CreateFontFace(font, &fontface);
1834 ok(hr == S_OK, "Failed to create fontface, hr %#lx.\n", hr);
1835
1836 hr = IDWriteFont_GetFaceNames(font, &names);
1837 ok(hr == S_OK, "Failed to get face names, hr %#lx.\n", hr);
1838 get_enus_string(names, faceW, ARRAY_SIZE(faceW));
1839 IDWriteLocalizedStrings_Release(names);
1840
1841 test_glyph_props(analyzer, familyW, faceW, fontface);
1842
1843 IDWriteFontFace_Release(fontface);
1844 IDWriteFont_Release(font);
1845 }
1846
1847 IDWriteFontFamily_Release(family);
1848 }
1849
1850 IDWriteFontCollection_Release(syscoll);
1851
1852 IDWriteTextAnalyzer_Release(analyzer);
1853}
1854
1856{
1857 static const WCHAR arabicW[] = {0x064a,0x064f,0x0633,0};
1859 IDWriteTextAnalyzer2 *analyzer;
1860 IDWriteFontFace *fontface;
1862 UINT32 count;
1863 HRESULT hr;
1864
1865 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer2);
1866 if (!analyzer)
1867 {
1868 win_skip("GetTypographicFeatures() is not supported.\n");
1869 return;
1870 }
1871
1872 fontface = create_fontface();
1873
1874 get_script_analysis(L"abc", &sa);
1875 count = 0;
1876 hr = IDWriteTextAnalyzer2_GetTypographicFeatures(analyzer, fontface, sa, NULL, 0, &count, NULL);
1877 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1878 ok(!!count, "Unexpected count %u.\n", count);
1879
1880 /* invalid locale name is ignored */
1881 get_script_analysis(L"abc", &sa);
1882 count = 0;
1883 hr = IDWriteTextAnalyzer2_GetTypographicFeatures(analyzer, fontface, sa, L"cadabra", 0, &count, NULL);
1884 ok(hr == E_NOT_SUFFICIENT_BUFFER, "Unexpected hr %#lx.\n", hr);
1885 ok(!!count, "Unexpected count %u.\n", count);
1886
1887 /* Make some calls for different scripts. */
1888
1889 get_script_analysis(arabicW, &sa);
1890 memset(tags, 0, sizeof(tags));
1891 count = 0;
1892 hr = IDWriteTextAnalyzer2_GetTypographicFeatures(analyzer, fontface, sa, NULL, ARRAY_SIZE(tags), &count, tags);
1893 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1894 ok(!!count, "Unexpected count %u.\n", count);
1895
1896 get_script_analysis(L"abc", &sa);
1897 memset(tags, 0, sizeof(tags));
1898 count = 0;
1899 hr = IDWriteTextAnalyzer2_GetTypographicFeatures(analyzer, fontface, sa, NULL, ARRAY_SIZE(tags), &count, tags);
1900 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1901 ok(!!count, "Unexpected count %u.\n", count);
1902
1903 IDWriteFontFace_Release(fontface);
1904 IDWriteTextAnalyzer2_Release(analyzer);
1905}
1906
1908{
1909 DWRITE_SHAPING_GLYPH_PROPERTIES glyphprops[2];
1910 DWRITE_SHAPING_TEXT_PROPERTIES textprops[2];
1911 static const WCHAR aW[] = {'A','D',0};
1912 UINT16 clustermap[2], glyphs[2];
1914 IDWriteTextAnalyzer *analyzer;
1915 IDWriteFontFace *fontface;
1917 FLOAT advances[2];
1918 UINT32 count, len;
1919 WCHAR *path;
1920 HRESULT hr;
1921
1922 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer);
1923 ok(!!analyzer, "Failed to create analyzer instance.\n");
1924
1925 path = create_testfontfile(L"wine_test_font.ttf");
1926 fontface = create_testfontface(path);
1927
1929 count = 0;
1930 len = lstrlenW(aW);
1931 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, aW, len, fontface, FALSE, FALSE, &sa, NULL,
1932 NULL, NULL, NULL, 0, len, clustermap, textprops, glyphs, glyphprops, &count);
1933 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1934 ok(count == 2, "got %u\n", count);
1935
1936 /* just return on zero glyphs */
1937 advances[0] = advances[1] = 1.0;
1938 offsets[0].advanceOffset = offsets[0].ascenderOffset = 2.0;
1939 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops,
1940 len, glyphs, glyphprops, 0, fontface, 0.0, FALSE, FALSE, &sa, NULL, NULL,
1941 NULL, 0, advances, offsets);
1942 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1943 ok(advances[0] == 1.0, "got %.2f\n", advances[0]);
1944 ok(offsets[0].advanceOffset == 2.0 && offsets[0].ascenderOffset == 2.0, "got %.2f,%.2f\n",
1945 offsets[0].advanceOffset, offsets[0].ascenderOffset);
1946
1947 /* advances/offsets are scaled with provided font emSize and designed eM box size */
1948 advances[0] = advances[1] = 1.0;
1949 memset(offsets, 0xcc, sizeof(offsets));
1950 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops,
1951 len, glyphs, glyphprops, len, fontface, 0.0, FALSE, FALSE, &sa, NULL, NULL,
1952 NULL, 0, advances, offsets);
1953 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1954 ok(advances[0] == 0.0, "got %.2f\n", advances[0]);
1955 ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n",
1956 offsets[0].advanceOffset, offsets[0].ascenderOffset);
1957
1958 advances[0] = advances[1] = 1.0;
1959 memset(offsets, 0xcc, sizeof(offsets));
1960 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops,
1961 len, glyphs, glyphprops, len, fontface, 2048.0, FALSE, FALSE, &sa, NULL, NULL,
1962 NULL, 0, advances, offsets);
1963 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1964 ok(advances[0] == 1000.0, "got %.2f\n", advances[0]);
1965 ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n",
1966 offsets[0].advanceOffset, offsets[0].ascenderOffset);
1967
1968 advances[0] = advances[1] = 1.0;
1969 memset(offsets, 0xcc, sizeof(offsets));
1970 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops,
1971 len, glyphs, glyphprops, len, fontface, 1024.0, FALSE, FALSE, &sa, NULL, NULL,
1972 NULL, 0, advances, offsets);
1973 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1974 ok(advances[0] == 500.0, "got %.2f\n", advances[0]);
1975 ok(advances[1] == 500.0, "got %.2f\n", advances[1]);
1976 ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n",
1977 offsets[0].advanceOffset, offsets[0].ascenderOffset);
1978
1979 advances[0] = advances[1] = 1.0;
1980 memset(offsets, 0xcc, sizeof(offsets));
1981 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops,
1982 len, glyphs, glyphprops, len, fontface, 20.48, FALSE, FALSE, &sa, NULL, NULL,
1983 NULL, 0, advances, offsets);
1984 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1985 ok(advances[0] == 10.0, "got %.2f\n", advances[0]);
1986 ok(advances[1] == 10.0, "got %.2f\n", advances[1]);
1987 ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n",
1988 offsets[0].advanceOffset, offsets[0].ascenderOffset);
1989
1990 /* without clustermap */
1991 advances[0] = advances[1] = 1.0;
1992 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, NULL, textprops,
1993 len, glyphs, glyphprops, len, fontface, 1024.0, FALSE, FALSE, &sa, NULL, NULL,
1994 NULL, 0, advances, offsets);
1995 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
1996 ok(advances[0] == 500.0, "got %.2f\n", advances[0]);
1997 ok(advances[1] == 500.0, "got %.2f\n", advances[1]);
1998
1999 /* it's happy to use negative size too */
2000 advances[0] = advances[1] = 1.0;
2001 memset(offsets, 0xcc, sizeof(offsets));
2002 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops,
2003 len, glyphs, glyphprops, len, fontface, -10.24, FALSE, FALSE, &sa, NULL, NULL,
2004 NULL, 0, advances, offsets);
2005 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2006 ok(advances[0] == -5.0, "got %.2f\n", advances[0]);
2007 ok(offsets[0].advanceOffset == 0.0 && offsets[0].ascenderOffset == 0.0, "got %.2f,%.2f\n",
2008 offsets[0].advanceOffset, offsets[0].ascenderOffset);
2009
2010 /* DWRITE_SCRIPT_SHAPES_NO_VISUAL has no effect on placement */
2012 advances[0] = advances[1] = 1.0f;
2013 memset(offsets, 0xcc, sizeof(offsets));
2014 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops,
2015 len, glyphs, glyphprops, len, fontface, 2048.0f, FALSE, FALSE, &sa, NULL, NULL,
2016 NULL, 0, advances, offsets);
2017 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2018 ok(advances[0] == 1000.0f, "got %.2f\n", advances[0]);
2019 ok(advances[1] == 1000.0f, "got %.2f\n", advances[1]);
2020 ok(offsets[0].advanceOffset == 0.0f && offsets[0].ascenderOffset == 0.0f, "got %.2f,%.2f\n",
2021 offsets[0].advanceOffset, offsets[0].ascenderOffset);
2022
2023 /* isZeroWidthSpace */
2025 advances[0] = advances[1] = 1.0f;
2026 memset(offsets, 0xcc, sizeof(offsets));
2027 glyphprops[0].isZeroWidthSpace = 1;
2028 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, aW, clustermap, textprops,
2029 len, glyphs, glyphprops, len, fontface, 2048.0f, FALSE, FALSE, &sa, NULL, NULL,
2030 NULL, 0, advances, offsets);
2031 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2032 ok(advances[0] == 0.0f, "got %.2f\n", advances[0]);
2033 ok(advances[1] == 1000.0f, "got %.2f\n", advances[1]);
2034 ok(offsets[0].advanceOffset == 0.0f && offsets[0].ascenderOffset == 0.0f, "got %.2f,%.2f\n",
2035 offsets[0].advanceOffset, offsets[0].ascenderOffset);
2036
2037 IDWriteTextAnalyzer_Release(analyzer);
2038 IDWriteFontFace_Release(fontface);
2040}
2041
2052};
2053
2054static const struct spacing_test spacing_tests[] =
2055{
2056/* Default spacing glyph properties. */
2057#define P_S { 0 }
2058/* isZeroWidthSpace */
2059#define P_Z { 0, 0, 0, 1, 0 }
2060/* isDiacritic */
2061#define P_D { 0, 0, 1, 0, 0 }
2062/* isDiacritic + isZeroWidthSpace, that's how diacritics are shaped. */
2063#define P_D_Z { 0, 0, 1, 1, 0 }
2064
2065 { 0.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 } }, /* 0 */
2066 { 0.0, 0.0, 2.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 } },
2067 { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, { 3.0, 4.0 } },
2068 { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 12.0, 13.0 }, { 3.0, 4.0 } },
2069 { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 4.0 } },
2070 { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 1.0 }, { 2.0, 3.0 } }, /* 5 */
2071 { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { -1.0, -0.5 } },
2072 { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { -0.5, 0.0 } },
2073 { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 7.0, 7.0 }, { 6.0, 6.5 } },
2074 { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 8.0, 8.0 }, { 6.0, 6.5 } },
2075 { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 7.0, 7.0 }, { 4.0, 5.0 } }, /* 10 */
2076 { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { 3.0, 4.0 } },
2077 { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { -3.0, -3.0 } },
2078 { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { 2.0, 3.0 } },
2079 { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 } },
2080 { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { -1.0, -3.0 } }, /* 15 */
2081 /* cluster of more than 1 glyph */
2082 { 0.0f, 0.0f, 0.0f, { 10.0f, 11.0f }, { 2.0f, 3.0f }, { 10.0f, 11.0f }, { 2.0f, 3.0f }, TRUE },
2083 { 1.0f, 0.0f, 0.0f, { 10.0f, 11.0f }, { 2.0f, 3.5f }, { 11.0f, 11.0f }, { 3.0f, 3.5f }, TRUE },
2084 { 1.0f, 1.0f, 0.0f, { 10.0f, 11.0f }, { 2.0f, 3.0f }, { 11.0f, 12.0f }, { 3.0f, 3.0f }, TRUE },
2085 { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 10.0 }, { 3.0, 3.0 }, TRUE },
2086 { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE }, /* 20 */
2087 { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE },
2088 { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, TRUE },
2089 { -5.0, -10.0, 4.0, { 10.0, 11.0, 12.0 }, { 2.0, 3.0, 4.0 }, { 5.0, 11.0, 2.0 }, { -3.0, 3.0, 4.0 }, TRUE },
2090 { -10.0, -10.0, 4.0, { 10.0, 11.0, 12.0 }, { 2.0, 3.0, 4.0 }, { 0.0, 11.0, 2.0 }, { -8.0, 3.0, 4.0 }, TRUE },
2091 { -10.0, -10.0, 5.0, { 10.0, 1.0, 12.0 }, { 2.0, 3.0, 4.0 }, { 1.0, 1.0, 3.0 }, { -7.0, 3.0, 4.0 }, TRUE }, /* 25 */
2092 { -10.0, 1.0, 5.0, { 10.0, 1.0, 2.0 }, { 2.0, 3.0, 4.0 }, { 2.0, 1.0, 3.0 }, { -6.0, 3.0, 4.0 }, TRUE },
2093 { 1.0, -10.0, 5.0, { 2.0, 1.0, 10.0 }, { 2.0, 3.0, 4.0 }, { 3.0, 1.0, 2.0 }, { 3.0, 3.0, 4.0 }, TRUE },
2094 { -10.0, -10.0, 5.0, { 11.0, 1.0, 11.0 }, { 2.0, 3.0, 4.0 }, { 2.0, 1.0, 2.0 }, { -7.0, 3.0, 4.0 }, TRUE },
2095 /* isZeroWidthSpace set */
2096 { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, { 2.0, 4.0 }, FALSE, { P_Z, P_S } },
2097 { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, { 2.0, 4.0 }, FALSE, { P_Z, P_S } }, /* 30 */
2098 { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 3.0 }, FALSE, { P_S, P_Z } },
2099 { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_S } },
2100 { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { -1.0, 3.0 }, FALSE, { P_S, P_Z } },
2101 { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_Z } },
2102 { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 7.0, 2.0 }, { 6.0, 3.0 }, FALSE, { P_S, P_Z } }, /* 35 */
2103 { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 8.0, 2.0 }, { 6.0, 3.0 }, FALSE, { P_S, P_Z } },
2104 { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_Z } },
2105 { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { 3.0, 3.0 }, FALSE, { P_S, P_Z } },
2106 { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_Z } },
2107 { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_S, P_Z } }, /* 40 */
2108 { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, FALSE, { P_Z, P_S } },
2109 { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { -1.0, 3.0 }, FALSE, { P_S, P_Z } },
2110 /* isDiacritic */
2111 { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, { 3.0, 4.0 }, FALSE, { P_D, P_S } },
2112 { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 12.0, 13.0 }, { 3.0, 4.0 }, FALSE, { P_D, P_S } },
2113 { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 4.0 }, FALSE, { P_S, P_D } }, /* 45 */
2114 { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 1.0 }, { 2.0, 3.0 }, FALSE, { P_D, P_S } },
2115 { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { -1.0, -0.5 }, FALSE, { P_S, P_D } },
2116 { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { -0.5, 0.0 }, FALSE, { P_D, P_D } },
2117 { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 7.0, 7.0 }, { 6.0, 6.5 }, FALSE, { P_S, P_D } },
2118 { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 8.0, 8.0 }, { 6.0, 6.5 }, FALSE, { P_S, P_D } }, /* 50 */
2119 { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 7.0, 7.0 }, { 4.0, 5.0 }, FALSE, { P_D, P_D } },
2120 { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { 3.0, 4.0 }, FALSE, { P_S, P_D } },
2121 { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { -3.0, -3.0 }, FALSE, { P_D, P_D } },
2122 { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 5.0 }, { 2.0, 3.0 }, FALSE, { P_S, P_D } },
2123 { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, FALSE, { P_D, P_S } }, /* 55 */
2124 { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 6.0 }, { -1.0, -3.0 }, FALSE, { P_S, P_D } },
2125 /* isZeroWidthSpace in a cluster */
2126 { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, { 3.0, 4.0 }, TRUE, { P_Z, P_S } },
2127 { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, { 3.0, 4.0 }, TRUE, { P_Z, P_S } },
2128 { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 4.0 }, TRUE, { P_S, P_Z } },
2129 { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_S } }, /* 60 */
2130 { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 1.0, 11.0 }, { -3.0, 7.0 }, TRUE, { P_S, P_Z } },
2131 { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_Z } },
2132 { 0.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 3.0, 2.0 }, { 3.0, 2.0 }, TRUE, { P_S, P_Z } },
2133 { 0.0, 0.0, 5.0, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 1.5, 2.0, 1.5 }, { 2.5, 3.0, 5.0 }, TRUE, { P_S, P_Z, P_S } },
2134 { 0.0, 0.0, 5.0, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 1.5, 2.5, 1.0 }, { 2.5, 3.0, 4.5 }, TRUE, { P_S, P_S, P_Z } },
2135 { 0.0, 0.0, 5.0, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 2.0, 2.0, 1.0 }, { 2.5, 2.5, 4.5 }, TRUE, { P_S, P_Z, P_Z } },
2136 { 0.0, 0.0, 5.0, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, { 1.0, 2.0, 1.0 }, { 2.0, 3.0, 5.0 }, TRUE, { P_Z, P_Z, P_Z } },
2137 { 2.0, 1.0, 1.0, { 1.0, 2.0, 3.0 }, { 2.0, 3.0, 4.0 }, { 3.0, 2.0, 4.0 }, { 4.0, 3.0, 4.0 }, TRUE, { P_S, P_Z, P_S } },
2138 { 0.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 3.0, 2.0 }, { 3.0, 2.0 }, TRUE, { P_S, P_Z } },
2139 { 0.0, 0.0, 5.0, { 1.0, 2.0, 6.0 }, { 2.0, 3.0, 4.0 }, { 1.0, 2.0, 6.0 }, { 2.0, 3.0, 4.0 }, TRUE, { P_S, P_Z, P_S } },
2140 { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_Z } }, /* 65 */
2141 { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 1.0, 11.0 }, { 3.0, 13.0 }, TRUE, { P_S, P_Z } },
2142 { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_Z } },
2143 { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 11.0 }, { 2.0, 13.0 }, TRUE, { P_S, P_Z } },
2144 { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, TRUE, { P_Z, P_S } },
2145 { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { -1.0, 11.0 }, { -8.0, 2.0 }, TRUE, { P_S, P_Z } }, /* 70 */
2146 /* isDiacritic in a cluster */
2147 { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 11.0 }, { 3.0, 3.0 }, TRUE, { P_D, P_S } },
2148 { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 12.0 }, { 3.0, 3.0 }, TRUE, { P_D, P_S } },
2149 { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 10.0 }, { 3.0, 3.0 }, TRUE, { P_S, P_D } },
2150 { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE, { P_D, P_S } },
2151 { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 7.0 }, { -3.0, 3.0 }, TRUE, { P_S, P_D } }, /* 75 */
2152 { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 6.0 }, { -3.0, 3.0 }, TRUE, { P_D, P_D } },
2153 { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 4.0, 3.0 }, { 5.0, 3.0 }, TRUE, { P_S, P_D } },
2154 { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 4.0, 4.0 }, { 5.0, 3.0 }, TRUE, { P_S, P_D } },
2155 { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 12.0, 1.0 }, { 4.0, 3.0 }, TRUE, { P_D, P_D } },
2156 { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 11.0, 1.0 }, { 3.0, 3.0 }, TRUE, { P_S, P_D } }, /* 80 */
2157 { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 12.0 }, { -8.0, 3.0 }, TRUE, { P_D, P_D } },
2158 { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE, { P_S, P_D } },
2159 { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, TRUE, { P_D, P_S } },
2160 { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { -2.0, 12.0 }, { -8.0, 3.0 }, TRUE, { P_S, P_D } },
2161 /* isZeroWidthSpace + isDiacritic */
2162 { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, { 2.0, 4.0 }, FALSE, { P_D_Z, P_S } }, /* 85 */
2163 { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, { 2.0, 4.0 }, FALSE, { P_D_Z, P_S } },
2164 { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 3.0 }, FALSE, { P_S, P_D_Z } },
2165 { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_S } },
2166 { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { -1.0, 3.0 }, FALSE, { P_S, P_D_Z } },
2167 { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_D_Z } }, /* 90 */
2168 { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 7.0, 2.0 }, { 6.0, 3.0 }, FALSE, { P_S, P_D_Z } },
2169 { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 8.0, 2.0 }, { 6.0, 3.0 }, FALSE, { P_S, P_D_Z } },
2170 { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_D_Z } },
2171 { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { 3.0, 3.0 }, FALSE, { P_S, P_D_Z } },
2172 { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_D_Z } }, /* 95 */
2173 { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 5.0, 11.0 }, { 2.0, 3.0 }, FALSE, { P_S, P_D_Z } },
2174 { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, FALSE, { P_D_Z, P_S } },
2175 { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { 6.0, 11.0 }, { -1.0, 3.0 }, FALSE, { P_S, P_D_Z } },
2176 /* isZeroWidthSpace + isDiacritic in a cluster */
2177 { 1.0, 0.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 12.0 }, { 3.0, 4.0 }, TRUE, { P_D_Z, P_S } },
2178 { 1.0, 1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 13.0 }, { 3.0, 4.0 }, TRUE, { P_D_Z, P_S } }, /* 100 */
2179 { 1.0, -1.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 3.0, 4.0 }, TRUE, { P_S, P_D_Z } },
2180 { 0.0, -10.0, 0.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 1.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_S } },
2181 { -5.0, -4.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 1.0, 11.0 }, { -3.0, 7.0 }, TRUE, { P_S, P_D_Z } },
2182 { -5.0, -5.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_D_Z } },
2183 { 2.0, 0.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 5.0, 2.0 }, { 5.0, 2.0 }, TRUE, { P_S, P_D_Z } }, /* 105 */
2184 { 2.0, 1.0, 5.0, { 1.0, 2.0 }, { 2.0, 3.0 }, { 6.0, 2.0 }, { 5.0, 1.0 }, TRUE, { P_S, P_D_Z } },
2185 { 2.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_D_Z } },
2186 { 1.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 1.0, 11.0 }, { 3.0, 13.0 }, TRUE, { P_S, P_D_Z } },
2187 { -10.0, 1.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 10.0, 11.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_D_Z } },
2188 { 0.0, -10.0, 5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 11.0 }, { 2.0, 13.0 }, TRUE, { P_S, P_D_Z } }, /* 110 */
2189 { 1.0, -10.0, -5.0, { 10.0, 11.0 }, { 2.0, 3.0 }, { 0.0, 0.0 }, { 2.0, 3.0 }, TRUE, { P_D_Z, P_S } },
2190 { -10.0, 1.0, 5.0, { 8.0, 11.0 }, { 2.0, 3.0 }, { -1.0, 11.0 }, { -8.0, 2.0 }, TRUE, { P_S, P_D_Z } },
2191
2192#undef P_S
2193#undef P_D
2194#undef P_Z
2195#undef P_D_Z
2196};
2197
2199{
2201 IDWriteTextAnalyzer1 *analyzer;
2202 UINT16 clustermap[2];
2203 HRESULT hr;
2204 int i;
2205
2206 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer1);
2207 if (!analyzer)
2208 {
2209 win_skip("ApplyCharacterSpacing() is not supported.\n");
2210 return;
2211 }
2212
2213 for (i = 0; i < ARRAY_SIZE(spacing_tests); ++i)
2214 {
2215 const struct spacing_test *ptr = spacing_tests + i;
2217 UINT32 glyph_count;
2218 FLOAT advances[3];
2219
2220 offsets[0].advanceOffset = ptr->offsets[0];
2221 offsets[1].advanceOffset = ptr->offsets[1];
2222 offsets[2].advanceOffset = ptr->offsets[2];
2223 /* Ascender offsets are never touched as spacing applies in reading direction only,
2224 we'll only test them to see if they are not changed */
2225 offsets[0].ascenderOffset = 23.0;
2226 offsets[1].ascenderOffset = 32.0;
2227 offsets[2].ascenderOffset = 31.0;
2228
2229 advances[0] = advances[1] = 123.45f;
2230 memcpy(props, ptr->props, sizeof(props));
2231 glyph_count = ptr->advances[2] > 0.0 ? 3 : 2;
2232 if (ptr->single_cluster)
2233 {
2234 clustermap[0] = 0;
2235 clustermap[1] = 0;
2236 props[0].isClusterStart = 1;
2237 }
2238 else
2239 {
2240 /* trivial case with one glyph per cluster */
2241 clustermap[0] = 0;
2242 clustermap[1] = 1;
2243 props[0].isClusterStart = props[1].isClusterStart = 1;
2244 }
2245
2246 winetest_push_context("Test %u", i);
2247
2248 hr = IDWriteTextAnalyzer1_ApplyCharacterSpacing(analyzer,
2249 ptr->leading,
2250 ptr->trailing,
2251 ptr->min_advance,
2252 ARRAY_SIZE(clustermap),
2253 glyph_count,
2254 clustermap,
2255 ptr->advances,
2256 offsets,
2257 props,
2258 advances,
2259 offsets);
2260 ok(hr == (ptr->min_advance < 0.0f ? E_INVALIDARG : S_OK), "Unexpected hr %#lx.\n", hr);
2261
2262 if (hr == S_OK) {
2263 ok(ptr->modified_advances[0] == advances[0], "Got advance[0] %.2f, expected %.2f.\n", advances[0], ptr->modified_advances[0]);
2264 ok(ptr->modified_advances[1] == advances[1], "Got advance[1] %.2f, expected %.2f.\n", advances[1], ptr->modified_advances[1]);
2265 if (glyph_count > 2)
2266 ok(ptr->modified_advances[2] == advances[2], "Got advance[2] %.2f, expected %.2f.\n", advances[2], ptr->modified_advances[2]);
2267
2268 ok(ptr->modified_offsets[0] == offsets[0].advanceOffset, "Got offset[0] %.2f, expected %.2f.\n",
2269 offsets[0].advanceOffset, ptr->modified_offsets[0]);
2270 ok(ptr->modified_offsets[1] == offsets[1].advanceOffset, "Got offset[1] %.2f, expected %.2f.\n",
2271 offsets[1].advanceOffset, ptr->modified_offsets[1]);
2272 if (glyph_count > 2)
2273 ok(ptr->modified_offsets[2] == offsets[2].advanceOffset, "Got offset[2] %.2f, expected %.2f.\n",
2274 offsets[2].advanceOffset, ptr->modified_offsets[2]);
2275
2276 ok(offsets[0].ascenderOffset == 23.0, "Unexpected ascenderOffset %.2f.\n", offsets[0].ascenderOffset);
2277 ok(offsets[1].ascenderOffset == 32.0, "Unexpected ascenderOffset %.2f.\n", offsets[1].ascenderOffset);
2278 ok(offsets[2].ascenderOffset == 31.0, "Unexpected ascenderOffset %.2f.\n", offsets[2].ascenderOffset);
2279 }
2280 else {
2281 ok(ptr->modified_advances[0] == advances[0], "Got advance[0] %.2f, expected %.2f.\n", advances[0], ptr->modified_advances[0]);
2282 ok(ptr->modified_advances[1] == advances[1], "Got advance[1] %.2f, expected %.2f.\n", advances[1], ptr->modified_advances[1]);
2283 ok(ptr->offsets[0] == offsets[0].advanceOffset, "Got offset[0] %.2f, expected %.2f.\n",
2284 offsets[0].advanceOffset, ptr->modified_offsets[0]);
2285 ok(ptr->offsets[1] == offsets[1].advanceOffset, "Got offset[1] %.2f, expected %.2f.\n",
2286 offsets[1].advanceOffset, ptr->modified_offsets[1]);
2287 ok(offsets[0].ascenderOffset == 23.0, "Unexpected ascenderOffset %.2f.\n", offsets[0].ascenderOffset);
2288 ok(offsets[1].ascenderOffset == 32.0, "Unexpected ascenderOffset %.2f.\n", offsets[1].ascenderOffset);
2289 }
2290
2291 /* same, with argument aliasing */
2292 memcpy(advances, ptr->advances, glyph_count * sizeof(*advances));
2293 offsets[0].advanceOffset = ptr->offsets[0];
2294 offsets[1].advanceOffset = ptr->offsets[1];
2295 offsets[2].advanceOffset = ptr->offsets[2];
2296 /* Ascender offsets are never touched as spacing applies in reading direction only,
2297 we'll only test them to see if they are not changed */
2298 offsets[0].ascenderOffset = 23.0f;
2299 offsets[1].ascenderOffset = 32.0f;
2300 offsets[2].ascenderOffset = 31.0f;
2301
2302 hr = IDWriteTextAnalyzer1_ApplyCharacterSpacing(analyzer,
2303 ptr->leading,
2304 ptr->trailing,
2305 ptr->min_advance,
2306 ARRAY_SIZE(clustermap),
2307 glyph_count,
2308 clustermap,
2309 advances,
2310 offsets,
2311 props,
2312 advances,
2313 offsets);
2314 ok(hr == (ptr->min_advance < 0.0f ? E_INVALIDARG : S_OK), "Unexpected hr %#lx.\n", hr);
2315
2316 if (hr == S_OK)
2317 {
2318 ok(ptr->modified_advances[0] == advances[0], "Got advance[0] %.2f, expected %.2f.\n", advances[0], ptr->modified_advances[0]);
2319 ok(ptr->modified_advances[1] == advances[1], "Got advance[1] %.2f, expected %.2f.\n", advances[1], ptr->modified_advances[1]);
2320 if (glyph_count > 2)
2321 ok(ptr->modified_advances[2] == advances[2], "Got advance[2] %.2f, expected %.2f.\n", advances[2], ptr->modified_advances[2]);
2322
2323 ok(ptr->modified_offsets[0] == offsets[0].advanceOffset, "Got offset[0] %.2f, expected %.2f.\n",
2324 offsets[0].advanceOffset, ptr->modified_offsets[0]);
2325 ok(ptr->modified_offsets[1] == offsets[1].advanceOffset, "Got offset[1] %.2f, expected %.2f.\n",
2326 offsets[1].advanceOffset, ptr->modified_offsets[1]);
2327 if (glyph_count > 2)
2328 ok(ptr->modified_offsets[2] == offsets[2].advanceOffset, "Got offset[2] %.2f, expected %.2f.\n",
2329 offsets[2].advanceOffset, ptr->modified_offsets[2]);
2330
2331 ok(offsets[0].ascenderOffset == 23.0f, "Unexpected ascenderOffset %.2f.\n", offsets[0].ascenderOffset);
2332 ok(offsets[1].ascenderOffset == 32.0f, "Unexpected ascenderOffset %.2f.\n", offsets[1].ascenderOffset);
2333 ok(offsets[2].ascenderOffset == 31.0f, "Unexpected ascenderOffset %.2f.\n", offsets[2].ascenderOffset);
2334 }
2335 else
2336 {
2337 /* with aliased advances original values are retained */
2338 ok(ptr->advances[0] == advances[0], "Got advance[0] %.2f, expected %.2f.\n", advances[0], ptr->advances[0]);
2339 ok(ptr->advances[1] == advances[1], "Got advance[1] %.2f, expected %.2f.\n", advances[1], ptr->advances[1]);
2340 ok(ptr->offsets[0] == offsets[0].advanceOffset, "Got offset[0] %.2f, expected %.2f.\n",
2341 offsets[0].advanceOffset, ptr->modified_offsets[0]);
2342 ok(ptr->offsets[1] == offsets[1].advanceOffset, "Got offset[1] %.2f, expected %.2f.\n",
2343 offsets[1].advanceOffset, ptr->modified_offsets[1]);
2344 ok(offsets[0].ascenderOffset == 23.0f, "Unexpected ascenderOffset %.2f.\n", offsets[0].ascenderOffset);
2345 ok(offsets[1].ascenderOffset == 32.0f, "Unexpected ascenderOffset %.2f.\n", offsets[1].ascenderOffset);
2346 }
2347
2349 }
2350
2351 IDWriteTextAnalyzer1_Release(analyzer);
2352}
2353
2358};
2359
2360static const struct orientation_transf_test ot_tests[] = {
2361 { DWRITE_GLYPH_ORIENTATION_ANGLE_0_DEGREES, FALSE, { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 } },
2362 { DWRITE_GLYPH_ORIENTATION_ANGLE_90_DEGREES, FALSE, { 0.0, 1.0, -1.0, 0.0, 0.0, 0.0 } },
2363 { DWRITE_GLYPH_ORIENTATION_ANGLE_180_DEGREES, FALSE, { -1.0, 0.0, 0.0, -1.0, 0.0, 0.0 } },
2364 { DWRITE_GLYPH_ORIENTATION_ANGLE_270_DEGREES, FALSE, { 0.0, -1.0, 1.0, 0.0, 0.0, 0.0 } },
2365 { DWRITE_GLYPH_ORIENTATION_ANGLE_0_DEGREES, TRUE, { 0.0, 1.0, -1.0, 0.0, 0.0, 0.0 } },
2366 { DWRITE_GLYPH_ORIENTATION_ANGLE_90_DEGREES, TRUE, { -1.0, 0.0, 0.0, -1.0, 0.0, 0.0 } },
2367 { DWRITE_GLYPH_ORIENTATION_ANGLE_180_DEGREES, TRUE, { 0.0, -1.0, 1.0, 0.0, 0.0, 0.0 } },
2368 { DWRITE_GLYPH_ORIENTATION_ANGLE_270_DEGREES, TRUE, { 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 } }
2369};
2370
2371static inline const char *dbgstr_matrix(const DWRITE_MATRIX *m)
2372{
2373 static char buff[64];
2374 sprintf(buff, "{%.2f, %.2f, %.2f, %.2f, %.2f, %.2f}", m->m11, m->m12,
2375 m->m21, m->m22, m->dx, m->dy);
2376 return buff;
2377}
2378
2380{
2381 IDWriteTextAnalyzer2 *analyzer2;
2382 IDWriteTextAnalyzer1 *analyzer;
2383 FLOAT originx, originy;
2385 HRESULT hr;
2386 int i;
2387
2388 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer1);
2389 if (!analyzer)
2390 {
2391 win_skip("GetGlyphOrientationTransform() is not supported.\n");
2392 return;
2393 }
2394
2395 /* invalid angle value */
2396 memset(&m, 0xcc, sizeof(m));
2397 hr = IDWriteTextAnalyzer1_GetGlyphOrientationTransform(analyzer,
2399 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2400 ok(m.m11 == 0.0, "got %.2f\n", m.m11);
2401
2402 for (i = 0; i < ARRAY_SIZE(ot_tests); ++i)
2403 {
2404 memset(&m, 0, sizeof(m));
2405 hr = IDWriteTextAnalyzer1_GetGlyphOrientationTransform(analyzer, ot_tests[i].angle,
2406 ot_tests[i].is_sideways, &m);
2407 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2408 ok(!memcmp(&ot_tests[i].m, &m, sizeof(m)), "%d: wrong matrix %s\n", i, dbgstr_matrix(&m));
2409 }
2410
2411 IDWriteTextAnalyzer1_Release(analyzer);
2412
2413 analyzer2 = create_text_analyzer(&IID_IDWriteTextAnalyzer2);
2414 if (!analyzer2)
2415 {
2416 win_skip("IDWriteTextAnalyzer2::GetGlyphOrientationTransform() is not supported.\n");
2417 return;
2418 }
2419
2420 /* invalid angle value */
2421 memset(&m, 0xcc, sizeof(m));
2422 hr = IDWriteTextAnalyzer2_GetGlyphOrientationTransform(analyzer2,
2424 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2425 ok(m.m11 == 0.0, "got %.2f\n", m.m11);
2426
2427 originx = 50.0;
2428 originy = 60.0;
2429 for (i = 0; i < ARRAY_SIZE(ot_tests); i++) {
2431 DWRITE_MATRIX m_exp;
2432
2433 memset(&m, 0, sizeof(m));
2434
2435 /* zero offset gives same result as a call from IDWriteTextAnalyzer1 */
2436 hr = IDWriteTextAnalyzer2_GetGlyphOrientationTransform(analyzer2, ot_tests[i].angle,
2437 ot_tests[i].is_sideways, 0.0, 0.0, &m);
2438 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2439 ok(!memcmp(&ot_tests[i].m, &m, sizeof(m)), "%d: wrong matrix %s\n", i, dbgstr_matrix(&m));
2440
2441 m_exp = ot_tests[i].m;
2442 hr = IDWriteTextAnalyzer2_GetGlyphOrientationTransform(analyzer2, ot_tests[i].angle,
2443 ot_tests[i].is_sideways, originx, originy, &m);
2444 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2445
2446 /* 90 degrees more for sideways */
2447 if (ot_tests[i].is_sideways) {
2448 switch (ot_tests[i].angle)
2449 {
2452 break;
2455 break;
2458 break;
2461 break;
2462 default:
2463 ;
2464 }
2465 }
2466 else
2467 angle = ot_tests[i].angle;
2468
2469 /* set expected offsets */
2470 switch (angle)
2471 {
2473 break;
2475 m_exp.dx = originx + originy;
2476 m_exp.dy = originy - originx;
2477 break;
2479 m_exp.dx = originx + originx;
2480 m_exp.dy = originy + originy;
2481 break;
2483 m_exp.dx = originx - originy;
2484 m_exp.dy = originy + originx;
2485 break;
2486 default:
2487 ;
2488 }
2489
2490 ok(!memcmp(&m_exp, &m, sizeof(m)), "%d: wrong matrix %s\n", i, dbgstr_matrix(&m));
2491 }
2492
2493 IDWriteTextAnalyzer2_Release(analyzer2);
2494}
2495
2496static void test_GetBaseline(void)
2497{
2498 DWRITE_SCRIPT_ANALYSIS sa = { 0 };
2499 IDWriteTextAnalyzer1 *analyzer;
2500 IDWriteFontFace *fontface;
2502 BOOL exists;
2503 HRESULT hr;
2504
2505 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer1);
2506 if (!analyzer)
2507 {
2508 win_skip("GetBaseline() is not supported.\n");
2509 return;
2510 }
2511
2512 fontface = create_fontface();
2513
2514 /* Tahoma does not have a BASE table. */
2515
2516 exists = TRUE;
2517 baseline = 456;
2518 hr = IDWriteTextAnalyzer1_GetBaseline(analyzer, fontface, DWRITE_BASELINE_DEFAULT, FALSE,
2519 TRUE, sa, NULL, &baseline, &exists);
2520 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2521 ok(!baseline, "Unexpected baseline %d.\n", baseline);
2522 ok(!exists, "Unexpected flag %d.\n", exists);
2523
2524 exists = TRUE;
2525 baseline = 456;
2526 hr = IDWriteTextAnalyzer1_GetBaseline(analyzer, fontface, DWRITE_BASELINE_DEFAULT, FALSE,
2527 FALSE, sa, NULL, &baseline, &exists);
2528 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2529 ok(!baseline, "Unexpected baseline %d.\n", baseline);
2530 ok(!exists, "Unexpected flag %d.\n", exists);
2531
2532 exists = TRUE;
2533 baseline = 0;
2534 hr = IDWriteTextAnalyzer1_GetBaseline(analyzer, fontface, DWRITE_BASELINE_CENTRAL, FALSE,
2535 TRUE, sa, NULL, &baseline, &exists);
2536 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2537 ok(baseline != 0, "Unexpected baseline %d.\n", baseline);
2538 ok(!exists, "Unexpected flag %d.\n", exists);
2539
2540 exists = TRUE;
2541 baseline = 0;
2542 hr = IDWriteTextAnalyzer1_GetBaseline(analyzer, fontface, DWRITE_BASELINE_CENTRAL, FALSE,
2543 FALSE, sa, NULL, &baseline, &exists);
2544 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2545 ok(!baseline, "Unexpected baseline %d.\n", baseline);
2546 ok(!exists, "Unexpected flag %d.\n", exists);
2547
2548 exists = TRUE;
2549 baseline = 456;
2550 hr = IDWriteTextAnalyzer1_GetBaseline(analyzer, fontface, DWRITE_BASELINE_DEFAULT + 100, FALSE,
2551 TRUE, sa, NULL, &baseline, &exists);
2552 ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
2553 ok(!baseline, "Unexpected baseline %d.\n", baseline);
2554 ok(!exists, "Unexpected flag %d.\n", exists);
2555
2556 IDWriteFontFace_Release(fontface);
2557 IDWriteTextAnalyzer1_Release(analyzer);
2558}
2559
2561{
2562 int x = *(int *)&left;
2563 int y = *(int *)&right;
2564
2565 if (x < 0)
2566 x = INT_MIN - x;
2567 if (y < 0)
2568 y = INT_MIN - y;
2569
2570 return abs(x - y) <= 8;
2571}
2572
2574{
2575 DWRITE_SHAPING_GLYPH_PROPERTIES glyphprops[1];
2576 DWRITE_SHAPING_TEXT_PROPERTIES textprops[1];
2577 DWRITE_SCRIPT_ANALYSIS sa = { 0 };
2578 IDWriteTextAnalyzer *analyzer;
2579 IDWriteFontFace *fontface;
2580 UINT16 clustermap[1];
2581 HRESULT hr;
2582 UINT32 count;
2583 UINT16 glyphs[1];
2584 FLOAT advance;
2586 DWRITE_FONT_METRICS fontmetrics;
2587 float emsize;
2588
2589 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer);
2590 ok(!!analyzer, "Failed to create analyzer instance.\n");
2591
2592 fontface = create_fontface();
2593
2594 IDWriteFontFace_GetMetrics(fontface, &fontmetrics);
2595
2596 count = 0;
2597 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, L"A", 1, fontface, FALSE, FALSE, &sa, NULL, NULL, NULL, NULL, 0, 1,
2598 clustermap, textprops, glyphs, glyphprops, &count);
2599 ok(hr == S_OK, "Failed to get glyphs, hr %#lx.\n", hr);
2600 ok(count == 1, "got %u\n", count);
2601
2602 for (emsize = 12.0f; emsize <= 20.0f; emsize += 1.0f)
2603 {
2604 FLOAT compatadvance, expected, ppdip;
2606
2607 hr = IDWriteTextAnalyzer_GetGlyphPlacements(analyzer, L"A", clustermap, textprops, 1, glyphs, glyphprops,
2608 count, fontface, emsize, FALSE, FALSE, &sa, NULL, NULL, NULL, 0, &advance, offsets);
2609 ok(hr == S_OK, "Failed to get glyph placements, hr %#lx.\n", hr);
2610 ok(advance > 0.0f, "Unexpected advance %f.\n", advance);
2611
2612 /* 1 ppdip, no transform */
2613 ppdip = 1.0;
2614 hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(fontface, emsize, ppdip, NULL, FALSE,
2615 glyphs, 1, &metrics, FALSE);
2616 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2617
2618 expected = floorf(metrics.advanceWidth * emsize * ppdip / fontmetrics.designUnitsPerEm + 0.5f) / ppdip;
2619 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, L"A", clustermap, textprops, 1, glyphs,
2620 glyphprops, count, fontface, emsize, ppdip, NULL, FALSE, FALSE, FALSE, &sa, NULL, NULL, NULL, 0,
2621 &compatadvance, offsets);
2622 ok(hr == S_OK, "Failed to get glyph placements, hr %#lx.\n", hr);
2623 ok(compatadvance == expected, "%.0f: got advance %f, expected %f, natural %f\n", emsize,
2624 compatadvance, expected, advance);
2625
2626 /* 1.2 ppdip, no transform */
2627 ppdip = 1.2f;
2628 hr = IDWriteFontFace_GetGdiCompatibleGlyphMetrics(fontface, emsize, ppdip, NULL, FALSE,
2629 glyphs, 1, &metrics, FALSE);
2630 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2631
2632 expected = floorf(metrics.advanceWidth * emsize * ppdip / fontmetrics.designUnitsPerEm + 0.5f) / ppdip;
2633 hr = IDWriteTextAnalyzer_GetGdiCompatibleGlyphPlacements(analyzer, L"A", clustermap, textprops, 1, glyphs,
2634 glyphprops, count, fontface, emsize, ppdip, NULL, FALSE, FALSE, FALSE, &sa, NULL, NULL, NULL, 0,
2635 &compatadvance, offsets);
2636 ok(hr == S_OK, "Failed to get glyph placements, hr %#lx.\n", hr);
2637 ok(float_eq(compatadvance, expected), "%.0f: got advance %f, expected %f, natural %f\n", emsize,
2638 compatadvance, expected, advance);
2639 }
2640
2641 IDWriteFontFace_Release(fontface);
2642 IDWriteTextAnalyzer_Release(analyzer);
2643}
2644
2646{
2652};
2653
2654static const struct bidi_test bidi_tests[] = {
2655 {
2656 { 0x645, 0x6cc, 0x200c, 0x6a9, 0x646, 0x645, 0 },
2658 { 1, 1, 1, 1, 1, 1 },
2659 { 1, 1, 1, 1, 1, 1 }
2660 },
2661 {
2662 { 0x645, 0x6cc, 0x200c, 0x6a9, 0x646, 0x645, 0 },
2664 { 0, 0, 0, 0, 0, 0 },
2665 { 1, 1, 1, 1, 1, 1 }
2666 },
2667 {
2668 { 0x200c, 0x645, 0x6cc, 0x6a9, 0x646, 0x645, 0 },
2670 { 1, 1, 1, 1, 1, 1 },
2671 { 1, 1, 1, 1, 1, 1 }
2672 },
2673 {
2674 { 0x200c, 0x645, 0x6cc, 0x6a9, 0x646, 0x645, 0 },
2676 { 0, 0, 0, 0, 0, 0 },
2677 { 0, 1, 1, 1, 1, 1 }
2678 },
2679 {
2680 { 'A', 0x200c, 'B', 0 },
2682 { 1, 1, 1 },
2683 { 2, 2, 2 }
2684 },
2685 {
2686 { 'A', 0x200c, 'B', 0 },
2688 { 0, 0, 0 },
2689 { 0, 0, 0 }
2690 },
2691 {
2692 { LRE, PDF, 'a', 'b', 0 },
2694 { 2, 2, 0, 0 },
2695 { 0, 0, 0, 0 },
2696 },
2697 {
2698 { 'a', LRE, PDF, 'b', 0 },
2700 { 0, 2, 2, 0 },
2701 { 0, 0, 0, 0 },
2702 },
2703 {
2704 { RLE, PDF, 'a', 'b', 0 },
2706 { 1, 1, 0, 0 },
2707 { 0, 0, 0, 0 },
2708 },
2709 {
2710 { 'a', RLE, PDF, 'b', 0 },
2712 { 0, 1, 1, 0 },
2713 { 0, 0, 0, 0 },
2714 },
2715 {
2716 { 'a', RLE, PDF, 'b', 0 },
2718 { 1, 3, 3, 1 },
2719 { 2, 2, 2, 2 },
2720 },
2721 {
2722 { LRE, PDF, 'a', 'b', 0 },
2724 { 2, 2, 1, 1 },
2725 { 1, 1, 2, 2 },
2726 },
2727 {
2728 { PDF, 'a', 'b', 0 },
2730 { 0, 0, 0, 0 },
2731 { 0, 0, 0, 0 }
2732 },
2733 {
2734 { LRE, 'a', 'b', PDF, 0 },
2736 { 2, 2, 2, 2 },
2737 { 0, 2, 2, 2 },
2738 TRUE
2739 },
2740 {
2741 { LRI, 'a', 'b', PDI, 0 },
2743 { 0, 0, 0, 0 },
2744 { 0, 0, 0, 0 },
2745 TRUE
2746 },
2747 {
2748 { RLI, 'a', 'b', PDI, 0 },
2750 { 0, 0, 0, 0 },
2751 { 0, 0, 0, 0 },
2752 TRUE
2753 },
2754 {
2755 { 0 }
2756 }
2757};
2758
2759static void compare_bidi_levels(unsigned int seq, const struct bidi_test *test, UINT32 len, UINT8 *explicit, UINT8 *resolved)
2760{
2761 unsigned int i, failcount = 0;
2762 BOOL match;
2763
2764 match = !memcmp(explicit, test->explicit, len);
2765 if (!match) {
2766 if (test->todo) {
2767 failcount++;
2768 todo_wine
2769 ok(0, "test %u: %s wrong explicit levels:\n", seq, wine_dbgstr_w(test->text));
2770 }
2771 else
2772 ok(0, "test %u: %s wrong explicit levels:\n", seq, wine_dbgstr_w(test->text));
2773
2774 for (i = 0; i < len; i++) {
2775 if (test->explicit[i] != explicit[i]) {
2776 if (test->todo) {
2777 failcount++;
2778 todo_wine
2779 ok(0, "\tat %u, explicit level %u, expected %u\n", i, explicit[i], test->explicit[i]);
2780 }
2781 else
2782 ok(0, "\tat %u, explicit level %u, expected %u\n", i, explicit[i], test->explicit[i]);
2783 }
2784 }
2785 }
2786
2787 match = !memcmp(resolved, test->resolved, len);
2788 if (!match) {
2789 if (test->todo) {
2790 failcount++;
2791 todo_wine
2792 ok(0, "test %u: %s wrong resolved levels:\n", seq, wine_dbgstr_w(test->text));
2793 }
2794 else
2795 ok(0, "test %u: %s wrong resolved levels:\n", seq, wine_dbgstr_w(test->text));
2796
2797 for (i = 0; i < len; i++) {
2798 if (test->resolved[i] != resolved[i]) {
2799 if (test->todo) {
2800 failcount++;
2801 todo_wine
2802 ok(0, "\tat %u, resolved level %u, expected %u\n", i, resolved[i], test->resolved[i]);
2803 }
2804 else
2805 ok(0, "\tat %u, resolved level %u, expected %u\n", i, resolved[i], test->resolved[i]);
2806 }
2807 }
2808 }
2809
2810 todo_wine_if(test->todo && failcount == 0)
2811 ok(1, "test %u: marked as \"todo_wine\" but succeeds\n", seq);
2812}
2813
2814static void test_AnalyzeBidi(void)
2815{
2816 const struct bidi_test *ptr = bidi_tests;
2817 IDWriteTextAnalyzer *analyzer;
2818 UINT32 i = 0;
2819 HRESULT hr;
2820
2821 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer);
2822 ok(!!analyzer, "Failed to create analyzer instance.\n");
2823
2824 while (*ptr->text)
2825 {
2826 UINT32 len;
2827
2828 init_textsource(&analysissource, ptr->text, -1, ptr->direction);
2829
2830 len = lstrlenW(ptr->text);
2831 if (len > BIDI_LEVELS_COUNT) {
2832 ok(0, "test %u: increase BIDI_LEVELS_COUNT to at least %u\n", i, len);
2833 i++;
2834 ptr++;
2835 continue;
2836 }
2837
2840 hr = IDWriteTextAnalyzer_AnalyzeBidi(analyzer, &analysissource.IDWriteTextAnalysisSource_iface, 0,
2841 len, &analysissink);
2842 ok(hr == S_OK, "%u: unexpected hr %#lx.\n", i, hr);
2844
2845 i++;
2846 ptr++;
2847 }
2848
2849 IDWriteTextAnalyzer_Release(analyzer);
2850}
2851
2853{
2857};
2858
2860{
2861 static const struct
2862 {
2863 enum script_id script;
2864 const WCHAR *text;
2865 unsigned short justification[10];
2866 } tests[] =
2867 {
2868 {
2870 L"a b\tc",
2871 {
2877 },
2878 },
2879 {
2881 L" a b",
2882 {
2887 },
2888 },
2889 {
2891 L" a b",
2892 {
2897 },
2898 },
2900 { Script_Latin, L"\x640", { SCRIPT_JUSTIFY_CHARACTER } },
2902
2907
2909
2913
2915 };
2916 DWRITE_SHAPING_GLYPH_PROPERTIES glyph_props[16];
2917 DWRITE_SHAPING_TEXT_PROPERTIES text_props[16];
2918 UINT16 clustermap[16], glyphs[16];
2919 IDWriteTextAnalyzer *analyzer;
2921 IDWriteFontFace *fontface;
2922 UINT32 glyph_count;
2923 unsigned int i, j;
2924 HRESULT hr;
2925
2926 analyzer = create_text_analyzer(&IID_IDWriteTextAnalyzer);
2927 ok(!!analyzer, "Failed to create analyzer instance.\n");
2928
2929 fontface = create_fontface();
2930
2931 for (i = 0; i < ARRAY_SIZE(tests); ++i)
2932 {
2933 if (tests[i].script == Script_Arabic && !strcmp(winetest_platform, "wine"))
2934 continue;
2935
2937
2938 sa.script = tests[i].script;
2940
2941 /* Use RTL for Arabic, it affects returned justification classes. */
2942 hr = IDWriteTextAnalyzer_GetGlyphs(analyzer, tests[i].text, wcslen(tests[i].text), fontface,
2943 FALSE, sa.script == Script_Arabic, &sa, L"en-US", NULL, NULL, NULL, 0, ARRAY_SIZE(glyphs), clustermap,
2944 text_props, glyphs, glyph_props, &glyph_count);
2945 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2946
2947 for (j = 0; j < glyph_count; ++j)
2948 {
2949 winetest_push_context("Glyph %u", j);
2950 ok(glyph_props[j].justification == tests[i].justification[j], "Unexpected justification value %u.\n",
2951 glyph_props[j].justification);
2953 }
2954
2956 }
2957
2958 IDWriteFontFace_Release(fontface);
2959}
2960
2961START_TEST(analyzer)
2962{
2963 HRESULT hr;
2964
2966 ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
2967 if (hr != S_OK)
2968 {
2969 win_skip("failed to create factory\n");
2970 return;
2971 }
2972
2975
2990
2991 IDWriteFactory_Release(factory);
2992}
static void flush_sequence(void)
Definition: SystemMenu.c:184
static struct recvd_message * sequence
Definition: SystemMenu.c:63
_STLP_MOVE_TO_STD_NAMESPACE void _STLP_CALL advance(_InputIterator &__i, _Distance __n)
unsigned short UINT16
Definition: actypes.h:129
unsigned char UINT8
Definition: actypes.h:128
static struct sockaddr_in sa
Definition: adnsresfilter.c:69
#define ok(value,...)
Definition: atltest.h:57
#define START_TEST(x)
Definition: atltest.h:75
#define ok_(x1, x2)
Definition: atltest.h:61
#define index(s, c)
Definition: various.h:29
#define ARRAY_SIZE(A)
Definition: main.h:20
const GUID IID_IUnknown
Definition: _locale.h:75
range
Definition: d3dx9_private.h:58
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#define E_FAIL
Definition: ddrawi.h:102
#define realloc
Definition: debug_ros.c:6
#define free
Definition: debug_ros.c:5
#define malloc
Definition: debug_ros.c:4
HRESULT hr
Definition: delayimp.cpp:582
ot_gdef_class
Definition: opentype.c:435
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
WORD face[3]
Definition: mesh.c:4854
static const GUID * classes[]
Definition: loader.c:49
HRESULT WINAPI DWriteCreateFactory(DWRITE_FACTORY_TYPE type, REFIID riid, IUnknown **ret)
Definition: main.c:2110
#define CloseHandle
Definition: compat.h:739
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
#define GENERIC_READ
Definition: compat.h:135
#define MAX_PATH
Definition: compat.h:34
#define CreateFileW
Definition: compat.h:741
#define lstrcpyW
Definition: compat.h:749
#define lstrlenW
Definition: compat.h:750
BOOL WINAPI DeleteFileW(IN LPCWSTR lpFileName)
Definition: delete.c:39
BOOL WINAPI WriteFile(_In_ HANDLE hFile, _In_reads_bytes_opt_(nNumberOfBytesToWrite) LPCVOID lpBuffer, _In_ DWORD nNumberOfBytesToWrite, _Out_opt_ LPDWORD lpNumberOfBytesWritten, _Inout_opt_ LPOVERLAPPED lpOverlapped)
Definition: rw.c:25
HMODULE WINAPI DECLSPEC_HOTPATCH GetModuleHandleA(LPCSTR lpModuleName)
Definition: loader.c:812
DWORD WINAPI GetTempPathW(IN DWORD count, OUT LPWSTR path)
Definition: path.c:2098
HRSRC WINAPI FindResourceA(HMODULE hModule, LPCSTR name, LPCSTR type)
Definition: res.c:155
DWORD WINAPI SizeofResource(HINSTANCE hModule, HRSRC hRsrc)
Definition: res.c:568
LPVOID WINAPI LockResource(HGLOBAL handle)
Definition: res.c:550
HGLOBAL WINAPI LoadResource(HINSTANCE hModule, HRSRC hRsrc)
Definition: res.c:532
const WCHAR * text
Definition: package.c:1826
unsigned char ch[4][2]
Definition: console.c:118
#define assert(_expr)
Definition: assert.h:32
_ACRTIMP size_t __cdecl wcslen(const wchar_t *)
Definition: wcs.c:2988
_ACRTIMP int __cdecl memcmp(const void *, const void *, size_t)
Definition: string.c:2807
#define INT_MIN
Definition: limits.h:25
_ACRTIMP int __cdecl strcmp(const char *, const char *)
Definition: string.c:3324
return ret
Definition: mutex.c:147
#define L(x)
Definition: resources.c:13
DWRITE_SCRIPT_SHAPES
Definition: dwrite.idl:328
@ DWRITE_SCRIPT_SHAPES_NO_VISUAL
Definition: dwrite.idl:330
@ DWRITE_SCRIPT_SHAPES_DEFAULT
Definition: dwrite.idl:329
@ DWRITE_BREAK_CONDITION_MUST_BREAK
Definition: dwrite.idl:226
@ DWRITE_BREAK_CONDITION_CAN_BREAK
Definition: dwrite.idl:224
@ DWRITE_BREAK_CONDITION_MAY_NOT_BREAK
Definition: dwrite.idl:225
@ DWRITE_NUMBER_SUBSTITUTION_METHOD_NONE
Definition: dwrite.idl:338
@ DWRITE_NUMBER_SUBSTITUTION_METHOD_CONTEXTUAL
Definition: dwrite.idl:337
@ DWRITE_NUMBER_SUBSTITUTION_METHOD_TRADITIONAL
Definition: dwrite.idl:340
@ DWRITE_NUMBER_SUBSTITUTION_METHOD_NATIONAL
Definition: dwrite.idl:339
@ DWRITE_FONT_FACE_TYPE_TRUETYPE
Definition: dwrite.idl:62
@ DWRITE_FONT_SIMULATIONS_NONE
Definition: dwrite.idl:146
@ DWRITE_FACTORY_TYPE_ISOLATED
Definition: dwrite.idl:43
DWRITE_READING_DIRECTION
Definition: dwrite.idl:199
@ DWRITE_READING_DIRECTION_RIGHT_TO_LEFT
Definition: dwrite.idl:201
@ DWRITE_READING_DIRECTION_LEFT_TO_RIGHT
Definition: dwrite.idl:200
DWRITE_FONT_FEATURE_TAG
Definition: dwrite.idl:243
@ DWRITE_BASELINE_DEFAULT
Definition: dwrite_1.idl:414
@ DWRITE_BASELINE_CENTRAL
Definition: dwrite_1.idl:416
DWRITE_GLYPH_ORIENTATION_ANGLE
Definition: dwrite_1.idl:432
@ DWRITE_GLYPH_ORIENTATION_ANGLE_180_DEGREES
Definition: dwrite_1.idl:435
@ DWRITE_GLYPH_ORIENTATION_ANGLE_90_DEGREES
Definition: dwrite_1.idl:434
@ DWRITE_GLYPH_ORIENTATION_ANGLE_0_DEGREES
Definition: dwrite_1.idl:433
@ DWRITE_GLYPH_ORIENTATION_ANGLE_270_DEGREES
Definition: dwrite_1.idl:436
FLOAT baseline
Definition: dwrite_3.idl:860
@ SCRIPT_JUSTIFY_ARABIC_HA
@ SCRIPT_JUSTIFY_ARABIC_SEEN
@ SCRIPT_JUSTIFY_ARABIC_BLANK
@ SCRIPT_JUSTIFY_ARABIC_NORMAL
@ SCRIPT_JUSTIFY_ARABIC_SEEN_M
@ SCRIPT_JUSTIFY_NONE
@ SCRIPT_JUSTIFY_ARABIC_BARA
@ SCRIPT_JUSTIFY_BLANK
@ SCRIPT_JUSTIFY_CHARACTER
@ SCRIPT_JUSTIFY_ARABIC_ALEF
@ SCRIPT_JUSTIFY_ARABIC_KASHIDA
#define abs(i)
Definition: fconv.c:206
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
static const FxOffsetAndName offsets[]
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
GLuint GLuint GLsizei count
Definition: gl.h:1545
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
GLuint GLuint GLsizei GLenum const GLvoid * indices
Definition: gl.h:1545
GLdouble n
Definition: glext.h:7729
GLuint res
Definition: glext.h:9613
GLuint GLuint * names
Definition: glext.h:11545
GLsizei const GLchar *const * strings
Definition: glext.h:7622
GLsizeiptr size
Definition: glext.h:5919
GLintptr offset
Definition: glext.h:5920
GLuint index
Definition: glext.h:6031
GLdouble GLdouble right
Definition: glext.h:10859
GLenum GLuint GLint GLenum face
Definition: glext.h:7025
GLsizei GLenum const GLvoid GLuint GLsizei GLfloat * metrics
Definition: glext.h:11745
GLint left
Definition: glext.h:7726
GLuint GLsizei GLsizei * length
Definition: glext.h:6040
const GLint * first
Definition: glext.h:5794
GLboolean GLboolean g
Definition: glext.h:6204
GLfloat angle
Definition: glext.h:10853
GLenum GLsizei len
Definition: glext.h:6722
const GLfloat * m
Definition: glext.h:10848
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
unsigned int UINT
Definition: sysinfo.c:13
static const WCHAR aW[]
Definition: htmlelem.c:21
#define FLOAT
Definition: i386-dis.c:525
REFIID riid
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
const char * filename
Definition: ioapi.h:137
uint32_t entry
Definition: isohybrid.c:63
#define debugstr_w
Definition: kernel32.h:32
#define wine_dbgstr_w
Definition: kernel32.h:34
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
const char * winetest_platform
#define win_skip
Definition: minitest.h:67
#define todo_wine_if(is_todo)
Definition: minitest.h:81
void __cdecl void __cdecl void __cdecl void __cdecl void __cdecl void winetest_pop_context(void)
void __cdecl void __cdecl void __cdecl void __cdecl void __cdecl winetest_push_context(const char *fmt,...) __WINE_PRINTF_ATTR(1
Definition: test.h:539
#define todo_wine
Definition: minitest.h:80
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define CREATE_ALWAYS
Definition: disk.h:72
const char * tags[99]
Definition: apphelp.c:216
static PVOID ptr
Definition: dispmode.c:27
static struct test_info tests[]
#define sprintf
Definition: sprintf.c:45
BOOL todo
Definition: filedlg.c:313
BOOL expected
Definition: store.c:2000
static void test_GetTypographicFeatures(void)
Definition: analyzer.c:1855
static IDWriteTextAnalysisSinkVtbl analysissinkvtbl2
Definition: analyzer.c:382
static struct sa_test sa_tests[]
Definition: analyzer.c:582
#define MS_GDEF_TAG
Definition: analyzer.c:62
#define RLE
Definition: analyzer.c:53
static const struct textcomplexity_test textcomplexity_tests[]
Definition: analyzer.c:1297
script_id
Definition: analyzer.c:2853
@ Script_Arabic
Definition: analyzer.c:2855
@ Script_Latin
Definition: analyzer.c:2856
static void test_GetGdiCompatibleGlyphPlacements(void)
Definition: analyzer.c:2573
static WORD table_read_be_word(const struct dwrite_fonttable *table, unsigned int offset)
Definition: analyzer.c:1484
static void test_AnalyzeBidi(void)
Definition: analyzer.c:2814
#define LRE
Definition: analyzer.c:52
#define P_D_Z
static const struct orientation_transf_test ot_tests[]
Definition: analyzer.c:2360
static DWRITE_READING_DIRECTION WINAPI analysissource_GetParagraphReadingDirection(IDWriteTextAnalysisSource *iface)
Definition: analyzer.c:461
static ULONG WINAPI analysissource_Release(IDWriteTextAnalysisSource *iface)
Definition: analyzer.c:408
static void _delete_testfontfile(const WCHAR *filename, int line)
Definition: analyzer.c:552
#define BREAKPOINT_COUNT
Definition: analyzer.c:329
static HRESULT WINAPI analysissink_SetBidiLevel(IDWriteTextAnalysisSink *iface, UINT32 position, UINT32 length, UINT8 explicitLevel, UINT8 resolvedLevel)
Definition: analyzer.c:348
static unsigned int get_glyph_class(const struct dwrite_fonttable *table, UINT16 glyph)
Definition: analyzer.c:1503
static HRESULT WINAPI analysissource_GetNumberSubstitution(IDWriteTextAnalysisSource *iface, UINT32 position, UINT32 *text_len, IDWriteNumberSubstitution **substitution)
Definition: analyzer.c:476
#define BIDI_LEVELS_COUNT
Definition: analyzer.c:345
static void test_AnalyzeLineBreakpoints(void)
Definition: analyzer.c:1220
static const struct bidi_test bidi_tests[]
Definition: analyzer.c:2654
static BOOL float_eq(FLOAT left, FLOAT right)
Definition: analyzer.c:2560
static void test_ApplyCharacterSpacing(void)
Definition: analyzer.c:2198
static void * create_text_analyzer(REFIID riid)
Definition: analyzer.c:38
static HRESULT WINAPI analysissink_SetScriptAnalysis2(IDWriteTextAnalysisSink *iface, UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const *sa)
Definition: analyzer.c:322
static void test_uint(UINT32 actual, UINT32 expected, const char *name, const struct testcontext *ctxt)
Definition: analyzer.c:183
#define DELETE_FONTFILE(filename)
Definition: analyzer.c:551
#define PDF
Definition: analyzer.c:54
static DWRITE_SCRIPT_ANALYSIS g_sa
Definition: analyzer.c:321
#define P_D
static void add_call(struct call_sequence **seq, int sequence_index, const struct call_entry *call)
Definition: analyzer.c:145
static const struct spacing_test spacing_tests[]
Definition: analyzer.c:2054
static HRESULT WINAPI analysissink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface, UINT32 position, UINT32 length, IDWriteNumberSubstitution *substitution)
Definition: analyzer.c:363
static IDWriteFontFace * create_testfontface(const WCHAR *filename)
Definition: analyzer.c:558
static WCHAR * create_testfontfile(const WCHAR *filename)
Definition: analyzer.c:526
static void get_fontface_advances(IDWriteFontFace *fontface, FLOAT emsize, const UINT16 *glyphs, FLOAT *advances, UINT32 count)
Definition: analyzer.c:1442
static void test_GetGlyphs(void)
Definition: analyzer.c:1662
static void init_call_sequences(struct call_sequence **seq, int n)
Definition: analyzer.c:175
static void init_expected_sa(struct call_sequence **seq, const struct sa_test *test)
Definition: analyzer.c:1062
@ GDEF_CLASS_UNCLASSIFIED
Definition: analyzer.c:1461
@ GDEF_CLASS_MAX
Definition: analyzer.c:1466
@ GDEF_CLASS_BASE
Definition: analyzer.c:1462
@ GDEF_CLASS_LIGATURE
Definition: analyzer.c:1463
@ GDEF_CLASS_MARK
Definition: analyzer.c:1464
@ GDEF_CLASS_COMPONENT
Definition: analyzer.c:1465
static ULONG WINAPI analysissource_AddRef(IDWriteTextAnalysisSource *iface)
Definition: analyzer.c:402
static HRESULT WINAPI analysissink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface, UINT32 position, UINT32 length, DWRITE_LINE_BREAKPOINT const *breakpoints)
Definition: analyzer.c:332
static IDWriteTextAnalysisSourceVtbl analysissourcevtbl
Definition: analyzer.c:483
static void test_numbersubstitution(void)
Definition: analyzer.c:1383
#define RLI
Definition: analyzer.c:58
static void test_glyph_justification_property(void)
Definition: analyzer.c:2859
static void test_AnalyzeScript(void)
Definition: analyzer.c:1104
static DWRITE_LINE_BREAKPOINT g_actual_bp[BREAKPOINT_COUNT]
Definition: analyzer.c:330
static void compare_breakpoints(const struct linebreaks_test *test, DWRITE_LINE_BREAKPOINT *actual)
Definition: analyzer.c:1191
static UINT8 g_resolved_levels[BIDI_LEVELS_COUNT]
Definition: analyzer.c:347
#define LRI
Definition: analyzer.c:57
#define ok_sequence(seq, index, exp, contx, todo)
Definition: analyzer.c:284
static IDWriteTextAnalysisSink analysissink
Definition: analyzer.c:392
static void ok_sequence_(struct call_sequence **seq, int sequence_index, const struct call_entry *expected, const char *context, BOOL todo, const char *file, int line)
Definition: analyzer.c:195
#define ANALYZER_ID
Definition: analyzer.c:141
static UINT8 g_explicit_levels[BIDI_LEVELS_COUNT]
Definition: analyzer.c:346
#define P_Z
static void test_GetGlyphOrientationTransform(void)
Definition: analyzer.c:2379
static HRESULT WINAPI analysissource_GetTextAtPosition(IDWriteTextAnalysisSource *iface, UINT32 position, WCHAR const **text, UINT32 *text_len)
Definition: analyzer.c:435
static void test_GetScriptProperties(void)
Definition: analyzer.c:1262
static void init_textsource(struct testanalysissource *source, const WCHAR *text, INT text_length, DWRITE_READING_DIRECTION direction)
Definition: analyzer.c:422
#define NUM_CALL_SEQUENCES
Definition: analyzer.c:140
static ULONG WINAPI analysissink_Release(IDWriteTextAnalysisSink *iface)
Definition: analyzer.c:304
static void get_enus_string(IDWriteLocalizedStrings *strings, WCHAR *buff, unsigned int size)
Definition: analyzer.c:1549
static HRESULT WINAPI analysissource_QueryInterface(IDWriteTextAnalysisSource *iface, REFIID riid, void **obj)
Definition: analyzer.c:395
static IDWriteFontFace * create_fontface(void)
Definition: analyzer.c:496
static HRESULT WINAPI analysissink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface, UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const *sa)
Definition: analyzer.c:309
static struct testanalysissource analysissource
Definition: analyzer.c:494
static IDWriteTextAnalysisSink analysissink2
Definition: analyzer.c:393
static void compare_bidi_levels(unsigned int seq, const struct bidi_test *test, UINT32 len, UINT8 *explicit, UINT8 *resolved)
Definition: analyzer.c:2759
#define PDI
Definition: analyzer.c:60
static const char * dbgstr_matrix(const DWRITE_MATRIX *m)
Definition: analyzer.c:2371
static void test_GetGlyphPlacements(void)
Definition: analyzer.c:1907
static struct call_sequence * expected_seq[1]
Definition: analyzer.c:143
static HRESULT WINAPI analysissource_GetLocaleName(IDWriteTextAnalysisSource *iface, UINT32 position, UINT32 *text_len, WCHAR const **locale)
Definition: analyzer.c:468
#define GET_BE_WORD(x)
Definition: analyzer.c:70
static ULONG WINAPI analysissink_AddRef(IDWriteTextAnalysisSink *iface)
Definition: analyzer.c:299
analysis_kind
Definition: analyzer.c:98
@ LastKind
Definition: analyzer.c:100
@ ScriptAnalysis
Definition: analyzer.c:99
static const char * get_analysis_kind_name(enum analysis_kind kind)
Definition: analyzer.c:103
static struct call_sequence * sequences[NUM_CALL_SEQUENCES]
Definition: analyzer.c:142
static IDWriteTextAnalysisSinkVtbl analysissinkvtbl
Definition: analyzer.c:372
static void test_GetTextComplexity(void)
Definition: analyzer.c:1320
#define P_S
static const struct linebreaks_test linebreaks_tests[]
Definition: analyzer.c:1138
static HRESULT WINAPI analysissource_GetTextBeforePosition(IDWriteTextAnalysisSource *iface, UINT32 position, WCHAR const **text, UINT32 *text_len)
Definition: analyzer.c:454
static void get_fontface_glyphs(IDWriteFontFace *fontface, const WCHAR *str, UINT16 *glyphs)
Definition: analyzer.c:1430
static const void * table_read_ensure(const struct dwrite_fonttable *table, unsigned int offset, unsigned int size)
Definition: analyzer.c:1476
static HRESULT WINAPI analysissink_QueryInterface(IDWriteTextAnalysisSink *iface, REFIID riid, void **obj)
Definition: analyzer.c:287
static void test_glyph_props(IDWriteTextAnalyzer *analyzer, const WCHAR *family, const WCHAR *face, IDWriteFontFace *fontface)
Definition: analyzer.c:1566
static void test_GetBaseline(void)
Definition: analyzer.c:2496
static struct testanalysissource * impl_from_IDWriteTextAnalysisSource(IDWriteTextAnalysisSource *iface)
Definition: analyzer.c:430
static void get_script_analysis(const WCHAR *str, DWRITE_SCRIPT_ANALYSIS *sa)
Definition: analyzer.c:1085
static int gdef_class_compare_format2(const void *g, const void *r)
Definition: analyzer.c:1490
static const WCHAR pathW[]
Definition: path.c:2368
#define cmp(status, error)
Definition: error.c:118
script
Definition: msipriv.h:396
#define floorf(x)
Definition: mymath.h:65
Definition: mk_font.cpp:20
direction
Definition: netio.c:882
#define GENERIC_WRITE
Definition: nt_native.h:90
#define MAKEINTRESOURCE(i)
Definition: ntverrsrc.c:25
short WCHAR
Definition: pedump.c:58
#define RT_RCDATA
Definition: pedump.c:372
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define REFIID
Definition: guiddef.h:118
#define calloc
Definition: rosglue.h:14
#define test
Definition: rosglue.h:37
#define wine_dbgstr_wn
Definition: testlist.c:2
const WCHAR * str
@ Script_Unknown
Definition: scripts.h:6
#define memset(x, y, z)
Definition: compat.h:39
static const char *static const char const char DWORD void DWORD *static const char const char DWORD void DWORD *static const char DWORD DWORD void * buff
Definition: shcore.c:41
UINT16 designUnitsPerEm
Definition: dwrite.idl:353
BYTE lfItalic
Definition: dimm.idl:64
LONG lfHeight
Definition: dimm.idl:59
LONG lfWeight
Definition: dimm.idl:63
WCHAR lfFaceName[LF_FACESIZE]
Definition: dimm.idl:72
LONG lfWidth
Definition: dimm.idl:60
DWRITE_READING_DIRECTION direction
Definition: analyzer.c:2648
UINT8 resolved[BIDI_LEVELS_COUNT]
Definition: analyzer.c:2650
BOOL todo
Definition: analyzer.c:2651
const WCHAR text[BIDI_LEVELS_COUNT]
Definition: analyzer.c:2647
Definition: analyzer.c:120
struct script_analysis sa
Definition: analyzer.c:122
enum analysis_kind kind
Definition: analyzer.c:121
struct call_entry * sequence
Definition: analyzer.c:137
Definition: http.c:7252
const BYTE * data
unsigned int size
Definition: analyzer.c:1473
Definition: main.c:439
Definition: fci.c:123
Definition: parser.c:49
const WCHAR text[BREAKPOINT_COUNT+1]
Definition: analyzer.c:1134
DWRITE_LINE_BREAKPOINT bp[BREAKPOINT_COUNT]
Definition: analyzer.c:1135
Definition: match.c:28
Definition: name.c:39
DWRITE_GLYPH_ORIENTATION_ANGLE angle
Definition: analyzer.c:2355
uint16_t glyph_class
Definition: opentype.c:467
struct ot_gdef_class_range ranges[1]
Definition: opentype.c:474
int item_count
Definition: analyzer.c:578
int str_len
Definition: analyzer.c:577
struct script_analysis sa[10]
Definition: analyzer.c:579
DWRITE_SCRIPT_SHAPES shapes
Definition: analyzer.c:117
FLOAT min_advance
Definition: analyzer.c:2045
FLOAT modified_advances[3]
Definition: analyzer.c:2048
FLOAT advances[3]
Definition: analyzer.c:2046
DWRITE_SHAPING_GLYPH_PROPERTIES props[3]
Definition: analyzer.c:2051
FLOAT leading
Definition: analyzer.c:2043
FLOAT modified_offsets[3]
Definition: analyzer.c:2049
FLOAT trailing
Definition: analyzer.c:2044
BOOL single_cluster
Definition: analyzer.c:2050
FLOAT offsets[3]
Definition: analyzer.c:2047
BYTE * data
UINT32 text_length
Definition: analyzer.c:418
IDWriteTextAnalysisSource IDWriteTextAnalysisSource_iface
Definition: analyzer.c:416
const WCHAR * text
Definition: analyzer.c:417
DWRITE_READING_DIRECTION direction
Definition: analyzer.c:419
enum analysis_kind kind
Definition: analyzer.c:126
int * failcount
Definition: analyzer.c:128
BOOL todo
Definition: analyzer.c:127
const char * file
Definition: analyzer.c:129
const WCHAR text[5]
Definition: analyzer.c:1291
#define bsearch
#define str_len
Definition: treelist.c:89
const char * LPCSTR
Definition: typedefs.h:52
int32_t INT32
Definition: typedefs.h:58
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
float FLOAT
Definition: typedefs.h:69
int32_t INT
Definition: typedefs.h:58
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t UINT32
Definition: typedefs.h:59
uint32_t ULONG
Definition: typedefs.h:59
static const WCHAR props[]
Definition: wbemdisp.c:288
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define WINAPI
Definition: msvc.h:6
#define E_NOT_SUFFICIENT_BUFFER
Definition: winerror.h:3437
#define E_NOINTERFACE
Definition: winerror.h:3479
#define FW_NORMAL
Definition: wingdi.h:373
unsigned char BYTE
Definition: xxhash.c:193