push 9d6e510d5bb9560a6aa2e6ec402cb2d2444b5081
[wine/hacks.git] / dlls / usp10 / tests / usp10.c
blob1dba6829ac7b06690a4f4754bd1cdf6d2c8c054b
1 /*
2 * Tests for usp10 dll
4 * Copyright 2006 Jeff Latimer
5 * Copyright 2006 Hans Leidekker
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.
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.
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
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.
26 #include <assert.h>
27 #include <stdio.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>
37 static void test_ScriptShape(HDC hdc)
39 static const WCHAR test1[] = {'t', 'e', 's', 't',0};
40 BOOL ret;
41 HRESULT hr;
42 SCRIPT_CACHE sc = NULL;
43 WORD glyphs[4];
44 SCRIPT_VISATTR attrs[4];
45 SCRIPT_ITEM items[2];
46 int nb, widths[4];
48 hr = ScriptItemize(NULL, 4, 2, NULL, NULL, items, NULL);
49 ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr);
51 hr = ScriptItemize(test1, 4, 2, NULL, NULL, NULL, NULL);
52 ok(hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG not %08x\n", hr);
54 hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL);
55 ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
56 ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
58 hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, NULL, &nb);
59 ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr);
61 hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, NULL);
62 ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr);
64 hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb);
65 ok(hr == E_PENDING, "ScriptShape should return E_PENDING not %08x\n", hr);
67 hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb);
68 ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
69 ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
71 hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb);
72 ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
74 hr = ScriptPlace(hdc, &sc, glyphs, 4, NULL, &items[0].a, widths, NULL, NULL);
75 ok(hr == E_INVALIDARG, "ScriptPlace should return E_INVALIDARG not %08x\n", hr);
77 hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, NULL);
78 ok(hr == E_PENDING, "ScriptPlace should return E_PENDING not %08x\n", hr);
80 hr = ScriptPlace(hdc, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, NULL);
81 ok(!hr, "ScriptPlace should return S_OK not %08x\n", hr);
82 ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
84 ret = ExtTextOutW(hdc, 1, 1, 0, NULL, glyphs, 4, widths);
85 ok(ret, "ExtTextOutW should return TRUE\n");
87 ScriptFreeCache(&sc);
90 static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256])
92 HRESULT hr;
93 int iMaxProps;
94 const SCRIPT_PROPERTIES **ppSp;
96 int cInChars;
97 int cMaxItems;
98 SCRIPT_ITEM pItem[255];
99 int pcItems;
100 WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
101 WCHAR TestItem2[] = {'T', 'e', 's', 't', 'b', 0};
102 WCHAR TestItem3[] = {'T', 'e', 's', 't', 'c',' ','1','2','3',' ',' ','e','n','d',0};
103 WCHAR TestItem4[] = {'T', 'e', 's', 't', 'c',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0};
104 WCHAR TestItem5[] = {0x0684,'T','e','s','t','c',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0};
106 SCRIPT_CACHE psc;
107 int cChars;
108 int cMaxGlyphs;
109 unsigned short pwOutGlyphs1[256];
110 unsigned short pwOutGlyphs2[256];
111 unsigned short pwLogClust[256];
112 SCRIPT_VISATTR psva[256];
113 int pcGlyphs;
114 int piAdvance[256];
115 GOFFSET pGoffset[256];
116 ABC pABC[256];
117 int cnt;
119 /* Start testing usp10 functions */
120 /* This test determines that the pointer returned by ScriptGetProperties is valid
121 * by checking a known value in the table */
122 hr = ScriptGetProperties(&ppSp, &iMaxProps);
123 trace("number of script properties %d\n", iMaxProps);
124 ok (iMaxProps > 0, "Number of scripts returned should not be 0\n");
125 if (iMaxProps > 0)
126 ok( ppSp[5]->langid == 9, "Langid[5] not = to 9\n"); /* Check a known value to ensure */
127 /* ptrs work */
130 /* This set of tests are to check that the various edits in ScriptIemize work */
131 cInChars = 5; /* Length of test without NULL */
132 cMaxItems = 1; /* Check threshold value */
133 hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
134 ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cMaxItems < 2. Was %d\n",
135 cMaxItems);
136 cInChars = 5;
137 cMaxItems = 255;
138 hr = ScriptItemize(NULL, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
139 ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pwcInChars is NULL\n");
141 cInChars = 5;
142 cMaxItems = 255;
143 hr = ScriptItemize(TestItem1, 0, cMaxItems, NULL, NULL, pItem, &pcItems);
144 ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cInChars is 0\n");
146 cInChars = 5;
147 cMaxItems = 255;
148 hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, NULL, &pcItems);
149 ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pItems is NULL\n");
151 /* This is a valid test that will cause parsing to take place */
152 cInChars = 5;
153 cMaxItems = 255;
154 hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
155 ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
156 /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
157 * returned. */
158 ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
159 if (pcItems > 0)
160 ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
161 "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
162 pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
164 /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
165 * ie. ScriptItemize has succeeded and that pItem has been set */
166 cInChars = 5;
167 cMaxItems = 255;
168 if (hr == 0) {
169 psc = NULL; /* must be null on first call */
170 cChars = cInChars;
171 cMaxGlyphs = cInChars;
172 hr = ScriptShape(NULL, &psc, TestItem1, cChars,
173 cMaxGlyphs, &pItem[0].a,
174 pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
175 ok (hr == E_PENDING, "If psc is NULL (%08x) the E_PENDING should be returned\n", hr);
176 cMaxGlyphs = 4;
177 hr = ScriptShape(hdc, &psc, TestItem1, cChars,
178 cMaxGlyphs, &pItem[0].a,
179 pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
180 ok (hr == E_OUTOFMEMORY, "If not enough output area cChars (%d) is > than CMaxGlyphs "
181 "(%d) but not E_OUTOFMEMORY\n",
182 cChars, cMaxGlyphs);
183 cMaxGlyphs = 256;
184 hr = ScriptShape(hdc, &psc, TestItem1, cChars,
185 cMaxGlyphs, &pItem[0].a,
186 pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
187 ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
188 ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
189 ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
190 if (hr ==0) {
191 hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
192 pGoffset, pABC);
193 ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
194 hr = ScriptPlace(NULL, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
195 pGoffset, pABC);
196 ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
197 for (cnt=0; cnt < pcGlyphs; cnt++)
198 pwOutGlyphs[cnt] = pwOutGlyphs1[cnt]; /* Send to next function */
201 /* This test will check to make sure that SCRIPT_CACHE is reused and that not translation *
202 * takes place if fNoGlyphIndex is set. */
204 cInChars = 5;
205 cMaxItems = 255;
206 hr = ScriptItemize(TestItem2, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
207 ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
208 /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
209 * returned. */
210 ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
211 "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
212 pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
213 /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue */
214 if (hr == 0) {
215 cChars = cInChars;
216 cMaxGlyphs = 256;
217 pItem[0].a.fNoGlyphIndex = 1; /* say no translate */
218 hr = ScriptShape(NULL, &psc, TestItem2, cChars,
219 cMaxGlyphs, &pItem[0].a,
220 pwOutGlyphs2, pwLogClust, psva, &pcGlyphs);
221 ok (hr != E_PENDING, "If psc should not be NULL (%08x) and the E_PENDING should be returned\n", hr);
222 ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
223 ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
224 ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
225 for (cnt=0; cnt < cChars && TestItem2[cnt] == pwOutGlyphs2[cnt]; cnt++) {}
226 ok (cnt == cChars, "Translation to place when told not to. WCHAR %d - %04x != %04x\n",
227 cnt, TestItem2[cnt], pwOutGlyphs2[cnt]);
228 if (hr ==0) {
229 hr = ScriptPlace(hdc, &psc, pwOutGlyphs2, pcGlyphs, psva, &pItem[0].a, piAdvance,
230 pGoffset, pABC);
231 ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
234 hr = ScriptFreeCache( &psc);
235 ok (!psc, "psc is not null after ScriptFreeCache\n");
239 /* This is a valid test that will cause parsing to take place and create 3 script_items */
240 cInChars = (sizeof(TestItem3)/2)-1;
241 cMaxItems = 255;
242 hr = ScriptItemize(TestItem3, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
243 ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
244 if (hr == 0)
246 ok (pcItems == 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems);
247 if (pcItems > 2)
249 ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
250 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
251 pItem[0].iCharPos, pItem[1].iCharPos);
252 ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
253 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
254 pItem[1].iCharPos, pItem[2].iCharPos);
255 ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == cInChars,
256 "Start pos [2] not = 11 (%d) or end [3] pos not = 14 (%d), cInChars = %d\n",
257 pItem[2].iCharPos, pItem[3].iCharPos, cInChars);
259 hr = ScriptFreeCache( &psc);
260 ok (!psc, "psc is not null after ScriptFreeCache\n");
263 /* This is a valid test that will cause parsing to take place and create 3 script_items */
264 cInChars = (sizeof(TestItem4)/2)-1;
265 cMaxItems = 255;
266 hr = ScriptItemize(TestItem4, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
267 ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
268 if (hr == 0)
270 ok (pcItems == 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems);
271 if (pcItems > 2)
273 ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
274 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
275 pItem[0].iCharPos, pItem[1].iCharPos);
276 ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
277 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
278 pItem[1].iCharPos, pItem[2].iCharPos);
279 ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == cInChars,
280 "Start pos [2] not = 11 (%d) or end [3] pos not = 14 (%d), cInChars = %d\n",
281 pItem[2].iCharPos, pItem[3].iCharPos, cInChars);
283 hr = ScriptFreeCache( &psc);
284 ok (!psc, "psc is not null after ScriptFreeCache\n");
288 * This test is for when the first unicode character requires bidi support
290 cInChars = (sizeof(TestItem5)-1)/sizeof(WCHAR);
291 hr = ScriptItemize(TestItem5, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
292 ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
293 ok (pcItems == 4, "There should have been 4 items, found %d\n", pcItems);
294 ok (pItem[0].a.s.uBidiLevel == 1, "The first character should have been bidi=1 not %d\n",
295 pItem[0].a.s.uBidiLevel);
298 static void test_ScriptGetCMap(HDC hdc, unsigned short pwOutGlyphs[256])
300 HRESULT hr;
301 SCRIPT_CACHE psc = NULL;
302 int cInChars;
303 int cChars;
304 unsigned short pwOutGlyphs3[256];
305 WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
306 DWORD dwFlags;
307 int cnt;
309 /* Check to make sure that SCRIPT_CACHE gets allocated ok */
310 dwFlags = 0;
311 cInChars = cChars = 5;
312 /* Some sanity checks for ScriptGetCMap */
314 hr = ScriptGetCMap(NULL, NULL, NULL, 0, 0, NULL);
315 ok( hr == E_INVALIDARG, "(NULL,NULL,NULL,0,0,NULL), "
316 "expected E_INVALIDARG, got %08x\n", hr);
318 hr = ScriptGetCMap(NULL, NULL, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
319 ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
320 "expected E_INVALIDARG, got %08x\n", hr);
322 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
323 psc = NULL;
324 hr = ScriptGetCMap(NULL, &psc, NULL, 0, 0, NULL);
325 ok( hr == E_PENDING, "(NULL,&psc,NULL,0,0NULL), expected E_PENDING, "
326 "got %08x\n", hr);
327 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
329 /* Set psc to NULL but add hdc, to be able to check if a pointer is returned in psc */
330 psc = NULL;
331 hr = ScriptGetCMap(hdc, &psc, NULL, 0, 0, NULL);
332 ok( hr == S_OK, "ScriptGetCMap(NULL,&psc,NULL,0,0,NULL), expected S_OK, "
333 "got %08x\n", hr);
334 ok( psc != NULL, "ScritpGetCMap expected psc to be not NULL\n");
335 ScriptFreeCache( &psc);
337 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
338 psc = NULL;
339 hr = ScriptGetCMap(NULL, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
340 ok( hr == E_PENDING, "(NULL,&psc,), expected E_PENDING, got %08x\n", hr);
341 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
342 /* Check to see if the results are the same as those returned by ScriptShape */
343 hr = ScriptGetCMap(hdc, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
344 ok (hr == 0, "ScriptGetCMap should return 0 not (%08x)\n", hr);
345 ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
346 for (cnt=0; cnt < cChars && pwOutGlyphs[cnt] == pwOutGlyphs3[cnt]; cnt++) {}
347 ok (cnt == cInChars, "Translation not correct. WCHAR %d - %04x != %04x\n",
348 cnt, pwOutGlyphs[cnt], pwOutGlyphs3[cnt]);
350 hr = ScriptFreeCache( &psc);
351 ok (!psc, "psc is not null after ScriptFreeCache\n");
355 static void test_ScriptGetFontProperties(HDC hdc)
357 HRESULT hr;
358 SCRIPT_CACHE psc,old_psc;
359 SCRIPT_FONTPROPERTIES sfp;
361 /* Some sanity checks for ScriptGetFontProperties */
363 hr = ScriptGetFontProperties(NULL,NULL,NULL);
364 ok( hr == E_INVALIDARG, "(NULL,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
366 hr = ScriptGetFontProperties(NULL,NULL,&sfp);
367 ok( hr == E_INVALIDARG, "(NULL,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
369 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
370 psc = NULL;
371 hr = ScriptGetFontProperties(NULL,&psc,NULL);
372 ok( hr == E_INVALIDARG, "(NULL,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr);
373 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
375 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
376 psc = NULL;
377 hr = ScriptGetFontProperties(NULL,&psc,&sfp);
378 ok( hr == E_PENDING, "(NULL,&psc,&sfp), expected E_PENDING, got %08x\n", hr);
379 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
381 hr = ScriptGetFontProperties(hdc,NULL,NULL);
382 ok( hr == E_INVALIDARG, "(hdc,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
384 hr = ScriptGetFontProperties(hdc,NULL,&sfp);
385 ok( hr == E_INVALIDARG, "(hdc,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
387 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
388 psc = NULL;
389 hr = ScriptGetFontProperties(hdc,&psc,NULL);
390 ok( hr == E_INVALIDARG, "(hdc,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr);
391 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
393 /* Pass an invalid sfp */
394 psc = NULL;
395 sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES) - 1;
396 hr = ScriptGetFontProperties(hdc,&psc,&sfp);
397 ok( hr == E_INVALIDARG, "(hdc,&psc,&sfp) invalid, expected E_INVALIDARG, got %08x\n", hr);
398 ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
399 ScriptFreeCache(&psc);
400 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
402 /* Give it the correct cBytes, we don't care about what's coming back */
403 sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES);
404 psc = NULL;
405 hr = ScriptGetFontProperties(hdc,&psc,&sfp);
406 ok( hr == S_OK, "(hdc,&psc,&sfp) partly initialized, expected S_OK, got %08x\n", hr);
407 ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
409 /* Save the psc pointer */
410 old_psc = psc;
411 /* Now a NULL hdc again */
412 hr = ScriptGetFontProperties(NULL,&psc,&sfp);
413 ok( hr == S_OK, "(NULL,&psc,&sfp), expected S_OK, got %08x\n", hr);
414 ok( psc == old_psc, "Expected psc not to be changed, was %p is now %p\n", old_psc, psc);
415 ScriptFreeCache(&psc);
416 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
419 static void test_ScriptTextOut(HDC hdc)
421 HRESULT hr;
423 int cInChars;
424 int cMaxItems;
425 SCRIPT_ITEM pItem[255];
426 int pcItems;
427 WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
429 SCRIPT_CACHE psc;
430 int cChars;
431 int cMaxGlyphs;
432 unsigned short pwOutGlyphs1[256];
433 WORD pwLogClust[256];
434 SCRIPT_VISATTR psva[256];
435 int pcGlyphs;
436 int piAdvance[256];
437 GOFFSET pGoffset[256];
438 ABC pABC[256];
439 RECT rect;
440 int piX;
441 int iCP = 1;
442 BOOL fTrailing = FALSE;
443 SCRIPT_LOGATTR *psla;
444 SCRIPT_LOGATTR sla[256];
446 /* This is a valid test that will cause parsing to take place */
447 cInChars = 5;
448 cMaxItems = 255;
449 hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
450 ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
451 /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
452 * returned. */
453 ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
454 if (pcItems > 0)
455 ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
456 "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
457 pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
459 /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
460 * ie. ScriptItemize has succeeded and that pItem has been set */
461 cInChars = 5;
462 cMaxItems = 255;
463 if (hr == 0) {
464 psc = NULL; /* must be null on first call */
465 cChars = cInChars;
466 cMaxGlyphs = cInChars;
467 cMaxGlyphs = 256;
468 hr = ScriptShape(hdc, &psc, TestItem1, cChars,
469 cMaxGlyphs, &pItem[0].a,
470 pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
471 ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
472 ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
473 ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
474 if (hr ==0) {
475 /* Note hdc is needed as glyph info is not yet in psc */
476 hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
477 pGoffset, pABC);
478 ok (hr == 0, "Should return 0 not (%08x)\n", hr);
479 ScriptFreeCache(&psc); /* Get rid of psc for next test set */
480 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
482 hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL);
483 ok (hr == E_INVALIDARG, "Should return 0 not (%08x)\n", hr);
485 hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
486 piAdvance, NULL, pGoffset);
487 ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
488 "expected E_INVALIDARG, got %08x\n", hr);
490 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
491 psc = NULL;
492 hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0,
493 NULL, NULL, NULL);
494 ok( hr == E_INVALIDARG, "(NULL,&psc,NULL,0,0,0,NULL,), expected E_INVALIDARG, "
495 "got %08x\n", hr);
496 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
498 /* hdc is required for this one rather than the usual optional */
499 psc = NULL;
500 hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
501 piAdvance, NULL, pGoffset);
502 ok( hr == E_INVALIDARG, "(NULL,&psc,), expected E_INVALIDARG, got %08x\n", hr);
503 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
505 /* Set that it returns 0 status */
506 hr = ScriptTextOut(hdc, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
507 piAdvance, NULL, pGoffset);
508 ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
510 /* Test Rect Rgn is acceptable */
511 rect.top = 10;
512 rect.bottom = 20;
513 rect.left = 10;
514 rect.right = 40;
515 hr = ScriptTextOut(hdc, &psc, 0, 0, 0, &rect, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
516 piAdvance, NULL, pGoffset);
517 ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
519 iCP = 1;
520 hr = ScriptCPtoX(iCP, fTrailing, cChars, pcGlyphs, (const WORD *) &pwLogClust,
521 (const SCRIPT_VISATTR *) &psva, (const int *)&piAdvance, &pItem[0].a, &piX);
522 ok(hr == S_OK, "ScriptCPtoX Stub should return S_OK not %08x\n", hr);
524 psla = (SCRIPT_LOGATTR *)&sla;
525 hr = ScriptBreak(TestItem1, cChars, &pItem[0].a, psla);
526 ok(hr == S_OK, "ScriptBreak Stub should return S_OK not %08x\n", hr);
528 /* Clean up and go */
529 ScriptFreeCache(&psc);
530 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
535 static void test_ScriptTextOut2(HDC hdc)
537 /* Intent is to validate that the HDC passed into ScriptTextOut is
538 * used instead of the (possibly) invalid cached one
540 HRESULT hr;
542 HDC hdc1, hdc2;
543 int cInChars;
544 int cMaxItems;
545 SCRIPT_ITEM pItem[255];
546 int pcItems;
547 WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
549 SCRIPT_CACHE psc;
550 int cChars;
551 int cMaxGlyphs;
552 unsigned short pwOutGlyphs1[256];
553 WORD pwLogClust[256];
554 SCRIPT_VISATTR psva[256];
555 int pcGlyphs;
556 int piAdvance[256];
557 GOFFSET pGoffset[256];
558 ABC pABC[256];
560 /* Create an extra DC that will be used until the ScriptTextOut */
561 hdc1 = CreateCompatibleDC(hdc);
562 ok (hdc1 != 0, "CreateCompatibleDC failed to create a DC\n");
563 hdc2 = CreateCompatibleDC(hdc);
564 ok (hdc2 != 0, "CreateCompatibleDC failed to create a DC\n");
566 /* This is a valid test that will cause parsing to take place */
567 cInChars = 5;
568 cMaxItems = 255;
569 hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
570 ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
571 /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
572 * returned. */
573 ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
574 if (pcItems > 0)
575 ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
576 "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
577 pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
579 /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
580 * ie. ScriptItemize has succeeded and that pItem has been set */
581 cInChars = 5;
582 cMaxItems = 255;
583 if (hr == 0) {
584 psc = NULL; /* must be null on first call */
585 cChars = cInChars;
586 cMaxGlyphs = cInChars;
587 cMaxGlyphs = 256;
588 hr = ScriptShape(hdc2, &psc, TestItem1, cChars,
589 cMaxGlyphs, &pItem[0].a,
590 pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
591 ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
592 ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
593 ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
594 if (hr ==0) {
595 /* Note hdc is needed as glyph info is not yet in psc */
596 hr = ScriptPlace(hdc2, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
597 pGoffset, pABC);
598 ok (hr == 0, "Should return 0 not (%08x)\n", hr);
600 /* key part!!! cached dc is being deleted */
601 hr = DeleteDC(hdc2);
602 ok(hr == 1, "DeleteDC should return 1 not %08x\n", hr);
604 /* At this point the cached hdc (hdc2) has been destroyed,
605 * however, we are passing in a *real* hdc (the original hdc).
606 * The text should be written to that DC
608 hr = ScriptTextOut(hdc1, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
609 piAdvance, NULL, pGoffset);
610 ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
611 ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
613 DeleteDC(hdc1);
615 /* Clean up and go */
616 ScriptFreeCache(&psc);
617 ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
622 static void test_ScriptXtoX(void)
623 /****************************************************************************************
624 * This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables *
625 ****************************************************************************************/
627 static const WCHAR test[] = {'t', 'e', 's', 't',0};
628 SCRIPT_ITEM items[2];
629 int iX, iCP;
630 int cChars;
631 int cGlyphs;
632 WORD pwLogClust[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
633 SCRIPT_VISATTR psva[10];
634 int piAdvance[10] = {200, 190, 210, 180, 170, 204, 189, 195, 212, 203};
635 int piCP, piX;
636 int piTrailing;
637 BOOL fTrailing;
638 HRESULT hr;
640 hr = ScriptItemize(test, lstrlenW(test), sizeof(items)/sizeof(items[0]), NULL, NULL, items, NULL);
641 ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
643 iX = -1;
644 cChars = 10;
645 cGlyphs = 10;
646 hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
647 ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
648 if (piTrailing)
649 ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
650 else /* win2k3 */
651 ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
653 iX = 1954;
654 cChars = 10;
655 cGlyphs = 10;
656 hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
657 ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
658 if (piTrailing) /* win2k3 */
659 ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
660 else
661 ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
663 iX = 779;
664 cChars = 10;
665 cGlyphs = 10;
666 hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
667 ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
668 ok(piCP == 3 ||
669 piCP == -1, /* win2k3 */
670 "iX=%d should return piCP=3 or piCP=-1 not %d\n", iX, piCP);
671 ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
673 iX = 780;
674 cChars = 10;
675 cGlyphs = 10;
676 hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
677 ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
678 ok(piCP == 3 ||
679 piCP == -1, /* win2k3 */
680 "iX=%d should return piCP=3 or piCP=-1 not %d\n", iX, piCP);
681 ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
683 iX = 868;
684 cChars = 10;
685 cGlyphs = 10;
686 hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
687 ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
688 ok(piCP == 4 ||
689 piCP == -1, /* win2k3 */
690 "iX=%d should return piCP=4 or piCP=-1 not %d\n", iX, piCP);
692 iX = 0;
693 cChars = 10;
694 cGlyphs = 10;
695 hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
696 ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
697 ok(piCP == 0 ||
698 piCP == 10, /* win2k3 */
699 "iX=%d should return piCP=0 piCP=10 not %d\n", iX, piCP);
701 iX = 195;
702 cChars = 10;
703 cGlyphs = 10;
704 hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
705 ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
706 ok(piCP == 0, "iX=%d should return piCP=0 not %d\n", iX, piCP);
708 iX = 196;
709 cChars = 10;
710 cGlyphs = 10;
711 hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
712 ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
713 ok(piCP == 1 ||
714 piCP == 0, /* win2k3 */
715 "iX=%d should return piCP=1 or piCP=0 not %d\n", iX, piCP);
717 iCP=5;
718 fTrailing = FALSE;
719 cChars = 10;
720 cGlyphs = 10;
721 hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
722 ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
723 ok(piX == 976 ||
724 piX == 100, /* win2k3 */
725 "iCP=%d should return piX=976 or piX=100 not %d\n", iCP, piX);
727 iCP=5;
728 fTrailing = TRUE;
729 cChars = 10;
730 cGlyphs = 10;
731 hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
732 ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
733 ok(piX == 1171 ||
734 piX == 80, /* win2k3 */
735 "iCP=%d should return piX=1171 or piX=80 not %d\n", iCP, piX);
737 iCP=6;
738 fTrailing = FALSE;
739 cChars = 10;
740 cGlyphs = 10;
741 hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
742 ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
743 ok(piX == 1171 ||
744 piX == 80, /* win2k3 */
745 "iCP=%d should return piX=1171 or piX=80 not %d\n", iCP, piX);
747 iCP=11;
748 fTrailing = FALSE;
749 cChars = 10;
750 cGlyphs = 10;
751 hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
752 ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
753 ok(piX == 1953 ||
754 piX == 0, /* win2k3 */
755 "iCP=%d should return piX=1953 or piX=0 not %d\n", iCP, piX);
757 iCP=11;
758 fTrailing = TRUE;
759 cChars = 10;
760 cGlyphs = 10;
761 hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
762 ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
763 ok(piX == 1953 ||
764 piX == 0, /* win2k3 */
765 "iCP=%d should return piX=1953 or piX=0 not %d\n", iCP, piX);
768 static void test_ScriptString(HDC hdc)
770 /*******************************************************************************************
772 * This set of tests are for the string functions of uniscribe. The ScriptStringAnalyse
773 * function allocates memory pointed to by the SCRIPT_STRING_ANALYSIS ssa pointer. This
774 * memory if freed by ScriptStringFree. There needs to be a valid hdc for this as
775 * ScriptStringAnalyse calls ScriptSItemize, ScriptShape and ScriptPlace which require it.
779 HRESULT hr;
780 WCHAR teststr[] = {'T','e','s','t','1',' ','a','2','b','3', '\0'};
781 int len = (sizeof(teststr) / sizeof(WCHAR)) - 1;
782 int Glyphs = len * 2 + 16;
783 int Charset;
784 DWORD Flags = SSA_GLYPHS;
785 int ReqWidth = 100;
786 SCRIPT_CONTROL Control;
787 SCRIPT_STATE State;
788 const int Dx[5] = {10, 10, 10, 10, 10};
789 SCRIPT_TABDEF Tabdef;
790 const BYTE InClass = 0;
791 SCRIPT_STRING_ANALYSIS ssa = NULL;
793 int X = 10;
794 int Y = 100;
795 UINT Options = 0;
796 const RECT rc = {0, 50, 100, 100};
797 int MinSel = 0;
798 int MaxSel = 0;
799 BOOL Disabled = FALSE;
800 const int *clip_len;
801 int i;
802 UINT *order;
805 Charset = -1; /* this flag indicates unicode input */
806 /* Test without hdc to get E_PENDING */
807 hr = ScriptStringAnalyse( NULL, teststr, len, Glyphs, Charset, Flags,
808 ReqWidth, &Control, &State, Dx, &Tabdef,
809 &InClass, &ssa);
810 ok(hr == E_PENDING, "ScriptStringAnalyse Stub should return E_PENDING not %08x\n", hr);
812 /* test with hdc, this should be a valid test */
813 hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
814 ReqWidth, &Control, &State, Dx, &Tabdef,
815 &InClass, &ssa);
816 ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
817 ScriptStringFree(&ssa);
819 /* test makes sure that a call with a valid pssa still works */
820 hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
821 ReqWidth, &Control, &State, Dx, &Tabdef,
822 &InClass, &ssa);
823 ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
824 ok(ssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
826 if (hr == S_OK)
828 hr = ScriptStringOut(ssa, X, Y, Options, &rc, MinSel, MaxSel, Disabled);
829 ok(hr == S_OK, "ScriptStringOut should return S_OK not %08x\n", hr);
832 clip_len = ScriptString_pcOutChars(ssa);
833 ok(*clip_len == len, "ScriptString_pcOutChars failed, got %d, expected %d\n", *clip_len, len);
835 order = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *clip_len * sizeof(UINT));
836 hr = ScriptStringGetOrder(ssa, order);
837 ok(hr == S_OK, "ScriptStringGetOrder failed, got %08x, expected S_OK\n", hr);
839 for (i = 0; i < *clip_len; i++) ok(order[i] == i, "%d: got %d expected %d\n", i, order[i], i);
840 HeapFree(GetProcessHeap(), 0, order);
842 hr = ScriptStringFree(&ssa);
843 ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
846 static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
848 /*****************************************************************************************
850 * This test is for the ScriptStringXtoCP and ScriptStringXtoCP functions. Due to the
851 * nature of the fonts between Windows and Wine, the test is implemented by generating
852 * values using one one function then checking the output of the second. In this way
853 * the validity of the functions is established using Windows as a base and confirming
854 * similar behaviour in wine.
857 HRESULT hr;
858 WCHAR teststr1[] = {'T', 'e', 's', 't', 'e', '1', '2', ' ', 'a', '\0'};
859 void *String = (WCHAR *) &teststr1; /* ScriptStringAnalysis needs void */
860 int String_len = (sizeof(teststr1)/sizeof(WCHAR))-1;
861 int Glyphs = String_len * 2 + 16; /* size of buffer as recommended */
862 int Charset = -1; /* unicode */
863 DWORD Flags = SSA_GLYPHS;
864 int ReqWidth = 100;
865 SCRIPT_CONTROL Control;
866 SCRIPT_STATE State;
867 SCRIPT_TABDEF Tabdef;
868 const BYTE InClass = 0;
869 SCRIPT_STRING_ANALYSIS ssa = NULL;
871 int Ch; /* Character position in string */
872 int iTrailing;
873 int Cp; /* Character position in string */
874 int X;
875 BOOL fTrailing;
877 /* Test with hdc, this should be a valid test
878 * Here we generate an SCRIPT_STRING_ANALYSIS that will be used as input to the
879 * following character positions to X and X to character position functions.
881 hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
882 ReqWidth, &Control, &State, NULL, &Tabdef,
883 &InClass, &ssa);
884 ok(hr == S_OK ||
885 hr == E_INVALIDARG, /* NT */
886 "ScriptStringAnalyse should return S_OK or E_INVALIDARG not %08x\n", hr);
888 if (hr == S_OK)
890 ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
893 * Loop to generate character positions to provide starting positions for the
894 * ScriptStringCPtoX and ScriptStringXtoCP functions
896 for (Cp = 0; Cp < String_len; Cp++)
898 /* The fTrailing flag is used to indicate whether the X being returned is at
899 * the beginning or the end of the character. What happens here is that if
900 * fTrailing indicates the end of the character, ie. FALSE, then ScriptStringXtoCP
901 * returns the beginning of the next character and iTrailing is FALSE. So for this
902 * loop iTrailing will be FALSE in both cases.
904 fTrailing = FALSE;
905 hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
906 ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
907 hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
908 ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
909 ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
910 ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
911 iTrailing, X);
912 fTrailing = TRUE;
913 hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
914 ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
915 hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
916 ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
919 * Check that character position returned by ScriptStringXtoCP in Ch matches the
920 * one input to ScriptStringCPtoX. This means that the Cp to X position and back
921 * again works
923 ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
924 ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
925 iTrailing, X);
928 * This test is to check that if the X position is just inside the trailing edge of the
929 * character then iTrailing will indicate the trailing edge, ie. TRUE
931 fTrailing = TRUE;
932 Cp = 3;
933 hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
934 ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
935 X--; /* put X just inside the trailing edge */
936 hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
937 ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
938 ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, X);
939 ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
940 iTrailing, X);
943 * This test is to check that if the X position is just outside the trailing edge of the
944 * character then iTrailing will indicate the leading edge, ie. FALSE, and Ch will indicate
945 * the next character, ie. Cp + 1
947 fTrailing = TRUE;
948 Cp = 3;
949 hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
950 ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
951 X++; /* put X just outside the trailing edge */
952 hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
953 ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
954 ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, X);
955 ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
956 iTrailing, X);
959 * This test is to check that if the X position is just outside the leading edge of the
960 * character then iTrailing will indicate the trailing edge, ie. TRUE, and Ch will indicate
961 * the next character down , ie. Cp - 1
963 fTrailing = FALSE;
964 Cp = 3;
965 hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
966 ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
967 X--; /* put X just outside the leading edge */
968 hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
969 ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
970 ok(Cp - 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp - 1, Ch, X);
971 ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
972 iTrailing, X);
975 * Cleanup the SSA for the next round of tests
977 hr = ScriptStringFree(&ssa);
978 ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
981 * Test to see that exceeding the number of chars returns E_INVALIDARG. First
982 * generate an SSA for the subsequent tests.
984 hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
985 ReqWidth, &Control, &State, NULL, &Tabdef,
986 &InClass, &ssa);
987 ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
990 * When ScriptStringCPtoX is called with a character position Cp that exceeds the
991 * string length, return E_INVALIDARG. This also invalidates the ssa so a
992 * ScriptStringFree should also fail.
994 fTrailing = FALSE;
995 Cp = String_len + 1;
996 hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
997 ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr);
999 hr = ScriptStringFree(&ssa);
1001 * ScriptStringCPtoX should free ssa, hence ScriptStringFree should fail
1003 ok(hr == E_INVALIDARG ||
1004 hr == E_FAIL, /* win2k3 */
1005 "ScriptStringFree should return E_INVALIDARG or E_FAIL not %08x\n", hr);
1009 static void test_ScriptCacheGetHeight(HDC hdc)
1011 HRESULT hr;
1012 SCRIPT_CACHE sc = NULL;
1013 LONG height;
1015 hr = ScriptCacheGetHeight(NULL, NULL, NULL);
1016 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1018 hr = ScriptCacheGetHeight(NULL, &sc, NULL);
1019 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1021 hr = ScriptCacheGetHeight(NULL, &sc, &height);
1022 ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1024 height = 0;
1026 hr = ScriptCacheGetHeight(hdc, &sc, &height);
1027 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1028 ok(height > 0, "expected height > 0\n");
1030 ScriptFreeCache(&sc);
1033 static void test_ScriptGetGlyphABCWidth(HDC hdc)
1035 HRESULT hr;
1036 SCRIPT_CACHE sc = NULL;
1037 ABC abc;
1039 hr = ScriptGetGlyphABCWidth(NULL, NULL, 'a', NULL);
1040 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1042 hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', NULL);
1043 ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1045 if (0) { /* crashes on WinXP */
1046 hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', NULL);
1047 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1050 hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', &abc);
1051 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1053 ScriptFreeCache(&sc);
1056 static void test_ScriptLayout(void)
1058 HRESULT hr;
1059 static const BYTE levels[][5] =
1061 { 0, 0, 0, 0, 0 },
1062 { 1, 1, 1, 1, 1 },
1063 { 2, 2, 2, 2, 2 },
1064 { 3, 3, 3, 3, 3 },
1066 static const int expect[][5] =
1068 { 0, 1, 2, 3, 4 },
1069 { 4, 3, 2, 1, 0 },
1070 { 0, 1, 2, 3, 4 },
1071 { 4, 3, 2, 1, 0 }
1073 int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])];
1075 hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis);
1076 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1078 hr = ScriptLayout(sizeof(levels[0]), levels[0], NULL, NULL);
1079 ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1081 for (i = 0; i < sizeof(levels)/sizeof(levels[0]); i++)
1083 hr = ScriptLayout(sizeof(levels[0]), levels[i], vistolog, logtovis);
1084 ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1086 for (j = 0; j < sizeof(levels[i]); j++)
1088 ok(expect[i][j] == vistolog[j],
1089 "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n",
1090 i, j, levels[i][j], j, vistolog[j] );
1093 for (j = 0; j < sizeof(levels[i]); j++)
1095 ok(expect[i][j] == logtovis[j],
1096 "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n",
1097 i, j, levels[i][j], j, logtovis[j] );
1102 static const struct
1104 LGRPID group;
1105 LCID lcid;
1106 SCRIPT_DIGITSUBSTITUTE sds;
1107 DWORD uDefaultLanguage;
1108 DWORD fContextDigits;
1109 WORD fDigitSubstitute;
1111 subst_data[] =
1113 { 0x01, 0x00403, { 9, 3, 1, 0 }, 9, 0, 0 },
1114 { 0x01, 0x00406, { 9, 6, 1, 0 }, 9, 0, 0 },
1115 { 0x01, 0x00407, { 9, 7, 1, 0 }, 9, 0, 0 },
1116 { 0x01, 0x00409, { 9, 9, 1, 0 }, 9, 0, 0 },
1117 { 0x01, 0x0040a, { 9, 10, 1, 0 }, 9, 0, 0 },
1118 { 0x01, 0x0040b, { 9, 11, 1, 0 }, 9, 0, 0 },
1119 { 0x01, 0x0040c, { 9, 12, 1, 0 }, 9, 0, 0 },
1120 { 0x01, 0x0040f, { 9, 15, 1, 0 }, 9, 0, 0 },
1121 { 0x01, 0x00410, { 9, 16, 1, 0 }, 9, 0, 0 },
1122 { 0x01, 0x00413, { 9, 19, 1, 0 }, 9, 0, 0 },
1123 { 0x01, 0x00414, { 9, 20, 1, 0 }, 9, 0, 0 },
1124 { 0x01, 0x00416, { 9, 22, 1, 0 }, 9, 0, 0 },
1125 { 0x01, 0x0041d, { 9, 29, 1, 0 }, 9, 0, 0 },
1126 { 0x01, 0x00421, { 9, 33, 1, 0 }, 9, 0, 0 },
1127 { 0x01, 0x0042d, { 9, 45, 1, 0 }, 9, 0, 0 },
1128 { 0x01, 0x00432, { 9, 50, 1, 0 }, 9, 0, 0 },
1129 { 0x01, 0x00434, { 9, 52, 1, 0 }, 9, 0, 0 },
1130 { 0x01, 0x00435, { 9, 53, 1, 0 }, 9, 0, 0 },
1131 { 0x01, 0x00436, { 9, 54, 1, 0 }, 9, 0, 0 },
1132 { 0x01, 0x00438, { 9, 56, 1, 0 }, 9, 0, 0 },
1133 { 0x01, 0x0043a, { 9, 58, 1, 0 }, 9, 0, 0 },
1134 { 0x01, 0x0043b, { 9, 59, 1, 0 }, 9, 0, 0 },
1135 { 0x01, 0x0043e, { 9, 62, 1, 0 }, 9, 0, 0 },
1136 { 0x01, 0x00441, { 9, 65, 1, 0 }, 9, 0, 0 },
1137 { 0x01, 0x00452, { 9, 82, 1, 0 }, 9, 0, 0 },
1138 { 0x01, 0x00456, { 9, 86, 1, 0 }, 9, 0, 0 },
1139 { 0x01, 0x0046b, { 9, 107, 1, 0 }, 9, 0, 0 },
1140 { 0x01, 0x0046c, { 9, 108, 1, 0 }, 9, 0, 0 },
1141 { 0x01, 0x00481, { 9, 129, 1, 0 }, 9, 0, 0 },
1142 { 0x01, 0x00807, { 9, 7, 1, 0 }, 9, 0, 0 },
1143 { 0x01, 0x00809, { 9, 9, 1, 0 }, 9, 0, 0 },
1144 { 0x01, 0x0080a, { 9, 10, 1, 0 }, 9, 0, 0 },
1145 { 0x01, 0x0080c, { 9, 12, 1, 0 }, 9, 0, 0 },
1146 { 0x01, 0x00810, { 9, 16, 1, 0 }, 9, 0, 0 },
1147 { 0x01, 0x00813, { 9, 19, 1, 0 }, 9, 0, 0 },
1148 { 0x01, 0x00814, { 9, 20, 1, 0 }, 9, 0, 0 },
1149 { 0x01, 0x00816, { 9, 22, 1, 0 }, 9, 0, 0 },
1150 { 0x01, 0x0081d, { 9, 29, 1, 0 }, 9, 0, 0 },
1151 { 0x01, 0x0083b, { 9, 59, 1, 0 }, 9, 0, 0 },
1152 { 0x01, 0x0083e, { 9, 62, 1, 0 }, 9, 0, 0 },
1153 { 0x01, 0x0086b, { 9, 107, 1, 0 }, 9, 0, 0 },
1154 { 0x01, 0x00c07, { 9, 7, 1, 0 }, 9, 0, 0 },
1155 { 0x01, 0x00c09, { 9, 9, 1, 0 }, 9, 0, 0 },
1156 { 0x01, 0x00c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1157 { 0x01, 0x00c0c, { 9, 12, 1, 0 }, 9, 0, 0 },
1158 { 0x01, 0x00c3b, { 9, 59, 1, 0 }, 9, 0, 0 },
1159 { 0x01, 0x00c6b, { 9, 107, 1, 0 }, 9, 0, 0 },
1160 { 0x01, 0x01007, { 9, 7, 1, 0 }, 9, 0, 0 },
1161 { 0x01, 0x01009, { 9, 9, 1, 0 }, 9, 0, 0 },
1162 { 0x01, 0x0100a, { 9, 10, 1, 0 }, 9, 0, 0 },
1163 { 0x01, 0x0100c, { 9, 12, 1, 0 }, 9, 0, 0 },
1164 { 0x01, 0x0103b, { 9, 59, 1, 0 }, 9, 0, 0 },
1165 { 0x01, 0x01407, { 9, 7, 1, 0 }, 9, 0, 0 },
1166 { 0x01, 0x01409, { 9, 9, 1, 0 }, 9, 0, 0 },
1167 { 0x01, 0x0140a, { 9, 10, 1, 0 }, 9, 0, 0 },
1168 { 0x01, 0x0140c, { 9, 12, 1, 0 }, 9, 0, 0 },
1169 { 0x01, 0x0143b, { 9, 59, 1, 0 }, 9, 0, 0 },
1170 { 0x01, 0x01809, { 9, 9, 1, 0 }, 9, 0, 0 },
1171 { 0x01, 0x0180a, { 9, 10, 1, 0 }, 9, 0, 0 },
1172 { 0x01, 0x0180c, { 9, 12, 1, 0 }, 9, 0, 0 },
1173 { 0x01, 0x0183b, { 9, 59, 1, 0 }, 9, 0, 0 },
1174 { 0x01, 0x01c09, { 9, 9, 1, 0 }, 9, 0, 0 },
1175 { 0x01, 0x01c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1176 { 0x01, 0x01c3b, { 9, 59, 1, 0 }, 9, 0, 0 },
1177 { 0x01, 0x02009, { 9, 9, 1, 0 }, 9, 0, 0 },
1178 { 0x01, 0x0200a, { 9, 10, 1, 0 }, 9, 0, 0 },
1179 { 0x01, 0x0203b, { 9, 59, 1, 0 }, 9, 0, 0 },
1180 { 0x01, 0x02409, { 9, 9, 1, 0 }, 9, 0, 0 },
1181 { 0x01, 0x0240a, { 9, 10, 1, 0 }, 9, 0, 0 },
1182 { 0x01, 0x0243b, { 9, 59, 1, 0 }, 9, 0, 0 },
1183 { 0x01, 0x02809, { 9, 9, 1, 0 }, 9, 0, 0 },
1184 { 0x01, 0x0280a, { 9, 10, 1, 0 }, 9, 0, 0 },
1185 { 0x01, 0x02c09, { 9, 9, 1, 0 }, 9, 0, 0 },
1186 { 0x01, 0x02c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1187 { 0x01, 0x03009, { 9, 9, 1, 0 }, 9, 0, 0 },
1188 { 0x01, 0x0300a, { 9, 10, 1, 0 }, 9, 0, 0 },
1189 { 0x01, 0x03409, { 9, 9, 1, 0 }, 9, 0, 0 },
1190 { 0x01, 0x0340a, { 9, 10, 1, 0 }, 9, 0, 0 },
1191 { 0x01, 0x0380a, { 9, 10, 1, 0 }, 9, 0, 0 },
1192 { 0x01, 0x03c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1193 { 0x01, 0x0400a, { 9, 10, 1, 0 }, 9, 0, 0 },
1194 { 0x01, 0x0440a, { 9, 10, 1, 0 }, 9, 0, 0 },
1195 { 0x01, 0x0480a, { 9, 10, 1, 0 }, 9, 0, 0 },
1196 { 0x01, 0x04c0a, { 9, 10, 1, 0 }, 9, 0, 0 },
1197 { 0x01, 0x0500a, { 9, 10, 1, 0 }, 9, 0, 0 },
1198 { 0x01, 0x10407, { 9, 7, 1, 0 }, 9, 0, 0 },
1199 { 0x02, 0x00405, { 9, 5, 1, 0 }, 9, 0, 0 },
1200 { 0x02, 0x0040e, { 9, 14, 1, 0 }, 9, 0, 0 },
1201 { 0x02, 0x00415, { 9, 21, 1, 0 }, 9, 0, 0 },
1202 { 0x02, 0x00418, { 9, 24, 1, 0 }, 9, 0, 0 },
1203 { 0x02, 0x0041a, { 9, 26, 1, 0 }, 9, 0, 0 },
1204 { 0x02, 0x0041b, { 9, 27, 1, 0 }, 9, 0, 0 },
1205 { 0x02, 0x0041c, { 9, 28, 1, 0 }, 9, 0, 0 },
1206 { 0x02, 0x00424, { 9, 36, 1, 0 }, 9, 0, 0 },
1207 { 0x02, 0x0081a, { 9, 26, 1, 0 }, 9, 0, 0 },
1208 { 0x02, 0x0101a, { 9, 26, 1, 0 }, 9, 0, 0 },
1209 { 0x02, 0x0141a, { 9, 26, 1, 0 }, 9, 0, 0 },
1210 { 0x02, 0x0181a, { 9, 26, 1, 0 }, 9, 0, 0 },
1211 { 0x02, 0x1040e, { 9, 14, 1, 0 }, 9, 0, 0 },
1212 { 0x03, 0x00425, { 9, 37, 1, 0 }, 9, 0, 0 },
1213 { 0x03, 0x00426, { 9, 38, 1, 0 }, 9, 0, 0 },
1214 { 0x03, 0x00427, { 9, 39, 1, 0 }, 9, 0, 0 },
1215 { 0x04, 0x00408, { 9, 8, 1, 0 }, 9, 0, 0 },
1216 { 0x05, 0x00402, { 9, 2, 1, 0 }, 9, 0, 0 },
1217 { 0x05, 0x00419, { 9, 25, 1, 0 }, 9, 0, 0 },
1218 { 0x05, 0x00422, { 9, 34, 1, 0 }, 9, 0, 0 },
1219 { 0x05, 0x00423, { 9, 35, 1, 0 }, 9, 0, 0 },
1220 { 0x05, 0x0042f, { 9, 47, 1, 0 }, 9, 0, 0 },
1221 { 0x05, 0x0043f, { 9, 63, 1, 0 }, 9, 0, 0 },
1222 { 0x05, 0x00440, { 9, 64, 1, 0 }, 9, 0, 0 },
1223 { 0x05, 0x00444, { 9, 68, 1, 0 }, 9, 0, 0 },
1224 { 0x05, 0x00450, { 9, 80, 1, 0 }, 9, 0, 0 },
1225 { 0x05, 0x0082c, { 9, 44, 1, 0 }, 9, 0, 0 },
1226 { 0x05, 0x00843, { 9, 67, 1, 0 }, 9, 0, 0 },
1227 { 0x05, 0x00c1a, { 9, 26, 1, 0 }, 9, 0, 0 },
1228 { 0x05, 0x01c1a, { 9, 26, 1, 0 }, 9, 0, 0 },
1229 { 0x06, 0x0041f, { 9, 31, 1, 0 }, 9, 0, 0 },
1230 { 0x06, 0x0042c, { 9, 44, 1, 0 }, 9, 0, 0 },
1231 { 0x06, 0x00443, { 9, 67, 1, 0 }, 9, 0, 0 },
1232 { 0x07, 0x00411, { 9, 17, 1, 0 }, 9, 0, 0 },
1233 { 0x08, 0x00412, { 9, 18, 1, 0 }, 9, 0, 0 },
1234 { 0x09, 0x00404, { 9, 4, 1, 0 }, 9, 0, 0 },
1235 { 0x09, 0x00c04, { 9, 4, 1, 0 }, 9, 0, 0 },
1236 { 0x09, 0x01404, { 9, 4, 1, 0 }, 9, 0, 0 },
1237 { 0x09, 0x21404, { 9, 4, 1, 0 }, 9, 0, 0 },
1238 { 0x09, 0x30404, { 9, 4, 1, 0 }, 9, 0, 0 },
1239 { 0x0a, 0x00804, { 9, 4, 1, 0 }, 9, 0, 0 },
1240 { 0x0a, 0x01004, { 9, 4, 1, 0 }, 9, 0, 0 },
1241 { 0x0a, 0x20804, { 9, 4, 1, 0 }, 9, 0, 0 },
1242 { 0x0a, 0x21004, { 9, 4, 1, 0 }, 9, 0, 0 },
1243 { 0x0b, 0x0041e, { 9, 30, 1, 0 }, 9, 0, 0 },
1244 { 0x0c, 0x0040d, { 9, 13, 1, 0 }, 9, 0, 0 },
1245 { 0x0d, 0x00401, { 1, 1, 0, 0 }, 9, 0, 0 },
1246 { 0x0d, 0x00420, { 9, 32, 1, 0 }, 9, 0, 0 },
1247 { 0x0d, 0x00429, { 41, 41, 0, 0 }, 9, 0, 0 },
1248 { 0x0d, 0x0045a, { 9, 90, 1, 0 }, 9, 0, 0 },
1249 { 0x0d, 0x00465, { 9, 101, 1, 0 }, 9, 0, 0 },
1250 { 0x0d, 0x00801, { 1, 1, 0, 0 }, 9, 0, 0 },
1251 { 0x0d, 0x00c01, { 1, 1, 0, 0 }, 9, 0, 0 },
1252 { 0x0d, 0x01001, { 1, 1, 0, 0 }, 9, 0, 0 },
1253 { 0x0d, 0x01401, { 1, 1, 0, 0 }, 9, 0, 0 },
1254 { 0x0d, 0x01801, { 1, 1, 0, 0 }, 9, 0, 0 },
1255 { 0x0d, 0x01c01, { 1, 1, 0, 0 }, 9, 0, 0 },
1256 { 0x0d, 0x02001, { 1, 1, 0, 0 }, 9, 0, 0 },
1257 { 0x0d, 0x02401, { 1, 1, 0, 0 }, 9, 0, 0 },
1258 { 0x0d, 0x02801, { 1, 1, 0, 0 }, 9, 0, 0 },
1259 { 0x0d, 0x02c01, { 1, 1, 0, 0 }, 9, 0, 0 },
1260 { 0x0d, 0x03001, { 1, 1, 0, 0 }, 9, 0, 0 },
1261 { 0x0d, 0x03401, { 1, 1, 0, 0 }, 9, 0, 0 },
1262 { 0x0d, 0x03801, { 1, 1, 0, 0 }, 9, 0, 0 },
1263 { 0x0d, 0x03c01, { 1, 1, 0, 0 }, 9, 0, 0 },
1264 { 0x0d, 0x04001, { 1, 1, 0, 0 }, 9, 0, 0 },
1265 { 0x0e, 0x0042a, { 9, 42, 1, 0 }, 9, 0, 0 },
1266 { 0x0f, 0x00439, { 9, 57, 1, 0 }, 9, 0, 0 },
1267 { 0x0f, 0x00446, { 9, 70, 1, 0 }, 9, 0, 0 },
1268 { 0x0f, 0x00447, { 9, 71, 1, 0 }, 9, 0, 0 },
1269 { 0x0f, 0x00449, { 9, 73, 1, 0 }, 9, 0, 0 },
1270 { 0x0f, 0x0044a, { 9, 74, 1, 0 }, 9, 0, 0 },
1271 { 0x0f, 0x0044b, { 9, 75, 1, 0 }, 9, 0, 0 },
1272 { 0x0f, 0x0044e, { 9, 78, 1, 0 }, 9, 0, 0 },
1273 { 0x0f, 0x0044f, { 9, 79, 1, 0 }, 9, 0, 0 },
1274 { 0x0f, 0x00457, { 9, 87, 1, 0 }, 9, 0, 0 },
1275 { 0x10, 0x00437, { 9, 55, 1, 0 }, 9, 0, 0 },
1276 { 0x10, 0x10437, { 9, 55, 1, 0 }, 9, 0, 0 },
1277 { 0x11, 0x0042b, { 9, 43, 1, 0 }, 9, 0, 0 }
1280 static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR lparam)
1282 HRESULT hr;
1283 SCRIPT_DIGITSUBSTITUTE sds;
1284 SCRIPT_CONTROL sc;
1285 SCRIPT_STATE ss;
1286 LCID lcid_old;
1287 unsigned int i;
1289 if (!IsValidLocale(lcid, LCID_INSTALLED)) return TRUE;
1291 memset(&sds, 0, sizeof(sds));
1292 memset(&sc, 0, sizeof(sc));
1293 memset(&ss, 0, sizeof(ss));
1295 lcid_old = GetThreadLocale();
1296 if (!SetThreadLocale(lcid)) return TRUE;
1298 hr = ScriptRecordDigitSubstitution(lcid, &sds);
1299 ok(hr == S_OK, "ScriptRecordDigitSubstitution failed: 0x%08x\n", hr);
1301 hr = ScriptApplyDigitSubstitution(&sds, &sc, &ss);
1302 ok(hr == S_OK, "ScriptApplyDigitSubstitution failed: 0x%08x\n", hr);
1304 for (i = 0; i < sizeof(subst_data)/sizeof(subst_data[0]); i++)
1306 if (group == subst_data[i].group && lcid == subst_data[i].lcid)
1308 ok(!memcmp(&sds, &subst_data[i].sds, sizeof(sds)),
1309 "substitution data does not match\n");
1311 ok(sc.uDefaultLanguage == subst_data[i].uDefaultLanguage,
1312 "sc.uDefaultLanguage does not match\n");
1313 ok(sc.fContextDigits == subst_data[i].fContextDigits,
1314 "sc.fContextDigits does not match\n");
1315 ok(ss.fDigitSubstitute == subst_data[i].fDigitSubstitute,
1316 "ss.fDigitSubstitute does not match\n");
1319 SetThreadLocale(lcid_old);
1320 return TRUE;
1323 static void test_digit_substitution(void)
1325 BOOL ret;
1326 unsigned int i;
1327 static const LGRPID groups[] =
1329 LGRPID_WESTERN_EUROPE,
1330 LGRPID_CENTRAL_EUROPE,
1331 LGRPID_BALTIC,
1332 LGRPID_GREEK,
1333 LGRPID_CYRILLIC,
1334 LGRPID_TURKISH,
1335 LGRPID_JAPANESE,
1336 LGRPID_KOREAN,
1337 LGRPID_TRADITIONAL_CHINESE,
1338 LGRPID_SIMPLIFIED_CHINESE,
1339 LGRPID_THAI,
1340 LGRPID_HEBREW,
1341 LGRPID_ARABIC,
1342 LGRPID_VIETNAMESE,
1343 LGRPID_INDIC,
1344 LGRPID_GEORGIAN,
1345 LGRPID_ARMENIAN
1347 HMODULE hKernel32;
1348 static BOOL (WINAPI * pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROC,LGRPID,DWORD,LONG_PTR);
1350 hKernel32 = GetModuleHandleA("kernel32.dll");
1351 pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
1353 if (!pEnumLanguageGroupLocalesA)
1355 win_skip("EnumLanguageGroupLocalesA not available on this platform\n");
1356 return;
1359 for (i = 0; i < sizeof(groups)/sizeof(groups[0]); i++)
1361 ret = pEnumLanguageGroupLocalesA(enum_proc, groups[i], 0, 0);
1362 ok(ret, "EnumLanguageGroupLocalesA failed unexpectedly: %u\n", GetLastError());
1366 static void test_ScriptGetProperties(void)
1368 const SCRIPT_PROPERTIES **props;
1369 HRESULT hr;
1370 int num;
1372 hr = ScriptGetProperties(NULL, NULL);
1373 ok(hr == E_INVALIDARG, "ScriptGetProperties succeeded\n");
1375 hr = ScriptGetProperties(NULL, &num);
1376 ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1378 hr = ScriptGetProperties(&props, NULL);
1379 ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1381 hr = ScriptGetProperties(&props, &num);
1382 ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
1385 static void test_ScriptBreak(void)
1387 static const WCHAR test[] = {' ','\r','\n',0};
1388 SCRIPT_ITEM items[4];
1389 SCRIPT_LOGATTR la;
1390 HRESULT hr;
1392 hr = ScriptItemize(test, 3, 4, NULL, NULL, items, NULL);
1393 ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
1395 memset(&la, 0, sizeof(la));
1396 hr = ScriptBreak(test, 1, &items[0].a, &la);
1397 ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
1399 ok(!la.fSoftBreak, "fSoftBreak set\n");
1400 ok(la.fWhiteSpace, "fWhiteSpace not set\n");
1401 ok(la.fCharStop, "fCharStop not set\n");
1402 ok(!la.fWordStop, "fWordStop set\n");
1403 ok(!la.fInvalid, "fInvalid set\n");
1404 ok(!la.fReserved, "fReserved set\n");
1406 memset(&la, 0, sizeof(la));
1407 hr = ScriptBreak(test + 1, 1, &items[1].a, &la);
1408 ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
1410 ok(!la.fSoftBreak, "fSoftBreak set\n");
1411 ok(!la.fWhiteSpace, "fWhiteSpace set\n");
1412 ok(la.fCharStop, "fCharStop not set\n");
1413 ok(!la.fWordStop, "fWordStop set\n");
1414 ok(!la.fInvalid, "fInvalid set\n");
1415 ok(!la.fReserved, "fReserved set\n");
1417 memset(&la, 0, sizeof(la));
1418 hr = ScriptBreak(test + 2, 1, &items[2].a, &la);
1419 ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
1421 ok(!la.fSoftBreak, "fSoftBreak set\n");
1422 ok(!la.fWhiteSpace, "fWhiteSpace set\n");
1423 ok(la.fCharStop, "fCharStop not set\n");
1424 ok(!la.fWordStop, "fWordStop set\n");
1425 ok(!la.fInvalid, "fInvalid set\n");
1426 ok(!la.fReserved, "fReserved set\n");
1429 static void test_newlines(void)
1431 static const WCHAR test1[] = {'t','e','x','t','\r','t','e','x','t',0};
1432 static const WCHAR test2[] = {'t','e','x','t','\n','t','e','x','t',0};
1433 static const WCHAR test3[] = {'t','e','x','t','\r','\n','t','e','x','t',0};
1434 static const WCHAR test4[] = {'t','e','x','t','\n','\r','t','e','x','t',0};
1435 static const WCHAR test5[] = {'1','2','3','4','\n','\r','1','2','3','4',0};
1436 SCRIPT_ITEM items[5];
1437 HRESULT hr;
1438 int count;
1440 count = 0;
1441 hr = ScriptItemize(test1, lstrlenW(test1), 5, NULL, NULL, items, &count);
1442 ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1443 ok(count == 3, "got %d expected 3\n", count);
1445 count = 0;
1446 hr = ScriptItemize(test2, lstrlenW(test2), 5, NULL, NULL, items, &count);
1447 ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1448 ok(count == 3, "got %d expected 3\n", count);
1450 count = 0;
1451 hr = ScriptItemize(test3, lstrlenW(test3), 5, NULL, NULL, items, &count);
1452 ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1453 ok(count == 4, "got %d expected 4\n", count);
1455 count = 0;
1456 hr = ScriptItemize(test4, lstrlenW(test4), 5, NULL, NULL, items, &count);
1457 ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1458 ok(count == 4, "got %d expected 4\n", count);
1460 count = 0;
1461 hr = ScriptItemize(test5, lstrlenW(test5), 5, NULL, NULL, items, &count);
1462 ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
1463 ok(count == 4, "got %d expected 4\n", count);
1466 START_TEST(usp10)
1468 HWND hwnd;
1469 HDC hdc;
1470 LOGFONTA lf;
1471 HFONT hfont;
1473 unsigned short pwOutGlyphs[256];
1475 /* We need a valid HDC to drive a lot of Script functions which requires the following *
1476 * to set up for the tests. */
1477 hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
1478 0, 0, 0, NULL);
1479 assert(hwnd != 0);
1480 ShowWindow(hwnd, SW_SHOW);
1481 UpdateWindow(hwnd);
1483 hdc = GetDC(hwnd); /* We now have a hdc */
1484 ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
1486 memset(&lf, 0, sizeof(LOGFONTA));
1487 lstrcpyA(lf.lfFaceName, "Tahoma");
1488 lf.lfHeight = 10;
1489 lf.lfWeight = 3;
1490 lf.lfWidth = 10;
1492 hfont = SelectObject(hdc, CreateFontIndirectA(&lf));
1494 test_ScriptItemIzeShapePlace(hdc,pwOutGlyphs);
1495 test_ScriptGetCMap(hdc, pwOutGlyphs);
1496 test_ScriptCacheGetHeight(hdc);
1497 test_ScriptGetGlyphABCWidth(hdc);
1498 test_ScriptShape(hdc);
1500 test_ScriptGetFontProperties(hdc);
1501 test_ScriptTextOut(hdc);
1502 test_ScriptTextOut2(hdc);
1503 test_ScriptXtoX();
1504 test_ScriptString(hdc);
1505 test_ScriptStringXtoCP_CPtoX(hdc);
1507 test_ScriptLayout();
1508 test_digit_substitution();
1509 test_ScriptGetProperties();
1510 test_ScriptBreak();
1511 test_newlines();
1513 ReleaseDC(hwnd, hdc);
1514 DestroyWindow(hwnd);