kernel32: Make CopyFile() call CopyFileEx() instead of the other way around.
[wine] / dlls / dwrite / tests / analyzer.c
1 /*
2  *    Text analyzing tests
3  *
4  * Copyright 2012 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
25 #include "initguid.h"
26 #include "windows.h"
27 #include "dwrite.h"
28
29 #include "wine/test.h"
30
31 static IDWriteFactory *factory;
32
33 enum analysis_kind {
34     ScriptAnalysis,
35     LastKind
36 };
37
38 static const char *get_analysis_kind_name(enum analysis_kind kind)
39 {
40     switch (kind)
41     {
42     case ScriptAnalysis:
43         return "ScriptAnalysis";
44     default:
45         return "unknown";
46     }
47 }
48
49 struct script_analysis {
50     UINT32 pos;
51     UINT32 len;
52     DWRITE_SCRIPT_ANALYSIS a;
53 };
54
55 struct call_entry {
56     enum analysis_kind kind;
57     struct script_analysis sa;
58 };
59
60 struct testcontext {
61     enum analysis_kind kind;
62     int todo;
63     int *failcount;
64     const char *file;
65     int line;
66 };
67
68 struct call_sequence
69 {
70     int count;
71     int size;
72     struct call_entry *sequence;
73 };
74
75 #define NUM_CALL_SEQUENCES    1
76 #define ANALYZER_ID 0
77 static struct call_sequence *sequences[NUM_CALL_SEQUENCES];
78 static struct call_sequence *expected_seq[1];
79
80 static void add_call(struct call_sequence **seq, int sequence_index, const struct call_entry *call)
81 {
82     struct call_sequence *call_seq = seq[sequence_index];
83
84     if (!call_seq->sequence)
85     {
86         call_seq->size = 10;
87         call_seq->sequence = HeapAlloc(GetProcessHeap(), 0,
88                                       call_seq->size * sizeof (struct call_entry));
89     }
90
91     if (call_seq->count == call_seq->size)
92     {
93         call_seq->size *= 2;
94         call_seq->sequence = HeapReAlloc(GetProcessHeap(), 0,
95                                         call_seq->sequence,
96                                         call_seq->size * sizeof (struct call_entry));
97     }
98
99     assert(call_seq->sequence);
100
101     call_seq->sequence[call_seq->count++] = *call;
102 }
103
104 static inline void flush_sequence(struct call_sequence **seg, int sequence_index)
105 {
106     struct call_sequence *call_seq = seg[sequence_index];
107
108     HeapFree(GetProcessHeap(), 0, call_seq->sequence);
109     call_seq->sequence = NULL;
110     call_seq->count = call_seq->size = 0;
111 }
112
113 static inline void flush_sequences(struct call_sequence **seq, int n)
114 {
115     int i;
116     for (i = 0; i < n; i++)
117         flush_sequence(seq, i);
118 }
119
120 static void init_call_sequences(struct call_sequence **seq, int n)
121 {
122     int i;
123
124     for (i = 0; i < n; i++)
125         seq[i] = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct call_sequence));
126 }
127
128 static void test_uint(UINT32 actual, UINT32 expected, const char *name, const struct testcontext *ctxt)
129 {
130     if (expected != actual && ctxt->todo)
131     {
132         (*ctxt->failcount)++;
133         ok_(ctxt->file, ctxt->line) (0, "%s: \"%s\" expecting %u, got %u\n", get_analysis_kind_name(ctxt->kind), name, expected, actual);
134     }
135     else
136         ok_(ctxt->file, ctxt->line) (expected == actual, "%s: \"%s\" expecting %u, got %u\n", get_analysis_kind_name(ctxt->kind), name,
137             expected, actual);
138 }
139
140 static void ok_sequence_(struct call_sequence **seq, int sequence_index,
141     const struct call_entry *expected, const char *context, int todo,
142     const char *file, int line)
143 {
144     struct call_sequence *call_seq = seq[sequence_index];
145     static const struct call_entry end_of_sequence = { LastKind };
146     const struct call_entry *actual, *sequence;
147     int failcount = 0;
148     struct testcontext ctxt;
149
150     add_call(seq, sequence_index, &end_of_sequence);
151
152     sequence = call_seq->sequence;
153     actual = sequence;
154
155     ctxt.failcount = &failcount;
156     ctxt.todo = todo;
157     ctxt.file = file;
158     ctxt.line = line;
159
160     while (expected->kind != LastKind && actual->kind != LastKind)
161     {
162         if (expected->kind == actual->kind)
163         {
164             ctxt.kind = expected->kind;
165
166             switch (actual->kind)
167             {
168             case ScriptAnalysis:
169             {
170                 const struct script_analysis *sa_act = &actual->sa;
171                 const struct script_analysis *sa_exp = &expected->sa;
172
173                 test_uint(sa_act->pos, sa_exp->pos, "position", &ctxt);
174                 test_uint(sa_act->len, sa_exp->len, "length", &ctxt);
175                 test_uint(sa_act->a.script, sa_exp->a.script, "script", &ctxt);
176
177                 break;
178             }
179             default:
180                 ok(0, "%s: callback not handled, %s\n", context, get_analysis_kind_name(actual->kind));
181             }
182             expected++;
183             actual++;
184         }
185         else if (todo)
186         {
187             failcount++;
188             todo_wine
189             {
190                 ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
191                     context, get_analysis_kind_name(expected->kind), get_analysis_kind_name(actual->kind));
192             }
193
194             flush_sequence(seq, sequence_index);
195             return;
196         }
197         else
198         {
199             ok_(file, line) (0, "%s: call %s was expected, but got call %s instead\n",
200                 context, get_analysis_kind_name(expected->kind), get_analysis_kind_name(actual->kind));
201             expected++;
202             actual++;
203         }
204     }
205
206     if (todo)
207     {
208         todo_wine
209         {
210             if (expected->kind != LastKind || actual->kind != LastKind)
211             {
212                 failcount++;
213                 ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
214                     context, get_analysis_kind_name(expected->kind), get_analysis_kind_name(actual->kind));
215             }
216         }
217     }
218     else if (expected->kind != LastKind || actual->kind != LastKind)
219     {
220         ok_(file, line) (0, "%s: the call sequence is not complete: expected %s - actual %s\n",
221             context, get_analysis_kind_name(expected->kind), get_analysis_kind_name(actual->kind));
222     }
223
224     if (todo && !failcount) /* succeeded yet marked todo */
225     {
226         todo_wine
227         {
228             ok_(file, line)(1, "%s: marked \"todo_wine\" but succeeds\n", context);
229         }
230     }
231
232     flush_sequence(seq, sequence_index);
233 }
234
235 #define ok_sequence(seq, index, exp, contx, todo) \
236         ok_sequence_(seq, index, (exp), (contx), (todo), __FILE__, __LINE__)
237
238 static HRESULT WINAPI analysissink_QueryInterface(IDWriteTextAnalysisSink *iface, REFIID riid, void **obj)
239 {
240     if (IsEqualIID(riid, &IID_IDWriteTextAnalysisSink) || IsEqualIID(riid, &IID_IUnknown))
241     {
242         *obj = iface;
243         return S_OK;
244     }
245
246     *obj = NULL;
247     return E_NOINTERFACE;
248 }
249
250 static ULONG WINAPI analysissink_AddRef(IDWriteTextAnalysisSink *iface)
251 {
252     return 2;
253 }
254
255 static ULONG WINAPI analysissink_Release(IDWriteTextAnalysisSink *iface)
256 {
257     return 1;
258 }
259
260 static HRESULT WINAPI analysissink_SetScriptAnalysis(IDWriteTextAnalysisSink *iface,
261     UINT32 position, UINT32 length, DWRITE_SCRIPT_ANALYSIS const* scriptanalysis)
262 {
263     struct call_entry entry;
264
265     entry.kind = ScriptAnalysis;
266     entry.sa.pos = position;
267     entry.sa.len = length;
268     entry.sa.a = *scriptanalysis;
269     add_call(sequences, ANALYZER_ID, &entry);
270     return S_OK;
271 }
272
273 static HRESULT WINAPI analysissink_SetLineBreakpoints(IDWriteTextAnalysisSink *iface,
274         UINT32 position,
275         UINT32 length,
276         DWRITE_LINE_BREAKPOINT const* breakpoints)
277 {
278     ok(0, "unexpected\n");
279     return E_NOTIMPL;
280 }
281
282 static HRESULT WINAPI analysissink_SetBidiLevel(IDWriteTextAnalysisSink *iface,
283         UINT32 position,
284         UINT32 length,
285         UINT8 explicitLevel,
286         UINT8 resolvedLevel)
287 {
288     ok(0, "unexpected\n");
289     return E_NOTIMPL;
290 }
291
292 static HRESULT WINAPI analysissink_SetNumberSubstitution(IDWriteTextAnalysisSink *iface,
293         UINT32 position,
294         UINT32 length,
295         IDWriteNumberSubstitution* substitution)
296 {
297     ok(0, "unexpected\n");
298     return E_NOTIMPL;
299 }
300
301 static IDWriteTextAnalysisSinkVtbl analysissinkvtbl = {
302     analysissink_QueryInterface,
303     analysissink_AddRef,
304     analysissink_Release,
305     analysissink_SetScriptAnalysis,
306     analysissink_SetLineBreakpoints,
307     analysissink_SetBidiLevel,
308     analysissink_SetNumberSubstitution
309 };
310
311 static IDWriteTextAnalysisSink analysissink = { &analysissinkvtbl };
312
313 static HRESULT WINAPI analysissource_QueryInterface(IDWriteTextAnalysisSource *iface,
314     REFIID riid, void **obj)
315 {
316     ok(0, "QueryInterface not expected\n");
317     return E_NOTIMPL;
318 }
319
320 static ULONG WINAPI analysissource_AddRef(IDWriteTextAnalysisSource *iface)
321 {
322     ok(0, "AddRef not expected\n");
323     return 2;
324 }
325
326 static ULONG WINAPI analysissource_Release(IDWriteTextAnalysisSource *iface)
327 {
328     ok(0, "Release not expected\n");
329     return 1;
330 }
331
332 static const WCHAR *g_source;
333
334 static HRESULT WINAPI analysissource_GetTextAtPosition(IDWriteTextAnalysisSource *iface,
335     UINT32 position, WCHAR const** text, UINT32* text_len)
336 {
337     if (position >= lstrlenW(g_source))
338     {
339         *text = NULL;
340         *text_len = 0;
341     }
342     else
343     {
344         *text = &g_source[position];
345         *text_len = lstrlenW(g_source) - position;
346     }
347
348     return S_OK;
349 }
350
351 static HRESULT WINAPI analysissource_GetTextBeforePosition(IDWriteTextAnalysisSource *iface,
352     UINT32 position, WCHAR const** text, UINT32* text_len)
353 {
354     ok(0, "unexpected\n");
355     return E_NOTIMPL;
356 }
357
358 static DWRITE_READING_DIRECTION WINAPI analysissource_GetParagraphReadingDirection(
359     IDWriteTextAnalysisSource *iface)
360 {
361     ok(0, "unexpected\n");
362     return DWRITE_READING_DIRECTION_RIGHT_TO_LEFT;
363 }
364
365 static HRESULT WINAPI analysissource_GetLocaleName(IDWriteTextAnalysisSource *iface,
366     UINT32 position, UINT32* text_len, WCHAR const** locale)
367 {
368     *locale = NULL;
369     *text_len = 0;
370     return S_OK;
371 }
372
373 static HRESULT WINAPI analysissource_GetNumberSubstitution(IDWriteTextAnalysisSource *iface,
374     UINT32 position, UINT32* text_len, IDWriteNumberSubstitution **substitution)
375 {
376     ok(0, "unexpected\n");
377     return E_NOTIMPL;
378 }
379
380 static IDWriteTextAnalysisSourceVtbl analysissourcevtbl = {
381     analysissource_QueryInterface,
382     analysissource_AddRef,
383     analysissource_Release,
384     analysissource_GetTextAtPosition,
385     analysissource_GetTextBeforePosition,
386     analysissource_GetParagraphReadingDirection,
387     analysissource_GetLocaleName,
388     analysissource_GetNumberSubstitution
389 };
390
391 static IDWriteTextAnalysisSource analysissource = { &analysissourcevtbl };
392
393 struct sa_test {
394     const WCHAR string[50];
395     int item_count;
396     struct script_analysis sa[10];
397 };
398
399 enum scriptcode {
400     Script_Arabic = 0,
401     Script_Armenian = 1,
402     Script_Balinese = 2,
403     Script_Bengali = 3,
404     Script_Buginese = 6,
405     Script_Canadian = 8,
406     Script_Cherokee = 11,
407     Script_Controls = 12,
408     Script_Coptic = 13,
409     Script_Cyrillic = 16,
410     Script_Devanagari = 18,
411     Script_Ethiopic = 19,
412     Script_Georgian = 20,
413     Script_Greek = 23,
414     Script_Gujarati = 24,
415     Script_Gurmukhi = 25,
416     Script_Hangul = 27,
417     Script_Hebrew = 29,
418     Script_Kannada = 32,
419     Script_Khmer = 36,
420     Script_Lao = 37,
421     Script_Latin = 38,
422     Script_Lepcha = 39,
423     Script_Limbu = 40,
424     Script_Malayalam = 44,
425     Script_Mongolian = 45,
426     Script_Myanmar = 46,
427     Script_New_TaiLue = 47,
428     Script_NKo = 48,
429     Script_Ogham = 49,
430     Script_OlChiki = 50,
431     Script_Oriya = 53,
432     Script_Runic = 58,
433     Script_Sinhala = 61,
434     Script_Sundanese = 62,
435     Script_Syriac = 64,
436     Script_TaiLe = 67,
437     Script_Tamil = 68,
438     Script_Telugu = 69,
439     Script_Thaana = 70,
440     Script_Thai = 71,
441     Script_Tibetan = 72,
442     Script_Undefined = 77
443 };
444
445 static struct sa_test sa_tests[] = {
446     {
447       /* just 1 char string */
448       {'t',0}, 1,
449           { { 0, 1, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
450     },
451     {
452       {'t','e','s','t',0}, 1,
453           { { 0, 4, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
454     },
455     {
456       {' ',' ',' ',' ','!','$','[','^','{','~',0}, 1,
457           { { 0, 10, { Script_Undefined, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
458     },
459     {
460       {' ',' ',' ','1','2',' ',0}, 1,
461           { { 0, 6, { Script_Undefined, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
462     },
463     {
464       /* digits only */
465       {'1','2',0}, 1,
466           { { 0, 2, { Script_Undefined, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
467     },
468     {
469       /* Arabic */
470       {0x064a,0x064f,0x0633,0x0627,0x0648,0x0650,0x064a,0}, 1,
471           { { 0, 7, { Script_Arabic, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
472     },
473     {
474       /* Arabic */
475       {0x0627,0x0644,0x0635,0x0651,0x0650,0x062d,0x0629,0x064f,' ',0x062a,0x064e,
476        0x0627,0x062c,0x064c,' ',0x0639,0x064e,0x0644,0x0649,' ',
477        0x0631,0x064f,0x0624,0x0648,0x0633,0x0650,' ',0x0627,0x0644,
478        0x0623,0x0635,0x0650,0x062d,0x0651,0x064e,0x0627,0x0621,0x0650,0x06f0,0x06f5,0}, 1,
479           { { 0, 40, { Script_Arabic, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
480     },
481     {
482       /* Arabic, Latin */
483       {'1','2','3','-','5','2',0x064a,0x064f,0x0633,0x0627,0x0648,0x0650,0x064a,'7','1','.',0}, 1,
484           { { 0, 16, { Script_Arabic, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
485     },
486     {
487       /* Arabic, English */
488       {'A','B','C','-','D','E','F',' ',0x0621,0x0623,0x0624,0}, 2,
489           { { 0, 8, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } },
490             { 8, 3, { Script_Arabic, DWRITE_SCRIPT_SHAPES_DEFAULT } },
491           }
492     },
493     {
494       /* leading space, Arabic, English */
495       {' ',0x0621,0x0623,0x0624,'A','B','C','-','D','E','F',0}, 2,
496           { { 0, 4, { Script_Arabic,  DWRITE_SCRIPT_SHAPES_DEFAULT } },
497             { 4, 7, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } },
498           }
499     },
500     {
501       /* English, Arabic, trailing space */
502       {'A','B','C','-','D','E','F',0x0621,0x0623,0x0624,' ',0}, 2,
503           { { 0, 7, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } },
504             { 7, 4, { Script_Arabic, DWRITE_SCRIPT_SHAPES_DEFAULT } },
505           }
506     },
507     {
508       /* C1 Controls, Latin-1 Supplement */
509       {0x80,0x90,0x9f,0xa0,0xc0,0xb8,0xbf,0xc0,0xff,0}, 2,
510           { { 0, 3, { Script_Controls, DWRITE_SCRIPT_SHAPES_DEFAULT } },
511             { 3, 6, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } },
512           }
513     },
514     {
515       /* Latin Extended-A */
516       {0x100,0x120,0x130,0x140,0x150,0x160,0x170,0x17f,0}, 1,
517           { { 0, 8, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
518     },
519     {
520       /* Latin Extended-B */
521       {0x180,0x190,0x1bf,0x1c0,0x1c3,0x1c4,0x1cc,0x1dc,0x1ff,0x217,0x21b,0x24f,0}, 1,
522           { { 0, 12, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
523     },
524     {
525       /* IPA Extensions */
526       {0x250,0x260,0x270,0x290,0x2af,0}, 1,
527           { { 0, 5, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
528     },
529     {
530       /* Spacing Modifier Letters */
531       {0x2b0,0x2ba,0x2d7,0x2dd,0x2ef,0x2ff,0}, 1,
532           { { 0, 6, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
533     },
534     {
535       /* Combining Diacritical Marks */
536       {0x300,0x320,0x340,0x345,0x350,0x36f,0}, 1,
537           { { 0, 6, { Script_Undefined, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
538     },
539     {
540       /* Greek and Coptic */
541       {0x370,0x388,0x3d8,0x3e1,0x3e2,0x3fa,0x3ff,0}, 3,
542           { { 0, 4, { Script_Greek, DWRITE_SCRIPT_SHAPES_DEFAULT } },
543             { 4, 1, { Script_Coptic, DWRITE_SCRIPT_SHAPES_DEFAULT } },
544             { 5, 2, { Script_Greek, DWRITE_SCRIPT_SHAPES_DEFAULT } }
545           }
546     },
547     {
548       /* Cyrillic and Cyrillic Supplement */
549       {0x400,0x40f,0x410,0x44f,0x450,0x45f,0x460,0x481,0x48a,0x4f0,0x4fa,0x4ff,0x500,0x510,0x520,0}, 1,
550           { { 0, 15, { Script_Cyrillic, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
551     },
552     {
553       /* Armenian */
554       {0x531,0x540,0x559,0x55f,0x570,0x589,0x58a,0}, 1,
555           { { 0, 7, { Script_Armenian, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
556     },
557     {
558       /* Hebrew */
559       {0x5e9,0x5dc,0x5d5,0x5dd,0}, 1,
560           { { 0, 4, { Script_Hebrew, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
561     },
562     {
563       /* Hebrew */
564       {'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}, 3,
565           { { 0, 9, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } },
566             { 9, 10, { Script_Hebrew, DWRITE_SCRIPT_SHAPES_DEFAULT } },
567             { 19, 10, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
568     },
569     {
570       /* Syriac */
571       {0x710,0x712,0x712,0x714,'.',0}, 1,
572           { { 0, 5, { Script_Syriac, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
573     },
574     {
575       /* Arabic Supplement */
576       {0x750,0x760,0x76d,'.',0}, 1,
577           { { 0, 4, { Script_Arabic, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
578     },
579     {
580       /* Thaana */
581       {0x780,0x78e,0x798,0x7a6,0x7b0,'.',0}, 1,
582           { { 0, 6, { Script_Thaana, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
583     },
584     {
585       /* N'Ko */
586       {0x7c0,0x7ca,0x7e8,0x7eb,0x7f6,'.',0}, 1,
587           { { 0, 6, { Script_NKo, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
588     },
589     {
590       /* Thaana */
591       {0x780,0x798,0x7a5,0x7a6,0x7b0,'.',0}, 1,
592           { { 0, 6, { Script_Thaana, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
593     },
594     {
595       /* Devanagari */
596       {0x926,0x947,0x935,0x928,0x93e,0x917,0x930,0x940,'.',0}, 1,
597           { { 0, 9, { Script_Devanagari, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
598     },
599     {
600       /* Bengali */
601       {0x9ac,0x9be,0x982,0x9b2,0x9be,'.',0}, 1,
602           { { 0, 6, { Script_Bengali, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
603     },
604     {
605       /* Gurmukhi */
606       {0xa17,0xa41,0xa30,0xa2e,0xa41,0xa16,0xa40,'.',0}, 1,
607           { { 0, 8, { Script_Gurmukhi, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
608     },
609     {
610       /* Gujarati */
611       {0xa97,0xac1,0xa9c,0xab0,0xabe,0xaa4,0xac0,'.',0}, 1,
612           { { 0, 8, { Script_Gujarati, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
613     },
614     {
615       /* Oriya */
616       {0xb13,0xb21,0xb3c,0xb3f,0xb06,'.',0}, 1,
617           { { 0, 6, { Script_Oriya, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
618     },
619     {
620       /* Tamil */
621       {0xba4,0xbae,0xbbf,0xbb4,0xbcd,'.',0}, 1,
622           { { 0, 6, { Script_Tamil, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
623     },
624     {
625       /* Telugu */
626       {0xc24,0xc46,0xc32,0xc41,0xc17,0xc41,'.',0}, 1,
627           { { 0, 7, { Script_Telugu, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
628     },
629     {
630       /* Kannada */
631       {0xc95,0xca8,0xccd,0xca8,0xca1,'.',0}, 1,
632           { { 0, 6, { Script_Kannada, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
633     },
634     {
635       /* Malayalam */
636       {0xd2e,0xd32,0xd2f,0xd3e,0xd33,0xd02,'.',0}, 1,
637           { { 0, 7, { Script_Malayalam, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
638     },
639     {
640       /* Sinhala */
641       {0xd82,0xd85,0xd9a,0xdcf,'.',0}, 1,
642           { { 0, 5, { Script_Sinhala, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
643     },
644     {
645       /* Thai */
646       {0x0e04,0x0e27,0x0e32,0x0e21,0x0e1e,0x0e22,0x0e32,0x0e22,0x0e32,0x0e21,
647        0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e44,0x0e2b,0x0e19,
648        0x0e04,0x0e27,0x0e32,0x0e21,0x0e2a, 0x0e33,0x0e40,0x0e23,0x0e47,0x0e08,
649        0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e19,0x0e31,0x0e48,0x0e19,'.',0}, 1,
650           { { 0, 42, { Script_Thai, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
651     },
652     {
653       /* Lao */
654       {0xead,0xeb1,0xe81,0xeaa,0xead,0xe99,0xea5,0xeb2,0xea7,'.',0}, 1,
655           { { 0, 10, { Script_Lao, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
656     },
657     {
658       /* Tibetan */
659       {0xf04,0xf05,0xf0e,0x020,0xf51,0xf7c,0xf53,0xf0b,0xf5a,0xf53,0xf0b,
660        0xf51,0xf44,0xf0b,0xf54,0xf7c,0xf0d,'.',0}, 1,
661           { { 0, 18, { Script_Tibetan, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
662     },
663     {
664       /* Myanmar */
665       {0x1019,0x103c,0x1014,0x103a,0x1019,0x102c,0x1021,0x1000,0x1039,0x1001,0x101b,0x102c,'.',0}, 1,
666           { { 0, 13, { Script_Myanmar, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
667     },
668     {
669       /* Georgian */
670       {0x10a0,0x10d0,0x10da,0x10f1,0x10fb,'.',0}, 1,
671           { { 0, 6, { Script_Georgian, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
672     },
673     {
674       /* Hangul */
675       {0x1100,0x1110,0x1160,0x1170,0x11a8,'.',0}, 1,
676           { { 0, 6, { Script_Hangul, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
677     },
678     {
679       /* Ethiopic */
680       {0x130d,0x12d5,0x12dd,0}, 1,
681           { { 0, 3, { Script_Ethiopic, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
682     },
683     {
684       /* Cherokee */
685       {0x13e3,0x13b3,0x13a9,0x0020,0x13a6,0x13ec,0x13c2,0x13af,0x13cd,0x13d7,0}, 1,
686           { { 0, 10, { Script_Cherokee, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
687     },
688     {
689       /* Canadian */
690       {0x1403,0x14c4,0x1483,0x144e,0x1450,0x1466,0}, 1,
691           { { 0, 6, { Script_Canadian, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
692     },
693     {
694       /* Ogham */
695       {0x169b,0x1691,0x168c,0x1690,0x168b,0x169c,0}, 1,
696           { { 0, 6, { Script_Ogham, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
697     },
698     {
699       /* Runic */
700       {0x16a0,0x16a1,0x16a2,0x16a3,0x16a4,0x16a5,0}, 1,
701           { { 0, 6, { Script_Runic, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
702     },
703     {
704       /* Khmer */
705       {0x1781,0x17c1,0x1798,0x179a,0x1797,0x17b6,0x179f,0x17b6,0x19e0,0}, 1,
706           { { 0, 9, { Script_Khmer, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
707     },
708     {
709       /* Mongolian */
710       {0x182e,0x1823,0x1829,0x182d,0x1823,0x182f,0x0020,0x182a,0x1822,0x1834,0x1822,0x182d,0x180c,0}, 1,
711           { { 0, 13, { Script_Mongolian, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
712     },
713     {
714       /* Limbu */
715       {0x1900,0x1910,0x1920,0x1930,0}, 1,
716           { { 0, 4, { Script_Limbu, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
717     },
718     {
719       /* Tai Le */
720       {0x1956,0x196d,0x1970,0x1956,0x196c,0x1973,0x1951,0x1968,0x1952,0x1970,0}, 1,
721           { { 0, 10, { Script_TaiLe, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
722     },
723     {
724       /* New Tai Lue */
725       {0x1992,0x19c4,0}, 1,
726           { { 0, 2, { Script_New_TaiLue, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
727     },
728     {
729       /* Buginese */
730       {0x1a00,0x1a10,0}, 1,
731           { { 0, 2, { Script_Buginese, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
732     },
733     {
734       /* Tai Tham */
735       {0x1a20,0x1a40,0x1a50,0}, 1,
736           { { 0, 3, { Script_Undefined, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
737     },
738     {
739       /* Balinese */
740       {0x1b00,0x1b05,0x1b20,0}, 1,
741           { { 0, 3, { Script_Balinese, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
742     },
743     {
744       /* Sundanese */
745       {0x1b80,0x1b85,0x1ba0,0}, 1,
746           { { 0, 3, { Script_Sundanese, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
747     },
748     {
749       /* Batak */
750       {0x1bc0,0x1be5,0x1bfc,0}, 1,
751           { { 0, 3, { Script_Undefined, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
752     },
753     {
754       /* Lepcha */
755       {0x1c00,0x1c20,0x1c40,0}, 1,
756           { { 0, 3, { Script_Lepcha, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
757     },
758     {
759       /* Ol Chiki */
760       {0x1c50,0x1c5a,0x1c77,0}, 1,
761           { { 0, 3, { Script_OlChiki, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
762     },
763     {
764       /* Sundanese Supplement */
765       {0x1cc0,0x1cc5,0x1cc8,0}, 1,
766           { { 0, 3, { Script_Undefined, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
767     },
768     {
769       /* Phonetic Extensions */
770       {0x1d00,0x1d40,0x1d70,0}, 1,
771           { { 0, 3, { Script_Latin, DWRITE_SCRIPT_SHAPES_DEFAULT } }}
772     },
773     /* keep this as end marker */
774     { {0} }
775 };
776
777 static void init_expected_sa(struct call_sequence **seq, const struct sa_test *test)
778 {
779     static const struct call_entry end_of_sequence = { LastKind };
780     int i;
781
782     flush_sequence(seq, 0);
783
784     /* add expected calls */
785     for (i = 0; i < test->item_count; i++)
786     {
787         struct call_entry call;
788
789         call.kind = ScriptAnalysis;
790         call.sa.pos = test->sa[i].pos;
791         call.sa.len = test->sa[i].len;
792         call.sa.a = test->sa[i].a;
793         add_call(seq, 0, &call);
794     }
795
796     /* and stop marker */
797     add_call(seq, 0, &end_of_sequence);
798 }
799
800 static void test_AnalyzeScript(void)
801 {
802     const struct sa_test *ptr = sa_tests;
803     IDWriteTextAnalyzer *analyzer;
804     HRESULT hr;
805
806     hr = IDWriteFactory_CreateTextAnalyzer(factory, &analyzer);
807     ok(hr == S_OK, "got 0x%08x\n", hr);
808
809     while (*ptr->string)
810     {
811         g_source = ptr->string;
812
813         init_expected_sa(expected_seq, ptr);
814         hr = IDWriteTextAnalyzer_AnalyzeScript(analyzer, &analysissource, 0, lstrlenW(g_source), &analysissink);
815         ok(hr == S_OK, "got 0x%08x\n", hr);
816         ok_sequence(sequences, ANALYZER_ID, expected_seq[0]->sequence, "AnalyzeScript", FALSE);
817         ptr++;
818     }
819
820     IDWriteTextAnalyzer_Release(analyzer);
821 }
822
823 START_TEST(analyzer)
824 {
825     HRESULT hr;
826
827     hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_ISOLATED, &IID_IDWriteFactory, (IUnknown**)&factory);
828     ok(hr == S_OK, "got 0x%08x\n", hr);
829     if (hr != S_OK)
830     {
831         win_skip("failed to create factory\n");
832         return;
833     }
834
835     init_call_sequences(sequences, NUM_CALL_SEQUENCES);
836     init_call_sequences(expected_seq, 1);
837
838     test_AnalyzeScript();
839
840     IDWriteFactory_Release(factory);
841 }