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