usp10: Implement ScriptStringCPtoX.
[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 static 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 static 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 static 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     iX = 0;
578     cChars = 10;
579     cGlyphs = 10;
580     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing);
581     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
582     ok(piCP == 0, "iX=%d should return piCP=0 not %d\n", iX, piCP);
583     iX = 195;
584     cChars = 10;
585     cGlyphs = 10;
586     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing);
587     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
588     ok(piCP == 0, "iX=%d should return piCP=0 not %d\n", iX, piCP);
589     iX = 196;
590     cChars = 10;
591     cGlyphs = 10;
592     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piCP, &piTrailing);
593     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
594     ok(piCP == 1, "iX=%d should return piCP=1 not %d\n", iX, piCP);
595
596     iCP=5;
597     fTrailing = FALSE;
598     cChars = 10;
599     cGlyphs = 10;
600     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
601     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
602     ok(piX == 976, "iCP=%d should return piX=976 not %d\n", iCP, piX);
603     iCP=5;
604     fTrailing = TRUE;
605     cChars = 10;
606     cGlyphs = 10;
607     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
608     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
609     ok(piX == 1171, "iCP=%d should return piX=1171 not %d\n", iCP, piX);   
610     iCP=6;
611     fTrailing = FALSE;
612     cChars = 10;
613     cGlyphs = 10;
614     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
615     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
616     ok(piX == 1171, "iCP=%d should return piX=1171 not %d\n", iCP, piX);
617     iCP=11;
618     fTrailing = FALSE;
619     cChars = 10;
620     cGlyphs = 10;
621     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
622     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
623     ok(piX == 1953, "iCP=%d should return piX=1953 not %d\n", iCP, piX);
624     iCP=11;
625     fTrailing = TRUE;
626     cChars = 10;
627     cGlyphs = 10;
628     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &psa, &piX);
629     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
630     ok(piX == 1953, "iCP=%d should return piX=1953 not %d\n", iCP, piX); 
631
632 }
633
634 static void test_ScriptString(void)
635 {
636 /*******************************************************************************************
637  *
638  * This set of tests are for the string functions of uniscribe.  The ScriptStringAnalyse
639  * function allocates memory pointed to by the SCRIPT_STRING_ANALYSIS ssa pointer.  This 
640  * memory if freed by ScriptStringFree.  There needs to be a valid hdc for this this as 
641  * ScriptStrinAnalyse calls ScriptSItemize, ScriptShape and ScriptPlace which require it.
642  *
643  */
644
645     HRESULT         hr;
646     HWND            hwnd;
647     HDC             hdc = 0;
648     WCHAR           teststr[] = {'T','e','s','t','1',' ','a','2','b','3', '\0'};
649     int             String = (sizeof(teststr)/sizeof(WCHAR))-1;
650     int             Glyphs = String * 2 + 16;
651     int             Charset;
652     DWORD           Flags = SSA_GLYPHS;
653     int             ReqWidth = 100;
654     SCRIPT_CONTROL  Control;
655     SCRIPT_STATE    State;
656     const int       Dx[5] = {10, 10, 10, 10, 10};
657     SCRIPT_TABDEF   Tabdef;
658     const BYTE      InClass = 0;
659     SCRIPT_STRING_ANALYSIS ssa = NULL;
660
661     int             X = 10; 
662     int             Y = 100;
663     UINT            Options = 0; 
664     const RECT      rc = {0, 50, 100, 100}; 
665     int             MinSel = 0; 
666     int             MaxSel = 0;
667     BOOL            Disabled = FALSE;
668
669     LOGFONTA        lf;
670     HFONT           zfont;
671
672     /* We need a valid HDC to drive a lot of Script functions which requires the following    *
673      * to set up for the tests.                                                               */
674     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
675                            0, 0, 0, NULL);
676     assert(hwnd != 0);
677
678     hdc = GetDC(hwnd);                                      /* We now have a hdc             */
679     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
680
681     lstrcpyA(lf.lfFaceName, "Symbol");
682     lf.lfHeight = 10;
683     lf.lfItalic = 0;
684     lf.lfEscapement = 0;
685     lf.lfOrientation = 0;
686     lf.lfUnderline = 0;
687     lf.lfStrikeOut = 0;
688     lf.lfWeight = 300;
689     lf.lfWidth = 10;
690
691     zfont = (HFONT) SelectObject(hdc, CreateFontIndirectA(&lf));
692  
693     Charset = -1;     /* this flag indicates unicode input */
694     /* Test without hdc to get E_INVALIDARG */
695     hr = ScriptStringAnalyse( NULL, teststr, String, Glyphs, Charset, Flags,
696                              ReqWidth, &Control, &State, Dx, &Tabdef,
697                              &InClass, &ssa);
698     ok(hr == E_PENDING, "ScriptStringAnalyse Stub should return E_PENDING not %08x\n", hr);
699
700     /* test with hdc, this should be a valid test  */
701     hr = ScriptStringAnalyse( hdc, teststr, String, Glyphs, Charset, Flags,
702                               ReqWidth, &Control, &State, Dx, &Tabdef,
703                               &InClass, &ssa);
704     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
705
706     /* test makes sure that a call with a valid pssa still works */
707     hr = ScriptStringAnalyse( hdc, teststr, String, Glyphs, Charset, Flags,
708                               ReqWidth, &Control, &State, Dx, &Tabdef,
709                               &InClass, &ssa);
710     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
711     ok(ssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
712
713     if  (hr == 0)
714     {
715         hr = ScriptStringOut(ssa, X, Y, Options, &rc, MinSel, MaxSel, Disabled);
716         todo_wine ok(hr == S_OK, "ScriptStringOut should return S_OK not %08x\n", hr);
717         hr = ScriptStringFree(&ssa);
718         ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
719     }
720 }
721
722 static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
723 {
724 /*****************************************************************************************
725  *
726  * This test is for the ScriptStringXtoCP and ScriptStringXtoCP functions.  Due to the
727  * nature of the fonts between Windows and Wine, the test is implemented by generating
728  * values using one one function then checking the output of the second.  In this way
729  * the validity of the functions is established using Windows as a base and confirming
730  * similar behaviour in wine.
731  */
732
733     HRESULT         hr;
734     WCHAR           teststr1[] = {'T', 'e', 's', 't', 'e', '1', '2', ' ', 'a', '\0'};
735     void            *String = (WCHAR *) &teststr1;      /* ScriptStringAnalysis needs void */
736     int             String_len = (sizeof(teststr1)/sizeof(WCHAR))-1;
737     int             Glyphs = String_len * 2 + 16;       /* size of buffer as recommended  */
738     int             Charset = -1;                       /* unicode                        */
739     DWORD           Flags = SSA_GLYPHS;
740     int             ReqWidth = 100;
741     SCRIPT_CONTROL  Control;
742     SCRIPT_STATE    State;
743     SCRIPT_TABDEF   Tabdef;
744     const BYTE      InClass = 0;
745     SCRIPT_STRING_ANALYSIS ssa = NULL;
746
747     int             Ch;                                  /* Character position in string */
748     int             iTrailing;
749     int             Cp;                                  /* Character position in string */
750     int             X;
751     BOOL            fTrailing;
752
753     LOGFONTA        lf;
754     HFONT           zfont;
755
756     lstrcpyA(lf.lfFaceName, "Symbol");
757     lf.lfHeight = 10;
758     lf.lfCharSet = 0;
759     lf.lfItalic = 0;
760     lf.lfEscapement = 0;
761     lf.lfOrientation = 0;
762     lf.lfUnderline = 0;
763     lf.lfStrikeOut = 0;
764     lf.lfWeight = 400;
765     lf.lfWidth = 0;
766     lf.lfPitchAndFamily = 0;
767
768     zfont = (HFONT) SelectObject(hdc, CreateFontIndirectA(&lf));
769
770     /* Test with hdc, this should be a valid test
771      * Here we generrate an SCRIPT_STRING_ANALYSIS that will be used as input to the
772      * following character positions to X and X to character position functions.
773      */
774     hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
775                               ReqWidth, &Control, &State, NULL, &Tabdef,
776                               &InClass, &ssa);
777     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
778     ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
779     if  (hr == 0)
780     {
781         /*
782          * Loop to generate character positions to provide starting positions for the
783          * ScriptStringCPtoX and ScriptStringXtoCP functions
784          */
785         for (Cp = 0; Cp < String_len; Cp++)
786         {
787             /* The fTrailing flag is used to indicate whether the X being returned is at
788              * the beginning or the end of the character. What happens here is that if
789              * fTrailing indicates the end of the character, ie. FALSE, then ScriptStringXtoCP
790              * returns the beginning of the next character and iTrailing is FALSE.  So for this
791              * loop iTrailing will be FALSE in both cases.
792              */
793             fTrailing = FALSE;
794             hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
795             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
796             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
797             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
798             ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
799             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
800                                   iTrailing, X);
801             fTrailing = TRUE;
802             hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
803             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
804             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
805             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
806
807             /*
808              * Check that character position returned by ScriptStringXtoCP in Ch matches the
809              * one input to ScriptStringCPtoX.  This means that the Cp to X position and back
810              * again works
811              */
812             ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
813             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
814                                    iTrailing, X);
815         }
816         /*
817          * This test is to check that if the X position is just inside the trailing edge of the
818          * character then iTrailing will indicate the trailing edge, ie. TRUE
819          */
820         fTrailing = TRUE;
821         Cp = 3;
822         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
823         ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
824         X--;                                /* put X just inside the trailing edge */
825         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
826         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
827         ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
828         ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", 
829                                   iTrailing, X);
830
831         /*
832          * This test is to check that if the X position is just outside the trailing edge of the
833          * character then iTrailing will indicate the leading edge, ie. FALSE, and Ch will indicate
834          * the next character, ie. Cp + 1 
835          */
836         fTrailing = TRUE;
837         Cp = 3;
838         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
839         ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
840         X++;                                /* put X just outside the trailing edge */
841         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
842         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
843         ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
844         ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
845                                   iTrailing, X);
846
847         /*
848          * This test is to check that if the X position is just outside the leading edge of the
849          * character then iTrailing will indicate the trailing edge, ie. TRUE, and Ch will indicate
850          * the next character down , ie. Cp - 1 
851          */
852         fTrailing = FALSE;
853         Cp = 3;
854         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
855         ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
856         X--;                                /* put X just outside the leading edge */
857         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
858         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
859         ok(Cp - 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp - 1, Ch, X);
860         ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", 
861                                   iTrailing, X);
862
863         /*
864          * Cleanup the the SSA for the next round of tests
865          */
866         hr = ScriptStringFree(&ssa);
867         ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
868
869         /*
870          * Test to see that exceeding the number of chars returns E_INVALIDARG.  First
871          * generate an SSA for the subsequent tests.
872          */
873         hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
874                                   ReqWidth, &Control, &State, NULL, &Tabdef,
875                                   &InClass, &ssa);
876         ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
877
878         /*
879          * When ScriptStringCPtoX is called with a character position Cp that exceeds the
880          * string length, return E_INVALIDARG.  This also invalidates the ssa so a 
881          * ScriptStringFree should also fail.
882          */
883         fTrailing = FALSE;
884         Cp = String_len + 1; 
885         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
886         ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr);
887
888         hr = ScriptStringFree(&ssa);
889         /*
890          * ScriptStringCPtoX should free ssa, hence ScriptStringFree should fail
891          */
892         ok(hr == E_INVALIDARG, "ScriptStringFree should return E_INVALIDARG not %08x\n", hr);
893     }
894 }
895
896 static void test_ScriptCacheGetHeight(HDC hdc)
897 {
898     HRESULT hr;
899     SCRIPT_CACHE sc = NULL;
900     long height;
901
902     hr = ScriptCacheGetHeight(NULL, NULL, NULL);
903     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
904
905     hr = ScriptCacheGetHeight(NULL, &sc, NULL);
906     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
907
908     hr = ScriptCacheGetHeight(NULL, &sc, &height);
909     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
910
911     height = 0;
912
913     hr = ScriptCacheGetHeight(hdc, &sc, &height);
914     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
915
916     ok(height > 0, "expected height > 0\n");
917 }
918
919 static void test_ScriptGetGlyphABCWidth(HDC hdc)
920 {
921     HRESULT hr;
922     LOGFONTA lf;
923     HFONT hfont;
924     SCRIPT_CACHE sc = NULL;
925     ABC abc;
926
927     memset(&lf, 0, sizeof(lf));
928
929     lstrcpyA(lf.lfFaceName, "Symbol");
930     hfont = CreateFontIndirectA(&lf);
931     hfont = SelectObject(hdc, hfont);
932
933     hr = ScriptGetGlyphABCWidth(NULL, NULL, 'a', NULL);
934     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
935
936     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', NULL);
937     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
938
939     if (0) {    /* crashes on WinXP */
940     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', NULL);
941     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
942     }
943
944     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', &abc);
945     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
946 }
947
948 static void test_ScriptLayout(void)
949 {
950     HRESULT hr;
951     static const BYTE levels[][5] =
952     {
953         { 0, 0, 0, 0, 0 },
954         { 1, 1, 1, 1, 1 },
955         { 2, 2, 2, 2, 2 },
956         { 3, 3, 3, 3, 3 },
957     };
958     static const int expect[][5] =
959     {
960         { 0, 1, 2, 3, 4 },
961         { 4, 3, 2, 1, 0 },
962         { 0, 1, 2, 3, 4 },
963         { 4, 3, 2, 1, 0 }
964     };
965     int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])];
966
967     hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis);
968     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
969
970     hr = ScriptLayout(sizeof(levels[0]), levels[0], NULL, NULL);
971     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
972
973     for (i = 0; i < sizeof(levels)/sizeof(levels[0]); i++)
974     {
975         hr = ScriptLayout(sizeof(levels[0]), levels[i], vistolog, logtovis);
976         ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
977
978         for (j = 0; j < sizeof(levels[i]); j++)
979         {
980             ok(expect[i][j] == vistolog[j],
981                "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n",
982                i, j, levels[i][j], j, vistolog[j] );
983         }
984
985         for (j = 0; j < sizeof(levels[i]); j++)
986         {
987             ok(expect[i][j] == logtovis[j],
988                "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n",
989                i, j, levels[i][j], j, logtovis[j] );
990         }
991     }
992 }
993
994 static const struct
995 {
996     LGRPID group;
997     LCID lcid;
998     SCRIPT_DIGITSUBSTITUTE sds;
999     DWORD uDefaultLanguage;
1000     DWORD fContextDigits;
1001     WORD fDigitSubstitute;
1002 }
1003 subst_data[] =
1004 {
1005     { 0x01, 0x00403, { 9, 3, 1, 0 }, 9, 0, 0 },
1006     { 0x01, 0x00406, { 9, 6, 1, 0 }, 9, 0, 0 },
1007     { 0x01, 0x00407, { 9, 7, 1, 0 }, 9, 0, 0 },
1008     { 0x01, 0x00409, { 9, 9, 1, 0 }, 9, 0, 0 },
1009     { 0x01, 0x0040a, { 9, 10, 1, 0 }, 9, 0, 0 },
1010     { 0x01, 0x0040b, { 9, 11, 1, 0 }, 9, 0, 0 },
1011     { 0x01, 0x0040c, { 9, 12, 1, 0 }, 9, 0, 0 },
1012     { 0x01, 0x0040f, { 9, 15, 1, 0 }, 9, 0, 0 },
1013     { 0x01, 0x00410, { 9, 16, 1, 0 }, 9, 0, 0 },
1014     { 0x01, 0x00413, { 9, 19, 1, 0 }, 9, 0, 0 },
1015     { 0x01, 0x00414, { 9, 20, 1, 0 }, 9, 0, 0 },
1016     { 0x01, 0x00416, { 9, 22, 1, 0 }, 9, 0, 0 },
1017     { 0x01, 0x0041d, { 9, 29, 1, 0 }, 9, 0, 0 },
1018     { 0x01, 0x00421, { 9, 33, 1, 0 }, 9, 0, 0 },
1019     { 0x01, 0x0042d, { 9, 45, 1, 0 }, 9, 0, 0 },
1020     { 0x01, 0x00432, { 9, 50, 1, 0 }, 9, 0, 0 },
1021     { 0x01, 0x00434, { 9, 52, 1, 0 }, 9, 0, 0 },
1022     { 0x01, 0x00435, { 9, 53, 1, 0 }, 9, 0, 0 },
1023     { 0x01, 0x00436, { 9, 54, 1, 0 }, 9, 0, 0 },
1024     { 0x01, 0x00438, { 9, 56, 1, 0 }, 9, 0, 0 },
1025     { 0x01, 0x0043a, { 9, 58, 1, 0 }, 9, 0, 0 },
1026     { 0x01, 0x0043b, { 9, 59, 1, 0 }, 9, 0, 0 },
1027     { 0x01, 0x0043e, { 9, 62, 1, 0 }, 9, 0, 0 },
1028     { 0x01, 0x00441, { 9, 65, 1, 0 }, 9, 0, 0 },
1029     { 0x01, 0x00452, { 9, 82, 1, 0 }, 9, 0, 0 },
1030     { 0x01, 0x00456, { 9, 86, 1, 0 }, 9, 0, 0 },
1031     { 0x01, 0x0046b, { 9, 107, 1, 0 }, 9, 0, 0 },
1032     { 0x01, 0x0046c, { 9, 108, 1, 0 }, 9, 0, 0 },
1033     { 0x01, 0x00481, { 9, 129, 1, 0 }, 9, 0, 0 },
1034     { 0x01, 0x00807, { 9, 7, 1, 0 }, 9, 0, 0 },
1035     { 0x01, 0x00809, { 9, 9, 1, 0 }, 9, 0, 0 },
1036     { 0x01, 0x0080a, { 9, 10, 1, 0 }, 9, 0, 0 },
1037     { 0x01, 0x0080c, { 9, 12, 1, 0 }, 9, 0, 0 },
1038     { 0x01, 0x00810, { 9, 16, 1, 0 }, 9, 0, 0 },
1039     { 0x01, 0x00813, { 9, 19, 1, 0 }, 9, 0, 0 },
1040     { 0x01, 0x00814, { 9, 20, 1, 0 }, 9, 0, 0 },
1041     { 0x01, 0x00816, { 9, 22, 1, 0 }, 9, 0, 0 },
1042     { 0x01, 0x0081d, { 9, 29, 1, 0 }, 9, 0, 0 },
1043     { 0x01, 0x0083b, { 9, 59, 1, 0 }, 9, 0, 0 },
1044     { 0x01, 0x0083e, { 9, 62, 1, 0 }, 9, 0, 0 },
1045     { 0x01, 0x0086b, { 9, 107, 1, 0 }, 9, 0, 0 },
1046     { 0x01, 0x00c07, { 9, 7, 1, 0 }, 9, 0, 0 },
1047     { 0x01, 0x00c09, { 9, 9, 1, 0 }, 9, 0, 0 },
1048     { 0x01, 0x00c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1049     { 0x01, 0x00c0c, { 9, 12, 1, 0 }, 9, 0, 0 },
1050     { 0x01, 0x00c3b, { 9, 59, 1, 0 }, 9, 0, 0 },
1051     { 0x01, 0x00c6b, { 9, 107, 1, 0 }, 9, 0, 0 },
1052     { 0x01, 0x01007, { 9, 7, 1, 0 }, 9, 0, 0 },
1053     { 0x01, 0x01009, { 9, 9, 1, 0 }, 9, 0, 0 },
1054     { 0x01, 0x0100a, { 9, 10, 1, 0 }, 9, 0, 0 },
1055     { 0x01, 0x0100c, { 9, 12, 1, 0 }, 9, 0, 0 },
1056     { 0x01, 0x0103b, { 9, 59, 1, 0 }, 9, 0, 0 },
1057     { 0x01, 0x01407, { 9, 7, 1, 0 }, 9, 0, 0 },
1058     { 0x01, 0x01409, { 9, 9, 1, 0 }, 9, 0, 0 },
1059     { 0x01, 0x0140a, { 9, 10, 1, 0 }, 9, 0, 0 },
1060     { 0x01, 0x0140c, { 9, 12, 1, 0 }, 9, 0, 0 },
1061     { 0x01, 0x0143b, { 9, 59, 1, 0 }, 9, 0, 0 },
1062     { 0x01, 0x01809, { 9, 9, 1, 0 }, 9, 0, 0 },
1063     { 0x01, 0x0180a, { 9, 10, 1, 0 }, 9, 0, 0 },
1064     { 0x01, 0x0180c, { 9, 12, 1, 0 }, 9, 0, 0 },
1065     { 0x01, 0x0183b, { 9, 59, 1, 0 }, 9, 0, 0 },
1066     { 0x01, 0x01c09, { 9, 9, 1, 0 }, 9, 0, 0 },
1067     { 0x01, 0x01c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1068     { 0x01, 0x01c3b, { 9, 59, 1, 0 }, 9, 0, 0 },
1069     { 0x01, 0x02009, { 9, 9, 1, 0 }, 9, 0, 0 },
1070     { 0x01, 0x0200a, { 9, 10, 1, 0 }, 9, 0, 0 },
1071     { 0x01, 0x0203b, { 9, 59, 1, 0 }, 9, 0, 0 },
1072     { 0x01, 0x02409, { 9, 9, 1, 0 }, 9, 0, 0 },
1073     { 0x01, 0x0240a, { 9, 10, 1, 0 }, 9, 0, 0 },
1074     { 0x01, 0x0243b, { 9, 59, 1, 0 }, 9, 0, 0 },
1075     { 0x01, 0x02809, { 9, 9, 1, 0 }, 9, 0, 0 },
1076     { 0x01, 0x0280a, { 9, 10, 1, 0 }, 9, 0, 0 },
1077     { 0x01, 0x02c09, { 9, 9, 1, 0 }, 9, 0, 0 },
1078     { 0x01, 0x02c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1079     { 0x01, 0x03009, { 9, 9, 1, 0 }, 9, 0, 0 },
1080     { 0x01, 0x0300a, { 9, 10, 1, 0 }, 9, 0, 0 },
1081     { 0x01, 0x03409, { 9, 9, 1, 0 }, 9, 0, 0 },
1082     { 0x01, 0x0340a, { 9, 10, 1, 0 }, 9, 0, 0 },
1083     { 0x01, 0x0380a, { 9, 10, 1, 0 }, 9, 0, 0 },
1084     { 0x01, 0x03c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1085     { 0x01, 0x0400a, { 9, 10, 1, 0 }, 9, 0, 0 },
1086     { 0x01, 0x0440a, { 9, 10, 1, 0 }, 9, 0, 0 },
1087     { 0x01, 0x0480a, { 9, 10, 1, 0 }, 9, 0, 0 },
1088     { 0x01, 0x04c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1089     { 0x01, 0x0500a, { 9, 10, 1, 0 }, 9, 0, 0 },
1090     { 0x01, 0x10407, { 9, 7, 1, 0 }, 9, 0, 0 },
1091     { 0x02, 0x00405, { 9, 5, 1, 0 }, 9, 0, 0 },
1092     { 0x02, 0x0040e, { 9, 14, 1, 0 }, 9, 0, 0 },
1093     { 0x02, 0x00415, { 9, 21, 1, 0 }, 9, 0, 0 },
1094     { 0x02, 0x00418, { 9, 24, 1, 0 }, 9, 0, 0 },
1095     { 0x02, 0x0041a, { 9, 26, 1, 0 }, 9, 0, 0 },
1096     { 0x02, 0x0041b, { 9, 27, 1, 0 }, 9, 0, 0 },
1097     { 0x02, 0x0041c, { 9, 28, 1, 0 }, 9, 0, 0 },
1098     { 0x02, 0x00424, { 9, 36, 1, 0 }, 9, 0, 0 },
1099     { 0x02, 0x0081a, { 9, 26, 1, 0 }, 9, 0, 0 },
1100     { 0x02, 0x0101a, { 9, 26, 1, 0 }, 9, 0, 0 },
1101     { 0x02, 0x0141a, { 9, 26, 1, 0 }, 9, 0, 0 },
1102     { 0x02, 0x0181a, { 9, 26, 1, 0 }, 9, 0, 0 },
1103     { 0x02, 0x1040e, { 9, 14, 1, 0 }, 9, 0, 0 },
1104     { 0x03, 0x00425, { 9, 37, 1, 0 }, 9, 0, 0 },
1105     { 0x03, 0x00426, { 9, 38, 1, 0 }, 9, 0, 0 },
1106     { 0x03, 0x00427, { 9, 39, 1, 0 }, 9, 0, 0 },
1107     { 0x04, 0x00408, { 9, 8, 1, 0 }, 9, 0, 0 },
1108     { 0x05, 0x00402, { 9, 2, 1, 0 }, 9, 0, 0 },
1109     { 0x05, 0x00419, { 9, 25, 1, 0 }, 9, 0, 0 },
1110     { 0x05, 0x00422, { 9, 34, 1, 0 }, 9, 0, 0 },
1111     { 0x05, 0x00423, { 9, 35, 1, 0 }, 9, 0, 0 },
1112     { 0x05, 0x0042f, { 9, 47, 1, 0 }, 9, 0, 0 },
1113     { 0x05, 0x0043f, { 9, 63, 1, 0 }, 9, 0, 0 },
1114     { 0x05, 0x00440, { 9, 64, 1, 0 }, 9, 0, 0 },
1115     { 0x05, 0x00444, { 9, 68, 1, 0 }, 9, 0, 0 },
1116     { 0x05, 0x00450, { 9, 80, 1, 0 }, 9, 0, 0 },
1117     { 0x05, 0x0082c, { 9, 44, 1, 0 }, 9, 0, 0 },
1118     { 0x05, 0x00843, { 9, 67, 1, 0 }, 9, 0, 0 },
1119     { 0x05, 0x00c1a, { 9, 26, 1, 0 }, 9, 0, 0 },
1120     { 0x05, 0x01c1a, { 9, 26, 1, 0 }, 9, 0, 0 },
1121     { 0x06, 0x0041f, { 9, 31, 1, 0 }, 9, 0, 0 },
1122     { 0x06, 0x0042c, { 9, 44, 1, 0 }, 9, 0, 0 },
1123     { 0x06, 0x00443, { 9, 67, 1, 0 }, 9, 0, 0 },
1124     { 0x07, 0x00411, { 9, 17, 1, 0 }, 9, 0, 0 },
1125     { 0x08, 0x00412, { 9, 18, 1, 0 }, 9, 0, 0 },
1126     { 0x09, 0x00404, { 9, 4, 1, 0 }, 9, 0, 0 },
1127     { 0x09, 0x00c04, { 9, 4, 1, 0 }, 9, 0, 0 },
1128     { 0x09, 0x01404, { 9, 4, 1, 0 }, 9, 0, 0 },
1129     { 0x09, 0x21404, { 9, 4, 1, 0 }, 9, 0, 0 },
1130     { 0x09, 0x30404, { 9, 4, 1, 0 }, 9, 0, 0 },
1131     { 0x0a, 0x00804, { 9, 4, 1, 0 }, 9, 0, 0 },
1132     { 0x0a, 0x01004, { 9, 4, 1, 0 }, 9, 0, 0 },
1133     { 0x0a, 0x20804, { 9, 4, 1, 0 }, 9, 0, 0 },
1134     { 0x0a, 0x21004, { 9, 4, 1, 0 }, 9, 0, 0 },
1135     { 0x0b, 0x0041e, { 9, 30, 1, 0 }, 9, 0, 0 },
1136     { 0x0c, 0x0040d, { 9, 13, 1, 0 }, 9, 0, 0 },
1137     { 0x0d, 0x00401, { 1, 1, 0, 0 }, 9, 0, 0 },
1138     { 0x0d, 0x00420, { 9, 32, 1, 0 }, 9, 0, 0 },
1139     { 0x0d, 0x00429, { 41, 41, 0, 0 }, 9, 0, 0 },
1140     { 0x0d, 0x0045a, { 9, 90, 1, 0 }, 9, 0, 0 },
1141     { 0x0d, 0x00465, { 9, 101, 1, 0 }, 9, 0, 0 },
1142     { 0x0d, 0x00801, { 1, 1, 0, 0 }, 9, 0, 0 },
1143     { 0x0d, 0x00c01, { 1, 1, 0, 0 }, 9, 0, 0 },
1144     { 0x0d, 0x01001, { 1, 1, 0, 0 }, 9, 0, 0 },
1145     { 0x0d, 0x01401, { 1, 1, 0, 0 }, 9, 0, 0 },
1146     { 0x0d, 0x01801, { 1, 1, 0, 0 }, 9, 0, 0 },
1147     { 0x0d, 0x01c01, { 1, 1, 0, 0 }, 9, 0, 0 },
1148     { 0x0d, 0x02001, { 1, 1, 0, 0 }, 9, 0, 0 },
1149     { 0x0d, 0x02401, { 1, 1, 0, 0 }, 9, 0, 0 },
1150     { 0x0d, 0x02801, { 1, 1, 0, 0 }, 9, 0, 0 },
1151     { 0x0d, 0x02c01, { 1, 1, 0, 0 }, 9, 0, 0 },
1152     { 0x0d, 0x03001, { 1, 1, 0, 0 }, 9, 0, 0 },
1153     { 0x0d, 0x03401, { 1, 1, 0, 0 }, 9, 0, 0 },
1154     { 0x0d, 0x03801, { 1, 1, 0, 0 }, 9, 0, 0 },
1155     { 0x0d, 0x03c01, { 1, 1, 0, 0 }, 9, 0, 0 },
1156     { 0x0d, 0x04001, { 1, 1, 0, 0 }, 9, 0, 0 },
1157     { 0x0e, 0x0042a, { 9, 42, 1, 0 }, 9, 0, 0 },
1158     { 0x0f, 0x00439, { 9, 57, 1, 0 }, 9, 0, 0 },
1159     { 0x0f, 0x00446, { 9, 70, 1, 0 }, 9, 0, 0 },
1160     { 0x0f, 0x00447, { 9, 71, 1, 0 }, 9, 0, 0 },
1161     { 0x0f, 0x00449, { 9, 73, 1, 0 }, 9, 0, 0 },
1162     { 0x0f, 0x0044a, { 9, 74, 1, 0 }, 9, 0, 0 },
1163     { 0x0f, 0x0044b, { 9, 75, 1, 0 }, 9, 0, 0 },
1164     { 0x0f, 0x0044e, { 9, 78, 1, 0 }, 9, 0, 0 },
1165     { 0x0f, 0x0044f, { 9, 79, 1, 0 }, 9, 0, 0 },
1166     { 0x0f, 0x00457, { 9, 87, 1, 0 }, 9, 0, 0 },
1167     { 0x10, 0x00437, { 9, 55, 1, 0 }, 9, 0, 0 },
1168     { 0x10, 0x10437, { 9, 55, 1, 0 }, 9, 0, 0 },
1169     { 0x11, 0x0042b, { 9, 43, 1, 0 }, 9, 0, 0 }
1170 };
1171
1172 static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR lparam)
1173 {
1174     HRESULT hr;
1175     SCRIPT_DIGITSUBSTITUTE sds;
1176     SCRIPT_CONTROL sc;
1177     SCRIPT_STATE ss;
1178     LCID lcid_old;
1179     unsigned int i;
1180
1181     if (!IsValidLocale(lcid, LCID_INSTALLED)) return TRUE;
1182
1183     memset(&sds, 0, sizeof(sds));
1184     memset(&sc, 0, sizeof(sc));
1185     memset(&ss, 0, sizeof(ss));
1186
1187     lcid_old = GetThreadLocale();
1188     if (!SetThreadLocale(lcid)) return TRUE;
1189
1190     hr = ScriptRecordDigitSubstitution(lcid, &sds);
1191     ok(hr == S_OK, "ScriptRecordDigitSubstitution failed: 0x%08x\n", hr);
1192
1193     hr = ScriptApplyDigitSubstitution(&sds, &sc, &ss);
1194     ok(hr == S_OK, "ScriptApplyDigitSubstitution failed: 0x%08x\n", hr);
1195
1196     for (i = 0; i < sizeof(subst_data)/sizeof(subst_data[0]); i++)
1197     {
1198         if (group == subst_data[i].group && lcid == subst_data[i].lcid)
1199         {
1200             ok(!memcmp(&sds, &subst_data[i].sds, sizeof(sds)),
1201                "substitution data does not match\n");
1202
1203             ok(sc.uDefaultLanguage == subst_data[i].uDefaultLanguage,
1204                "sc.uDefaultLanguage does not match\n");
1205             ok(sc.fContextDigits == subst_data[i].fContextDigits,
1206                "sc.fContextDigits does not match\n");
1207             ok(ss.fDigitSubstitute == subst_data[i].fDigitSubstitute,
1208                "ss.fDigitSubstitute does not match\n");
1209         }
1210     }
1211     SetThreadLocale(lcid_old);
1212     return TRUE;
1213 }
1214
1215 static void test_digit_substitution(void)
1216 {
1217     BOOL ret;
1218     unsigned int i;
1219     static const LGRPID groups[] =
1220     {
1221         LGRPID_WESTERN_EUROPE,
1222         LGRPID_CENTRAL_EUROPE,
1223         LGRPID_BALTIC,
1224         LGRPID_GREEK,
1225         LGRPID_CYRILLIC,
1226         LGRPID_TURKISH,
1227         LGRPID_JAPANESE,
1228         LGRPID_KOREAN,
1229         LGRPID_TRADITIONAL_CHINESE,
1230         LGRPID_SIMPLIFIED_CHINESE,
1231         LGRPID_THAI,
1232         LGRPID_HEBREW,
1233         LGRPID_ARABIC,
1234         LGRPID_VIETNAMESE,
1235         LGRPID_INDIC,
1236         LGRPID_GEORGIAN,
1237         LGRPID_ARMENIAN
1238     };
1239     HMODULE hKernel32;
1240     static BOOL (WINAPI * pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROC,LGRPID,DWORD,LONG_PTR);
1241
1242     hKernel32 = GetModuleHandleA("kernel32.dll");
1243     pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
1244
1245     if (!pEnumLanguageGroupLocalesA)
1246     {
1247         trace("EnumLanguageGroupLocalesA not available on this platform\n");
1248         return;
1249     }
1250
1251     for (i = 0; i < sizeof(groups)/sizeof(groups[0]); i++)
1252     {
1253         ret = pEnumLanguageGroupLocalesA(enum_proc, groups[i], 0, 0);
1254         ok(ret, "EnumLanguageGroupLocalesA failed unexpectedly: 0x%08x\n", GetLastError());
1255     }
1256 }
1257
1258 START_TEST(usp10)
1259 {
1260     HWND            hwnd;
1261     HDC             hdc;
1262
1263     unsigned short  pwOutGlyphs[256];
1264
1265     /* We need a valid HDC to drive a lot of Script functions which requires the following    *
1266      * to set up for the tests.                                                               */
1267     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1268                            0, 0, 0, NULL);
1269     assert(hwnd != 0);
1270     ShowWindow(hwnd, SW_SHOW);
1271     UpdateWindow(hwnd);
1272
1273     hdc = GetDC(hwnd);                                      /* We now have a hdc             */
1274     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
1275
1276     test_ScriptItemIzeShapePlace(hdc,pwOutGlyphs);
1277     test_ScriptGetCMap(hdc, pwOutGlyphs);
1278     test_ScriptCacheGetHeight(hdc);
1279     test_ScriptGetGlyphABCWidth(hdc);
1280
1281     test_ScriptGetFontProperties();
1282     test_ScriptTextOut();
1283     test_ScriptXtoX();
1284     test_ScriptString();
1285     test_ScriptStringXtoCP_CPtoX(hdc);
1286
1287     test_ScriptLayout();
1288     test_digit_substitution();
1289
1290     ReleaseDC(hwnd, hdc);
1291     DestroyWindow(hwnd);
1292 }