wined3d: Handle stateblock capture for default lights created while recording.
[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_ScriptXtoX(void)
640 /****************************************************************************************
641  *  This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables *
642  ****************************************************************************************/
643 {
644     static const WCHAR test[] = {'t', 'e', 's', 't',0};
645     SCRIPT_ITEM items[2];
646     int iX, iCP;
647     int cChars;
648     int cGlyphs;
649     WORD pwLogClust[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
650     SCRIPT_VISATTR psva[10];
651     int piAdvance[10] = {200, 190, 210, 180, 170, 204, 189, 195, 212, 203};
652     int piCP, piX;
653     int piTrailing;
654     BOOL fTrailing;
655     HRESULT hr;
656
657     hr = ScriptItemize(test, lstrlenW(test), sizeof(items)/sizeof(items[0]), NULL, NULL, items, NULL);
658     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
659
660     iX = -1;
661     cChars = 10;
662     cGlyphs = 10;
663     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
664     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
665     if (piTrailing)
666         ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
667     else /* win2k3 */
668         ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
669
670     iX = 1954;
671     cChars = 10;
672     cGlyphs = 10;
673     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
674     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
675     if (piTrailing) /* win2k3 */
676         ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
677     else
678         ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
679
680     iX = 779;
681     cChars = 10;
682     cGlyphs = 10;
683     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
684     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
685     ok(piCP == 3 ||
686        piCP == -1, /* win2k3 */
687        "iX=%d should return piCP=3 or piCP=-1 not %d\n", iX, piCP);
688     ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
689
690     iX = 780;
691     cChars = 10;
692     cGlyphs = 10;
693     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
694     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
695     ok(piCP == 3 ||
696        piCP == -1, /* win2k3 */
697        "iX=%d should return piCP=3 or piCP=-1 not %d\n", iX, piCP);
698     ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
699
700     iX = 868;
701     cChars = 10;
702     cGlyphs = 10;
703     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
704     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
705     ok(piCP == 4 ||
706        piCP == -1, /* win2k3 */
707        "iX=%d should return piCP=4 or piCP=-1 not %d\n", iX, piCP);
708
709     iX = 0;
710     cChars = 10;
711     cGlyphs = 10;
712     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
713     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
714     ok(piCP == 0 ||
715        piCP == 10, /* win2k3 */
716        "iX=%d should return piCP=0 piCP=10 not %d\n", iX, piCP);
717
718     iX = 195;
719     cChars = 10;
720     cGlyphs = 10;
721     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
722     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
723     ok(piCP == 0, "iX=%d should return piCP=0 not %d\n", iX, piCP);
724
725     iX = 196;
726     cChars = 10;
727     cGlyphs = 10;
728     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
729     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
730     ok(piCP == 1 ||
731        piCP == 0, /* win2k3 */
732        "iX=%d should return piCP=1 or piCP=0 not %d\n", iX, piCP);
733
734     iCP=5;
735     fTrailing = FALSE;
736     cChars = 10;
737     cGlyphs = 10;
738     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
739     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
740     ok(piX == 976 ||
741        piX == 100, /* win2k3 */
742        "iCP=%d should return piX=976 or piX=100 not %d\n", iCP, piX);
743
744     iCP=5;
745     fTrailing = TRUE;
746     cChars = 10;
747     cGlyphs = 10;
748     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
749     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
750     ok(piX == 1171 ||
751        piX == 80, /* win2k3 */
752        "iCP=%d should return piX=1171 or piX=80 not %d\n", iCP, piX);
753
754     iCP=6;
755     fTrailing = FALSE;
756     cChars = 10;
757     cGlyphs = 10;
758     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
759     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
760     ok(piX == 1171 ||
761        piX == 80, /* win2k3 */
762        "iCP=%d should return piX=1171 or piX=80 not %d\n", iCP, piX);
763
764     iCP=11;
765     fTrailing = FALSE;
766     cChars = 10;
767     cGlyphs = 10;
768     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
769     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
770     ok(piX == 1953 ||
771        piX == 0, /* win2k3 */
772        "iCP=%d should return piX=1953 or piX=0 not %d\n", iCP, piX);
773
774     iCP=11;
775     fTrailing = TRUE;
776     cChars = 10;
777     cGlyphs = 10;
778     hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
779     ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
780     ok(piX == 1953 ||
781        piX == 0, /* win2k3 */
782        "iCP=%d should return piX=1953 or piX=0 not %d\n", iCP, piX);
783 }
784
785 static void test_ScriptString(HDC hdc)
786 {
787 /*******************************************************************************************
788  *
789  * This set of tests are for the string functions of uniscribe.  The ScriptStringAnalyse
790  * function allocates memory pointed to by the SCRIPT_STRING_ANALYSIS ssa pointer.  This
791  * memory if freed by ScriptStringFree.  There needs to be a valid hdc for this as
792  * ScriptStringAnalyse calls ScriptSItemize, ScriptShape and ScriptPlace which require it.
793  *
794  */
795
796     HRESULT         hr;
797     WCHAR           teststr[] = {'T','e','s','t','1',' ','a','2','b','3', '\0'};
798     int             len = (sizeof(teststr) / sizeof(WCHAR)) - 1;
799     int             Glyphs = len * 2 + 16;
800     int             Charset;
801     DWORD           Flags = SSA_GLYPHS;
802     int             ReqWidth = 100;
803     SCRIPT_CONTROL  Control;
804     SCRIPT_STATE    State;
805     const int       Dx[5] = {10, 10, 10, 10, 10};
806     SCRIPT_TABDEF   Tabdef;
807     const BYTE      InClass = 0;
808     SCRIPT_STRING_ANALYSIS ssa = NULL;
809
810     int             X = 10; 
811     int             Y = 100;
812     UINT            Options = 0; 
813     const RECT      rc = {0, 50, 100, 100}; 
814     int             MinSel = 0;
815     int             MaxSel = 0;
816     BOOL            Disabled = FALSE;
817     const int      *clip_len;
818     int            i;
819     UINT           *order;
820
821
822     Charset = -1;     /* this flag indicates unicode input */
823     /* Test without hdc to get E_PENDING */
824     hr = ScriptStringAnalyse( NULL, teststr, len, Glyphs, Charset, Flags,
825                              ReqWidth, &Control, &State, Dx, &Tabdef,
826                              &InClass, &ssa);
827     ok(hr == E_PENDING, "ScriptStringAnalyse Stub should return E_PENDING not %08x\n", hr);
828
829     /* test with hdc, this should be a valid test  */
830     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
831                               ReqWidth, &Control, &State, Dx, &Tabdef,
832                               &InClass, &ssa);
833     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
834     ScriptStringFree(&ssa);
835
836     /* test makes sure that a call with a valid pssa still works */
837     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
838                               ReqWidth, &Control, &State, Dx, &Tabdef,
839                               &InClass, &ssa);
840     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
841     ok(ssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
842
843     if (hr == S_OK)
844     {
845         hr = ScriptStringOut(ssa, X, Y, Options, &rc, MinSel, MaxSel, Disabled);
846         ok(hr == S_OK, "ScriptStringOut should return S_OK not %08x\n", hr);
847     }
848
849      clip_len = ScriptString_pcOutChars(ssa);
850      ok(*clip_len == len, "ScriptString_pcOutChars failed, got %d, expected %d\n", *clip_len, len);
851
852      order = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *clip_len * sizeof(UINT));
853      hr = ScriptStringGetOrder(ssa, order);
854      ok(hr == S_OK, "ScriptStringGetOrder failed, got %08x, expected S_OK\n", hr);
855
856      for (i = 0; i < *clip_len; i++) ok(order[i] == i, "%d: got %d expected %d\n", i, order[i], i);
857      HeapFree(GetProcessHeap(), 0, order);
858
859      hr = ScriptStringFree(&ssa);
860      ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
861 }
862
863 static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
864 {
865 /*****************************************************************************************
866  *
867  * This test is for the ScriptStringXtoCP and ScriptStringXtoCP functions.  Due to the
868  * nature of the fonts between Windows and Wine, the test is implemented by generating
869  * values using one one function then checking the output of the second.  In this way
870  * the validity of the functions is established using Windows as a base and confirming
871  * similar behaviour in wine.
872  */
873
874     HRESULT         hr;
875     WCHAR           teststr1[] = {'T', 'e', 's', 't', 'e', '1', '2', ' ', 'a', '\0'};
876     void            *String = (WCHAR *) &teststr1;      /* ScriptStringAnalysis needs void */
877     int             String_len = (sizeof(teststr1)/sizeof(WCHAR))-1;
878     int             Glyphs = String_len * 2 + 16;       /* size of buffer as recommended  */
879     int             Charset = -1;                       /* unicode                        */
880     DWORD           Flags = SSA_GLYPHS;
881     int             ReqWidth = 100;
882     SCRIPT_CONTROL  Control;
883     SCRIPT_STATE    State;
884     SCRIPT_TABDEF   Tabdef;
885     const BYTE      InClass = 0;
886     SCRIPT_STRING_ANALYSIS ssa = NULL;
887
888     int             Ch;                                  /* Character position in string */
889     int             iTrailing;
890     int             Cp;                                  /* Character position in string */
891     int             X;
892     BOOL            fTrailing;
893
894     /* Test with hdc, this should be a valid test
895      * Here we generate an SCRIPT_STRING_ANALYSIS that will be used as input to the
896      * following character positions to X and X to character position functions.
897      */
898     hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
899                               ReqWidth, &Control, &State, NULL, &Tabdef,
900                               &InClass, &ssa);
901     ok(hr == S_OK ||
902        hr == E_INVALIDARG, /* NT */
903        "ScriptStringAnalyse should return S_OK or E_INVALIDARG not %08x\n", hr);
904
905     if  (hr == S_OK)
906     {
907         ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
908
909         /*
910          * Loop to generate character positions to provide starting positions for the
911          * ScriptStringCPtoX and ScriptStringXtoCP functions
912          */
913         for (Cp = 0; Cp < String_len; Cp++)
914         {
915             /* The fTrailing flag is used to indicate whether the X being returned is at
916              * the beginning or the end of the character. What happens here is that if
917              * fTrailing indicates the end of the character, ie. FALSE, then ScriptStringXtoCP
918              * returns the beginning of the next character and iTrailing is FALSE.  So for this
919              * loop iTrailing will be FALSE in both cases.
920              */
921             fTrailing = FALSE;
922             hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
923             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
924             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
925             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
926             ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
927             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
928                                   iTrailing, X);
929             fTrailing = TRUE;
930             hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
931             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
932             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
933             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
934
935             /*
936              * Check that character position returned by ScriptStringXtoCP in Ch matches the
937              * one input to ScriptStringCPtoX.  This means that the Cp to X position and back
938              * again works
939              */
940             ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
941             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
942                                    iTrailing, X);
943         }
944         /*
945          * This test is to check that if the X position is just inside the trailing edge of the
946          * character then iTrailing will indicate the trailing edge, ie. TRUE
947          */
948         fTrailing = TRUE;
949         Cp = 3;
950         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
951         ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
952         X--;                                /* put X just inside the trailing edge */
953         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
954         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
955         ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
956         ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", 
957                                   iTrailing, X);
958
959         /*
960          * This test is to check that if the X position is just outside the trailing edge of the
961          * character then iTrailing will indicate the leading edge, ie. FALSE, and Ch will indicate
962          * the next character, ie. Cp + 1 
963          */
964         fTrailing = TRUE;
965         Cp = 3;
966         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
967         ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
968         X++;                                /* put X just outside the trailing edge */
969         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
970         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
971         ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
972         ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n", 
973                                   iTrailing, X);
974
975         /*
976          * This test is to check that if the X position is just outside the leading edge of the
977          * character then iTrailing will indicate the trailing edge, ie. TRUE, and Ch will indicate
978          * the next character down , ie. Cp - 1 
979          */
980         fTrailing = FALSE;
981         Cp = 3;
982         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
983         ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
984         X--;                                /* put X just outside the leading edge */
985         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
986         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
987         ok(Cp - 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp - 1, Ch, X);
988         ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n", 
989                                   iTrailing, X);
990
991         /*
992          * Cleanup the SSA for the next round of tests
993          */
994         hr = ScriptStringFree(&ssa);
995         ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
996
997         /*
998          * Test to see that exceeding the number of chars returns E_INVALIDARG.  First
999          * generate an SSA for the subsequent tests.
1000          */
1001         hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
1002                                   ReqWidth, &Control, &State, NULL, &Tabdef,
1003                                   &InClass, &ssa);
1004         ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
1005
1006         /*
1007          * When ScriptStringCPtoX is called with a character position Cp that exceeds the
1008          * string length, return E_INVALIDARG.  This also invalidates the ssa so a 
1009          * ScriptStringFree should also fail.
1010          */
1011         fTrailing = FALSE;
1012         Cp = String_len + 1; 
1013         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
1014         ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr);
1015
1016         hr = ScriptStringFree(&ssa);
1017         /*
1018          * ScriptStringCPtoX should free ssa, hence ScriptStringFree should fail
1019          */
1020         ok(hr == E_INVALIDARG ||
1021            hr == E_FAIL, /* win2k3 */
1022            "ScriptStringFree should return E_INVALIDARG or E_FAIL not %08x\n", hr);
1023     }
1024 }
1025
1026 static void test_ScriptCacheGetHeight(HDC hdc)
1027 {
1028     HRESULT hr;
1029     SCRIPT_CACHE sc = NULL;
1030     LONG height;
1031
1032     hr = ScriptCacheGetHeight(NULL, NULL, NULL);
1033     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1034
1035     hr = ScriptCacheGetHeight(NULL, &sc, NULL);
1036     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1037
1038     hr = ScriptCacheGetHeight(NULL, &sc, &height);
1039     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1040
1041     height = 0;
1042
1043     hr = ScriptCacheGetHeight(hdc, &sc, &height);
1044     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1045     ok(height > 0, "expected height > 0\n");
1046
1047     ScriptFreeCache(&sc);
1048 }
1049
1050 static void test_ScriptGetGlyphABCWidth(HDC hdc)
1051 {
1052     HRESULT hr;
1053     SCRIPT_CACHE sc = NULL;
1054     ABC abc;
1055
1056     hr = ScriptGetGlyphABCWidth(NULL, NULL, 'a', NULL);
1057     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1058
1059     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', NULL);
1060     ok(broken(hr == E_PENDING) ||
1061        hr == E_INVALIDARG, /* WIN7 */
1062        "expected E_INVALIDARG, got 0x%08x\n", hr);
1063
1064     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', &abc);
1065     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1066
1067     if (0) {    /* crashes on WinXP */
1068     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', NULL);
1069     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1070     }
1071
1072     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', &abc);
1073     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1074
1075     ScriptFreeCache(&sc);
1076 }
1077
1078 static void test_ScriptLayout(void)
1079 {
1080     HRESULT hr;
1081     static const BYTE levels[][5] =
1082     {
1083         { 0, 0, 0, 0, 0 },
1084         { 1, 1, 1, 1, 1 },
1085         { 2, 2, 2, 2, 2 },
1086         { 3, 3, 3, 3, 3 },
1087     };
1088     static const int expect[][5] =
1089     {
1090         { 0, 1, 2, 3, 4 },
1091         { 4, 3, 2, 1, 0 },
1092         { 0, 1, 2, 3, 4 },
1093         { 4, 3, 2, 1, 0 }
1094     };
1095     int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])];
1096
1097     hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis);
1098     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1099
1100     hr = ScriptLayout(sizeof(levels[0]), levels[0], NULL, NULL);
1101     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1102
1103     for (i = 0; i < sizeof(levels)/sizeof(levels[0]); i++)
1104     {
1105         hr = ScriptLayout(sizeof(levels[0]), levels[i], vistolog, logtovis);
1106         ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1107
1108         for (j = 0; j < sizeof(levels[i]); j++)
1109         {
1110             ok(expect[i][j] == vistolog[j],
1111                "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n",
1112                i, j, levels[i][j], j, vistolog[j] );
1113         }
1114
1115         for (j = 0; j < sizeof(levels[i]); j++)
1116         {
1117             ok(expect[i][j] == logtovis[j],
1118                "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n",
1119                i, j, levels[i][j], j, logtovis[j] );
1120         }
1121     }
1122 }
1123
1124 static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR lparam)
1125 {
1126     HRESULT hr;
1127     SCRIPT_DIGITSUBSTITUTE sds;
1128     SCRIPT_CONTROL sc;
1129     SCRIPT_STATE ss;
1130     LCID lcid_old;
1131
1132     if (!IsValidLocale(lcid, LCID_INSTALLED)) return TRUE;
1133
1134     memset(&sds, 0, sizeof(sds));
1135     memset(&sc, 0, sizeof(sc));
1136     memset(&ss, 0, sizeof(ss));
1137
1138     lcid_old = GetThreadLocale();
1139     if (!SetThreadLocale(lcid)) return TRUE;
1140
1141     hr = ScriptRecordDigitSubstitution(lcid, &sds);
1142     ok(hr == S_OK, "ScriptRecordDigitSubstitution failed: 0x%08x\n", hr);
1143
1144     hr = ScriptApplyDigitSubstitution(&sds, &sc, &ss);
1145     ok(hr == S_OK, "ScriptApplyDigitSubstitution failed: 0x%08x\n", hr);
1146
1147     SetThreadLocale(lcid_old);
1148     return TRUE;
1149 }
1150
1151 static void test_digit_substitution(void)
1152 {
1153     BOOL ret;
1154     unsigned int i;
1155     static const LGRPID groups[] =
1156     {
1157         LGRPID_WESTERN_EUROPE,
1158         LGRPID_CENTRAL_EUROPE,
1159         LGRPID_BALTIC,
1160         LGRPID_GREEK,
1161         LGRPID_CYRILLIC,
1162         LGRPID_TURKISH,
1163         LGRPID_JAPANESE,
1164         LGRPID_KOREAN,
1165         LGRPID_TRADITIONAL_CHINESE,
1166         LGRPID_SIMPLIFIED_CHINESE,
1167         LGRPID_THAI,
1168         LGRPID_HEBREW,
1169         LGRPID_ARABIC,
1170         LGRPID_VIETNAMESE,
1171         LGRPID_INDIC,
1172         LGRPID_GEORGIAN,
1173         LGRPID_ARMENIAN
1174     };
1175     HMODULE hKernel32;
1176     static BOOL (WINAPI * pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA,LGRPID,DWORD,LONG_PTR);
1177
1178     hKernel32 = GetModuleHandleA("kernel32.dll");
1179     pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
1180
1181     if (!pEnumLanguageGroupLocalesA)
1182     {
1183         win_skip("EnumLanguageGroupLocalesA not available on this platform\n");
1184         return;
1185     }
1186
1187     for (i = 0; i < sizeof(groups)/sizeof(groups[0]); i++)
1188     {
1189         ret = pEnumLanguageGroupLocalesA(enum_proc, groups[i], 0, 0);
1190         if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1191         {
1192             win_skip("EnumLanguageGroupLocalesA not implemented on this platform\n");
1193             break;
1194         }
1195         
1196         ok(ret, "EnumLanguageGroupLocalesA failed unexpectedly: %u\n", GetLastError());
1197     }
1198 }
1199
1200 static void test_ScriptGetProperties(void)
1201 {
1202     const SCRIPT_PROPERTIES **props;
1203     HRESULT hr;
1204     int num;
1205
1206     hr = ScriptGetProperties(NULL, NULL);
1207     ok(hr == E_INVALIDARG, "ScriptGetProperties succeeded\n");
1208
1209     hr = ScriptGetProperties(NULL, &num);
1210     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1211
1212     hr = ScriptGetProperties(&props, NULL);
1213     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1214
1215     hr = ScriptGetProperties(&props, &num);
1216     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1217 }
1218
1219 static void test_ScriptBreak(void)
1220 {
1221     static const WCHAR test[] = {' ','\r','\n',0};
1222     SCRIPT_ITEM items[4];
1223     SCRIPT_LOGATTR la;
1224     HRESULT hr;
1225
1226     hr = ScriptItemize(test, 3, 4, NULL, NULL, items, NULL);
1227     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
1228
1229     memset(&la, 0, sizeof(la));
1230     hr = ScriptBreak(test, 1, &items[0].a, &la);
1231     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
1232
1233     ok(!la.fSoftBreak, "fSoftBreak set\n");
1234     ok(la.fWhiteSpace, "fWhiteSpace not set\n");
1235     ok(la.fCharStop, "fCharStop not set\n");
1236     ok(!la.fWordStop, "fWordStop set\n");
1237     ok(!la.fInvalid, "fInvalid set\n");
1238     ok(!la.fReserved, "fReserved set\n");
1239
1240     memset(&la, 0, sizeof(la));
1241     hr = ScriptBreak(test + 1, 1, &items[1].a, &la);
1242     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
1243
1244     ok(!la.fSoftBreak, "fSoftBreak set\n");
1245     ok(!la.fWhiteSpace, "fWhiteSpace set\n");
1246     ok(la.fCharStop, "fCharStop not set\n");
1247     ok(!la.fWordStop, "fWordStop set\n");
1248     ok(!la.fInvalid, "fInvalid set\n");
1249     ok(!la.fReserved, "fReserved set\n");
1250
1251     memset(&la, 0, sizeof(la));
1252     hr = ScriptBreak(test + 2, 1, &items[2].a, &la);
1253     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
1254
1255     ok(!la.fSoftBreak, "fSoftBreak set\n");
1256     ok(!la.fWhiteSpace, "fWhiteSpace set\n");
1257     ok(la.fCharStop, "fCharStop not set\n");
1258     ok(!la.fWordStop, "fWordStop set\n");
1259     ok(!la.fInvalid, "fInvalid set\n");
1260     ok(!la.fReserved, "fReserved set\n");
1261 }
1262
1263 static void test_newlines(void)
1264 {
1265     static const WCHAR test1[] = {'t','e','x','t','\r','t','e','x','t',0};
1266     static const WCHAR test2[] = {'t','e','x','t','\n','t','e','x','t',0};
1267     static const WCHAR test3[] = {'t','e','x','t','\r','\n','t','e','x','t',0};
1268     static const WCHAR test4[] = {'t','e','x','t','\n','\r','t','e','x','t',0};
1269     static const WCHAR test5[] = {'1','2','3','4','\n','\r','1','2','3','4',0};
1270     SCRIPT_ITEM items[5];
1271     HRESULT hr;
1272     int count;
1273
1274     count = 0;
1275     hr = ScriptItemize(test1, lstrlenW(test1), 5, NULL, NULL, items, &count);
1276     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1277     ok(count == 3, "got %d expected 3\n", count);
1278
1279     count = 0;
1280     hr = ScriptItemize(test2, lstrlenW(test2), 5, NULL, NULL, items, &count);
1281     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1282     ok(count == 3, "got %d expected 3\n", count);
1283
1284     count = 0;
1285     hr = ScriptItemize(test3, lstrlenW(test3), 5, NULL, NULL, items, &count);
1286     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1287     ok(count == 4, "got %d expected 4\n", count);
1288
1289     count = 0;
1290     hr = ScriptItemize(test4, lstrlenW(test4), 5, NULL, NULL, items, &count);
1291     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1292     ok(count == 4, "got %d expected 4\n", count);
1293
1294     count = 0;
1295     hr = ScriptItemize(test5, lstrlenW(test5), 5, NULL, NULL, items, &count);
1296     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1297     ok(count == 4, "got %d expected 4\n", count);
1298 }
1299
1300 START_TEST(usp10)
1301 {
1302     HWND            hwnd;
1303     HDC             hdc;
1304     LOGFONTA        lf;
1305     HFONT           hfont;
1306
1307     unsigned short  pwOutGlyphs[256];
1308
1309     /* We need a valid HDC to drive a lot of Script functions which requires the following    *
1310      * to set up for the tests.                                                               */
1311     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1312                            0, 0, 0, NULL);
1313     assert(hwnd != 0);
1314     ShowWindow(hwnd, SW_SHOW);
1315     UpdateWindow(hwnd);
1316
1317     hdc = GetDC(hwnd);                                      /* We now have a hdc             */
1318     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
1319
1320     memset(&lf, 0, sizeof(LOGFONTA));
1321     lstrcpyA(lf.lfFaceName, "Tahoma");
1322     lf.lfHeight = 10;
1323     lf.lfWeight = 3;
1324     lf.lfWidth = 10;
1325
1326     hfont = SelectObject(hdc, CreateFontIndirectA(&lf));
1327
1328     test_ScriptItemIzeShapePlace(hdc,pwOutGlyphs);
1329     test_ScriptGetCMap(hdc, pwOutGlyphs);
1330     test_ScriptCacheGetHeight(hdc);
1331     test_ScriptGetGlyphABCWidth(hdc);
1332     test_ScriptShape(hdc);
1333
1334     test_ScriptGetFontProperties(hdc);
1335     test_ScriptTextOut(hdc);
1336     test_ScriptTextOut2(hdc);
1337     test_ScriptXtoX();
1338     test_ScriptString(hdc);
1339     test_ScriptStringXtoCP_CPtoX(hdc);
1340
1341     test_ScriptLayout();
1342     test_digit_substitution();
1343     test_ScriptGetProperties();
1344     test_ScriptBreak();
1345     test_newlines();
1346
1347     ReleaseDC(hwnd, hdc);
1348     DestroyWindow(hwnd);
1349 }