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