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