janitorial: Remove remaining NULL checks before free() (found by Smatch).
[wine] / dlls / usp10 / tests / usp10.c
1 /*
2  * Tests for usp10 dll
3  *
4  * Copyright 2006 Jeff Latimer
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  * Notes:
21  * Uniscribe allows for processing of complex scripts such as joining
22  * and filtering characters and bi-directional text with custom line breaks.
23  */
24
25 #include <assert.h>
26 #include <stdio.h>
27
28 #include <wine/test.h>
29 #include <winbase.h>
30 #include <wingdi.h>
31 #include <winuser.h>
32 #include <winerror.h>
33 #include <winnls.h>
34 #include <usp10.h>
35
36 static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256])
37 {
38     HRESULT         hr;
39     int             iMaxProps;
40     const SCRIPT_PROPERTIES **ppSp;
41
42     int             cInChars;
43     int             cMaxItems;
44     SCRIPT_ITEM     pItem[255];
45     int             pcItems;
46     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
47     WCHAR           TestItem2[] = {'T', 'e', 's', 't', 'b', 0}; 
48     WCHAR           TestItem3[] = {'T', 'e', 's', 't', 'c',' ','1','2','3',' ',' ','e','n','d',0}; 
49     WCHAR           TestItem4[] = {'T', 'e', 's', 't', 'c',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0}; 
50
51     SCRIPT_CACHE    psc;
52     int             cChars;
53     int             cMaxGlyphs;
54     unsigned short  pwOutGlyphs1[256];
55     unsigned short  pwOutGlyphs2[256];
56     unsigned short  pwLogClust[256];
57     SCRIPT_VISATTR  psva[256];
58     int             pcGlyphs;
59     int             piAdvance[256];
60     GOFFSET         pGoffset[256];
61     ABC             pABC[256];
62     LOGFONTA        lf;
63     HFONT           zfont;
64     int             cnt;
65
66
67     lstrcpyA(lf.lfFaceName, "Symbol");
68     lf.lfHeight = 10;
69     lf.lfItalic = 0;
70     lf.lfEscapement = 0;
71     lf.lfOrientation = 0;
72     lf.lfUnderline = 0;
73     lf.lfStrikeOut = 0;
74     lf.lfWeight = 3;
75     lf.lfWidth = 10;
76
77     zfont = (HFONT) SelectObject(hdc, CreateFontIndirectA(&lf));
78
79     /* Start testing usp10 functions                                                         */
80     /* This test determines that the pointer returned by ScriptGetProperties is valid
81      * by checking a known value in the table                                                */
82     hr = ScriptGetProperties(&ppSp, &iMaxProps);
83     trace("number of script properties %d\n", iMaxProps);
84     ok (iMaxProps > 0, "Number of scripts returned should not be 0\n"); 
85     if  (iMaxProps > 0)
86          ok( ppSp[5]->langid == 9, "Langid[5] not = to 9\n"); /* Check a known value to ensure   */
87                                                               /* ptrs work                       */
88
89
90     /* This set of tests are to check that the various edits in ScriptIemize work           */
91     cInChars = 5;                                        /* Length of test without NULL     */
92     cMaxItems = 1;                                       /* Check threshold value           */
93     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
94     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cMaxItems < 2.  Was %d\n",
95         cMaxItems);
96     cInChars = 5;
97     cMaxItems = 255;
98     hr = ScriptItemize(NULL, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
99     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pwcInChars is NULL\n");
100
101     cInChars = 5;
102     cMaxItems = 255;
103     hr = ScriptItemize(TestItem1, 0, cMaxItems, NULL, NULL, pItem, &pcItems);
104     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cInChars is 0\n");
105
106     cInChars = 5;
107     cMaxItems = 255;
108     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, NULL, &pcItems);
109     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pItems is NULL\n");
110
111     /* This is a valid test that will cause parsing to take place                             */
112     cInChars = 5;
113     cMaxItems = 255;
114     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
115     ok (hr == 0, "ScriptItemize should return 0, returned %08lx\n", hr);
116     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
117      *  returned.                                                                             */
118     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
119     if (pcItems > 0)
120         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
121             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
122             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
123
124     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
125      * ie. ScriptItemize has succeeded and that pItem has been set                            */
126     cInChars = 5;
127     cMaxItems = 255;
128     if (hr == 0) {
129         psc = NULL;                                   /* must be null on first call           */
130         cChars = cInChars;
131         cMaxGlyphs = cInChars;
132         hr = ScriptShape(NULL, &psc, TestItem1, cChars,
133                          cMaxGlyphs, &pItem[0].a,
134                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
135         ok (hr == E_PENDING, "If psc is NULL (%08lx) the E_PENDING should be returned\n", hr);
136         cMaxGlyphs = 4;
137         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
138                          cMaxGlyphs, &pItem[0].a,
139                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
140         ok (hr == E_OUTOFMEMORY, "If not enough output area cChars (%d) is > than CMaxGlyphs "
141                                  "(%d) but not E_OUTOFMEMORY\n",
142                                  cChars, cMaxGlyphs);
143         cMaxGlyphs = 256;
144         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
145                          cMaxGlyphs, &pItem[0].a,
146                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
147         ok (hr == 0, "ScriptShape should return 0 not (%08lx)\n", hr);
148         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
149         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
150         if (hr ==0) {
151             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
152                              pGoffset, pABC);
153             ok (hr == 0, "ScriptPlace should return 0 not (%08lx)\n", hr);
154             hr = ScriptPlace(NULL, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
155                              pGoffset, pABC);
156             ok (hr == 0, "ScriptPlace should return 0 not (%08lx)\n", hr);
157             for (cnt=0; cnt < pcGlyphs; cnt++)
158                 pwOutGlyphs[cnt] = pwOutGlyphs1[cnt];                 /* Send to next function */
159         }
160
161         /* This test will check to make sure that SCRIPT_CACHE is reused and that not translation   *
162          * takes place if fNoGlyphIndex is set.                                                     */
163
164         cInChars = 5;
165         cMaxItems = 255;
166         hr = ScriptItemize(TestItem2, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
167         ok (hr == 0, "ScriptItemize should return 0, returned %08lx\n", hr);
168         /*  This test is for the intertrim operation of ScriptItemize where only one SCRIPT_ITEM is *
169          *  returned.                                                                               */
170         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
171                             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
172                              pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
173         /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue                    */
174         if (hr == 0) {
175              cChars = cInChars;
176              cMaxGlyphs = 256;
177              pItem[0].a.fNoGlyphIndex = 1;                /* say no translate                     */
178              hr = ScriptShape(NULL, &psc, TestItem2, cChars,
179                               cMaxGlyphs, &pItem[0].a,
180                               pwOutGlyphs2, pwLogClust, psva, &pcGlyphs);
181              ok (hr != E_PENDING, "If psc should not be NULL (%08lx) and the E_PENDING should be returned\n", hr);
182              ok (hr == 0, "ScriptShape should return 0 not (%08lx)\n", hr);
183              ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
184              ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
185              for (cnt=0; cnt < cChars && TestItem2[cnt] == pwOutGlyphs2[cnt]; cnt++) {}
186              ok (cnt == cChars, "Translation to place when told not to. WCHAR %d - %04x != %04x\n",
187                            cnt, TestItem2[cnt], pwOutGlyphs2[cnt]);
188              if (hr ==0) {
189                  hr = ScriptPlace(hdc, &psc, pwOutGlyphs2, pcGlyphs, psva, &pItem[0].a, piAdvance,
190                                   pGoffset, pABC);
191                  ok (hr == 0, "ScriptPlace should return 0 not (%08lx)\n", hr);
192              }
193         }
194         hr = ScriptFreeCache( &psc);
195         ok (!psc, "psc is not null after ScriptFreeCache\n");
196
197     }
198
199     /* This is a valid test that will cause parsing to take place and create 3 script_items   */
200     cInChars = (sizeof(TestItem3)/2)-1;
201     cMaxItems = 255;
202     hr = ScriptItemize(TestItem3, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
203     ok (hr == 0, "ScriptItemize should return 0, returned %08lx\n", hr);
204     if  (hr == 0)
205         {
206         ok (pcItems == 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems);
207         if (pcItems > 2)
208         {
209             ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
210                 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
211                 pItem[0].iCharPos, pItem[1].iCharPos);
212             ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
213                 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
214                 pItem[1].iCharPos, pItem[2].iCharPos);
215             ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == cInChars,
216                 "Start pos [2] not = 11 (%d) or end [3] pos not = 14 (%d), cInChars = %d\n",
217                 pItem[2].iCharPos, pItem[3].iCharPos, cInChars);
218         }
219         hr = ScriptFreeCache( &psc);
220         ok (!psc, "psc is not null after ScriptFreeCache\n");
221     }
222
223     /* This is a valid test that will cause parsing to take place and create 3 script_items   */
224     cInChars = (sizeof(TestItem4)/2)-1;
225     cMaxItems = 255;
226     hr = ScriptItemize(TestItem4, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
227     ok (hr == 0, "ScriptItemize should return 0, returned %08lx\n", hr);
228     if  (hr == 0)
229         {
230         ok (pcItems == 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems);
231         if (pcItems > 2)
232         {
233             ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
234                 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
235                 pItem[0].iCharPos, pItem[1].iCharPos);
236             ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
237                 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
238                 pItem[1].iCharPos, pItem[2].iCharPos);
239             ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == cInChars,
240                 "Start pos [2] not = 11 (%d) or end [3] pos not = 14 (%d), cInChars = %d\n",
241                 pItem[2].iCharPos, pItem[3].iCharPos, cInChars);
242         }
243         hr = ScriptFreeCache( &psc);
244         ok (!psc, "psc is not null after ScriptFreeCache\n");
245     }
246 }
247
248 void test_ScriptGetCMap(HDC hdc, unsigned short pwOutGlyphs[256])
249 {
250     HRESULT         hr;
251     SCRIPT_CACHE    psc = NULL;
252     int             cInChars;
253     int             cChars;
254     unsigned short  pwOutGlyphs3[256];
255     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
256     DWORD           dwFlags;
257     int             cnt;
258
259     /*  Check to make sure that SCRIPT_CACHE gets allocated ok                     */
260     dwFlags = 0;
261     cInChars = cChars = 5;
262     /* Some sanity checks for ScriptGetCMap */
263
264     hr = ScriptGetCMap(NULL, NULL, NULL, 0, 0, NULL);
265     ok( hr == E_INVALIDARG, "(NULL,NULL,NULL,0,0,NULL), "
266                             "expected E_INVALIDARG, got %08lx\n", hr);
267
268     hr = ScriptGetCMap(NULL, NULL, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
269     ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
270                             "expected E_INVALIDARG, got %08lx\n", hr);
271
272     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
273     psc = NULL;
274     hr = ScriptGetCMap(NULL, &psc, NULL, 0, 0, NULL);
275     ok( hr == E_PENDING, "(NULL,&psc,NULL,0,0NULL), expected E_PENDING, "
276                          "got %08lx\n", hr);
277     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
278
279     /* Set psc to NULL but add hdc, to be able to check if a pointer is returned in psc */
280     psc = NULL;
281     hr = ScriptGetCMap(hdc, &psc, NULL, 0, 0, NULL);
282     ok( hr == S_OK, "ScriptGetCMap(NULL,&psc,NULL,0,0,NULL), expected S_OK, "
283                     "got %08lx\n", hr);
284     ok( psc != NULL, "ScritpGetCMap expected psc to be not NULL\n");
285
286     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
287     psc = NULL;
288     hr = ScriptGetCMap(NULL, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
289     ok( hr == E_PENDING, "(NULL,&psc,), expected E_PENDING, got %08lx\n", hr);
290     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
291     /*  Check to see if the results are the same as those returned by ScriptShape  */
292     hr = ScriptGetCMap(hdc, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
293     ok (hr == 0, "ScriptGetCMap should return 0 not (%08lx)\n", hr);
294     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
295     for (cnt=0; cnt < cChars && pwOutGlyphs[cnt] == pwOutGlyphs3[cnt]; cnt++) {}
296     ok (cnt == cInChars, "Translation not correct. WCHAR %d - %04x != %04x\n",
297                          cnt, pwOutGlyphs[cnt], pwOutGlyphs3[cnt]);
298         
299     hr = ScriptFreeCache( &psc);
300     ok (!psc, "psc is not null after ScriptFreeCache\n");
301
302 }
303
304 void test_ScriptGetFontProperties(void)
305 {
306     HRESULT         hr;
307     HDC             hdc;
308     HWND            hwnd;
309     SCRIPT_CACHE    psc,old_psc;
310     SCRIPT_FONTPROPERTIES sfp;
311
312     /* Only do the bare minumum to get a valid hdc */
313     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,0, 0, 0, NULL);
314     assert(hwnd != 0);
315
316     hdc = GetDC(hwnd);
317     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
318
319     /* Some sanity checks for ScriptGetFontProperties */
320
321     hr = ScriptGetFontProperties(NULL,NULL,NULL);
322     ok( hr == E_INVALIDARG, "(NULL,NULL,NULL), expected E_INVALIDARG, got %08lx\n", hr);
323
324     hr = ScriptGetFontProperties(NULL,NULL,&sfp);
325     ok( hr == E_INVALIDARG, "(NULL,NULL,&sfp), expected E_INVALIDARG, got %08lx\n", hr);
326
327     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
328     psc = NULL;
329     hr = ScriptGetFontProperties(NULL,&psc,NULL);
330     ok( hr == E_INVALIDARG, "(NULL,&psc,NULL), expected E_INVALIDARG, got %08lx\n", hr);
331     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
332
333     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
334     psc = NULL;
335     hr = ScriptGetFontProperties(NULL,&psc,&sfp);
336     ok( hr == E_PENDING, "(NULL,&psc,&sfp), expected E_PENDING, got %08lx\n", hr);
337     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
338
339     hr = ScriptGetFontProperties(hdc,NULL,NULL);
340     ok( hr == E_INVALIDARG, "(hdc,NULL,NULL), expected E_INVALIDARG, got %08lx\n", hr);
341
342     hr = ScriptGetFontProperties(hdc,NULL,&sfp);
343     ok( hr == E_INVALIDARG, "(hdc,NULL,&sfp), expected E_INVALIDARG, got %08lx\n", hr);
344
345     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
346     psc = NULL;
347     hr = ScriptGetFontProperties(hdc,&psc,NULL);
348     ok( hr == E_INVALIDARG, "(hdc,&psc,NULL), expected E_INVALIDARG, got %08lx\n", hr);
349     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
350
351     /* Pass an uninitialized sfp */
352     psc = NULL;
353     hr = ScriptGetFontProperties(hdc,&psc,&sfp);
354     ok( hr == E_INVALIDARG, "(hdc,&psc,&sfp) partly uninitialized, expected E_INVALIDARG, got %08lx\n", hr);
355     ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
356     ScriptFreeCache(&psc);
357     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
358
359     /* Give it the correct cBytes, we don't care about what's coming back */
360     sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES);
361     psc = NULL;
362     hr = ScriptGetFontProperties(hdc,&psc,&sfp);
363     ok( hr == S_OK, "(hdc,&psc,&sfp) partly initialized, expected S_OK, got %08lx\n", hr);
364     ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
365
366     /* Save the psc pointer */
367     old_psc = psc;
368     /* Now a NULL hdc again */
369     hr = ScriptGetFontProperties(NULL,&psc,&sfp);
370     ok( hr == S_OK, "(NULL,&psc,&sfp), expected S_OK, got %08lx\n", hr);
371     ok( psc == old_psc, "Expected psc not to be changed, was %p is now %p\n", old_psc, psc);
372     ScriptFreeCache(&psc);
373     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
374
375     /* Cleanup */
376     ReleaseDC(hwnd, hdc);
377     DestroyWindow(hwnd);
378 }
379
380 void test_ScriptTextOut(void)
381 {
382     HRESULT         hr;
383     HWND            hwnd;
384     HDC             hdc;
385
386     int             cInChars;
387     int             cMaxItems;
388     SCRIPT_ITEM     pItem[255];
389     int             pcItems;
390     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
391
392     SCRIPT_CACHE    psc;
393     int             cChars;
394     int             cMaxGlyphs;
395     unsigned short  pwOutGlyphs1[256];
396     WORD            pwLogClust[256];
397     SCRIPT_VISATTR  psva[256];
398     int             pcGlyphs;
399     int             piAdvance[256];
400     GOFFSET         pGoffset[256];
401     ABC             pABC[256];
402     RECT            rect;
403     int             piX;
404     int             iCP = 1;
405     BOOL            fTrailing = FALSE;
406     SCRIPT_LOGATTR  *psla;
407     SCRIPT_LOGATTR  sla[256];
408
409     /* We need a valid HDC to drive a lot of Script functions which requires the following    *
410      * to set up for the tests.                                                               */
411     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
412                            0, 0, 0, NULL);
413     assert(hwnd != 0);
414     ShowWindow(hwnd, SW_SHOW);
415     UpdateWindow(hwnd);
416
417     hdc = GetDC(hwnd);                                      /* We now have a hdc             */
418     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
419
420     /* This is a valid test that will cause parsing to take place                             */
421     cInChars = 5;
422     cMaxItems = 255;
423     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
424     ok (hr == 0, "ScriptItemize should return 0, returned %08lx\n", hr);
425     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
426      *  returned.                                                                             */
427     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
428     if (pcItems > 0)
429         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
430             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
431             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
432
433     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
434      * ie. ScriptItemize has succeeded and that pItem has been set                            */
435     cInChars = 5;
436     cMaxItems = 255;
437     if (hr == 0) {
438         psc = NULL;                                   /* must be null on first call           */
439         cChars = cInChars;
440         cMaxGlyphs = cInChars;
441         cMaxGlyphs = 256;
442         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
443                          cMaxGlyphs, &pItem[0].a,
444                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
445         ok (hr == 0, "ScriptShape should return 0 not (%08lx)\n", hr);
446         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
447         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
448         if (hr ==0) {
449             /* Note hdc is needed as glyph info is not yet in psc                  */
450             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
451                              pGoffset, pABC);
452             ok (hr == 0, "Should return 0 not (%08lx)\n", hr);
453             ScriptFreeCache(&psc);              /* Get rid of psc for next test set */
454             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
455
456             hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL);
457             ok (hr == E_INVALIDARG, "Should return 0 not (%08lx)\n", hr);
458
459             hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
460                                piAdvance, NULL, pGoffset);
461             ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
462                                     "expected E_INVALIDARG, got %08lx\n", hr);
463
464             /* Set psc to NULL, to be able to check if a pointer is returned in psc */
465             psc = NULL;
466             hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0,
467                                NULL, NULL, NULL);
468             ok( hr == E_INVALIDARG, "(NULL,&psc,NULL,0,0,0,NULL,), expected E_INVALIDARG, "
469                                     "got %08lx\n", hr);
470             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
471
472             /* Set psc to NULL, to be able to check if a pointer is returned in psc
473              * hdc is required for this one rather than the usual optional          */
474             psc = NULL;
475             hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
476                                piAdvance, NULL, pGoffset);
477             ok( hr == E_INVALIDARG, "(NULL,&psc,), expected E_INVALIDARG, got %08lx\n", hr);
478             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
479
480             /* Set that is gets a psc and that returns 0 status */
481             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
482                                piAdvance, NULL, pGoffset);
483             ok (hr == 0, "ScriptTextOut should return 0 not (%08lx)\n", hr);
484             ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
485
486             /* Test Rect Rgn is acceptable */
487             rect.top = 10;
488             rect.bottom = 20;
489             rect.left = 10;
490             rect.right = 40;
491             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, &rect, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
492                                piAdvance, NULL, pGoffset);
493             ok (hr == 0, "ScriptTextOut should return 0 not (%08lx)\n", hr);
494             ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
495
496             iCP = 1;
497             hr = ScriptCPtoX(iCP, fTrailing, cChars, pcGlyphs, (const WORD *) &pwLogClust,
498                             (const SCRIPT_VISATTR *) &psva, (const int *)&piAdvance, &pItem[0].a, &piX);
499             ok(hr == S_OK, "ScriptCPtoX Stub should return S_OK not %08lx\n", hr);
500
501             psla = (SCRIPT_LOGATTR *)&sla;
502             hr = ScriptBreak(TestItem1, cChars, &pItem[0].a, psla);
503             ok(hr == S_OK, "ScriptBreak Stub should return S_OK not %08lx\n", hr);
504
505             /* Clean up and go   */
506             ScriptFreeCache(&psc);
507             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
508         }
509     }
510     ReleaseDC(hwnd, hdc);
511     DestroyWindow(hwnd);
512 }
513
514 static void test_ScriptXtoX(void)
515 /****************************************************************************************
516  *  This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables *
517  ****************************************************************************************/
518 {
519     int iX, iCP;
520     int cChars;
521     int cGlyphs;
522     WORD pwLogClust[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
523     SCRIPT_VISATTR psva[10];
524     int piAdvance[10] = {200, 190, 210, 180, 170, 204, 189, 195, 212, 203};
525     SCRIPT_ANALYSIS psa;
526     int piCP, piX;
527     int piTrailing;
528     BOOL fTrailing;
529     HRESULT hr;
530
531     iX = -1;
532     cChars = 10;
533     cGlyphs = 10;
534     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing);
535     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08lx\n", hr);
536     ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
537     ok(piTrailing == TRUE, "Negative iX should return piTrailing=TRUE not %d\n", piTrailing);
538     iX = 1954;
539     cChars = 10;
540     cGlyphs = 10;
541     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing);
542     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08lx\n", hr);
543     ok(piCP == 10, "Excessive iX should return piCP=10 not %d\n", piCP);
544     ok(piTrailing == FALSE, "Excessive iX should return piTrailing=FALSE not %d\n", piTrailing);
545     iX = 779;
546     cChars = 10;
547     cGlyphs = 10;
548     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing);
549     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08lx\n", hr);
550     ok(piCP == 3, "iX=%d should return piCP=3 not %d\n", iX, piCP);
551     ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
552     iX = 780;
553     cChars = 10;
554     cGlyphs = 10;
555     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing);
556     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08lx\n", hr);
557     ok(piCP == 3, "iX=%d should return piCP=3 not %d\n", iX, piCP);
558     ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
559     iX = 868;
560     cChars = 10;
561     cGlyphs = 10;
562     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing);
563     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08lx\n", hr);
564     ok(piCP == 4, "iX=%d should return piCP=4 not %d\n", iX, piCP);
565
566     iCP=5;
567     fTrailing = FALSE;
568     cChars = 10;
569     cGlyphs = 10;
570     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
571     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08lx\n", hr);
572     ok(piX == 976, "iCP=%d should return piX=976 not %d\n", iCP, piX);
573     iCP=5;
574     fTrailing = TRUE;
575     cChars = 10;
576     cGlyphs = 10;
577     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
578     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08lx\n", hr);
579     ok(piX == 1171, "iCP=%d should return piX=1171 not %d\n", iCP, piX);   
580     iCP=6;
581     fTrailing = FALSE;
582     cChars = 10;
583     cGlyphs = 10;
584     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
585     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08lx\n", hr);
586     ok(piX == 1171, "iCP=%d should return piX=1171 not %d\n", iCP, piX);
587     iCP=11;
588     fTrailing = FALSE;
589     cChars = 10;
590     cGlyphs = 10;
591     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
592     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08lx\n", hr);
593     ok(piX == 1953, "iCP=%d should return piX=1953 not %d\n", iCP, piX);
594     iCP=11;
595     fTrailing = TRUE;
596     cChars = 10;
597     cGlyphs = 10;
598     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
599     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08lx\n", hr);
600     ok(piX == 1953, "iCP=%d should return piX=1953 not %d\n", iCP, piX); 
601
602 }
603
604 static void test_ScriptString(void)
605 {
606     HRESULT         hr;
607     HWND            hwnd;
608     HDC             hdc = 0;
609     WCHAR           teststr[] = {'T', 'e', 's', 't', 'a', '\0'};
610     void            *pString = (WCHAR *) &teststr;
611     int             cString = 5;
612     int             cGlyphs = cString * 2 + 16;
613     int             iCharset = -1;
614     DWORD           dwFlags = SSA_GLYPHS;
615     int             iReqWidth = 100;
616     SCRIPT_CONTROL  psControl;
617     SCRIPT_STATE    psState;
618     const int       piDx[5] = {10, 10, 10, 10, 10};
619     SCRIPT_TABDEF   pTabdef;
620     const BYTE      pbInClass = 0;
621     SCRIPT_STRING_ANALYSIS pssa = NULL;
622
623     int             iX = 10; 
624     int             iY = 100;
625     UINT            uOptions = 0; 
626     const RECT      prc = {0, 50, 100, 100}; 
627     int             iMinSel = 0; 
628     int             iMaxSel = 0;
629     BOOL            fDisabled = FALSE;
630
631     LOGFONTA        lf;
632     HFONT           zfont;
633
634     /* We need a valid HDC to drive a lot of Script functions which requires the following    *
635      * to set up for the tests.                                                               */
636     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
637                            0, 0, 0, NULL);
638     assert(hwnd != 0);
639
640     hdc = GetDC(hwnd);                                      /* We now have a hdc             */
641     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
642
643     lstrcpyA(lf.lfFaceName, "Symbol");
644     lf.lfHeight = 10;
645     lf.lfItalic = 0;
646     lf.lfEscapement = 0;
647     lf.lfOrientation = 0;
648     lf.lfUnderline = 0;
649     lf.lfStrikeOut = 0;
650     lf.lfWeight = 3;
651     lf.lfWidth = 10;
652
653     zfont = (HFONT) SelectObject(hdc, CreateFontIndirectA(&lf));
654  
655     /* Test without hdc to get E_INVALIDARG */
656     hr = ScriptStringAnalyse( NULL, pString, cString, cGlyphs, iCharset, dwFlags,
657                              iReqWidth, &psControl, &psState, piDx, &pTabdef,
658                              &pbInClass, &pssa);
659     ok(hr == E_PENDING, "ScriptStringAnalyse Stub should return E_PENDING not %08lx\n", hr);
660
661     /* test with hdc, this should be a valid test  */
662     hr = ScriptStringAnalyse( hdc, pString, cString, cGlyphs, iCharset, dwFlags,
663                               iReqWidth, &psControl, &psState, piDx, &pTabdef,
664                               &pbInClass, &pssa);
665     ok(hr == E_NOTIMPL, "ScriptStringAnalyse Stub should return E_NOTIMPL not %08lx\n", hr);
666 /*    Commented code it pending new code in ScriptStringAnalysis */
667 /*    ok(hr == S_OK, "ScriptStringAnalyse Stub should return S_OK not %08x\n", (unsigned int) hr);*/
668 /*    ok(pssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");*/
669     if  (hr == 0)
670     {
671         hr = ScriptStringOut(pssa, iX, iY, uOptions, &prc, iMinSel, iMaxSel,fDisabled);
672         ok(hr == E_NOTIMPL, "ScriptStringOut Stub should return E_NOTIMPL not %08lx\n", hr);
673         hr = ScriptStringFree(&pssa);
674         ok(hr == S_OK, "ScriptStringFree Stub should return S_OK not %08lx\n", hr);
675     }
676 }
677
678 void test_ScriptCacheGetHeight(HDC hdc)
679 {
680     HRESULT hr;
681     SCRIPT_CACHE sc = NULL;
682     LONG height;
683
684     hr = ScriptCacheGetHeight(NULL, NULL, NULL);
685     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08lx\n", hr);
686
687     hr = ScriptCacheGetHeight(NULL, &sc, NULL);
688     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08lx\n", hr);
689
690     hr = ScriptCacheGetHeight(NULL, &sc, &height);
691     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08lx\n", hr);
692
693     height = 0;
694
695     hr = ScriptCacheGetHeight(hdc, &sc, &height);
696     ok(hr == S_OK, "expected S_OK, got 0x%08lx\n", hr);
697
698     ok(height > 0, "expected height > 0\n");
699 }
700
701 void test_ScriptGetGlyphABCWidth(HDC hdc)
702 {
703     HRESULT hr;
704     LOGFONTA lf;
705     HFONT hfont;
706     SCRIPT_CACHE sc = NULL;
707     ABC abc;
708
709     memset(&lf, 0, sizeof(lf));
710
711     lstrcpyA(lf.lfFaceName, "Symbol");
712     hfont = CreateFontIndirectA(&lf);
713     hfont = SelectObject(hdc, hfont);
714
715     hr = ScriptGetGlyphABCWidth(NULL, NULL, 'a', NULL);
716     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08lx\n", hr);
717
718     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', NULL);
719     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08lx\n", hr);
720
721     if (0) {    /* crashes on WinXP */
722     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', NULL);
723     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08lx\n", hr);
724     }
725
726     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', &abc);
727     ok(hr == S_OK, "expected S_OK, got 0x%08lx\n", hr);
728 }
729
730 void test_ScriptLayout(void)
731 {
732     HRESULT hr;
733     static const BYTE levels[][5] =
734     {
735         { 0, 0, 0, 0, 0 },
736         { 1, 1, 1, 1, 1 },
737         { 2, 2, 2, 2, 2 },
738         { 3, 3, 3, 3, 3 },
739     };
740     static const int expect[][5] =
741     {
742         { 0, 1, 2, 3, 4 },
743         { 4, 3, 2, 1, 0 },
744         { 0, 1, 2, 3, 4 },
745         { 4, 3, 2, 1, 0 }
746     };
747     int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])];
748
749     hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis);
750     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08lx\n", hr);
751
752     hr = ScriptLayout(sizeof(levels[0]), levels[0], NULL, NULL);
753     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08lx\n", hr);
754
755     for (i = 0; i < sizeof(levels)/sizeof(levels[0]); i++)
756     {
757         hr = ScriptLayout(sizeof(levels[0]), levels[i], vistolog, logtovis);
758         ok(hr == S_OK, "expected S_OK, got 0x%08lx\n", hr);
759
760         for (j = 0; j < sizeof(levels[i]); j++)
761         {
762             ok(expect[i][j] == vistolog[j],
763                "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n",
764                i, j, levels[i][j], j, vistolog[j] );
765         }
766
767         for (j = 0; j < sizeof(levels[i]); j++)
768         {
769             ok(expect[i][j] == logtovis[j],
770                "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n",
771                i, j, levels[i][j], j, logtovis[j] );
772         }
773     }
774 }
775
776 static const struct
777 {
778     LGRPID group;
779     LCID lcid;
780     SCRIPT_DIGITSUBSTITUTE sds;
781     DWORD uDefaultLanguage;
782     DWORD fContextDigits;
783     WORD fDigitSubstitute;
784 }
785 subst_data[] =
786 {
787     { 0x01, 0x00403, { 9, 3, 1, 0 }, 9, 0, 0 },
788     { 0x01, 0x00406, { 9, 6, 1, 0 }, 9, 0, 0 },
789     { 0x01, 0x00407, { 9, 7, 1, 0 }, 9, 0, 0 },
790     { 0x01, 0x00409, { 9, 9, 1, 0 }, 9, 0, 0 },
791     { 0x01, 0x0040a, { 9, 10, 1, 0 }, 9, 0, 0 },
792     { 0x01, 0x0040b, { 9, 11, 1, 0 }, 9, 0, 0 },
793     { 0x01, 0x0040c, { 9, 12, 1, 0 }, 9, 0, 0 },
794     { 0x01, 0x0040f, { 9, 15, 1, 0 }, 9, 0, 0 },
795     { 0x01, 0x00410, { 9, 16, 1, 0 }, 9, 0, 0 },
796     { 0x01, 0x00413, { 9, 19, 1, 0 }, 9, 0, 0 },
797     { 0x01, 0x00414, { 9, 20, 1, 0 }, 9, 0, 0 },
798     { 0x01, 0x00416, { 9, 22, 1, 0 }, 9, 0, 0 },
799     { 0x01, 0x0041d, { 9, 29, 1, 0 }, 9, 0, 0 },
800     { 0x01, 0x00421, { 9, 33, 1, 0 }, 9, 0, 0 },
801     { 0x01, 0x0042d, { 9, 45, 1, 0 }, 9, 0, 0 },
802     { 0x01, 0x00432, { 9, 50, 1, 0 }, 9, 0, 0 },
803     { 0x01, 0x00434, { 9, 52, 1, 0 }, 9, 0, 0 },
804     { 0x01, 0x00435, { 9, 53, 1, 0 }, 9, 0, 0 },
805     { 0x01, 0x00436, { 9, 54, 1, 0 }, 9, 0, 0 },
806     { 0x01, 0x00438, { 9, 56, 1, 0 }, 9, 0, 0 },
807     { 0x01, 0x0043a, { 9, 58, 1, 0 }, 9, 0, 0 },
808     { 0x01, 0x0043b, { 9, 59, 1, 0 }, 9, 0, 0 },
809     { 0x01, 0x0043e, { 9, 62, 1, 0 }, 9, 0, 0 },
810     { 0x01, 0x00441, { 9, 65, 1, 0 }, 9, 0, 0 },
811     { 0x01, 0x00452, { 9, 82, 1, 0 }, 9, 0, 0 },
812     { 0x01, 0x00456, { 9, 86, 1, 0 }, 9, 0, 0 },
813     { 0x01, 0x0046b, { 9, 107, 1, 0 }, 9, 0, 0 },
814     { 0x01, 0x0046c, { 9, 108, 1, 0 }, 9, 0, 0 },
815     { 0x01, 0x00481, { 9, 129, 1, 0 }, 9, 0, 0 },
816     { 0x01, 0x00807, { 9, 7, 1, 0 }, 9, 0, 0 },
817     { 0x01, 0x00809, { 9, 9, 1, 0 }, 9, 0, 0 },
818     { 0x01, 0x0080a, { 9, 10, 1, 0 }, 9, 0, 0 },
819     { 0x01, 0x0080c, { 9, 12, 1, 0 }, 9, 0, 0 },
820     { 0x01, 0x00810, { 9, 16, 1, 0 }, 9, 0, 0 },
821     { 0x01, 0x00813, { 9, 19, 1, 0 }, 9, 0, 0 },
822     { 0x01, 0x00814, { 9, 20, 1, 0 }, 9, 0, 0 },
823     { 0x01, 0x00816, { 9, 22, 1, 0 }, 9, 0, 0 },
824     { 0x01, 0x0081d, { 9, 29, 1, 0 }, 9, 0, 0 },
825     { 0x01, 0x0083b, { 9, 59, 1, 0 }, 9, 0, 0 },
826     { 0x01, 0x0083e, { 9, 62, 1, 0 }, 9, 0, 0 },
827     { 0x01, 0x0086b, { 9, 107, 1, 0 }, 9, 0, 0 },
828     { 0x01, 0x00c07, { 9, 7, 1, 0 }, 9, 0, 0 },
829     { 0x01, 0x00c09, { 9, 9, 1, 0 }, 9, 0, 0 },
830     { 0x01, 0x00c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
831     { 0x01, 0x00c0c, { 9, 12, 1, 0 }, 9, 0, 0 },
832     { 0x01, 0x00c3b, { 9, 59, 1, 0 }, 9, 0, 0 },
833     { 0x01, 0x00c6b, { 9, 107, 1, 0 }, 9, 0, 0 },
834     { 0x01, 0x01007, { 9, 7, 1, 0 }, 9, 0, 0 },
835     { 0x01, 0x01009, { 9, 9, 1, 0 }, 9, 0, 0 },
836     { 0x01, 0x0100a, { 9, 10, 1, 0 }, 9, 0, 0 },
837     { 0x01, 0x0100c, { 9, 12, 1, 0 }, 9, 0, 0 },
838     { 0x01, 0x0103b, { 9, 59, 1, 0 }, 9, 0, 0 },
839     { 0x01, 0x01407, { 9, 7, 1, 0 }, 9, 0, 0 },
840     { 0x01, 0x01409, { 9, 9, 1, 0 }, 9, 0, 0 },
841     { 0x01, 0x0140a, { 9, 10, 1, 0 }, 9, 0, 0 },
842     { 0x01, 0x0140c, { 9, 12, 1, 0 }, 9, 0, 0 },
843     { 0x01, 0x0143b, { 9, 59, 1, 0 }, 9, 0, 0 },
844     { 0x01, 0x01809, { 9, 9, 1, 0 }, 9, 0, 0 },
845     { 0x01, 0x0180a, { 9, 10, 1, 0 }, 9, 0, 0 },
846     { 0x01, 0x0180c, { 9, 12, 1, 0 }, 9, 0, 0 },
847     { 0x01, 0x0183b, { 9, 59, 1, 0 }, 9, 0, 0 },
848     { 0x01, 0x01c09, { 9, 9, 1, 0 }, 9, 0, 0 },
849     { 0x01, 0x01c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
850     { 0x01, 0x01c3b, { 9, 59, 1, 0 }, 9, 0, 0 },
851     { 0x01, 0x02009, { 9, 9, 1, 0 }, 9, 0, 0 },
852     { 0x01, 0x0200a, { 9, 10, 1, 0 }, 9, 0, 0 },
853     { 0x01, 0x0203b, { 9, 59, 1, 0 }, 9, 0, 0 },
854     { 0x01, 0x02409, { 9, 9, 1, 0 }, 9, 0, 0 },
855     { 0x01, 0x0240a, { 9, 10, 1, 0 }, 9, 0, 0 },
856     { 0x01, 0x0243b, { 9, 59, 1, 0 }, 9, 0, 0 },
857     { 0x01, 0x02809, { 9, 9, 1, 0 }, 9, 0, 0 },
858     { 0x01, 0x0280a, { 9, 10, 1, 0 }, 9, 0, 0 },
859     { 0x01, 0x02c09, { 9, 9, 1, 0 }, 9, 0, 0 },
860     { 0x01, 0x02c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
861     { 0x01, 0x03009, { 9, 9, 1, 0 }, 9, 0, 0 },
862     { 0x01, 0x0300a, { 9, 10, 1, 0 }, 9, 0, 0 },
863     { 0x01, 0x03409, { 9, 9, 1, 0 }, 9, 0, 0 },
864     { 0x01, 0x0340a, { 9, 10, 1, 0 }, 9, 0, 0 },
865     { 0x01, 0x0380a, { 9, 10, 1, 0 }, 9, 0, 0 },
866     { 0x01, 0x03c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
867     { 0x01, 0x0400a, { 9, 10, 1, 0 }, 9, 0, 0 },
868     { 0x01, 0x0440a, { 9, 10, 1, 0 }, 9, 0, 0 },
869     { 0x01, 0x0480a, { 9, 10, 1, 0 }, 9, 0, 0 },
870     { 0x01, 0x04c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
871     { 0x01, 0x0500a, { 9, 10, 1, 0 }, 9, 0, 0 },
872     { 0x01, 0x10407, { 9, 7, 1, 0 }, 9, 0, 0 },
873     { 0x02, 0x00405, { 9, 5, 1, 0 }, 9, 0, 0 },
874     { 0x02, 0x0040e, { 9, 14, 1, 0 }, 9, 0, 0 },
875     { 0x02, 0x00415, { 9, 21, 1, 0 }, 9, 0, 0 },
876     { 0x02, 0x00418, { 9, 24, 1, 0 }, 9, 0, 0 },
877     { 0x02, 0x0041a, { 9, 26, 1, 0 }, 9, 0, 0 },
878     { 0x02, 0x0041b, { 9, 27, 1, 0 }, 9, 0, 0 },
879     { 0x02, 0x0041c, { 9, 28, 1, 0 }, 9, 0, 0 },
880     { 0x02, 0x00424, { 9, 36, 1, 0 }, 9, 0, 0 },
881     { 0x02, 0x0081a, { 9, 26, 1, 0 }, 9, 0, 0 },
882     { 0x02, 0x0101a, { 9, 26, 1, 0 }, 9, 0, 0 },
883     { 0x02, 0x0141a, { 9, 26, 1, 0 }, 9, 0, 0 },
884     { 0x02, 0x0181a, { 9, 26, 1, 0 }, 9, 0, 0 },
885     { 0x02, 0x1040e, { 9, 14, 1, 0 }, 9, 0, 0 },
886     { 0x03, 0x00425, { 9, 37, 1, 0 }, 9, 0, 0 },
887     { 0x03, 0x00426, { 9, 38, 1, 0 }, 9, 0, 0 },
888     { 0x03, 0x00427, { 9, 39, 1, 0 }, 9, 0, 0 },
889     { 0x04, 0x00408, { 9, 8, 1, 0 }, 9, 0, 0 },
890     { 0x05, 0x00402, { 9, 2, 1, 0 }, 9, 0, 0 },
891     { 0x05, 0x00419, { 9, 25, 1, 0 }, 9, 0, 0 },
892     { 0x05, 0x00422, { 9, 34, 1, 0 }, 9, 0, 0 },
893     { 0x05, 0x00423, { 9, 35, 1, 0 }, 9, 0, 0 },
894     { 0x05, 0x0042f, { 9, 47, 1, 0 }, 9, 0, 0 },
895     { 0x05, 0x0043f, { 9, 63, 1, 0 }, 9, 0, 0 },
896     { 0x05, 0x00440, { 9, 64, 1, 0 }, 9, 0, 0 },
897     { 0x05, 0x00444, { 9, 68, 1, 0 }, 9, 0, 0 },
898     { 0x05, 0x00450, { 9, 80, 1, 0 }, 9, 0, 0 },
899     { 0x05, 0x0082c, { 9, 44, 1, 0 }, 9, 0, 0 },
900     { 0x05, 0x00843, { 9, 67, 1, 0 }, 9, 0, 0 },
901     { 0x05, 0x00c1a, { 9, 26, 1, 0 }, 9, 0, 0 },
902     { 0x05, 0x01c1a, { 9, 26, 1, 0 }, 9, 0, 0 },
903     { 0x06, 0x0041f, { 9, 31, 1, 0 }, 9, 0, 0 },
904     { 0x06, 0x0042c, { 9, 44, 1, 0 }, 9, 0, 0 },
905     { 0x06, 0x00443, { 9, 67, 1, 0 }, 9, 0, 0 },
906     { 0x07, 0x00411, { 9, 17, 1, 0 }, 9, 0, 0 },
907     { 0x08, 0x00412, { 9, 18, 1, 0 }, 9, 0, 0 },
908     { 0x09, 0x00404, { 9, 4, 1, 0 }, 9, 0, 0 },
909     { 0x09, 0x00c04, { 9, 4, 1, 0 }, 9, 0, 0 },
910     { 0x09, 0x01404, { 9, 4, 1, 0 }, 9, 0, 0 },
911     { 0x09, 0x21404, { 9, 4, 1, 0 }, 9, 0, 0 },
912     { 0x09, 0x30404, { 9, 4, 1, 0 }, 9, 0, 0 },
913     { 0x0a, 0x00804, { 9, 4, 1, 0 }, 9, 0, 0 },
914     { 0x0a, 0x01004, { 9, 4, 1, 0 }, 9, 0, 0 },
915     { 0x0a, 0x20804, { 9, 4, 1, 0 }, 9, 0, 0 },
916     { 0x0a, 0x21004, { 9, 4, 1, 0 }, 9, 0, 0 },
917     { 0x0b, 0x0041e, { 9, 30, 1, 0 }, 9, 0, 0 },
918     { 0x0c, 0x0040d, { 9, 13, 1, 0 }, 9, 0, 0 },
919     { 0x0d, 0x00401, { 1, 1, 0, 0 }, 9, 0, 0 },
920     { 0x0d, 0x00420, { 9, 32, 1, 0 }, 9, 0, 0 },
921     { 0x0d, 0x00429, { 41, 41, 0, 0 }, 9, 0, 0 },
922     { 0x0d, 0x0045a, { 9, 90, 1, 0 }, 9, 0, 0 },
923     { 0x0d, 0x00465, { 9, 101, 1, 0 }, 9, 0, 0 },
924     { 0x0d, 0x00801, { 1, 1, 0, 0 }, 9, 0, 0 },
925     { 0x0d, 0x00c01, { 1, 1, 0, 0 }, 9, 0, 0 },
926     { 0x0d, 0x01001, { 1, 1, 0, 0 }, 9, 0, 0 },
927     { 0x0d, 0x01401, { 1, 1, 0, 0 }, 9, 0, 0 },
928     { 0x0d, 0x01801, { 1, 1, 0, 0 }, 9, 0, 0 },
929     { 0x0d, 0x01c01, { 1, 1, 0, 0 }, 9, 0, 0 },
930     { 0x0d, 0x02001, { 1, 1, 0, 0 }, 9, 0, 0 },
931     { 0x0d, 0x02401, { 1, 1, 0, 0 }, 9, 0, 0 },
932     { 0x0d, 0x02801, { 1, 1, 0, 0 }, 9, 0, 0 },
933     { 0x0d, 0x02c01, { 1, 1, 0, 0 }, 9, 0, 0 },
934     { 0x0d, 0x03001, { 1, 1, 0, 0 }, 9, 0, 0 },
935     { 0x0d, 0x03401, { 1, 1, 0, 0 }, 9, 0, 0 },
936     { 0x0d, 0x03801, { 1, 1, 0, 0 }, 9, 0, 0 },
937     { 0x0d, 0x03c01, { 1, 1, 0, 0 }, 9, 0, 0 },
938     { 0x0d, 0x04001, { 1, 1, 0, 0 }, 9, 0, 0 },
939     { 0x0e, 0x0042a, { 9, 42, 1, 0 }, 9, 0, 0 },
940     { 0x0f, 0x00439, { 9, 57, 1, 0 }, 9, 0, 0 },
941     { 0x0f, 0x00446, { 9, 70, 1, 0 }, 9, 0, 0 },
942     { 0x0f, 0x00447, { 9, 71, 1, 0 }, 9, 0, 0 },
943     { 0x0f, 0x00449, { 9, 73, 1, 0 }, 9, 0, 0 },
944     { 0x0f, 0x0044a, { 9, 74, 1, 0 }, 9, 0, 0 },
945     { 0x0f, 0x0044b, { 9, 75, 1, 0 }, 9, 0, 0 },
946     { 0x0f, 0x0044e, { 9, 78, 1, 0 }, 9, 0, 0 },
947     { 0x0f, 0x0044f, { 9, 79, 1, 0 }, 9, 0, 0 },
948     { 0x0f, 0x00457, { 9, 87, 1, 0 }, 9, 0, 0 },
949     { 0x10, 0x00437, { 9, 55, 1, 0 }, 9, 0, 0 },
950     { 0x10, 0x10437, { 9, 55, 1, 0 }, 9, 0, 0 },
951     { 0x11, 0x0042b, { 9, 43, 1, 0 }, 9, 0, 0 }
952 };
953
954 static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR lparam)
955 {
956     HRESULT hr;
957     SCRIPT_DIGITSUBSTITUTE sds;
958     SCRIPT_CONTROL sc;
959     SCRIPT_STATE ss;
960     LCID lcid_old;
961     unsigned int i;
962
963     if (!IsValidLocale(lcid, LCID_INSTALLED)) return TRUE;
964
965     memset(&sds, 0, sizeof(sds));
966     memset(&sc, 0, sizeof(sc));
967     memset(&ss, 0, sizeof(ss));
968
969     lcid_old = GetThreadLocale();
970     if (!SetThreadLocale(lcid)) return TRUE;
971
972     hr = ScriptRecordDigitSubstitution(lcid, &sds);
973     ok(hr == S_OK, "ScriptRecordDigitSubstitution failed: 0x%08lx\n", hr);
974
975     hr = ScriptApplyDigitSubstitution(&sds, &sc, &ss);
976     ok(hr == S_OK, "ScriptApplyDigitSubstitution failed: 0x%08lx\n", hr);
977
978     for (i = 0; i < sizeof(subst_data)/sizeof(subst_data[0]); i++)
979     {
980         if (group == subst_data[i].group && lcid == subst_data[i].lcid)
981         {
982             ok(!memcmp(&sds, &subst_data[i].sds, sizeof(sds)),
983                "substitution data does not match\n");
984
985             ok(sc.uDefaultLanguage == subst_data[i].uDefaultLanguage,
986                "sc.uDefaultLanguage does not match\n");
987             ok(sc.fContextDigits == subst_data[i].fContextDigits,
988                "sc.fContextDigits does not match\n");
989             ok(ss.fDigitSubstitute == subst_data[i].fDigitSubstitute,
990                "ss.fDigitSubstitute does not match\n");
991         }
992     }
993     SetThreadLocale(lcid_old);
994     return TRUE;
995 }
996
997 static void test_digit_substitution(void)
998 {
999     BOOL ret;
1000     unsigned int i;
1001     static const LGRPID groups[] =
1002     {
1003         LGRPID_WESTERN_EUROPE,
1004         LGRPID_CENTRAL_EUROPE,
1005         LGRPID_BALTIC,
1006         LGRPID_GREEK,
1007         LGRPID_CYRILLIC,
1008         LGRPID_TURKISH,
1009         LGRPID_JAPANESE,
1010         LGRPID_KOREAN,
1011         LGRPID_TRADITIONAL_CHINESE,
1012         LGRPID_SIMPLIFIED_CHINESE,
1013         LGRPID_THAI,
1014         LGRPID_HEBREW,
1015         LGRPID_ARABIC,
1016         LGRPID_VIETNAMESE,
1017         LGRPID_INDIC,
1018         LGRPID_GEORGIAN,
1019         LGRPID_ARMENIAN
1020     };
1021
1022     for (i = 0; i < sizeof(groups)/sizeof(groups[0]); i++)
1023     {
1024         ret = EnumLanguageGroupLocales(enum_proc, groups[i], 0, 0);
1025         ok(ret, "EnumLanguageGroupLocales failed unexpectedly: 0x%08lx\n", GetLastError());
1026     }
1027 }
1028
1029 START_TEST(usp10)
1030 {
1031     HWND            hwnd;
1032     HDC             hdc;
1033
1034     unsigned short  pwOutGlyphs[256];
1035
1036     /* We need a valid HDC to drive a lot of Script functions which requires the following    *
1037      * to set up for the tests.                                                               */
1038     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1039                            0, 0, 0, NULL);
1040     assert(hwnd != 0);
1041     ShowWindow(hwnd, SW_SHOW);
1042     UpdateWindow(hwnd);
1043
1044     hdc = GetDC(hwnd);                                      /* We now have a hdc             */
1045     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
1046
1047     test_ScriptItemIzeShapePlace(hdc,pwOutGlyphs);
1048     test_ScriptGetCMap(hdc, pwOutGlyphs);
1049     test_ScriptCacheGetHeight(hdc);
1050     test_ScriptGetGlyphABCWidth(hdc);
1051
1052     ReleaseDC(hwnd, hdc);
1053     DestroyWindow(hwnd);
1054
1055     test_ScriptGetFontProperties();
1056     test_ScriptTextOut();
1057     test_ScriptXtoX();
1058     test_ScriptString();
1059     test_ScriptLayout();
1060
1061     test_digit_substitution();
1062 }