hlink/tests: Add a trailing '\n' to an ok() call.
[wine] / dlls / usp10 / tests / usp10.c
1 /*
2  * Tests for usp10 dll
3  *
4  * Copyright 2006 Jeff Latimer
5  * Copyright 2006 Hans Leidekker
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * Notes:
22  * Uniscribe allows for processing of complex scripts such as joining
23  * and filtering characters and bi-directional text with custom line breaks.
24  */
25
26 #include <assert.h>
27 #include <stdio.h>
28
29 #include <wine/test.h>
30 #include <windows.h>
31 #include <usp10.h>
32
33 static void test_ScriptShape(HDC hdc)
34 {
35     static const WCHAR test1[] = {'t', 'e', 's', 't',0};
36     BOOL ret;
37     HRESULT hr;
38     SCRIPT_CACHE sc = NULL;
39     WORD glyphs[4], logclust[4];
40     SCRIPT_VISATTR attrs[4];
41     SCRIPT_ITEM items[2];
42     int nb, widths[4];
43     GOFFSET offset[4];
44     ABC abc[4];
45
46     hr = ScriptItemize(NULL, 4, 2, NULL, NULL, items, NULL);
47     ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr);
48
49     hr = ScriptItemize(test1, 4, 2, NULL, NULL, NULL, NULL);
50     ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr);
51
52     hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL);
53     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
54     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
55
56     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, NULL, &nb);
57     ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr);
58
59     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, NULL);
60     ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr);
61
62     hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb);
63     ok(hr == E_PENDING, "ScriptShape should return E_PENDING not %08x\n", hr);
64
65     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb);
66     ok(broken(hr == S_OK) ||
67        hr == E_INVALIDARG || /* Vista, W2K8 */
68        hr == E_FAIL, /* WIN7 */
69        "ScriptShape should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
70     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
71
72     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
73     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
74     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
75
76     hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
77     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
78
79     hr = ScriptPlace(hdc, &sc, glyphs, 4, NULL, &items[0].a, widths, NULL, NULL);
80     ok(hr == E_INVALIDARG, "ScriptPlace should return E_INVALIDARG not %08x\n", hr);
81
82     hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, NULL);
83     ok(broken(hr == E_PENDING) ||
84        hr == E_INVALIDARG || /* Vista, W2K8 */
85        hr == E_FAIL, /* WIN7 */
86        "ScriptPlace should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
87
88     hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, offset, NULL);
89     ok(hr == E_PENDING, "ScriptPlace should return E_PENDING not %08x\n", hr);
90
91     hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, abc);
92     ok(broken(hr == E_PENDING) ||
93        hr == E_INVALIDARG || /* Vista, W2K8 */
94        hr == E_FAIL, /* WIN7 */
95        "ScriptPlace should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
96
97     hr = ScriptPlace(hdc, &sc, glyphs, 4, attrs, &items[0].a, widths, offset, NULL);
98     ok(!hr, "ScriptPlace should return S_OK not %08x\n", hr);
99     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
100
101     ret = ExtTextOutW(hdc, 1, 1, 0, NULL, glyphs, 4, widths);
102     ok(ret, "ExtTextOutW should return TRUE\n");
103
104     ScriptFreeCache(&sc);
105 }
106
107 static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256])
108 {
109     HRESULT         hr;
110     int             iMaxProps;
111     const SCRIPT_PROPERTIES **ppSp;
112
113     int             cInChars;
114     int             cMaxItems;
115     SCRIPT_ITEM     pItem[255];
116     int             pcItems;
117     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
118     WCHAR           TestItem2[] = {'T', 'e', 's', 't', 'b', 0}; 
119     WCHAR           TestItem3[] = {'T', 'e', 's', 't', 'c',' ','1','2','3',' ',' ','e','n','d',0}; 
120     WCHAR           TestItem4[] = {'T', 'e', 's', 't', 'c',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0};
121     WCHAR           TestItem5[] = {0x0684,'T','e','s','t','c',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0}; 
122
123     SCRIPT_CACHE    psc;
124     int             cChars;
125     int             cMaxGlyphs;
126     unsigned short  pwOutGlyphs1[256];
127     unsigned short  pwOutGlyphs2[256];
128     unsigned short  pwLogClust[256];
129     SCRIPT_VISATTR  psva[256];
130     int             pcGlyphs;
131     int             piAdvance[256];
132     GOFFSET         pGoffset[256];
133     ABC             pABC[256];
134     int             cnt;
135
136     /* Start testing usp10 functions                                                         */
137     /* This test determines that the pointer returned by ScriptGetProperties is valid
138      * by checking a known value in the table                                                */
139     hr = ScriptGetProperties(&ppSp, &iMaxProps);
140     trace("number of script properties %d\n", iMaxProps);
141     ok (iMaxProps > 0, "Number of scripts returned should not be 0\n"); 
142     if  (iMaxProps > 0)
143          ok( ppSp[5]->langid == 9, "Langid[5] not = to 9\n"); /* Check a known value to ensure   */
144                                                               /* ptrs work                       */
145
146
147     /* This set of tests are to check that the various edits in ScriptIemize work           */
148     cInChars = 5;                                        /* Length of test without NULL     */
149     cMaxItems = 1;                                       /* Check threshold value           */
150     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
151     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cMaxItems < 2.  Was %d\n",
152         cMaxItems);
153     cInChars = 5;
154     cMaxItems = 255;
155     hr = ScriptItemize(NULL, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
156     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pwcInChars is NULL\n");
157
158     cInChars = 5;
159     cMaxItems = 255;
160     hr = ScriptItemize(TestItem1, 0, cMaxItems, NULL, NULL, pItem, &pcItems);
161     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cInChars is 0\n");
162
163     cInChars = 5;
164     cMaxItems = 255;
165     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, NULL, &pcItems);
166     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pItems is NULL\n");
167
168     /* This is a valid test that will cause parsing to take place                             */
169     cInChars = 5;
170     cMaxItems = 255;
171     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
172     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
173     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
174      *  returned.                                                                             */
175     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
176     if (pcItems > 0)
177         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
178             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
179             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
180
181     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
182      * ie. ScriptItemize has succeeded and that pItem has been set                            */
183     cInChars = 5;
184     cMaxItems = 255;
185     if (hr == 0) {
186         psc = NULL;                                   /* must be null on first call           */
187         cChars = cInChars;
188         cMaxGlyphs = cInChars;
189         hr = ScriptShape(NULL, &psc, TestItem1, cChars,
190                          cMaxGlyphs, &pItem[0].a,
191                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
192         ok (hr == E_PENDING, "If psc is NULL (%08x) the E_PENDING should be returned\n", hr);
193         cMaxGlyphs = 4;
194         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
195                          cMaxGlyphs, &pItem[0].a,
196                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
197         ok (hr == E_OUTOFMEMORY, "If not enough output area cChars (%d) is > than CMaxGlyphs "
198                                  "(%d) but not E_OUTOFMEMORY\n",
199                                  cChars, cMaxGlyphs);
200         cMaxGlyphs = 256;
201         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
202                          cMaxGlyphs, &pItem[0].a,
203                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
204         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
205         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
206         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
207         if (hr ==0) {
208             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
209                              pGoffset, pABC);
210             ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
211             hr = ScriptPlace(NULL, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
212                              pGoffset, pABC);
213             ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
214             for (cnt=0; cnt < pcGlyphs; cnt++)
215                 pwOutGlyphs[cnt] = pwOutGlyphs1[cnt];                 /* Send to next function */
216         }
217
218         /* This test will check to make sure that SCRIPT_CACHE is reused and that not translation   *
219          * takes place if fNoGlyphIndex is set.                                                     */
220
221         cInChars = 5;
222         cMaxItems = 255;
223         hr = ScriptItemize(TestItem2, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
224         ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
225         /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
226          *  returned.                                                                               */
227         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
228                             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
229                              pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
230         /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue                    */
231         if (hr == 0) {
232              cChars = cInChars;
233              cMaxGlyphs = 256;
234              pItem[0].a.fNoGlyphIndex = 1;                /* say no translate                     */
235              hr = ScriptShape(NULL, &psc, TestItem2, cChars,
236                               cMaxGlyphs, &pItem[0].a,
237                               pwOutGlyphs2, pwLogClust, psva, &pcGlyphs);
238              ok (hr != E_PENDING, "If psc should not be NULL (%08x) and the E_PENDING should be returned\n", hr);
239              ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
240              ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
241              ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
242              for (cnt=0; cnt < cChars && TestItem2[cnt] == pwOutGlyphs2[cnt]; cnt++) {}
243              ok (cnt == cChars, "Translation to place when told not to. WCHAR %d - %04x != %04x\n",
244                            cnt, TestItem2[cnt], pwOutGlyphs2[cnt]);
245              if (hr ==0) {
246                  hr = ScriptPlace(hdc, &psc, pwOutGlyphs2, pcGlyphs, psva, &pItem[0].a, piAdvance,
247                                   pGoffset, pABC);
248                  ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
249              }
250         }
251         hr = ScriptFreeCache( &psc);
252         ok (!psc, "psc is not null after ScriptFreeCache\n");
253
254     }
255
256     /* This is a valid test that will cause parsing to take place and create 3 script_items   */
257     cInChars = (sizeof(TestItem3)/2)-1;
258     cMaxItems = 255;
259     hr = ScriptItemize(TestItem3, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
260     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
261     if  (hr == 0)
262         {
263         ok (pcItems == 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems);
264         if (pcItems > 2)
265         {
266             ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
267                 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
268                 pItem[0].iCharPos, pItem[1].iCharPos);
269             ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
270                 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
271                 pItem[1].iCharPos, pItem[2].iCharPos);
272             ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == cInChars,
273                 "Start pos [2] not = 11 (%d) or end [3] pos not = 14 (%d), cInChars = %d\n",
274                 pItem[2].iCharPos, pItem[3].iCharPos, cInChars);
275         }
276         hr = ScriptFreeCache( &psc);
277         ok (!psc, "psc is not null after ScriptFreeCache\n");
278     }
279
280     /* This is a valid test that will cause parsing to take place and create 3 script_items   */
281     cInChars = (sizeof(TestItem4)/2)-1;
282     cMaxItems = 255;
283     hr = ScriptItemize(TestItem4, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
284     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
285     if  (hr == 0)
286         {
287         ok (pcItems == 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems);
288         if (pcItems > 2)
289         {
290             ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
291                 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
292                 pItem[0].iCharPos, pItem[1].iCharPos);
293             ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
294                 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
295                 pItem[1].iCharPos, pItem[2].iCharPos);
296             ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == cInChars,
297                 "Start pos [2] not = 11 (%d) or end [3] pos not = 14 (%d), cInChars = %d\n",
298                 pItem[2].iCharPos, pItem[3].iCharPos, cInChars);
299         }
300         hr = ScriptFreeCache( &psc);
301         ok (!psc, "psc is not null after ScriptFreeCache\n");
302     }
303
304     /*
305      * This test is for when the first unicode character requires bidi support
306      */ 
307     cInChars = (sizeof(TestItem5)-1)/sizeof(WCHAR);
308     hr = ScriptItemize(TestItem5, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
309     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
310     ok (pcItems == 4, "There should have been 4 items, found %d\n", pcItems);
311     ok (pItem[0].a.s.uBidiLevel == 1, "The first character should have been bidi=1 not %d\n", 
312                                        pItem[0].a.s.uBidiLevel);
313 }
314
315 static void test_ScriptGetCMap(HDC hdc, unsigned short pwOutGlyphs[256])
316 {
317     HRESULT         hr;
318     SCRIPT_CACHE    psc = NULL;
319     int             cInChars;
320     int             cChars;
321     unsigned short  pwOutGlyphs3[256];
322     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
323     DWORD           dwFlags;
324     int             cnt;
325
326     /*  Check to make sure that SCRIPT_CACHE gets allocated ok                     */
327     dwFlags = 0;
328     cInChars = cChars = 5;
329     /* Some sanity checks for ScriptGetCMap */
330
331     hr = ScriptGetCMap(NULL, NULL, NULL, 0, 0, NULL);
332     ok( hr == E_INVALIDARG, "(NULL,NULL,NULL,0,0,NULL), "
333                             "expected E_INVALIDARG, got %08x\n", hr);
334
335     hr = ScriptGetCMap(NULL, NULL, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
336     ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
337                             "expected E_INVALIDARG, got %08x\n", hr);
338
339     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
340     psc = NULL;
341     hr = ScriptGetCMap(NULL, &psc, TestItem1, cInChars, 0, pwOutGlyphs3);
342     ok( hr == E_PENDING, "(NULL,&psc,NULL,0,0,NULL), expected E_PENDING, "
343                          "got %08x\n", hr);
344     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
345
346     /* Set psc to NULL but add hdc, to be able to check if a pointer is returned in psc */
347     psc = NULL;
348     hr = ScriptGetCMap(hdc, &psc, TestItem1, cInChars, 0, pwOutGlyphs3);
349     ok( hr == S_OK, "ScriptGetCMap(NULL,&psc,NULL,0,0,NULL), expected S_OK, "
350                     "got %08x\n", hr);
351     ok( psc != NULL, "ScritpGetCMap expected psc to be not NULL\n");
352     ScriptFreeCache( &psc);
353
354     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
355     psc = NULL;
356     hr = ScriptGetCMap(NULL, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
357     ok( hr == E_PENDING, "(NULL,&psc,), expected E_PENDING, got %08x\n", hr);
358     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
359     /*  Check to see if the results are the same as those returned by ScriptShape  */
360     hr = ScriptGetCMap(hdc, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
361     ok (hr == 0, "ScriptGetCMap should return 0 not (%08x)\n", hr);
362     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
363     for (cnt=0; cnt < cChars && pwOutGlyphs[cnt] == pwOutGlyphs3[cnt]; cnt++) {}
364     ok (cnt == cInChars, "Translation not correct. WCHAR %d - %04x != %04x\n",
365                          cnt, pwOutGlyphs[cnt], pwOutGlyphs3[cnt]);
366         
367     hr = ScriptFreeCache( &psc);
368     ok (!psc, "psc is not null after ScriptFreeCache\n");
369
370 }
371
372 static void test_ScriptGetFontProperties(HDC hdc)
373 {
374     HRESULT         hr;
375     SCRIPT_CACHE    psc,old_psc;
376     SCRIPT_FONTPROPERTIES sfp;
377
378     /* Some sanity checks for ScriptGetFontProperties */
379
380     hr = ScriptGetFontProperties(NULL,NULL,NULL);
381     ok( hr == E_INVALIDARG, "(NULL,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
382
383     hr = ScriptGetFontProperties(NULL,NULL,&sfp);
384     ok( hr == E_INVALIDARG, "(NULL,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
385
386     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
387     psc = NULL;
388     hr = ScriptGetFontProperties(NULL,&psc,NULL);
389     ok( hr == E_INVALIDARG, "(NULL,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr);
390     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
391
392     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
393     psc = NULL;
394     hr = ScriptGetFontProperties(NULL,&psc,&sfp);
395     ok( hr == E_PENDING, "(NULL,&psc,&sfp), expected E_PENDING, got %08x\n", hr);
396     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
397
398     hr = ScriptGetFontProperties(hdc,NULL,NULL);
399     ok( hr == E_INVALIDARG, "(hdc,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
400
401     hr = ScriptGetFontProperties(hdc,NULL,&sfp);
402     ok( hr == E_INVALIDARG, "(hdc,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
403
404     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
405     psc = NULL;
406     hr = ScriptGetFontProperties(hdc,&psc,NULL);
407     ok( hr == E_INVALIDARG, "(hdc,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr);
408     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
409
410     /* Pass an invalid sfp */
411     psc = NULL;
412     sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES) - 1;
413     hr = ScriptGetFontProperties(hdc,&psc,&sfp);
414     ok( hr == E_INVALIDARG, "(hdc,&psc,&sfp) invalid, expected E_INVALIDARG, got %08x\n", hr);
415     ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
416     ScriptFreeCache(&psc);
417     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
418
419     /* Give it the correct cBytes, we don't care about what's coming back */
420     sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES);
421     psc = NULL;
422     hr = ScriptGetFontProperties(hdc,&psc,&sfp);
423     ok( hr == S_OK, "(hdc,&psc,&sfp) partly initialized, expected S_OK, got %08x\n", hr);
424     ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
425
426     /* Save the psc pointer */
427     old_psc = psc;
428     /* Now a NULL hdc again */
429     hr = ScriptGetFontProperties(NULL,&psc,&sfp);
430     ok( hr == S_OK, "(NULL,&psc,&sfp), expected S_OK, got %08x\n", hr);
431     ok( psc == old_psc, "Expected psc not to be changed, was %p is now %p\n", old_psc, psc);
432     ScriptFreeCache(&psc);
433     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
434 }
435
436 static void test_ScriptTextOut(HDC hdc)
437 {
438     HRESULT         hr;
439
440     int             cInChars;
441     int             cMaxItems;
442     SCRIPT_ITEM     pItem[255];
443     int             pcItems;
444     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
445
446     SCRIPT_CACHE    psc;
447     int             cChars;
448     int             cMaxGlyphs;
449     unsigned short  pwOutGlyphs1[256];
450     WORD            pwLogClust[256];
451     SCRIPT_VISATTR  psva[256];
452     int             pcGlyphs;
453     int             piAdvance[256];
454     GOFFSET         pGoffset[256];
455     ABC             pABC[256];
456     RECT            rect;
457     int             piX;
458     int             iCP = 1;
459     BOOL            fTrailing = FALSE;
460     SCRIPT_LOGATTR  *psla;
461     SCRIPT_LOGATTR  sla[256];
462
463     /* This is a valid test that will cause parsing to take place                             */
464     cInChars = 5;
465     cMaxItems = 255;
466     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
467     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
468     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
469      *  returned.                                                                             */
470     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
471     if (pcItems > 0)
472         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
473             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
474             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
475
476     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
477      * ie. ScriptItemize has succeeded and that pItem has been set                            */
478     cInChars = 5;
479     cMaxItems = 255;
480     if (hr == 0) {
481         psc = NULL;                                   /* must be null on first call           */
482         cChars = cInChars;
483         cMaxGlyphs = cInChars;
484         cMaxGlyphs = 256;
485         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
486                          cMaxGlyphs, &pItem[0].a,
487                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
488         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
489         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
490         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
491         if (hr ==0) {
492             /* Note hdc is needed as glyph info is not yet in psc                  */
493             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
494                              pGoffset, pABC);
495             ok (hr == 0, "Should return 0 not (%08x)\n", hr);
496             ScriptFreeCache(&psc);              /* Get rid of psc for next test set */
497             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
498
499             hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL);
500             ok (hr == E_INVALIDARG, "Should return 0 not (%08x)\n", hr);
501
502             hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
503                                piAdvance, NULL, pGoffset);
504             ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
505                                     "expected E_INVALIDARG, got %08x\n", hr);
506
507             /* Set psc to NULL, to be able to check if a pointer is returned in psc */
508             psc = NULL;
509             hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0,
510                                NULL, NULL, NULL);
511             ok( hr == E_INVALIDARG, "(NULL,&psc,NULL,0,0,0,NULL,), expected E_INVALIDARG, "
512                                     "got %08x\n", hr);
513             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
514
515             /* hdc is required for this one rather than the usual optional          */
516             psc = NULL;
517             hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
518                                piAdvance, NULL, pGoffset);
519             ok( hr == E_INVALIDARG, "(NULL,&psc,), expected E_INVALIDARG, got %08x\n", hr);
520             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
521
522             /* Set that it returns 0 status */
523             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
524                                piAdvance, NULL, pGoffset);
525             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
526
527             /* Test Rect Rgn is acceptable */
528             rect.top = 10;
529             rect.bottom = 20;
530             rect.left = 10;
531             rect.right = 40;
532             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, &rect, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
533                                piAdvance, NULL, pGoffset);
534             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
535
536             iCP = 1;
537             hr = ScriptCPtoX(iCP, fTrailing, cChars, pcGlyphs, (const WORD *) &pwLogClust,
538                             (const SCRIPT_VISATTR *) &psva, (const int *)&piAdvance, &pItem[0].a, &piX);
539             ok(hr == S_OK, "ScriptCPtoX Stub should return S_OK not %08x\n", hr);
540
541             psla = (SCRIPT_LOGATTR *)&sla;
542             hr = ScriptBreak(TestItem1, cChars, &pItem[0].a, psla);
543             ok(hr == S_OK, "ScriptBreak Stub should return S_OK not %08x\n", hr);
544
545             /* Clean up and go   */
546             ScriptFreeCache(&psc);
547             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
548         }
549     }
550 }
551
552 static void test_ScriptTextOut2(HDC hdc)
553 {
554 /*  Intent is to validate that the HDC passed into ScriptTextOut is
555  *  used instead of the (possibly) invalid cached one
556  */
557     HRESULT         hr;
558
559     HDC             hdc1, hdc2;
560     int             cInChars;
561     int             cMaxItems;
562     SCRIPT_ITEM     pItem[255];
563     int             pcItems;
564     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
565
566     SCRIPT_CACHE    psc;
567     int             cChars;
568     int             cMaxGlyphs;
569     unsigned short  pwOutGlyphs1[256];
570     WORD            pwLogClust[256];
571     SCRIPT_VISATTR  psva[256];
572     int             pcGlyphs;
573     int             piAdvance[256];
574     GOFFSET         pGoffset[256];
575     ABC             pABC[256];
576
577     /* Create an extra DC that will be used until the ScriptTextOut */
578     hdc1 = CreateCompatibleDC(hdc);
579     ok (hdc1 != 0, "CreateCompatibleDC failed to create a DC\n");
580     hdc2 = CreateCompatibleDC(hdc);
581     ok (hdc2 != 0, "CreateCompatibleDC failed to create a DC\n");
582
583     /* This is a valid test that will cause parsing to take place                             */
584     cInChars = 5;
585     cMaxItems = 255;
586     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
587     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
588     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
589      *  returned.                                                                             */
590     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
591     if (pcItems > 0)
592         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
593             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
594             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
595
596     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
597      * ie. ScriptItemize has succeeded and that pItem has been set                            */
598     cInChars = 5;
599     cMaxItems = 255;
600     if (hr == 0) {
601         psc = NULL;                                   /* must be null on first call           */
602         cChars = cInChars;
603         cMaxGlyphs = cInChars;
604         cMaxGlyphs = 256;
605         hr = ScriptShape(hdc2, &psc, TestItem1, cChars,
606                          cMaxGlyphs, &pItem[0].a,
607                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
608         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
609         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
610         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
611         if (hr ==0) {
612             /* Note hdc is needed as glyph info is not yet in psc                  */
613             hr = ScriptPlace(hdc2, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
614                              pGoffset, pABC);
615             ok (hr == 0, "Should return 0 not (%08x)\n", hr);
616
617             /*   key part!!!   cached dc is being deleted  */
618             hr = DeleteDC(hdc2);
619             ok(hr == 1, "DeleteDC should return 1 not %08x\n", hr);
620
621             /* At this point the cached hdc (hdc2) has been destroyed,
622              * however, we are passing in a *real* hdc (the original hdc).
623              * The text should be written to that DC
624              */
625             hr = ScriptTextOut(hdc1, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
626                                piAdvance, NULL, pGoffset);
627             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
628             ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
629
630             DeleteDC(hdc1);
631
632             /* Clean up and go   */
633             ScriptFreeCache(&psc);
634             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
635         }
636     }
637 }
638
639 static void test_ScriptTextOut3(HDC hdc)
640 {
641     HRESULT         hr;
642
643     int             cInChars;
644     int             cMaxItems;
645     SCRIPT_ITEM     pItem[255];
646     int             pcItems;
647     WCHAR           TestItem1[] = {' ','\r', 0};
648
649     SCRIPT_CACHE    psc;
650     int             cChars;
651     int             cMaxGlyphs;
652     unsigned short  pwOutGlyphs1[256];
653     WORD            pwLogClust[256];
654     SCRIPT_VISATTR  psva[256];
655     int             pcGlyphs;
656     int             piAdvance[256];
657     GOFFSET         pGoffset[256];
658     ABC             pABC[256];
659     RECT            rect;
660
661     /* This is to ensure that non exisiting glyphs are translated into a valid glyph number */
662     cInChars = 2;
663     cMaxItems = 255;
664     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
665     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
666     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
667      *  returned.                                                                             */
668     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
669     if (pcItems > 0)
670         ok (pItem[0].iCharPos == 0 && pItem[2].iCharPos == cInChars,
671             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
672             pItem[0].iCharPos, cInChars, pItem[2].iCharPos);
673
674     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
675      * ie. ScriptItemize has succeeded and that pItem has been set                            */
676     cInChars = 2;
677     cMaxItems = 255;
678     if (hr == 0) {
679         psc = NULL;                                   /* must be null on first call           */
680         cChars = cInChars;
681         cMaxGlyphs = cInChars;
682         cMaxGlyphs = 256;
683         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
684                          cMaxGlyphs, &pItem[0].a,
685                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
686         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
687         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
688         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
689         if (hr ==0) {
690             /* Note hdc is needed as glyph info is not yet in psc                  */
691             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
692                              pGoffset, pABC);
693             ok (hr == 0, "Should return 0 not (%08x)\n", hr);
694
695             /* Test Rect Rgn is acceptable */
696             rect.top = 10;
697             rect.bottom = 20;
698             rect.left = 10;
699             rect.right = 40;
700             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, &rect, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
701                                piAdvance, NULL, pGoffset);
702             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
703
704         }
705         /* Clean up and go   */
706         ScriptFreeCache(&psc);
707         ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
708     }
709 }
710
711 static void test_ScriptXtoX(void)
712 /****************************************************************************************
713  *  This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables *
714  ****************************************************************************************/
715 {
716     static const WCHAR test[] = {'t', 'e', 's', 't',0};
717     SCRIPT_ITEM items[2];
718     int iX, iCP;
719     int cChars;
720     int cGlyphs;
721     WORD pwLogClust[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
722     SCRIPT_VISATTR psva[10];
723     int piAdvance[10] = {200, 190, 210, 180, 170, 204, 189, 195, 212, 203};
724     int piCP, piX;
725     int piTrailing;
726     BOOL fTrailing;
727     HRESULT hr;
728
729     hr = ScriptItemize(test, lstrlenW(test), sizeof(items)/sizeof(items[0]), NULL, NULL, items, NULL);
730     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
731
732     iX = -1;
733     cChars = 10;
734     cGlyphs = 10;
735     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
736     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
737     if (piTrailing)
738         ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
739     else /* win2k3 */
740         ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
741
742     iX = 1954;
743     cChars = 10;
744     cGlyphs = 10;
745     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
746     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
747     if (piTrailing) /* win2k3 */
748         ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
749     else
750         ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
751
752     iX = 779;
753     cChars = 10;
754     cGlyphs = 10;
755     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
756     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
757     ok(piCP == 3 ||
758        piCP == -1, /* win2k3 */
759        "iX=%d should return piCP=3 or piCP=-1 not %d\n", iX, piCP);
760     ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
761
762     iX = 780;
763     cChars = 10;
764     cGlyphs = 10;
765     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
766     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
767     ok(piCP == 3 ||
768        piCP == -1, /* win2k3 */
769        "iX=%d should return piCP=3 or piCP=-1 not %d\n", iX, piCP);
770     ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
771
772     iX = 868;
773     cChars = 10;
774     cGlyphs = 10;
775     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
776     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
777     ok(piCP == 4 ||
778        piCP == -1, /* win2k3 */
779        "iX=%d should return piCP=4 or piCP=-1 not %d\n", iX, piCP);
780
781     iX = 0;
782     cChars = 10;
783     cGlyphs = 10;
784     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
785     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
786     ok(piCP == 0 ||
787        piCP == 10, /* win2k3 */
788        "iX=%d should return piCP=0 piCP=10 not %d\n", iX, piCP);
789
790     iX = 195;
791     cChars = 10;
792     cGlyphs = 10;
793     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
794     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
795     ok(piCP == 0, "iX=%d should return piCP=0 not %d\n", iX, piCP);
796
797     iX = 196;
798     cChars = 10;
799     cGlyphs = 10;
800     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
801     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
802     ok(piCP == 1 ||
803        piCP == 0, /* win2k3 */
804        "iX=%d should return piCP=1 or piCP=0 not %d\n", iX, piCP);
805
806     iCP=5;
807     fTrailing = FALSE;
808     cChars = 10;
809     cGlyphs = 10;
810     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
811     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
812     ok(piX == 976 ||
813        piX == 100, /* win2k3 */
814        "iCP=%d should return piX=976 or piX=100 not %d\n", iCP, piX);
815
816     iCP=5;
817     fTrailing = TRUE;
818     cChars = 10;
819     cGlyphs = 10;
820     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
821     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
822     ok(piX == 1171 ||
823        piX == 80, /* win2k3 */
824        "iCP=%d should return piX=1171 or piX=80 not %d\n", iCP, piX);
825
826     iCP=6;
827     fTrailing = FALSE;
828     cChars = 10;
829     cGlyphs = 10;
830     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
831     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
832     ok(piX == 1171 ||
833        piX == 80, /* win2k3 */
834        "iCP=%d should return piX=1171 or piX=80 not %d\n", iCP, piX);
835
836     iCP=11;
837     fTrailing = FALSE;
838     cChars = 10;
839     cGlyphs = 10;
840     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
841     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
842     ok(piX == 1953 ||
843        piX == 0, /* win2k3 */
844        "iCP=%d should return piX=1953 or piX=0 not %d\n", iCP, piX);
845
846     iCP=11;
847     fTrailing = TRUE;
848     cChars = 10;
849     cGlyphs = 10;
850     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
851     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
852     ok(piX == 1953 ||
853        piX == 0, /* win2k3 */
854        "iCP=%d should return piX=1953 or piX=0 not %d\n", iCP, piX);
855 }
856
857 static void test_ScriptString(HDC hdc)
858 {
859 /*******************************************************************************************
860  *
861  * This set of tests are for the string functions of uniscribe.  The ScriptStringAnalyse
862  * function allocates memory pointed to by the SCRIPT_STRING_ANALYSIS ssa pointer.  This
863  * memory if freed by ScriptStringFree.  There needs to be a valid hdc for this as
864  * ScriptStringAnalyse calls ScriptSItemize, ScriptShape and ScriptPlace which require it.
865  *
866  */
867
868     HRESULT         hr;
869     WCHAR           teststr[] = {'T','e','s','t','1',' ','a','2','b','3', '\0'};
870     int             len = (sizeof(teststr) / sizeof(WCHAR)) - 1;
871     int             Glyphs = len * 2 + 16;
872     int             Charset;
873     DWORD           Flags = SSA_GLYPHS;
874     int             ReqWidth = 100;
875     SCRIPT_CONTROL  Control;
876     SCRIPT_STATE    State;
877     const int       Dx[5] = {10, 10, 10, 10, 10};
878     SCRIPT_TABDEF   Tabdef;
879     const BYTE      InClass = 0;
880     SCRIPT_STRING_ANALYSIS ssa = NULL;
881
882     int             X = 10; 
883     int             Y = 100;
884     UINT            Options = 0; 
885     const RECT      rc = {0, 50, 100, 100}; 
886     int             MinSel = 0;
887     int             MaxSel = 0;
888     BOOL            Disabled = FALSE;
889     const int      *clip_len;
890     int            i;
891     UINT           *order;
892
893
894     Charset = -1;     /* this flag indicates unicode input */
895     /* Test without hdc to get E_PENDING */
896     hr = ScriptStringAnalyse( NULL, teststr, len, Glyphs, Charset, Flags,
897                              ReqWidth, &Control, &State, Dx, &Tabdef,
898                              &InClass, &ssa);
899     ok(hr == E_PENDING, "ScriptStringAnalyse Stub should return E_PENDING not %08x\n", hr);
900
901     /* test with hdc, this should be a valid test  */
902     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
903                               ReqWidth, &Control, &State, Dx, &Tabdef,
904                               &InClass, &ssa);
905     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
906     ScriptStringFree(&ssa);
907
908     /* test makes sure that a call with a valid pssa still works */
909     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
910                               ReqWidth, &Control, &State, Dx, &Tabdef,
911                               &InClass, &ssa);
912     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
913     ok(ssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
914
915     if (hr == S_OK)
916     {
917         hr = ScriptStringOut(ssa, X, Y, Options, &rc, MinSel, MaxSel, Disabled);
918         ok(hr == S_OK, "ScriptStringOut should return S_OK not %08x\n", hr);
919     }
920
921      clip_len = ScriptString_pcOutChars(ssa);
922      ok(*clip_len == len, "ScriptString_pcOutChars failed, got %d, expected %d\n", *clip_len, len);
923
924      order = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *clip_len * sizeof(UINT));
925      hr = ScriptStringGetOrder(ssa, order);
926      ok(hr == S_OK, "ScriptStringGetOrder failed, got %08x, expected S_OK\n", hr);
927
928      for (i = 0; i < *clip_len; i++) ok(order[i] == i, "%d: got %d expected %d\n", i, order[i], i);
929      HeapFree(GetProcessHeap(), 0, order);
930
931      hr = ScriptStringFree(&ssa);
932      ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
933 }
934
935 static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
936 {
937 /*****************************************************************************************
938  *
939  * This test is for the ScriptStringXtoCP and ScriptStringXtoCP functions.  Due to the
940  * nature of the fonts between Windows and Wine, the test is implemented by generating
941  * values using one one function then checking the output of the second.  In this way
942  * the validity of the functions is established using Windows as a base and confirming
943  * similar behaviour in wine.
944  */
945
946     HRESULT         hr;
947     WCHAR           teststr1[] = {'T', 'e', 's', 't', 'e', '1', '2', ' ', 'a', '\0'};
948     void            *String = (WCHAR *) &teststr1;      /* ScriptStringAnalysis needs void */
949     int             String_len = (sizeof(teststr1)/sizeof(WCHAR))-1;
950     int             Glyphs = String_len * 2 + 16;       /* size of buffer as recommended  */
951     int             Charset = -1;                       /* unicode                        */
952     DWORD           Flags = SSA_GLYPHS;
953     int             ReqWidth = 100;
954     SCRIPT_CONTROL  Control;
955     SCRIPT_STATE    State;
956     SCRIPT_TABDEF   Tabdef;
957     const BYTE      InClass = 0;
958     SCRIPT_STRING_ANALYSIS ssa = NULL;
959
960     int             Ch;                                  /* Character position in string */
961     int             iTrailing;
962     int             Cp;                                  /* Character position in string */
963     int             X;
964     BOOL            fTrailing;
965
966     /* Test with hdc, this should be a valid test
967      * Here we generate an SCRIPT_STRING_ANALYSIS that will be used as input to the
968      * following character positions to X and X to character position functions.
969      */
970     hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
971                               ReqWidth, &Control, &State, NULL, &Tabdef,
972                               &InClass, &ssa);
973     ok(hr == S_OK ||
974        hr == E_INVALIDARG, /* NT */
975        "ScriptStringAnalyse should return S_OK or E_INVALIDARG not %08x\n", hr);
976
977     if  (hr == S_OK)
978     {
979         ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
980
981         /*
982          * Loop to generate character positions to provide starting positions for the
983          * ScriptStringCPtoX and ScriptStringXtoCP functions
984          */
985         for (Cp = 0; Cp < String_len; Cp++)
986         {
987             /* The fTrailing flag is used to indicate whether the X being returned is at
988              * the beginning or the end of the character. What happens here is that if
989              * fTrailing indicates the end of the character, ie. FALSE, then ScriptStringXtoCP
990              * returns the beginning of the next character and iTrailing is FALSE.  So for this
991              * loop iTrailing will be FALSE in both cases.
992              */
993             fTrailing = FALSE;
994             hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
995             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
996             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
997             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
998             ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
999             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
1000                                   iTrailing, X);
1001             fTrailing = TRUE;
1002             hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
1003             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1004             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1005             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1006
1007             /*
1008              * Check that character position returned by ScriptStringXtoCP in Ch matches the
1009              * one input to ScriptStringCPtoX.  This means that the Cp to X position and back
1010              * again works
1011              */
1012             ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
1013             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
1014                                    iTrailing, X);
1015         }
1016         /*
1017          * This test is to check that if the X position is just inside the trailing edge of the
1018          * character then iTrailing will indicate the trailing edge, ie. TRUE
1019          */
1020         fTrailing = TRUE;
1021         Cp = 3;
1022         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
1023         ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1024         X--;                                /* put X just inside the trailing edge */
1025         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1026         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1027         ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
1028         ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", 
1029                                   iTrailing, X);
1030
1031         /*
1032          * This test is to check that if the X position is just outside the trailing edge of the
1033          * character then iTrailing will indicate the leading edge, ie. FALSE, and Ch will indicate
1034          * the next character, ie. Cp + 1 
1035          */
1036         fTrailing = TRUE;
1037         Cp = 3;
1038         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
1039         ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1040         X++;                                /* put X just outside the trailing edge */
1041         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1042         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1043         ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
1044         ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
1045                                   iTrailing, X);
1046
1047         /*
1048          * This test is to check that if the X position is just outside the leading edge of the
1049          * character then iTrailing will indicate the trailing edge, ie. TRUE, and Ch will indicate
1050          * the next character down , ie. Cp - 1 
1051          */
1052         fTrailing = FALSE;
1053         Cp = 3;
1054         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
1055         ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1056         X--;                                /* put X just outside the leading edge */
1057         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1058         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1059         ok(Cp - 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp - 1, Ch, X);
1060         ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", 
1061                                   iTrailing, X);
1062
1063         /*
1064          * Cleanup the SSA for the next round of tests
1065          */
1066         hr = ScriptStringFree(&ssa);
1067         ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
1068
1069         /*
1070          * Test to see that exceeding the number of chars returns E_INVALIDARG.  First
1071          * generate an SSA for the subsequent tests.
1072          */
1073         hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
1074                                   ReqWidth, &Control, &State, NULL, &Tabdef,
1075                                   &InClass, &ssa);
1076         ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
1077
1078         /*
1079          * When ScriptStringCPtoX is called with a character position Cp that exceeds the
1080          * string length, return E_INVALIDARG.  This also invalidates the ssa so a 
1081          * ScriptStringFree should also fail.
1082          */
1083         fTrailing = FALSE;
1084         Cp = String_len + 1; 
1085         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
1086         ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr);
1087
1088         hr = ScriptStringFree(&ssa);
1089         /*
1090          * ScriptStringCPtoX should free ssa, hence ScriptStringFree should fail
1091          */
1092         ok(hr == E_INVALIDARG ||
1093            hr == E_FAIL, /* win2k3 */
1094            "ScriptStringFree should return E_INVALIDARG or E_FAIL not %08x\n", hr);
1095     }
1096 }
1097
1098 static void test_ScriptCacheGetHeight(HDC hdc)
1099 {
1100     HRESULT hr;
1101     SCRIPT_CACHE sc = NULL;
1102     LONG height;
1103
1104     hr = ScriptCacheGetHeight(NULL, NULL, NULL);
1105     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1106
1107     hr = ScriptCacheGetHeight(NULL, &sc, NULL);
1108     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1109
1110     hr = ScriptCacheGetHeight(NULL, &sc, &height);
1111     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1112
1113     height = 0;
1114
1115     hr = ScriptCacheGetHeight(hdc, &sc, &height);
1116     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1117     ok(height > 0, "expected height > 0\n");
1118
1119     ScriptFreeCache(&sc);
1120 }
1121
1122 static void test_ScriptGetGlyphABCWidth(HDC hdc)
1123 {
1124     HRESULT hr;
1125     SCRIPT_CACHE sc = NULL;
1126     ABC abc;
1127
1128     hr = ScriptGetGlyphABCWidth(NULL, NULL, 'a', NULL);
1129     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1130
1131     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', NULL);
1132     ok(broken(hr == E_PENDING) ||
1133        hr == E_INVALIDARG, /* WIN7 */
1134        "expected E_INVALIDARG, got 0x%08x\n", hr);
1135
1136     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', &abc);
1137     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1138
1139     if (0) {    /* crashes on WinXP */
1140     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', NULL);
1141     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1142     }
1143
1144     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', &abc);
1145     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1146
1147     ScriptFreeCache(&sc);
1148 }
1149
1150 static void test_ScriptLayout(void)
1151 {
1152     HRESULT hr;
1153     static const BYTE levels[][5] =
1154     {
1155         { 0, 0, 0, 0, 0 },
1156         { 1, 1, 1, 1, 1 },
1157         { 2, 2, 2, 2, 2 },
1158         { 3, 3, 3, 3, 3 },
1159     };
1160     static const int expect[][5] =
1161     {
1162         { 0, 1, 2, 3, 4 },
1163         { 4, 3, 2, 1, 0 },
1164         { 0, 1, 2, 3, 4 },
1165         { 4, 3, 2, 1, 0 }
1166     };
1167     int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])];
1168
1169     hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis);
1170     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1171
1172     hr = ScriptLayout(sizeof(levels[0]), levels[0], NULL, NULL);
1173     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1174
1175     for (i = 0; i < sizeof(levels)/sizeof(levels[0]); i++)
1176     {
1177         hr = ScriptLayout(sizeof(levels[0]), levels[i], vistolog, logtovis);
1178         ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1179
1180         for (j = 0; j < sizeof(levels[i]); j++)
1181         {
1182             ok(expect[i][j] == vistolog[j],
1183                "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n",
1184                i, j, levels[i][j], j, vistolog[j] );
1185         }
1186
1187         for (j = 0; j < sizeof(levels[i]); j++)
1188         {
1189             ok(expect[i][j] == logtovis[j],
1190                "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n",
1191                i, j, levels[i][j], j, logtovis[j] );
1192         }
1193     }
1194 }
1195
1196 static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR lparam)
1197 {
1198     HRESULT hr;
1199     SCRIPT_DIGITSUBSTITUTE sds;
1200     SCRIPT_CONTROL sc;
1201     SCRIPT_STATE ss;
1202     LCID lcid_old;
1203
1204     if (!IsValidLocale(lcid, LCID_INSTALLED)) return TRUE;
1205
1206     memset(&sds, 0, sizeof(sds));
1207     memset(&sc, 0, sizeof(sc));
1208     memset(&ss, 0, sizeof(ss));
1209
1210     lcid_old = GetThreadLocale();
1211     if (!SetThreadLocale(lcid)) return TRUE;
1212
1213     hr = ScriptRecordDigitSubstitution(lcid, &sds);
1214     ok(hr == S_OK, "ScriptRecordDigitSubstitution failed: 0x%08x\n", hr);
1215
1216     hr = ScriptApplyDigitSubstitution(&sds, &sc, &ss);
1217     ok(hr == S_OK, "ScriptApplyDigitSubstitution failed: 0x%08x\n", hr);
1218
1219     SetThreadLocale(lcid_old);
1220     return TRUE;
1221 }
1222
1223 static void test_digit_substitution(void)
1224 {
1225     BOOL ret;
1226     unsigned int i;
1227     static const LGRPID groups[] =
1228     {
1229         LGRPID_WESTERN_EUROPE,
1230         LGRPID_CENTRAL_EUROPE,
1231         LGRPID_BALTIC,
1232         LGRPID_GREEK,
1233         LGRPID_CYRILLIC,
1234         LGRPID_TURKISH,
1235         LGRPID_JAPANESE,
1236         LGRPID_KOREAN,
1237         LGRPID_TRADITIONAL_CHINESE,
1238         LGRPID_SIMPLIFIED_CHINESE,
1239         LGRPID_THAI,
1240         LGRPID_HEBREW,
1241         LGRPID_ARABIC,
1242         LGRPID_VIETNAMESE,
1243         LGRPID_INDIC,
1244         LGRPID_GEORGIAN,
1245         LGRPID_ARMENIAN
1246     };
1247     HMODULE hKernel32;
1248     static BOOL (WINAPI * pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA,LGRPID,DWORD,LONG_PTR);
1249
1250     hKernel32 = GetModuleHandleA("kernel32.dll");
1251     pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
1252
1253     if (!pEnumLanguageGroupLocalesA)
1254     {
1255         win_skip("EnumLanguageGroupLocalesA not available on this platform\n");
1256         return;
1257     }
1258
1259     for (i = 0; i < sizeof(groups)/sizeof(groups[0]); i++)
1260     {
1261         ret = pEnumLanguageGroupLocalesA(enum_proc, groups[i], 0, 0);
1262         if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1263         {
1264             win_skip("EnumLanguageGroupLocalesA not implemented on this platform\n");
1265             break;
1266         }
1267         
1268         ok(ret, "EnumLanguageGroupLocalesA failed unexpectedly: %u\n", GetLastError());
1269     }
1270 }
1271
1272 static void test_ScriptGetProperties(void)
1273 {
1274     const SCRIPT_PROPERTIES **props;
1275     HRESULT hr;
1276     int num;
1277
1278     hr = ScriptGetProperties(NULL, NULL);
1279     ok(hr == E_INVALIDARG, "ScriptGetProperties succeeded\n");
1280
1281     hr = ScriptGetProperties(NULL, &num);
1282     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1283
1284     hr = ScriptGetProperties(&props, NULL);
1285     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1286
1287     hr = ScriptGetProperties(&props, &num);
1288     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1289 }
1290
1291 static void test_ScriptBreak(void)
1292 {
1293     static const WCHAR test[] = {' ','\r','\n',0};
1294     SCRIPT_ITEM items[4];
1295     SCRIPT_LOGATTR la;
1296     HRESULT hr;
1297
1298     hr = ScriptItemize(test, 3, 4, NULL, NULL, items, NULL);
1299     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
1300
1301     memset(&la, 0, sizeof(la));
1302     hr = ScriptBreak(test, 1, &items[0].a, &la);
1303     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
1304
1305     ok(!la.fSoftBreak, "fSoftBreak set\n");
1306     ok(la.fWhiteSpace, "fWhiteSpace not set\n");
1307     ok(la.fCharStop, "fCharStop not set\n");
1308     ok(!la.fWordStop, "fWordStop set\n");
1309     ok(!la.fInvalid, "fInvalid set\n");
1310     ok(!la.fReserved, "fReserved set\n");
1311
1312     memset(&la, 0, sizeof(la));
1313     hr = ScriptBreak(test + 1, 1, &items[1].a, &la);
1314     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
1315
1316     ok(!la.fSoftBreak, "fSoftBreak set\n");
1317     ok(!la.fWhiteSpace, "fWhiteSpace set\n");
1318     ok(la.fCharStop, "fCharStop not set\n");
1319     ok(!la.fWordStop, "fWordStop set\n");
1320     ok(!la.fInvalid, "fInvalid set\n");
1321     ok(!la.fReserved, "fReserved set\n");
1322
1323     memset(&la, 0, sizeof(la));
1324     hr = ScriptBreak(test + 2, 1, &items[2].a, &la);
1325     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
1326
1327     ok(!la.fSoftBreak, "fSoftBreak set\n");
1328     ok(!la.fWhiteSpace, "fWhiteSpace set\n");
1329     ok(la.fCharStop, "fCharStop not set\n");
1330     ok(!la.fWordStop, "fWordStop set\n");
1331     ok(!la.fInvalid, "fInvalid set\n");
1332     ok(!la.fReserved, "fReserved set\n");
1333 }
1334
1335 static void test_newlines(void)
1336 {
1337     static const WCHAR test1[] = {'t','e','x','t','\r','t','e','x','t',0};
1338     static const WCHAR test2[] = {'t','e','x','t','\n','t','e','x','t',0};
1339     static const WCHAR test3[] = {'t','e','x','t','\r','\n','t','e','x','t',0};
1340     static const WCHAR test4[] = {'t','e','x','t','\n','\r','t','e','x','t',0};
1341     static const WCHAR test5[] = {'1','2','3','4','\n','\r','1','2','3','4',0};
1342     SCRIPT_ITEM items[5];
1343     HRESULT hr;
1344     int count;
1345
1346     count = 0;
1347     hr = ScriptItemize(test1, lstrlenW(test1), 5, NULL, NULL, items, &count);
1348     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1349     ok(count == 3, "got %d expected 3\n", count);
1350
1351     count = 0;
1352     hr = ScriptItemize(test2, lstrlenW(test2), 5, NULL, NULL, items, &count);
1353     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1354     ok(count == 3, "got %d expected 3\n", count);
1355
1356     count = 0;
1357     hr = ScriptItemize(test3, lstrlenW(test3), 5, NULL, NULL, items, &count);
1358     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1359     ok(count == 4, "got %d expected 4\n", count);
1360
1361     count = 0;
1362     hr = ScriptItemize(test4, lstrlenW(test4), 5, NULL, NULL, items, &count);
1363     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1364     ok(count == 4, "got %d expected 4\n", count);
1365
1366     count = 0;
1367     hr = ScriptItemize(test5, lstrlenW(test5), 5, NULL, NULL, items, &count);
1368     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1369     ok(count == 4, "got %d expected 4\n", count);
1370 }
1371
1372 START_TEST(usp10)
1373 {
1374     HWND            hwnd;
1375     HDC             hdc;
1376     LOGFONTA        lf;
1377     HFONT           hfont;
1378
1379     unsigned short  pwOutGlyphs[256];
1380
1381     /* We need a valid HDC to drive a lot of Script functions which requires the following    *
1382      * to set up for the tests.                                                               */
1383     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1384                            0, 0, 0, NULL);
1385     assert(hwnd != 0);
1386     ShowWindow(hwnd, SW_SHOW);
1387     UpdateWindow(hwnd);
1388
1389     hdc = GetDC(hwnd);                                      /* We now have a hdc             */
1390     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
1391
1392     memset(&lf, 0, sizeof(LOGFONTA));
1393     lstrcpyA(lf.lfFaceName, "Tahoma");
1394     lf.lfHeight = 10;
1395     lf.lfWeight = 3;
1396     lf.lfWidth = 10;
1397
1398     hfont = SelectObject(hdc, CreateFontIndirectA(&lf));
1399
1400     test_ScriptItemIzeShapePlace(hdc,pwOutGlyphs);
1401     test_ScriptGetCMap(hdc, pwOutGlyphs);
1402     test_ScriptCacheGetHeight(hdc);
1403     test_ScriptGetGlyphABCWidth(hdc);
1404     test_ScriptShape(hdc);
1405
1406     test_ScriptGetFontProperties(hdc);
1407     test_ScriptTextOut(hdc);
1408     test_ScriptTextOut2(hdc);
1409     test_ScriptTextOut3(hdc);
1410     test_ScriptXtoX();
1411     test_ScriptString(hdc);
1412     test_ScriptStringXtoCP_CPtoX(hdc);
1413
1414     test_ScriptLayout();
1415     test_digit_substitution();
1416     test_ScriptGetProperties();
1417     test_ScriptBreak();
1418     test_newlines();
1419
1420     ReleaseDC(hwnd, hdc);
1421     DestroyWindow(hwnd);
1422 }