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