pop fafc973c8c92ea6fa823adc8f5a7f591f01396fd
[wine/hacks.git] / dlls / usp10 / tests / usp10.c
blobefc0569d3be41da7e929d4508b1ff86c4cd67a39
1 /*
2 * Tests for usp10 dll
4 * Copyright 2006 Jeff Latimer
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
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.
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.
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
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.
27 #include <assert.h>
28 #include <stdio.h>
30 #include <wine/test.h>
31 #include <windows.h>
32 #include <usp10.h>
34 typedef struct _itemTest {
35 char todo_flag[4];
36 int iCharPos;
37 int fRTL;
38 int fLayoutRTL;
39 int uBidiLevel;
40 } itemTest;
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)
46 HRESULT hr;
47 int x, outnItems;
48 SCRIPT_ITEM outpItems[15];
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++)
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);
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);
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)
81 static void test_ScriptItemize( void )
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}};
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}};
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};
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}};
103 static const WCHAR test4[] = {'1','2','3','-','5','2',' ','i','s',' ','7','1','.',0};
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}};
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}};
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}};
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}};
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}};
135 SCRIPT_ITEM items[15];
136 SCRIPT_CONTROL Control;
137 SCRIPT_STATE State;
138 HRESULT hr;
139 int nItems;
141 memset(&Control, 0, sizeof(Control));
142 memset(&State, 0, sizeof(State));
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");
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");
150 hr = ScriptItemize(test1, 4, 1, &Control, &State, items, NULL);
151 ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cMaxItems < 2.\n");
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");
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);
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);
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);
193 static void test_ScriptShape(HDC hdc)
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;
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");
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);
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);
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);
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");
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");
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");
256 ScriptFreeCache(&sc);
257 sc = NULL;
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");
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");
321 ScriptFreeCache(&sc);
324 static void test_ScriptPlace(HDC hdc)
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];
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");
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");
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);
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);
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);
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);
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");
367 ret = ExtTextOutW(hdc, 1, 1, 0, NULL, glyphs, 4, widths);
368 ok(ret, "ExtTextOutW should return TRUE\n");
370 ScriptFreeCache(&sc);
373 static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256])
375 HRESULT hr;
376 int iMaxProps;
377 const SCRIPT_PROPERTIES **ppSp;
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};
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;
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 */
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);
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 */
463 /* This test will check to make sure that SCRIPT_CACHE is reused and that not translation *
464 * takes place if fNoGlyphIndex is set. */
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);
496 hr = ScriptFreeCache( &psc);
497 ok (!psc, "psc is not null after ScriptFreeCache\n");
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)
508 ok (pcItems == 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems);
509 if (pcItems > 2)
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);
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)
530 ok (pcItems == 5, "The number of SCRIPT_ITEMS should be 5 not %d\n", pcItems);
531 if (pcItems > 4)
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);
560 * This test is for when the first unicode character requires bidi support
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);
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);
579 static void test_ScriptGetCMap(HDC hdc, unsigned short pwOutGlyphs[256])
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;
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};
595 /* Check to make sure that SCRIPT_CACHE gets allocated ok */
596 dwFlags = 0;
597 cInChars = cChars = 5;
598 /* Some sanity checks for ScriptGetCMap */
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);
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);
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);
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);
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]);
636 hr = ScriptFreeCache( &psc);
637 ok (!psc, "psc is not null after ScriptFreeCache\n");
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");
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");
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");
667 hr = ScriptFreeCache( &psc);
668 ok (!psc, "psc is not null after ScriptFreeCache\n");
671 static void test_ScriptGetFontProperties(HDC hdc)
673 HRESULT hr;
674 SCRIPT_CACHE psc,old_psc;
675 SCRIPT_FONTPROPERTIES sfp;
677 /* Some sanity checks for ScriptGetFontProperties */
679 hr = ScriptGetFontProperties(NULL,NULL,NULL);
680 ok( hr == E_INVALIDARG, "(NULL,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
682 hr = ScriptGetFontProperties(NULL,NULL,&sfp);
683 ok( hr == E_INVALIDARG, "(NULL,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
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);
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);
697 hr = ScriptGetFontProperties(hdc,NULL,NULL);
698 ok( hr == E_INVALIDARG, "(hdc,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
700 hr = ScriptGetFontProperties(hdc,NULL,&sfp);
701 ok( hr == E_INVALIDARG, "(hdc,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
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);
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);
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");
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);
735 static void test_ScriptTextOut(HDC hdc)
737 HRESULT hr;
739 int cInChars;
740 int cMaxItems;
741 SCRIPT_ITEM pItem[255];
742 int pcItems;
743 WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
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];
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
844 /* Clean up and go */
845 ScriptFreeCache(&psc);
846 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
851 static void test_ScriptTextOut2(HDC hdc)
853 /* Intent is to validate that the HDC passed into ScriptTextOut is
854 * used instead of the (possibly) invalid cached one
856 HRESULT hr;
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};
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];
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");
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);
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);
916 /* key part!!! cached dc is being deleted */
917 hr = DeleteDC(hdc2);
918 ok(hr == 1, "DeleteDC should return 1 not %08x\n", hr);
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
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");
929 DeleteDC(hdc1);
931 /* Clean up and go */
932 ScriptFreeCache(&psc);
933 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
938 static void test_ScriptTextOut3(HDC hdc)
940 HRESULT hr;
942 int cInChars;
943 int cMaxItems;
944 SCRIPT_ITEM pItem[255];
945 int pcItems;
946 WCHAR TestItem1[] = {' ','\r', 0};
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;
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);
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);
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);
1004 /* Clean up and go */
1005 ScriptFreeCache(&psc);
1006 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1010 static void test_ScriptXtoX(void)
1011 /****************************************************************************************
1012 * This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables *
1013 ****************************************************************************************/
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;
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
1156 static void test_ScriptString(HDC hdc)
1158 /*******************************************************************************************
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.
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;
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;
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);
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);
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");
1214 if (hr == S_OK)
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);
1220 clip_len = ScriptString_pcOutChars(ssa);
1221 ok(*clip_len == len, "ScriptString_pcOutChars failed, got %d, expected %d\n", *clip_len, len);
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);
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);
1230 hr = ScriptStringFree(&ssa);
1231 ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
1234 static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
1236 /*****************************************************************************************
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.
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;
1259 int Ch; /* Character position in string */
1260 int iTrailing;
1261 int Cp; /* Character position in string */
1262 int X;
1263 BOOL fTrailing;
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.
1269 memset(&Control, 0, sizeof(SCRIPT_CONTROL));
1270 memset(&State, 0, sizeof(SCRIPT_STATE));
1271 memset(&Tabdef, 0, sizeof(SCRIPT_TABDEF));
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);
1280 if (hr == S_OK)
1282 ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
1285 * Loop to generate character positions to provide starting positions for the
1286 * ScriptStringCPtoX and ScriptStringXtoCP functions
1288 for (Cp = 0; Cp < String_len; Cp++)
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.
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);
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
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);
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
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);
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
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);
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
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);
1367 * Cleanup the SSA for the next round of tests
1369 hr = ScriptStringFree(&ssa);
1370 ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
1373 * Test to see that exceeding the number of chars returns E_INVALIDARG. First
1374 * generate an SSA for the subsequent tests.
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);
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.
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);
1391 ScriptStringFree(&ssa);
1395 static void test_ScriptCacheGetHeight(HDC hdc)
1397 HRESULT hr;
1398 SCRIPT_CACHE sc = NULL;
1399 LONG height;
1401 hr = ScriptCacheGetHeight(NULL, NULL, NULL);
1402 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1404 hr = ScriptCacheGetHeight(NULL, &sc, NULL);
1405 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1407 hr = ScriptCacheGetHeight(NULL, &sc, &height);
1408 ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1410 height = 0;
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");
1416 ScriptFreeCache(&sc);
1419 static void test_ScriptGetGlyphABCWidth(HDC hdc)
1421 HRESULT hr;
1422 SCRIPT_CACHE sc = NULL;
1423 ABC abc;
1425 hr = ScriptGetGlyphABCWidth(NULL, NULL, 'a', NULL);
1426 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
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);
1433 hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', &abc);
1434 ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
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);
1441 hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', &abc);
1442 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1444 ScriptFreeCache(&sc);
1447 static void test_ScriptLayout(void)
1449 HRESULT hr;
1450 static const BYTE levels[][10] =
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 },
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 },
1463 { 0, 0, 1, 1, 2, 2, 1, 1, 0, 1 },
1464 { 1, 0, 1, 2, 2, 1, 2, 1, 0, 1 },
1466 static const int expect_l2v[][10] =
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 },
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},
1479 { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1480 /**/ { 0, 1, 7, 5, 6, 4, 3 ,2 ,8, 9},
1482 static const int expect_v2l[][10] =
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 },
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},
1495 { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1496 { 0, 1, 7, 6, 5, 3, 4 ,2 ,8, 9},
1499 int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])];
1501 hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis);
1502 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1504 hr = ScriptLayout(sizeof(levels[0]), levels[0], NULL, NULL);
1505 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1507 for (i = 0; i < sizeof(levels)/sizeof(levels[0]); i++)
1509 hr = ScriptLayout(sizeof(levels[0]), levels[i], vistolog, logtovis);
1510 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1512 for (j = 0; j < sizeof(levels[i]); j++)
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] );
1519 for (j = 0; j < sizeof(levels[i]); j++)
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] );
1528 static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR lparam)
1530 HRESULT hr;
1531 SCRIPT_DIGITSUBSTITUTE sds;
1532 SCRIPT_CONTROL sc;
1533 SCRIPT_STATE ss;
1534 LCID lcid_old;
1536 if (!IsValidLocale(lcid, LCID_INSTALLED)) return TRUE;
1538 memset(&sds, 0, sizeof(sds));
1539 memset(&sc, 0, sizeof(sc));
1540 memset(&ss, 0, sizeof(ss));
1542 lcid_old = GetThreadLocale();
1543 if (!SetThreadLocale(lcid)) return TRUE;
1545 hr = ScriptRecordDigitSubstitution(lcid, &sds);
1546 ok(hr == S_OK, "ScriptRecordDigitSubstitution failed: 0x%08x\n", hr);
1548 hr = ScriptApplyDigitSubstitution(&sds, &sc, &ss);
1549 ok(hr == S_OK, "ScriptApplyDigitSubstitution failed: 0x%08x\n", hr);
1551 SetThreadLocale(lcid_old);
1552 return TRUE;
1555 static void test_digit_substitution(void)
1557 BOOL ret;
1558 unsigned int i;
1559 static const LGRPID groups[] =
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
1579 HMODULE hKernel32;
1580 static BOOL (WINAPI * pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA,LGRPID,DWORD,LONG_PTR);
1582 hKernel32 = GetModuleHandleA("kernel32.dll");
1583 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
1585 if (!pEnumLanguageGroupLocalesA)
1587 win_skip("EnumLanguageGroupLocalesA not available on this platform\n");
1588 return;
1591 for (i = 0; i < sizeof(groups)/sizeof(groups[0]); i++)
1593 ret = pEnumLanguageGroupLocalesA(enum_proc, groups[i], 0, 0);
1594 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1596 win_skip("EnumLanguageGroupLocalesA not implemented on this platform\n");
1597 break;
1600 ok(ret, "EnumLanguageGroupLocalesA failed unexpectedly: %u\n", GetLastError());
1604 static void test_ScriptGetProperties(void)
1606 const SCRIPT_PROPERTIES **props;
1607 HRESULT hr;
1608 int num;
1610 hr = ScriptGetProperties(NULL, NULL);
1611 ok(hr == E_INVALIDARG, "ScriptGetProperties succeeded\n");
1613 hr = ScriptGetProperties(NULL, &num);
1614 ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1616 hr = ScriptGetProperties(&props, NULL);
1617 ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1619 hr = ScriptGetProperties(&props, &num);
1620 ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1623 static void test_ScriptBreak(void)
1625 static const WCHAR test[] = {' ','\r','\n',0};
1626 SCRIPT_ITEM items[4];
1627 SCRIPT_LOGATTR la;
1628 HRESULT hr;
1630 hr = ScriptItemize(test, 3, 4, NULL, NULL, items, NULL);
1631 ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
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);
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");
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);
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");
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);
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");
1667 static void test_newlines(void)
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;
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);
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);
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);
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);
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);
1704 START_TEST(usp10)
1706 HWND hwnd;
1707 HDC hdc;
1708 LOGFONTA lf;
1709 HFONT hfont;
1711 unsigned short pwOutGlyphs[256];
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);
1721 hdc = GetDC(hwnd); /* We now have a hdc */
1722 ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
1724 memset(&lf, 0, sizeof(LOGFONTA));
1725 lstrcpyA(lf.lfFaceName, "Tahoma");
1726 lf.lfHeight = 10;
1727 lf.lfWeight = 3;
1728 lf.lfWidth = 10;
1730 hfont = SelectObject(hdc, CreateFontIndirectA(&lf));
1731 ok(hfont != NULL, "SelectObject failed: %p\n", hfont);
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);
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);
1749 test_ScriptLayout();
1750 test_digit_substitution();
1751 test_ScriptGetProperties();
1752 test_ScriptBreak();
1753 test_newlines();
1755 ReleaseDC(hwnd, hdc);
1756 DestroyWindow(hwnd);