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
23 * Uniscribe allows for processing of complex scripts such as joining
24 * and filtering characters and bi-directional text with custom line breaks.
30 #include <wine/test.h>
34 typedef struct _itemTest
{
42 static inline void _test_items_ok(LPCWSTR string
, DWORD cchString
,
43 SCRIPT_CONTROL
*Control
, SCRIPT_STATE
*State
,
44 DWORD nItems
, const itemTest
* items
, BOOL nItemsToDo
)
48 SCRIPT_ITEM outpItems
[15];
50 hr
= ScriptItemize(string
, cchString
, 15, Control
, State
, outpItems
, &outnItems
);
51 winetest_ok(!hr
, "ScriptItemize should return S_OK not %08x\n", hr
);
53 todo_wine
winetest_ok(outnItems
== nItems
, "Wrong number of items\n");
55 winetest_ok(outnItems
== nItems
, "Wrong number of items\n");
56 for (x
= 0; x
<= outnItems
; x
++)
58 if (items
[x
].todo_flag
[0])
59 todo_wine
winetest_ok(outpItems
[x
].iCharPos
== items
[x
].iCharPos
, "%i:Wrong CharPos\n",x
);
61 winetest_ok(outpItems
[x
].iCharPos
== items
[x
].iCharPos
, "%i:Wrong CharPos (%i)\n",x
,outpItems
[x
].iCharPos
);
63 if (items
[x
].todo_flag
[1])
64 todo_wine
winetest_ok(outpItems
[x
].a
.fRTL
== items
[x
].fRTL
, "%i:Wrong fRTL\n",x
);
66 winetest_ok(outpItems
[x
].a
.fRTL
== items
[x
].fRTL
, "%i:Wrong fRTL(%i)\n",x
,outpItems
[x
].a
.fRTL
);
67 if (items
[x
].todo_flag
[2])
68 todo_wine
winetest_ok(outpItems
[x
].a
.fLayoutRTL
== items
[x
].fLayoutRTL
, "%i:Wrong fLayoutRTL\n",x
);
70 winetest_ok(outpItems
[x
].a
.fLayoutRTL
== items
[x
].fLayoutRTL
, "%i:Wrong fLayoutRTL(%i)\n",x
,outpItems
[x
].a
.fLayoutRTL
);
71 if (items
[x
].todo_flag
[3])
72 todo_wine
winetest_ok(outpItems
[x
].a
.s
.uBidiLevel
== items
[x
].uBidiLevel
, "%i:Wrong BidiLevel\n",x
);
74 winetest_ok(outpItems
[x
].a
.s
.uBidiLevel
== items
[x
].uBidiLevel
, "%i:Wrong BidiLevel(%i)\n",x
,outpItems
[x
].a
.s
.uBidiLevel
);
78 #define test_items_ok(a,b,c,d,e,f,g) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _test_items_ok(a,b,c,d,e,f,g)
81 static void test_ScriptItemize( void )
83 static const WCHAR test1
[] = {'t', 'e', 's', 't',0};
84 static const itemTest t11
[2] = {{{0,0,0,0},0,0,0,0},{{0,0,0,0},4,0,0,0}};
85 static const itemTest t12
[2] = {{{0,0,0,0},0,0,0,2},{{0,0,0,0},4,0,0,0}};
88 static const WCHAR test2
[] = {'1','2','3','-','5','2',0x064a,0x064f,0x0633,0x0627,0x0648,0x0650,0x064a,'7','1','.',0};
89 static const itemTest t21
[7] = {{{0,0,0,0},0,0,0,0},{{0,0,0,0},3,0,0,0},{{0,0,0,0},4,0,0,0},{{0,0,0,0},6,1,1,1},{{0,0,0,0},13,0,0,0},{{0,0,0,0},15,0,0,0},{{0,0,0,0},16,0,0,0}};
90 static const itemTest t22
[5] = {{{0,0,0,1},0,0,0,2},{{0,0,0,0},6,1,1,1},{{0,0,1,0},13,0,1,2},{{0,0,0,0},15,0,0,0},{{0,0,0,0},16,0,0,0}};
91 static const itemTest t23
[5] = {{{0,0,1,0},0,0,1,2},{{0,0,0,0},6,1,1,1},{{0,0,1,0},13,0,1,2},{{0,0,0,0},15,1,1,1},{{0,0,0,0},16,0,0,0}};
94 static const WCHAR test3
[] =
95 {0x0e04,0x0e27,0x0e32,0x0e21,0x0e1e,0x0e22,0x0e32,0x0e22,0x0e32, 0x0e21
96 ,0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e44,0x0e2b,0x0e19
97 ,0x0e04,0x0e27,0x0e32,0x0e21,0x0e2a, 0x0e33,0x0e40,0x0e23,0x0e47,0x0e08,
98 0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e19,0x0e31,0x0e48,0x0e19,0};
100 static const itemTest t31
[2] = {{{0,0,0,0},0,0,0,0},{{0,0,0,0},41,0,0,0}};
101 static const itemTest t32
[2] = {{{0,0,0,0},0,0,0,2},{{0,0,0,0},41,0,0,0}};
103 static const WCHAR test4
[] = {'1','2','3','-','5','2',' ','i','s',' ','7','1','.',0};
105 static const itemTest t41
[6] = {{{0,0,0,0},0,0,0,0},{{0,0,0,0},3,0,0,0},{{0,0,0,0},4,0,0,0},{{0,0,0,0},7,0,0,0},{{0,0,0,0},10,0,0,0},{{0,0,0,0},12,0,0,0}};
106 static const itemTest t42
[5] = {{{0,0,1,0},0,0,1,2},{{0,0,0,0},6,1,1,1},{{0,0,0,0},7,0,0,2},{{1,0,0,1},10,0,0,2},{{1,0,0,0},12,0,0,0}};
109 static const WCHAR test5
[] =
110 {0x0627,0x0644,0x0635,0x0651,0x0650,0x062d,0x0629,0x064f,' ',0x062a,0x064e,
111 0x0627,0x062c,0x064c,' ',0x0639,0x064e,0x0644,0x0649,' ',
112 0x0631,0x064f,0x0624,0x0648,0x0633,0x0650,' ',0x0627,0x0644
113 ,0x0623,0x0635,0x0650,0x062d,0x0651,0x064e,0x0627,0x0621,0x0650,0};
114 static const itemTest t51
[2] = {{{0,0,0,0},0,1,1,1},{{0,0,0,0},38,0,0,0}};
117 static const WCHAR test6
[] = {0x05e9, 0x05dc, 0x05d5, 0x05dd, '.',0};
118 static const itemTest t61
[3] = {{{0,0,0,0},0,1,1,1},{{0,0,0,0},4,0,0,0},{{0,0,0,0},5,0,0,0}};
119 static const itemTest t62
[3] = {{{0,0,0,0},0,1,1,1},{{0,0,0,0},4,1,1,1},{{0,0,0,0},5,0,0,0}};
120 static const WCHAR test7
[] = {'p','a','r','t',' ','o','n','e',' ',0x05d7, 0x05dc, 0x05e7, ' ', 0x05e9, 0x05ea, 0x05d9, 0x05d9, 0x05dd, ' ','p','a','r','t',' ','t','h','r','e','e', 0};
121 static const itemTest t71
[4] = {{{0,0,0,0},0,0,0,0},{{0,0,0,0},9,1,1,1},{{0,0,0,0},19,0,0,0},{{0,0,0,0},29,0,0,0}};
122 static const itemTest t72
[4] = {{{0,0,0,0},0,0,0,0},{{0,0,0,0},9,1,1,1},{{0,0,0,0},18,0,0,0},{{0,0,0,0},29,0,0,0}};
123 static const itemTest t73
[4] = {{{0,0,0,0},0,0,0,2},{{0,0,0,0},8,1,1,1},{{0,0,0,0},19,0,0,2},{{0,0,0,0},29,0,0,0}};
124 static const WCHAR test8
[] = {0x0633, 0x0644, 0x0627, 0x0645,0};
125 static const itemTest t81
[2] = {{{0,0,0,0},0,1,1,1},{{0,0,0,0},4,0,0,0}};
127 /* Syriac (Like Arabic )*/
128 static const WCHAR test9
[] = {0x0710, 0x0712, 0x0712, 0x0714, '.',0};
129 static const itemTest t91
[3] = {{{0,0,0,0},0,1,1,1},{{0,0,0,0},4,0,0,0},{{0,0,0,0},5,0,0,0}};
130 static const itemTest t92
[3] = {{{0,0,0,0},0,1,1,1},{{0,0,0,0},4,1,1,1},{{0,0,0,0},5,0,0,0}};
132 static const WCHAR test10
[] = {0x0717, 0x0718, 0x071a, 0x071b,0};
133 static const itemTest t101
[2] = {{{0,0,0,0},0,1,1,1},{{0,0,0,0},4,0,0,0}};
135 SCRIPT_ITEM items
[15];
136 SCRIPT_CONTROL Control
;
141 memset(&Control
, 0, sizeof(Control
));
142 memset(&State
, 0, sizeof(State
));
144 hr
= ScriptItemize(NULL
, 4, 10, &Control
, &State
, items
, NULL
);
145 ok (hr
== E_INVALIDARG
, "ScriptItemize should return E_INVALIDARG if pwcInChars is NULL\n");
147 hr
= ScriptItemize(test1
, 4, 10, &Control
, &State
, NULL
, NULL
);
148 ok (hr
== E_INVALIDARG
, "ScriptItemize should return E_INVALIDARG if pItems is NULL\n");
150 hr
= ScriptItemize(test1
, 4, 1, &Control
, &State
, items
, NULL
);
151 ok (hr
== E_INVALIDARG
, "ScriptItemize should return E_INVALIDARG if cMaxItems < 2.");
153 hr
= ScriptItemize(test1
, 0, 10, NULL
, NULL
, items
, &nItems
);
154 ok (hr
== E_INVALIDARG
, "ScriptItemize should return E_INVALIDARG if cInChars is 0\n");
156 test_items_ok(test1
,4,NULL
,NULL
,1,t11
,FALSE
);
157 test_items_ok(test2
,16,NULL
,NULL
,6,t21
,FALSE
);
158 test_items_ok(test3
,41,NULL
,NULL
,1,t31
,FALSE
);
159 test_items_ok(test4
,12,NULL
,NULL
,5,t41
,FALSE
);
160 test_items_ok(test5
,38,NULL
,NULL
,1,t51
,FALSE
);
161 test_items_ok(test6
,5,NULL
,NULL
,2,t61
,FALSE
);
162 test_items_ok(test7
,29,NULL
,NULL
,3,t71
,FALSE
);
163 test_items_ok(test8
,4,NULL
,NULL
,1,t81
,FALSE
);
164 test_items_ok(test9
,5,NULL
,NULL
,2,t91
,FALSE
);
165 test_items_ok(test10
,4,NULL
,NULL
,1,t101
,FALSE
);
167 State
.uBidiLevel
= 0;
168 test_items_ok(test1
,4,&Control
,&State
,1,t11
,FALSE
);
169 test_items_ok(test2
,16,&Control
,&State
,4,t22
,FALSE
);
170 test_items_ok(test3
,41,&Control
,&State
,1,t31
,FALSE
);
171 test_items_ok(test4
,12,&Control
,&State
,5,t41
,FALSE
);
172 test_items_ok(test5
,38,&Control
,&State
,1,t51
,FALSE
);
173 test_items_ok(test6
,5,&Control
,&State
,2,t61
,FALSE
);
174 test_items_ok(test7
,29,&Control
,&State
,3,t72
,FALSE
);
175 test_items_ok(test8
,4,&Control
,&State
,1,t81
,FALSE
);
176 test_items_ok(test9
,5,&Control
,&State
,2,t91
,FALSE
);
177 test_items_ok(test10
,4,&Control
,&State
,1,t101
,FALSE
);
179 State
.uBidiLevel
= 1;
180 test_items_ok(test1
,4,&Control
,&State
,1,t12
,FALSE
);
181 test_items_ok(test2
,16,&Control
,&State
,4,t23
,FALSE
);
182 test_items_ok(test3
,41,&Control
,&State
,1,t32
,FALSE
);
183 test_items_ok(test4
,12,&Control
,&State
,4,t42
,TRUE
);
184 test_items_ok(test5
,38,&Control
,&State
,1,t51
,FALSE
);
185 test_items_ok(test6
,5,&Control
,&State
,2,t62
,FALSE
);
186 test_items_ok(test7
,29,&Control
,&State
,3,t73
,FALSE
);
187 test_items_ok(test8
,4,&Control
,&State
,1,t81
,FALSE
);
188 test_items_ok(test9
,5,&Control
,&State
,2,t92
,FALSE
);
189 test_items_ok(test10
,4,&Control
,&State
,1,t101
,FALSE
);
193 static void test_ScriptShape(HDC hdc
)
195 static const WCHAR test1
[] = {'w', 'i', 'n', 'e',0};
196 static const WCHAR test2
[] = {0x202B, 'i', 'n', 0x202C,0};
198 SCRIPT_CACHE sc
= NULL
;
199 WORD glyphs
[4], glyphs2
[4], logclust
[4];
200 SCRIPT_VISATTR attrs
[4];
201 SCRIPT_ITEM items
[2];
204 hr
= ScriptItemize(test1
, 4, 2, NULL
, NULL
, items
, NULL
);
205 ok(!hr
, "ScriptItemize should return S_OK not %08x\n", hr
);
206 ok(items
[0].a
.fNoGlyphIndex
== FALSE
, "fNoGlyphIndex TRUE\n");
208 hr
= ScriptShape(hdc
, &sc
, test1
, 4, 4, &items
[0].a
, glyphs
, NULL
, NULL
, &nb
);
209 ok(hr
== E_INVALIDARG
, "ScriptShape should return E_INVALIDARG not %08x\n", hr
);
211 hr
= ScriptShape(hdc
, &sc
, test1
, 4, 4, &items
[0].a
, glyphs
, NULL
, attrs
, NULL
);
212 ok(hr
== E_INVALIDARG
, "ScriptShape should return E_INVALIDARG not %08x\n", hr
);
214 hr
= ScriptShape(NULL
, &sc
, test1
, 4, 4, &items
[0].a
, glyphs
, NULL
, attrs
, &nb
);
215 ok(hr
== E_PENDING
, "ScriptShape should return E_PENDING not %08x\n", hr
);
217 hr
= ScriptShape(hdc
, &sc
, test1
, 4, 4, &items
[0].a
, glyphs
, NULL
, attrs
, &nb
);
218 ok(broken(hr
== S_OK
) ||
219 hr
== E_INVALIDARG
|| /* Vista, W2K8 */
220 hr
== E_FAIL
, /* WIN7 */
221 "ScriptShape should return E_FAIL or E_INVALIDARG, not %08x\n", hr
);
222 ok(items
[0].a
.fNoGlyphIndex
== FALSE
, "fNoGlyphIndex TRUE\n");
224 hr
= ScriptShape(hdc
, &sc
, test1
, 4, 4, &items
[0].a
, glyphs
, logclust
, attrs
, &nb
);
225 ok(!hr
, "ScriptShape should return S_OK not %08x\n", hr
);
226 ok(items
[0].a
.fNoGlyphIndex
== FALSE
, "fNoGlyphIndex TRUE\n");
229 memset(glyphs
,-1,sizeof(glyphs
));
230 memset(logclust
,-1,sizeof(logclust
));
231 memset(attrs
,-1,sizeof(attrs
));
232 hr
= ScriptShape(NULL
, &sc
, test1
, 4, 4, &items
[0].a
, glyphs
, logclust
, attrs
, &nb
);
233 ok(!hr
, "ScriptShape should return S_OK not %08x\n", hr
);
234 ok(nb
== 4, "Wrong number of items\n");
235 ok(logclust
[0] == 0, "clusters out of order\n");
236 ok(logclust
[1] == 1, "clusters out of order\n");
237 ok(logclust
[2] == 2, "clusters out of order\n");
238 ok(logclust
[3] == 3, "clusters out of order\n");
239 ok(attrs
[0].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
240 ok(attrs
[1].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
241 ok(attrs
[2].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
242 ok(attrs
[3].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
243 ok(attrs
[0].fClusterStart
== 1, "fClusterStart incorrect\n");
244 ok(attrs
[1].fClusterStart
== 1, "fClusterStart incorrect\n");
245 ok(attrs
[2].fClusterStart
== 1, "fClusterStart incorrect\n");
246 ok(attrs
[3].fClusterStart
== 1, "fClusterStart incorrect\n");
247 ok(attrs
[0].fDiacritic
== 0, "fDiacritic incorrect\n");
248 ok(attrs
[1].fDiacritic
== 0, "fDiacritic incorrect\n");
249 ok(attrs
[2].fDiacritic
== 0, "fDiacritic incorrect\n");
250 ok(attrs
[3].fDiacritic
== 0, "fDiacritic incorrect\n");
251 ok(attrs
[0].fZeroWidth
== 0, "fZeroWidth incorrect\n");
252 ok(attrs
[1].fZeroWidth
== 0, "fZeroWidth incorrect\n");
253 ok(attrs
[2].fZeroWidth
== 0, "fZeroWidth incorrect\n");
254 ok(attrs
[3].fZeroWidth
== 0, "fZeroWidth incorrect\n");
256 ScriptFreeCache(&sc
);
259 memset(glyphs2
,-1,sizeof(glyphs2
));
260 memset(logclust
,-1,sizeof(logclust
));
261 memset(attrs
,-1,sizeof(attrs
));
262 hr
= ScriptShape(hdc
, &sc
, test2
, 4, 4, &items
[0].a
, glyphs2
, logclust
, attrs
, &nb
);
263 ok(hr
== S_OK
, "ScriptShape should return S_OK not %08x\n", hr
);
264 ok(nb
== 4, "Wrong number of items\n");
265 ok(glyphs2
[0] == 0, "Incorrect glyph for 0x202B\n");
266 ok(glyphs2
[3] == 0, "Incorrect glyph for 0x202C\n");
267 ok(logclust
[0] == 0, "clusters out of order\n");
268 ok(logclust
[1] == 1, "clusters out of order\n");
269 ok(logclust
[2] == 2, "clusters out of order\n");
270 ok(logclust
[3] == 3, "clusters out of order\n");
271 ok(attrs
[0].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
272 ok(attrs
[1].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
273 ok(attrs
[2].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
274 ok(attrs
[3].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
275 ok(attrs
[0].fClusterStart
== 1, "fClusterStart incorrect\n");
276 ok(attrs
[1].fClusterStart
== 1, "fClusterStart incorrect\n");
277 ok(attrs
[2].fClusterStart
== 1, "fClusterStart incorrect\n");
278 ok(attrs
[3].fClusterStart
== 1, "fClusterStart incorrect\n");
279 ok(attrs
[0].fDiacritic
== 0, "fDiacritic incorrect\n");
280 ok(attrs
[1].fDiacritic
== 0, "fDiacritic incorrect\n");
281 ok(attrs
[2].fDiacritic
== 0, "fDiacritic incorrect\n");
282 ok(attrs
[3].fDiacritic
== 0, "fDiacritic incorrect\n");
283 ok(attrs
[0].fZeroWidth
== 0, "fZeroWidth incorrect\n");
284 ok(attrs
[1].fZeroWidth
== 0, "fZeroWidth incorrect\n");
285 ok(attrs
[2].fZeroWidth
== 0, "fZeroWidth incorrect\n");
286 ok(attrs
[3].fZeroWidth
== 0, "fZeroWidth incorrect\n");
288 /* modify LTR to RTL */
290 memset(glyphs2
,-1,sizeof(glyphs2
));
291 memset(logclust
,-1,sizeof(logclust
));
292 memset(attrs
,-1,sizeof(attrs
));
293 hr
= ScriptShape(hdc
, &sc
, test1
, 4, 4, &items
[0].a
, glyphs2
, logclust
, attrs
, &nb
);
294 ok(!hr
, "ScriptShape should return S_OK not %08x\n", hr
);
295 ok(nb
== 4, "Wrong number of items\n");
296 ok(glyphs2
[0] == glyphs
[3], "Glyphs not reordered properly\n");
297 ok(glyphs2
[1] == glyphs
[2], "Glyphs not reordered properly\n");
298 ok(glyphs2
[2] == glyphs
[1], "Glyphs not reordered properly\n");
299 ok(glyphs2
[3] == glyphs
[0], "Glyphs not reordered properly\n");
300 ok(logclust
[0] == 3, "clusters out of order\n");
301 ok(logclust
[1] == 2, "clusters out of order\n");
302 ok(logclust
[2] == 1, "clusters out of order\n");
303 ok(logclust
[3] == 0, "clusters out of order\n");
304 ok(attrs
[0].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
305 ok(attrs
[1].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
306 ok(attrs
[2].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
307 ok(attrs
[3].uJustification
== SCRIPT_JUSTIFY_CHARACTER
, "uJustification incorrect\n");
308 ok(attrs
[0].fClusterStart
== 1, "fClusterStart incorrect\n");
309 ok(attrs
[1].fClusterStart
== 1, "fClusterStart incorrect\n");
310 ok(attrs
[2].fClusterStart
== 1, "fClusterStart incorrect\n");
311 ok(attrs
[3].fClusterStart
== 1, "fClusterStart incorrect\n");
312 ok(attrs
[0].fDiacritic
== 0, "fDiacritic incorrect\n");
313 ok(attrs
[1].fDiacritic
== 0, "fDiacritic incorrect\n");
314 ok(attrs
[2].fDiacritic
== 0, "fDiacritic incorrect\n");
315 ok(attrs
[3].fDiacritic
== 0, "fDiacritic incorrect\n");
316 ok(attrs
[0].fZeroWidth
== 0, "fZeroWidth incorrect\n");
317 ok(attrs
[1].fZeroWidth
== 0, "fZeroWidth incorrect\n");
318 ok(attrs
[2].fZeroWidth
== 0, "fZeroWidth incorrect\n");
319 ok(attrs
[3].fZeroWidth
== 0, "fZeroWidth incorrect\n");
321 ScriptFreeCache(&sc
);
324 static void test_ScriptPlace(HDC hdc
)
326 static const WCHAR test1
[] = {'t', 'e', 's', 't',0};
329 SCRIPT_CACHE sc
= NULL
;
330 WORD glyphs
[4], logclust
[4];
331 SCRIPT_VISATTR attrs
[4];
332 SCRIPT_ITEM items
[2];
337 hr
= ScriptItemize(test1
, 4, 2, NULL
, NULL
, items
, NULL
);
338 ok(!hr
, "ScriptItemize should return S_OK not %08x\n", hr
);
339 ok(items
[0].a
.fNoGlyphIndex
== FALSE
, "fNoGlyphIndex TRUE\n");
341 hr
= ScriptShape(hdc
, &sc
, test1
, 4, 4, &items
[0].a
, glyphs
, logclust
, attrs
, &nb
);
342 ok(!hr
, "ScriptShape should return S_OK not %08x\n", hr
);
343 ok(items
[0].a
.fNoGlyphIndex
== FALSE
, "fNoGlyphIndex TRUE\n");
345 hr
= ScriptPlace(hdc
, &sc
, glyphs
, 4, NULL
, &items
[0].a
, widths
, NULL
, NULL
);
346 ok(hr
== E_INVALIDARG
, "ScriptPlace should return E_INVALIDARG not %08x\n", hr
);
348 hr
= ScriptPlace(NULL
, &sc
, glyphs
, 4, attrs
, &items
[0].a
, widths
, NULL
, NULL
);
349 ok(broken(hr
== E_PENDING
) ||
350 hr
== E_INVALIDARG
|| /* Vista, W2K8 */
351 hr
== E_FAIL
, /* WIN7 */
352 "ScriptPlace should return E_FAIL or E_INVALIDARG, not %08x\n", hr
);
354 hr
= ScriptPlace(NULL
, &sc
, glyphs
, 4, attrs
, &items
[0].a
, widths
, offset
, NULL
);
355 ok(hr
== E_PENDING
, "ScriptPlace should return E_PENDING not %08x\n", hr
);
357 hr
= ScriptPlace(NULL
, &sc
, glyphs
, 4, attrs
, &items
[0].a
, widths
, NULL
, abc
);
358 ok(broken(hr
== E_PENDING
) ||
359 hr
== E_INVALIDARG
|| /* Vista, W2K8 */
360 hr
== E_FAIL
, /* WIN7 */
361 "ScriptPlace should return E_FAIL or E_INVALIDARG, not %08x\n", hr
);
363 hr
= ScriptPlace(hdc
, &sc
, glyphs
, 4, attrs
, &items
[0].a
, widths
, offset
, NULL
);
364 ok(!hr
, "ScriptPlace should return S_OK not %08x\n", hr
);
365 ok(items
[0].a
.fNoGlyphIndex
== FALSE
, "fNoGlyphIndex TRUE\n");
367 ret
= ExtTextOutW(hdc
, 1, 1, 0, NULL
, glyphs
, 4, widths
);
368 ok(ret
, "ExtTextOutW should return TRUE\n");
370 ScriptFreeCache(&sc
);
373 static void test_ScriptItemIzeShapePlace(HDC hdc
, unsigned short pwOutGlyphs
[256])
377 const SCRIPT_PROPERTIES
**ppSp
;
381 SCRIPT_ITEM pItem
[255];
383 WCHAR TestItem1
[] = {'T', 'e', 's', 't', 'a', 0};
384 WCHAR TestItem2
[] = {'T', 'e', 's', 't', 'b', 0};
385 WCHAR TestItem3
[] = {'T', 'e', 's', 't', 'c',' ','1','2','3',' ',' ','e','n','d',0};
386 WCHAR TestItem4
[] = {'T', 'e', 's', 't', 'd',' ',0x0684,0x0694,0x06a4,' ',' ','\r','\n','e','n','d',0};
387 WCHAR TestItem5
[] = {0x0684,'T','e','s','t','e',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0};
388 WCHAR TestItem6
[] = {'T', 'e', 's', 't', 'f',' ',' ',' ','\r','\n','e','n','d',0};
393 unsigned short pwOutGlyphs1
[256];
394 unsigned short pwOutGlyphs2
[256];
395 unsigned short pwLogClust
[256];
396 SCRIPT_VISATTR psva
[256];
399 GOFFSET pGoffset
[256];
403 /* Start testing usp10 functions */
404 /* This test determines that the pointer returned by ScriptGetProperties is valid
405 * by checking a known value in the table */
406 hr
= ScriptGetProperties(&ppSp
, &iMaxProps
);
407 trace("number of script properties %d\n", iMaxProps
);
408 ok (iMaxProps
> 0, "Number of scripts returned should not be 0\n");
410 ok( ppSp
[5]->langid
== 9, "Langid[5] not = to 9\n"); /* Check a known value to ensure */
413 /* This is a valid test that will cause parsing to take place */
416 hr
= ScriptItemize(TestItem1
, cInChars
, cMaxItems
, NULL
, NULL
, pItem
, &pcItems
);
417 ok (hr
== 0, "ScriptItemize should return 0, returned %08x\n", hr
);
418 /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
420 ok (pcItems
> 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
422 ok (pItem
[0].iCharPos
== 0 && pItem
[1].iCharPos
== cInChars
,
423 "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
424 pItem
[0].iCharPos
, cInChars
, pItem
[1].iCharPos
);
426 /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
427 * ie. ScriptItemize has succeeded and that pItem has been set */
431 psc
= NULL
; /* must be null on first call */
433 cMaxGlyphs
= cInChars
;
434 hr
= ScriptShape(NULL
, &psc
, TestItem1
, cChars
,
435 cMaxGlyphs
, &pItem
[0].a
,
436 pwOutGlyphs1
, pwLogClust
, psva
, &pcGlyphs
);
437 ok (hr
== E_PENDING
, "If psc is NULL (%08x) the E_PENDING should be returned\n", hr
);
439 hr
= ScriptShape(hdc
, &psc
, TestItem1
, cChars
,
440 cMaxGlyphs
, &pItem
[0].a
,
441 pwOutGlyphs1
, pwLogClust
, psva
, &pcGlyphs
);
442 ok (hr
== E_OUTOFMEMORY
, "If not enough output area cChars (%d) is > than CMaxGlyphs "
443 "(%d) but not E_OUTOFMEMORY\n",
446 hr
= ScriptShape(hdc
, &psc
, TestItem1
, cChars
,
447 cMaxGlyphs
, &pItem
[0].a
,
448 pwOutGlyphs1
, pwLogClust
, psva
, &pcGlyphs
);
449 ok (hr
== 0, "ScriptShape should return 0 not (%08x)\n", hr
);
450 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
451 ok (pcGlyphs
== cChars
, "Chars in (%d) should equal Glyphs out (%d)\n", cChars
, pcGlyphs
);
453 hr
= ScriptPlace(hdc
, &psc
, pwOutGlyphs1
, pcGlyphs
, psva
, &pItem
[0].a
, piAdvance
,
455 ok (hr
== 0, "ScriptPlace should return 0 not (%08x)\n", hr
);
456 hr
= ScriptPlace(NULL
, &psc
, pwOutGlyphs1
, pcGlyphs
, psva
, &pItem
[0].a
, piAdvance
,
458 ok (hr
== 0, "ScriptPlace should return 0 not (%08x)\n", hr
);
459 for (cnt
=0; cnt
< pcGlyphs
; cnt
++)
460 pwOutGlyphs
[cnt
] = pwOutGlyphs1
[cnt
]; /* Send to next function */
463 /* This test will check to make sure that SCRIPT_CACHE is reused and that not translation *
464 * takes place if fNoGlyphIndex is set. */
468 hr
= ScriptItemize(TestItem2
, cInChars
, cMaxItems
, NULL
, NULL
, pItem
, &pcItems
);
469 ok (hr
== 0, "ScriptItemize should return 0, returned %08x\n", hr
);
470 /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
472 ok (pItem
[0].iCharPos
== 0 && pItem
[1].iCharPos
== cInChars
,
473 "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
474 pItem
[0].iCharPos
, cInChars
, pItem
[1].iCharPos
);
475 /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue */
479 pItem
[0].a
.fNoGlyphIndex
= 1; /* say no translate */
480 hr
= ScriptShape(NULL
, &psc
, TestItem2
, cChars
,
481 cMaxGlyphs
, &pItem
[0].a
,
482 pwOutGlyphs2
, pwLogClust
, psva
, &pcGlyphs
);
483 ok (hr
!= E_PENDING
, "If psc should not be NULL (%08x) and the E_PENDING should be returned\n", hr
);
484 ok (hr
== 0, "ScriptShape should return 0 not (%08x)\n", hr
);
485 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
486 ok (pcGlyphs
== cChars
, "Chars in (%d) should equal Glyphs out (%d)\n", cChars
, pcGlyphs
);
487 for (cnt
=0; cnt
< cChars
&& TestItem2
[cnt
] == pwOutGlyphs2
[cnt
]; cnt
++) {}
488 ok (cnt
== cChars
, "Translation to place when told not to. WCHAR %d - %04x != %04x\n",
489 cnt
, TestItem2
[cnt
], pwOutGlyphs2
[cnt
]);
491 hr
= ScriptPlace(hdc
, &psc
, pwOutGlyphs2
, pcGlyphs
, psva
, &pItem
[0].a
, piAdvance
,
493 ok (hr
== 0, "ScriptPlace should return 0 not (%08x)\n", hr
);
496 hr
= ScriptFreeCache( &psc
);
497 ok (!psc
, "psc is not null after ScriptFreeCache\n");
501 /* This is a valid test that will cause parsing to take place and create 3 script_items */
502 cInChars
= (sizeof(TestItem3
)/2)-1;
504 hr
= ScriptItemize(TestItem3
, cInChars
, cMaxItems
, NULL
, NULL
, pItem
, &pcItems
);
505 ok (hr
== 0, "ScriptItemize should return 0, returned %08x\n", hr
);
508 ok (pcItems
== 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems
);
511 ok (pItem
[0].iCharPos
== 0 && pItem
[1].iCharPos
== 6,
512 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
513 pItem
[0].iCharPos
, pItem
[1].iCharPos
);
514 ok (pItem
[1].iCharPos
== 6 && pItem
[2].iCharPos
== 11,
515 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
516 pItem
[1].iCharPos
, pItem
[2].iCharPos
);
517 ok (pItem
[2].iCharPos
== 11 && pItem
[3].iCharPos
== cInChars
,
518 "Start pos [2] not = 11 (%d) or end [3] pos not = 14 (%d), cInChars = %d\n",
519 pItem
[2].iCharPos
, pItem
[3].iCharPos
, cInChars
);
523 /* This is a valid test that will cause parsing to take place and create 5 script_items */
524 cInChars
= (sizeof(TestItem4
)/2)-1;
526 hr
= ScriptItemize(TestItem4
, cInChars
, cMaxItems
, NULL
, NULL
, pItem
, &pcItems
);
527 ok (hr
== 0, "ScriptItemize should return 0, returned %08x\n", hr
);
530 ok (pcItems
== 5, "The number of SCRIPT_ITEMS should be 5 not %d\n", pcItems
);
533 ok (pItem
[0].iCharPos
== 0 && pItem
[1].iCharPos
== 6,
534 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
535 pItem
[0].iCharPos
, pItem
[1].iCharPos
);
536 ok (pItem
[0].a
.s
.uBidiLevel
== 0, "Should have been bidi=0 not %d\n",
537 pItem
[0].a
.s
.uBidiLevel
);
538 ok (pItem
[1].iCharPos
== 6 && pItem
[2].iCharPos
== 11,
539 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
540 pItem
[1].iCharPos
, pItem
[2].iCharPos
);
541 ok (pItem
[1].a
.s
.uBidiLevel
== 1, "Should have been bidi=1 not %d\n",
542 pItem
[1].a
.s
.uBidiLevel
);
543 ok (pItem
[2].iCharPos
== 11 && pItem
[3].iCharPos
== 12,
544 "Start pos [2] not = 11 (%d) or end [3] pos not = 12 (%d)\n",
545 pItem
[2].iCharPos
, pItem
[3].iCharPos
);
546 ok (pItem
[2].a
.s
.uBidiLevel
== 0, "Should have been bidi=0 not %d\n",
547 pItem
[2].a
.s
.uBidiLevel
);
548 ok (pItem
[3].iCharPos
== 12 && pItem
[4].iCharPos
== 13,
549 "Start pos [3] not = 12 (%d) or end [4] pos not = 13 (%d)\n",
550 pItem
[3].iCharPos
, pItem
[4].iCharPos
);
551 ok (pItem
[3].a
.s
.uBidiLevel
== 0, "Should have been bidi=0 not %d\n",
552 pItem
[3].a
.s
.uBidiLevel
);
553 ok (pItem
[4].iCharPos
== 13 && pItem
[5].iCharPos
== cInChars
,
554 "Start pos [4] not = 13 (%d) or end [5] pos not = 16 (%d), cInChars = %d\n",
555 pItem
[4].iCharPos
, pItem
[5].iCharPos
, cInChars
);
560 * This test is for when the first unicode character requires bidi support
562 cInChars
= (sizeof(TestItem5
)-1)/sizeof(WCHAR
);
563 hr
= ScriptItemize(TestItem5
, cInChars
, cMaxItems
, NULL
, NULL
, pItem
, &pcItems
);
564 ok (hr
== 0, "ScriptItemize should return 0, returned %08x\n", hr
);
565 ok (pcItems
== 4, "There should have been 4 items, found %d\n", pcItems
);
566 ok (pItem
[0].a
.s
.uBidiLevel
== 1, "The first character should have been bidi=1 not %d\n",
567 pItem
[0].a
.s
.uBidiLevel
);
569 /* This test checks to make sure that the test to see if there are sufficient buffers to store *
570 * the pointer to the last char works. Note that windows often needs a greater number of *
571 * SCRIPT_ITEMS to process a string than is returned in pcItems. */
572 cInChars
= (sizeof(TestItem6
)/2)-1;
574 hr
= ScriptItemize(TestItem6
, cInChars
, cMaxItems
, NULL
, NULL
, pItem
, &pcItems
);
575 ok (hr
== E_OUTOFMEMORY
, "ScriptItemize should return E_OUTOFMEMORY, returned %08x\n", hr
);
579 static void test_ScriptGetCMap(HDC hdc
, unsigned short pwOutGlyphs
[256])
582 SCRIPT_CACHE psc
= NULL
;
585 unsigned short pwOutGlyphs2
[256];
586 unsigned short pwOutGlyphs3
[256];
590 static const WCHAR TestItem1
[] = {'T', 'e', 's', 't', 'a', 0};
591 static const WCHAR TestItem2
[] = {0x202B, 'i', 'n', 0x202C,0};
592 static const WCHAR TestItem3
[] = {'a','b','c','d','(','<','{','[',0x2039,0};
593 static const WCHAR TestItem3b
[] = {'a','b','c','d',')','>','}',']',0x203A,0};
595 /* Check to make sure that SCRIPT_CACHE gets allocated ok */
597 cInChars
= cChars
= 5;
598 /* Some sanity checks for ScriptGetCMap */
600 hr
= ScriptGetCMap(NULL
, NULL
, NULL
, 0, 0, NULL
);
601 ok( hr
== E_INVALIDARG
, "(NULL,NULL,NULL,0,0,NULL), "
602 "expected E_INVALIDARG, got %08x\n", hr
);
604 hr
= ScriptGetCMap(NULL
, NULL
, TestItem1
, cInChars
, dwFlags
, pwOutGlyphs3
);
605 ok( hr
== E_INVALIDARG
, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
606 "expected E_INVALIDARG, got %08x\n", hr
);
608 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
610 hr
= ScriptGetCMap(NULL
, &psc
, TestItem1
, cInChars
, 0, pwOutGlyphs3
);
611 ok( hr
== E_PENDING
, "(NULL,&psc,NULL,0,0,NULL), expected E_PENDING, "
613 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
615 /* Set psc to NULL but add hdc, to be able to check if a pointer is returned in psc */
617 hr
= ScriptGetCMap(hdc
, &psc
, TestItem1
, cInChars
, 0, pwOutGlyphs3
);
618 ok( hr
== S_OK
, "ScriptGetCMap(NULL,&psc,NULL,0,0,NULL), expected S_OK, "
620 ok( psc
!= NULL
, "ScritpGetCMap expected psc to be not NULL\n");
621 ScriptFreeCache( &psc
);
623 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
625 hr
= ScriptGetCMap(NULL
, &psc
, TestItem1
, cInChars
, dwFlags
, pwOutGlyphs3
);
626 ok( hr
== E_PENDING
, "(NULL,&psc,), expected E_PENDING, got %08x\n", hr
);
627 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
628 /* Check to see if the results are the same as those returned by ScriptShape */
629 hr
= ScriptGetCMap(hdc
, &psc
, TestItem1
, cInChars
, dwFlags
, pwOutGlyphs3
);
630 ok (hr
== 0, "ScriptGetCMap should return 0 not (%08x)\n", hr
);
631 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
632 for (cnt
=0; cnt
< cChars
&& pwOutGlyphs
[cnt
] == pwOutGlyphs3
[cnt
]; cnt
++) {}
633 ok (cnt
== cInChars
, "Translation not correct. WCHAR %d - %04x != %04x\n",
634 cnt
, pwOutGlyphs
[cnt
], pwOutGlyphs3
[cnt
]);
636 hr
= ScriptFreeCache( &psc
);
637 ok (!psc
, "psc is not null after ScriptFreeCache\n");
639 cInChars
= cChars
= 4;
640 hr
= ScriptGetCMap(hdc
, &psc
, TestItem2
, cInChars
, dwFlags
, pwOutGlyphs3
);
641 ok (hr
== S_FALSE
, "ScriptGetCMap should return S_FALSE not (%08x)\n", hr
);
642 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
643 ok(pwOutGlyphs3
[0] == 0, "Glyph 0 should be default glyph\n");
644 ok(pwOutGlyphs3
[3] == 0, "Glyph 0 should be default glyph\n");
647 cInChars
= cChars
= 9;
648 hr
= ScriptGetCMap(hdc
, &psc
, TestItem3b
, cInChars
, dwFlags
, pwOutGlyphs2
);
649 ok (hr
== S_OK
, "ScriptGetCMap should return S_OK not (%08x)\n", hr
);
650 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
652 cInChars
= cChars
= 9;
654 hr
= ScriptGetCMap(hdc
, &psc
, TestItem3
, cInChars
, dwFlags
, pwOutGlyphs3
);
655 ok (hr
== S_OK
, "ScriptGetCMap should return S_OK not (%08x)\n", hr
);
656 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
657 ok(pwOutGlyphs3
[0] == pwOutGlyphs2
[0], "glyph incorrectly altered\n");
658 ok(pwOutGlyphs3
[1] == pwOutGlyphs2
[1], "glyph incorreclty altered\n");
659 ok(pwOutGlyphs3
[2] == pwOutGlyphs2
[2], "glyph incorreclty altered\n");
660 ok(pwOutGlyphs3
[3] == pwOutGlyphs2
[3], "glyph incorreclty altered\n");
661 ok(pwOutGlyphs3
[4] == pwOutGlyphs2
[4], "glyph not mirrored correctly\n");
662 ok(pwOutGlyphs3
[5] == pwOutGlyphs2
[5], "glyph not mirrored correctly\n");
663 ok(pwOutGlyphs3
[6] == pwOutGlyphs2
[6], "glyph not mirrored correctly\n");
664 ok(pwOutGlyphs3
[7] == pwOutGlyphs2
[7], "glyph not mirrored correctly\n");
665 ok(pwOutGlyphs3
[8] == pwOutGlyphs2
[8], "glyph not mirrored correctly\n");
667 hr
= ScriptFreeCache( &psc
);
668 ok (!psc
, "psc is not null after ScriptFreeCache\n");
671 static void test_ScriptGetFontProperties(HDC hdc
)
674 SCRIPT_CACHE psc
,old_psc
;
675 SCRIPT_FONTPROPERTIES sfp
;
677 /* Some sanity checks for ScriptGetFontProperties */
679 hr
= ScriptGetFontProperties(NULL
,NULL
,NULL
);
680 ok( hr
== E_INVALIDARG
, "(NULL,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr
);
682 hr
= ScriptGetFontProperties(NULL
,NULL
,&sfp
);
683 ok( hr
== E_INVALIDARG
, "(NULL,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr
);
685 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
687 hr
= ScriptGetFontProperties(NULL
,&psc
,NULL
);
688 ok( hr
== E_INVALIDARG
, "(NULL,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr
);
689 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
691 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
693 hr
= ScriptGetFontProperties(NULL
,&psc
,&sfp
);
694 ok( hr
== E_PENDING
, "(NULL,&psc,&sfp), expected E_PENDING, got %08x\n", hr
);
695 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
697 hr
= ScriptGetFontProperties(hdc
,NULL
,NULL
);
698 ok( hr
== E_INVALIDARG
, "(hdc,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr
);
700 hr
= ScriptGetFontProperties(hdc
,NULL
,&sfp
);
701 ok( hr
== E_INVALIDARG
, "(hdc,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr
);
703 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
705 hr
= ScriptGetFontProperties(hdc
,&psc
,NULL
);
706 ok( hr
== E_INVALIDARG
, "(hdc,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr
);
707 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
709 /* Pass an invalid sfp */
711 sfp
.cBytes
= sizeof(SCRIPT_FONTPROPERTIES
) - 1;
712 hr
= ScriptGetFontProperties(hdc
,&psc
,&sfp
);
713 ok( hr
== E_INVALIDARG
, "(hdc,&psc,&sfp) invalid, expected E_INVALIDARG, got %08x\n", hr
);
714 ok( psc
!= NULL
, "Expected a pointer in psc, got NULL\n");
715 ScriptFreeCache(&psc
);
716 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
718 /* Give it the correct cBytes, we don't care about what's coming back */
719 sfp
.cBytes
= sizeof(SCRIPT_FONTPROPERTIES
);
721 hr
= ScriptGetFontProperties(hdc
,&psc
,&sfp
);
722 ok( hr
== S_OK
, "(hdc,&psc,&sfp) partly initialized, expected S_OK, got %08x\n", hr
);
723 ok( psc
!= NULL
, "Expected a pointer in psc, got NULL\n");
725 /* Save the psc pointer */
727 /* Now a NULL hdc again */
728 hr
= ScriptGetFontProperties(NULL
,&psc
,&sfp
);
729 ok( hr
== S_OK
, "(NULL,&psc,&sfp), expected S_OK, got %08x\n", hr
);
730 ok( psc
== old_psc
, "Expected psc not to be changed, was %p is now %p\n", old_psc
, psc
);
731 ScriptFreeCache(&psc
);
732 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
735 static void test_ScriptTextOut(HDC hdc
)
741 SCRIPT_ITEM pItem
[255];
743 WCHAR TestItem1
[] = {'T', 'e', 's', 't', 'a', 0};
748 unsigned short pwOutGlyphs1
[256];
749 WORD pwLogClust
[256];
750 SCRIPT_VISATTR psva
[256];
753 GOFFSET pGoffset
[256];
758 BOOL fTrailing
= FALSE
;
759 SCRIPT_LOGATTR
*psla
;
760 SCRIPT_LOGATTR sla
[256];
762 /* This is a valid test that will cause parsing to take place */
765 hr
= ScriptItemize(TestItem1
, cInChars
, cMaxItems
, NULL
, NULL
, pItem
, &pcItems
);
766 ok (hr
== 0, "ScriptItemize should return 0, returned %08x\n", hr
);
767 /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
769 ok (pcItems
> 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
771 ok (pItem
[0].iCharPos
== 0 && pItem
[1].iCharPos
== cInChars
,
772 "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
773 pItem
[0].iCharPos
, cInChars
, pItem
[1].iCharPos
);
775 /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
776 * ie. ScriptItemize has succeeded and that pItem has been set */
780 psc
= NULL
; /* must be null on first call */
782 cMaxGlyphs
= cInChars
;
784 hr
= ScriptShape(hdc
, &psc
, TestItem1
, cChars
,
785 cMaxGlyphs
, &pItem
[0].a
,
786 pwOutGlyphs1
, pwLogClust
, psva
, &pcGlyphs
);
787 ok (hr
== 0, "ScriptShape should return 0 not (%08x)\n", hr
);
788 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
789 ok (pcGlyphs
== cChars
, "Chars in (%d) should equal Glyphs out (%d)\n", cChars
, pcGlyphs
);
791 /* Note hdc is needed as glyph info is not yet in psc */
792 hr
= ScriptPlace(hdc
, &psc
, pwOutGlyphs1
, pcGlyphs
, psva
, &pItem
[0].a
, piAdvance
,
794 ok (hr
== 0, "Should return 0 not (%08x)\n", hr
);
795 ScriptFreeCache(&psc
); /* Get rid of psc for next test set */
796 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
798 hr
= ScriptTextOut(NULL
, NULL
, 0, 0, 0, NULL
, NULL
, NULL
, 0, NULL
, 0, NULL
, NULL
, NULL
);
799 ok (hr
== E_INVALIDARG
, "Should return 0 not (%08x)\n", hr
);
801 hr
= ScriptTextOut(NULL
, NULL
, 0, 0, 0, NULL
, &pItem
[0].a
, NULL
, 0, pwOutGlyphs1
, pcGlyphs
,
802 piAdvance
, NULL
, pGoffset
);
803 ok( hr
== E_INVALIDARG
, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
804 "expected E_INVALIDARG, got %08x\n", hr
);
806 /* Set psc to NULL, to be able to check if a pointer is returned in psc */
808 hr
= ScriptTextOut(NULL
, &psc
, 0, 0, 0, NULL
, NULL
, NULL
, 0, NULL
, 0,
810 ok( hr
== E_INVALIDARG
, "(NULL,&psc,NULL,0,0,0,NULL,), expected E_INVALIDARG, "
812 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
814 /* hdc is required for this one rather than the usual optional */
816 hr
= ScriptTextOut(NULL
, &psc
, 0, 0, 0, NULL
, &pItem
[0].a
, NULL
, 0, pwOutGlyphs1
, pcGlyphs
,
817 piAdvance
, NULL
, pGoffset
);
818 ok( hr
== E_INVALIDARG
, "(NULL,&psc,), expected E_INVALIDARG, got %08x\n", hr
);
819 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
821 /* Set that it returns 0 status */
822 hr
= ScriptTextOut(hdc
, &psc
, 0, 0, 0, NULL
, &pItem
[0].a
, NULL
, 0, pwOutGlyphs1
, pcGlyphs
,
823 piAdvance
, NULL
, pGoffset
);
824 ok (hr
== 0, "ScriptTextOut should return 0 not (%08x)\n", hr
);
826 /* Test Rect Rgn is acceptable */
831 hr
= ScriptTextOut(hdc
, &psc
, 0, 0, 0, &rect
, &pItem
[0].a
, NULL
, 0, pwOutGlyphs1
, pcGlyphs
,
832 piAdvance
, NULL
, pGoffset
);
833 ok (hr
== 0, "ScriptTextOut should return 0 not (%08x)\n", hr
);
836 hr
= ScriptCPtoX(iCP
, fTrailing
, cChars
, pcGlyphs
, (const WORD
*) &pwLogClust
,
837 (const SCRIPT_VISATTR
*) &psva
, (const int *)&piAdvance
, &pItem
[0].a
, &piX
);
838 ok(hr
== S_OK
, "ScriptCPtoX Stub should return S_OK not %08x\n", hr
);
840 psla
= (SCRIPT_LOGATTR
*)&sla
;
841 hr
= ScriptBreak(TestItem1
, cChars
, &pItem
[0].a
, psla
);
842 ok(hr
== S_OK
, "ScriptBreak Stub should return S_OK not %08x\n", hr
);
844 /* Clean up and go */
845 ScriptFreeCache(&psc
);
846 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
851 static void test_ScriptTextOut2(HDC hdc
)
853 /* Intent is to validate that the HDC passed into ScriptTextOut is
854 * used instead of the (possibly) invalid cached one
861 SCRIPT_ITEM pItem
[255];
863 WCHAR TestItem1
[] = {'T', 'e', 's', 't', 'a', 0};
868 unsigned short pwOutGlyphs1
[256];
869 WORD pwLogClust
[256];
870 SCRIPT_VISATTR psva
[256];
873 GOFFSET pGoffset
[256];
876 /* Create an extra DC that will be used until the ScriptTextOut */
877 hdc1
= CreateCompatibleDC(hdc
);
878 ok (hdc1
!= 0, "CreateCompatibleDC failed to create a DC\n");
879 hdc2
= CreateCompatibleDC(hdc
);
880 ok (hdc2
!= 0, "CreateCompatibleDC failed to create a DC\n");
882 /* This is a valid test that will cause parsing to take place */
885 hr
= ScriptItemize(TestItem1
, cInChars
, cMaxItems
, NULL
, NULL
, pItem
, &pcItems
);
886 ok (hr
== 0, "ScriptItemize should return 0, returned %08x\n", hr
);
887 /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
889 ok (pcItems
> 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
891 ok (pItem
[0].iCharPos
== 0 && pItem
[1].iCharPos
== cInChars
,
892 "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
893 pItem
[0].iCharPos
, cInChars
, pItem
[1].iCharPos
);
895 /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
896 * ie. ScriptItemize has succeeded and that pItem has been set */
900 psc
= NULL
; /* must be null on first call */
902 cMaxGlyphs
= cInChars
;
904 hr
= ScriptShape(hdc2
, &psc
, TestItem1
, cChars
,
905 cMaxGlyphs
, &pItem
[0].a
,
906 pwOutGlyphs1
, pwLogClust
, psva
, &pcGlyphs
);
907 ok (hr
== 0, "ScriptShape should return 0 not (%08x)\n", hr
);
908 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
909 ok (pcGlyphs
== cChars
, "Chars in (%d) should equal Glyphs out (%d)\n", cChars
, pcGlyphs
);
911 /* Note hdc is needed as glyph info is not yet in psc */
912 hr
= ScriptPlace(hdc2
, &psc
, pwOutGlyphs1
, pcGlyphs
, psva
, &pItem
[0].a
, piAdvance
,
914 ok (hr
== 0, "Should return 0 not (%08x)\n", hr
);
916 /* key part!!! cached dc is being deleted */
918 ok(hr
== 1, "DeleteDC should return 1 not %08x\n", hr
);
920 /* At this point the cached hdc (hdc2) has been destroyed,
921 * however, we are passing in a *real* hdc (the original hdc).
922 * The text should be written to that DC
924 hr
= ScriptTextOut(hdc1
, &psc
, 0, 0, 0, NULL
, &pItem
[0].a
, NULL
, 0, pwOutGlyphs1
, pcGlyphs
,
925 piAdvance
, NULL
, pGoffset
);
926 ok (hr
== 0, "ScriptTextOut should return 0 not (%08x)\n", hr
);
927 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
931 /* Clean up and go */
932 ScriptFreeCache(&psc
);
933 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
938 static void test_ScriptTextOut3(HDC hdc
)
944 SCRIPT_ITEM pItem
[255];
946 WCHAR TestItem1
[] = {' ','\r', 0};
951 unsigned short pwOutGlyphs1
[256];
952 WORD pwLogClust
[256];
953 SCRIPT_VISATTR psva
[256];
956 GOFFSET pGoffset
[256];
960 /* This is to ensure that non exisiting glyphs are translated into a valid glyph number */
963 hr
= ScriptItemize(TestItem1
, cInChars
, cMaxItems
, NULL
, NULL
, pItem
, &pcItems
);
964 ok (hr
== 0, "ScriptItemize should return 0, returned %08x\n", hr
);
965 /* This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
967 ok (pcItems
> 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
969 ok (pItem
[0].iCharPos
== 0 && pItem
[2].iCharPos
== cInChars
,
970 "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
971 pItem
[0].iCharPos
, cInChars
, pItem
[2].iCharPos
);
973 /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
974 * ie. ScriptItemize has succeeded and that pItem has been set */
978 psc
= NULL
; /* must be null on first call */
980 cMaxGlyphs
= cInChars
;
982 hr
= ScriptShape(hdc
, &psc
, TestItem1
, cChars
,
983 cMaxGlyphs
, &pItem
[0].a
,
984 pwOutGlyphs1
, pwLogClust
, psva
, &pcGlyphs
);
985 ok (hr
== 0, "ScriptShape should return 0 not (%08x)\n", hr
);
986 ok (psc
!= NULL
, "psc should not be null and have SCRIPT_CACHE buffer address\n");
987 ok (pcGlyphs
== cChars
, "Chars in (%d) should equal Glyphs out (%d)\n", cChars
, pcGlyphs
);
989 /* Note hdc is needed as glyph info is not yet in psc */
990 hr
= ScriptPlace(hdc
, &psc
, pwOutGlyphs1
, pcGlyphs
, psva
, &pItem
[0].a
, piAdvance
,
992 ok (hr
== 0, "Should return 0 not (%08x)\n", hr
);
994 /* Test Rect Rgn is acceptable */
999 hr
= ScriptTextOut(hdc
, &psc
, 0, 0, 0, &rect
, &pItem
[0].a
, NULL
, 0, pwOutGlyphs1
, pcGlyphs
,
1000 piAdvance
, NULL
, pGoffset
);
1001 ok (hr
== 0, "ScriptTextOut should return 0 not (%08x)\n", hr
);
1004 /* Clean up and go */
1005 ScriptFreeCache(&psc
);
1006 ok( psc
== NULL
, "Expected psc to be NULL, got %p\n", psc
);
1010 static void test_ScriptXtoX(void)
1011 /****************************************************************************************
1012 * This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables *
1013 ****************************************************************************************/
1015 static const WCHAR test
[] = {'t', 'e', 's', 't',0};
1016 SCRIPT_ITEM items
[2];
1020 WORD pwLogClust
[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1021 SCRIPT_VISATTR psva
[10];
1022 int piAdvance
[10] = {200, 190, 210, 180, 170, 204, 189, 195, 212, 203};
1028 hr
= ScriptItemize(test
, lstrlenW(test
), sizeof(items
)/sizeof(items
[0]), NULL
, NULL
, items
, NULL
);
1029 ok(!hr
, "ScriptItemize should return S_OK not %08x\n", hr
);
1034 hr
= ScriptXtoCP(iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piCP
, &piTrailing
);
1035 ok(hr
== S_OK
, "ScriptXtoCP should return S_OK not %08x\n", hr
);
1037 ok(piCP
== -1, "Negative iX should return piCP=-1 not %d\n", piCP
);
1039 ok(piCP
== 10, "Negative iX should return piCP=10 not %d\n", piCP
);
1044 hr
= ScriptXtoCP(iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piCP
, &piTrailing
);
1045 ok(hr
== S_OK
, "ScriptXtoCP should return S_OK not %08x\n", hr
);
1046 if (piTrailing
) /* win2k3 */
1047 ok(piCP
== -1, "Negative iX should return piCP=-1 not %d\n", piCP
);
1049 ok(piCP
== 10, "Negative iX should return piCP=10 not %d\n", piCP
);
1054 hr
= ScriptXtoCP(iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piCP
, &piTrailing
);
1055 ok(hr
== S_OK
, "ScriptXtoCP should return S_OK not %08x\n", hr
);
1057 piCP
== -1, /* win2k3 */
1058 "iX=%d should return piCP=3 or piCP=-1 not %d\n", iX
, piCP
);
1059 ok(piTrailing
== 1, "iX=%d should return piTrailing=1 not %d\n", iX
, piTrailing
);
1064 hr
= ScriptXtoCP(iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piCP
, &piTrailing
);
1065 ok(hr
== S_OK
, "ScriptXtoCP should return S_OK not %08x\n", hr
);
1067 piCP
== -1, /* win2k3 */
1068 "iX=%d should return piCP=3 or piCP=-1 not %d\n", iX
, piCP
);
1069 ok(piTrailing
== 1, "iX=%d should return piTrailing=1 not %d\n", iX
, piTrailing
);
1074 hr
= ScriptXtoCP(iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piCP
, &piTrailing
);
1075 ok(hr
== S_OK
, "ScriptXtoCP should return S_OK not %08x\n", hr
);
1077 piCP
== -1, /* win2k3 */
1078 "iX=%d should return piCP=4 or piCP=-1 not %d\n", iX
, piCP
);
1083 hr
= ScriptXtoCP(iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piCP
, &piTrailing
);
1084 ok(hr
== S_OK
, "ScriptXtoCP should return S_OK not %08x\n", hr
);
1086 piCP
== 10, /* win2k3 */
1087 "iX=%d should return piCP=0 piCP=10 not %d\n", iX
, piCP
);
1092 hr
= ScriptXtoCP(iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piCP
, &piTrailing
);
1093 ok(hr
== S_OK
, "ScriptXtoCP should return S_OK not %08x\n", hr
);
1094 ok(piCP
== 0, "iX=%d should return piCP=0 not %d\n", iX
, piCP
);
1099 hr
= ScriptXtoCP(iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piCP
, &piTrailing
);
1100 ok(hr
== S_OK
, "ScriptXtoCP should return S_OK not %08x\n", hr
);
1102 piCP
== 0, /* win2k3 */
1103 "iX=%d should return piCP=1 or piCP=0 not %d\n", iX
, piCP
);
1109 hr
= ScriptCPtoX(iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piX
);
1110 ok(hr
== S_OK
, "ScriptCPtoX should return S_OK not %08x\n", hr
);
1112 piX
== 100, /* win2k3 */
1113 "iCP=%d should return piX=976 or piX=100 not %d\n", iCP
, piX
);
1119 hr
= ScriptCPtoX(iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piX
);
1120 ok(hr
== S_OK
, "ScriptCPtoX should return S_OK not %08x\n", hr
);
1122 piX
== 80, /* win2k3 */
1123 "iCP=%d should return piX=1171 or piX=80 not %d\n", iCP
, piX
);
1129 hr
= ScriptCPtoX(iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piX
);
1130 ok(hr
== S_OK
, "ScriptCPtoX should return S_OK not %08x\n", hr
);
1132 piX
== 80, /* win2k3 */
1133 "iCP=%d should return piX=1171 or piX=80 not %d\n", iCP
, piX
);
1139 hr
= ScriptCPtoX(iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piX
);
1140 ok(hr
== S_OK
, "ScriptCPtoX should return S_OK not %08x\n", hr
);
1142 piX
== 0, /* win2k3 */
1143 "iCP=%d should return piX=1953 or piX=0 not %d\n", iCP
, piX
);
1149 hr
= ScriptCPtoX(iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
, &items
[0].a
, &piX
);
1150 ok(hr
== S_OK
, "ScriptCPtoX should return S_OK not %08x\n", hr
);
1152 piX
== 0, /* win2k3 */
1153 "iCP=%d should return piX=1953 or piX=0 not %d\n", iCP
, piX
);
1156 static void test_ScriptString(HDC hdc
)
1158 /*******************************************************************************************
1160 * This set of tests are for the string functions of uniscribe. The ScriptStringAnalyse
1161 * function allocates memory pointed to by the SCRIPT_STRING_ANALYSIS ssa pointer. This
1162 * memory if freed by ScriptStringFree. There needs to be a valid hdc for this as
1163 * ScriptStringAnalyse calls ScriptSItemize, ScriptShape and ScriptPlace which require it.
1168 WCHAR teststr
[] = {'T','e','s','t','1',' ','a','2','b','3', '\0'};
1169 int len
= (sizeof(teststr
) / sizeof(WCHAR
)) - 1;
1170 int Glyphs
= len
* 2 + 16;
1172 DWORD Flags
= SSA_GLYPHS
;
1174 SCRIPT_CONTROL Control
;
1176 const int Dx
[5] = {10, 10, 10, 10, 10};
1177 SCRIPT_TABDEF Tabdef
;
1178 const BYTE InClass
= 0;
1179 SCRIPT_STRING_ANALYSIS ssa
= NULL
;
1184 const RECT rc
= {0, 50, 100, 100};
1187 BOOL Disabled
= FALSE
;
1188 const int *clip_len
;
1193 Charset
= -1; /* this flag indicates unicode input */
1194 /* Test without hdc to get E_PENDING */
1195 hr
= ScriptStringAnalyse( NULL
, teststr
, len
, Glyphs
, Charset
, Flags
,
1196 ReqWidth
, &Control
, &State
, Dx
, &Tabdef
,
1198 ok(hr
== E_PENDING
, "ScriptStringAnalyse Stub should return E_PENDING not %08x\n", hr
);
1200 /* test with hdc, this should be a valid test */
1201 hr
= ScriptStringAnalyse( hdc
, teststr
, len
, Glyphs
, Charset
, Flags
,
1202 ReqWidth
, &Control
, &State
, Dx
, &Tabdef
,
1204 ok(hr
== S_OK
, "ScriptStringAnalyse should return S_OK not %08x\n", hr
);
1205 ScriptStringFree(&ssa
);
1207 /* test makes sure that a call with a valid pssa still works */
1208 hr
= ScriptStringAnalyse( hdc
, teststr
, len
, Glyphs
, Charset
, Flags
,
1209 ReqWidth
, &Control
, &State
, Dx
, &Tabdef
,
1211 ok(hr
== S_OK
, "ScriptStringAnalyse should return S_OK not %08x\n", hr
);
1212 ok(ssa
!= NULL
, "ScriptStringAnalyse pssa should not be NULL\n");
1216 hr
= ScriptStringOut(ssa
, X
, Y
, Options
, &rc
, MinSel
, MaxSel
, Disabled
);
1217 ok(hr
== S_OK
, "ScriptStringOut should return S_OK not %08x\n", hr
);
1220 clip_len
= ScriptString_pcOutChars(ssa
);
1221 ok(*clip_len
== len
, "ScriptString_pcOutChars failed, got %d, expected %d\n", *clip_len
, len
);
1223 order
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *clip_len
* sizeof(UINT
));
1224 hr
= ScriptStringGetOrder(ssa
, order
);
1225 ok(hr
== S_OK
, "ScriptStringGetOrder failed, got %08x, expected S_OK\n", hr
);
1227 for (i
= 0; i
< *clip_len
; i
++) ok(order
[i
] == i
, "%d: got %d expected %d\n", i
, order
[i
], i
);
1228 HeapFree(GetProcessHeap(), 0, order
);
1230 hr
= ScriptStringFree(&ssa
);
1231 ok(hr
== S_OK
, "ScriptStringFree should return S_OK not %08x\n", hr
);
1234 static void test_ScriptStringXtoCP_CPtoX(HDC hdc
)
1236 /*****************************************************************************************
1238 * This test is for the ScriptStringXtoCP and ScriptStringXtoCP functions. Due to the
1239 * nature of the fonts between Windows and Wine, the test is implemented by generating
1240 * values using one one function then checking the output of the second. In this way
1241 * the validity of the functions is established using Windows as a base and confirming
1242 * similar behaviour in wine.
1246 WCHAR teststr1
[] = {'T', 'e', 's', 't', 'e', 'a', 'b', ' ', 'a', '\0'};
1247 void *String
= (WCHAR
*) &teststr1
; /* ScriptStringAnalysis needs void */
1248 int String_len
= (sizeof(teststr1
)/sizeof(WCHAR
))-1;
1249 int Glyphs
= String_len
* 2 + 16; /* size of buffer as recommended */
1250 int Charset
= -1; /* unicode */
1251 DWORD Flags
= SSA_GLYPHS
;
1253 SCRIPT_CONTROL Control
;
1255 SCRIPT_TABDEF Tabdef
;
1256 const BYTE InClass
= 0;
1257 SCRIPT_STRING_ANALYSIS ssa
= NULL
;
1259 int Ch
; /* Character position in string */
1261 int Cp
; /* Character position in string */
1265 /* Test with hdc, this should be a valid test
1266 * Here we generate an SCRIPT_STRING_ANALYSIS that will be used as input to the
1267 * following character positions to X and X to character position functions.
1269 memset(&Control
, 0, sizeof(SCRIPT_CONTROL
));
1270 memset(&State
, 0, sizeof(SCRIPT_STATE
));
1271 memset(&Tabdef
, 0, sizeof(SCRIPT_TABDEF
));
1273 hr
= ScriptStringAnalyse( hdc
, String
, String_len
, Glyphs
, Charset
, Flags
,
1274 ReqWidth
, &Control
, &State
, NULL
, &Tabdef
,
1277 hr
== E_INVALIDARG
, /* NT */
1278 "ScriptStringAnalyse should return S_OK or E_INVALIDARG not %08x\n", hr
);
1282 ok(ssa
!= NULL
, "ScriptStringAnalyse ssa should not be NULL\n");
1285 * Loop to generate character positions to provide starting positions for the
1286 * ScriptStringCPtoX and ScriptStringXtoCP functions
1288 for (Cp
= 0; Cp
< String_len
; Cp
++)
1290 /* The fTrailing flag is used to indicate whether the X being returned is at
1291 * the beginning or the end of the character. What happens here is that if
1292 * fTrailing indicates the end of the character, ie. FALSE, then ScriptStringXtoCP
1293 * returns the beginning of the next character and iTrailing is FALSE. So for this
1294 * loop iTrailing will be FALSE in both cases.
1297 hr
= ScriptStringCPtoX(ssa
, Cp
, fTrailing
, &X
);
1298 ok(hr
== S_OK
, "ScriptStringCPtoX should return S_OK not %08x\n", hr
);
1299 hr
= ScriptStringXtoCP(ssa
, X
, &Ch
, &iTrailing
);
1300 ok(hr
== S_OK
, "ScriptStringXtoCP should return S_OK not %08x\n", hr
);
1301 ok(Cp
== Ch
, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp
, Ch
, X
);
1302 ok(iTrailing
== FALSE
, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
1305 hr
= ScriptStringCPtoX(ssa
, Cp
, fTrailing
, &X
);
1306 ok(hr
== S_OK
, "ScriptStringCPtoX should return S_OK not %08x\n", hr
);
1307 hr
= ScriptStringXtoCP(ssa
, X
, &Ch
, &iTrailing
);
1308 ok(hr
== S_OK
, "ScriptStringXtoCP should return S_OK not %08x\n", hr
);
1311 * Check that character position returned by ScriptStringXtoCP in Ch matches the
1312 * one input to ScriptStringCPtoX. This means that the Cp to X position and back
1315 ok(Cp
+ 1 == Ch
, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp
+ 1, Ch
, X
);
1316 ok(iTrailing
== FALSE
, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
1320 * This test is to check that if the X position is just inside the trailing edge of the
1321 * character then iTrailing will indicate the trailing edge, ie. TRUE
1325 hr
= ScriptStringCPtoX(ssa
, Cp
, fTrailing
, &X
);
1326 ok(hr
== S_OK
, "ScriptStringCPtoX should return S_OK not %08x\n", hr
);
1327 X
--; /* put X just inside the trailing edge */
1328 hr
= ScriptStringXtoCP(ssa
, X
, &Ch
, &iTrailing
);
1329 ok(hr
== S_OK
, "ScriptStringXtoCP should return S_OK not %08x\n", hr
);
1330 ok(Cp
== Ch
, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp
, Ch
, X
);
1331 ok(iTrailing
== TRUE
, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
1335 * This test is to check that if the X position is just outside the trailing edge of the
1336 * character then iTrailing will indicate the leading edge, ie. FALSE, and Ch will indicate
1337 * the next character, ie. Cp + 1
1341 hr
= ScriptStringCPtoX(ssa
, Cp
, fTrailing
, &X
);
1342 ok(hr
== S_OK
, "ScriptStringCPtoX should return S_OK not %08x\n", hr
);
1343 X
++; /* put X just outside the trailing edge */
1344 hr
= ScriptStringXtoCP(ssa
, X
, &Ch
, &iTrailing
);
1345 ok(hr
== S_OK
, "ScriptStringXtoCP should return S_OK not %08x\n", hr
);
1346 ok(Cp
+ 1 == Ch
, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp
+ 1, Ch
, X
);
1347 ok(iTrailing
== FALSE
, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
1351 * This test is to check that if the X position is just outside the leading edge of the
1352 * character then iTrailing will indicate the trailing edge, ie. TRUE, and Ch will indicate
1353 * the next character down , ie. Cp - 1
1357 hr
= ScriptStringCPtoX(ssa
, Cp
, fTrailing
, &X
);
1358 ok(hr
== S_OK
, "ScriptStringCPtoX should return S_OK not %08x\n", hr
);
1359 X
--; /* put X just outside the leading edge */
1360 hr
= ScriptStringXtoCP(ssa
, X
, &Ch
, &iTrailing
);
1361 ok(hr
== S_OK
, "ScriptStringXtoCP should return S_OK not %08x\n", hr
);
1362 ok(Cp
- 1 == Ch
, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp
- 1, Ch
, X
);
1363 ok(iTrailing
== TRUE
, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
1367 * Cleanup the SSA for the next round of tests
1369 hr
= ScriptStringFree(&ssa
);
1370 ok(hr
== S_OK
, "ScriptStringFree should return S_OK not %08x\n", hr
);
1373 * Test to see that exceeding the number of chars returns E_INVALIDARG. First
1374 * generate an SSA for the subsequent tests.
1376 hr
= ScriptStringAnalyse( hdc
, String
, String_len
, Glyphs
, Charset
, Flags
,
1377 ReqWidth
, &Control
, &State
, NULL
, &Tabdef
,
1379 ok(hr
== S_OK
, "ScriptStringAnalyse should return S_OK not %08x\n", hr
);
1382 * When ScriptStringCPtoX is called with a character position Cp that exceeds the
1383 * string length, return E_INVALIDARG. This also invalidates the ssa so a
1384 * ScriptStringFree should also fail.
1387 Cp
= String_len
+ 1;
1388 hr
= ScriptStringCPtoX(ssa
, Cp
, fTrailing
, &X
);
1389 ok(hr
== E_INVALIDARG
, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr
);
1391 hr
= ScriptStringFree(&ssa
);
1393 * ScriptStringCPtoX should free ssa, hence ScriptStringFree should fail
1395 ok(hr
== E_INVALIDARG
||
1396 hr
== E_FAIL
, /* win2k3 */
1397 "ScriptStringFree should return E_INVALIDARG or E_FAIL not %08x\n", hr
);
1401 static void test_ScriptCacheGetHeight(HDC hdc
)
1404 SCRIPT_CACHE sc
= NULL
;
1407 hr
= ScriptCacheGetHeight(NULL
, NULL
, NULL
);
1408 ok(hr
== E_INVALIDARG
, "expected E_INVALIDARG, got 0x%08x\n", hr
);
1410 hr
= ScriptCacheGetHeight(NULL
, &sc
, NULL
);
1411 ok(hr
== E_INVALIDARG
, "expected E_INVALIDARG, got 0x%08x\n", hr
);
1413 hr
= ScriptCacheGetHeight(NULL
, &sc
, &height
);
1414 ok(hr
== E_PENDING
, "expected E_PENDING, got 0x%08x\n", hr
);
1418 hr
= ScriptCacheGetHeight(hdc
, &sc
, &height
);
1419 ok(hr
== S_OK
, "expected S_OK, got 0x%08x\n", hr
);
1420 ok(height
> 0, "expected height > 0\n");
1422 ScriptFreeCache(&sc
);
1425 static void test_ScriptGetGlyphABCWidth(HDC hdc
)
1428 SCRIPT_CACHE sc
= NULL
;
1431 hr
= ScriptGetGlyphABCWidth(NULL
, NULL
, 'a', NULL
);
1432 ok(hr
== E_INVALIDARG
, "expected E_INVALIDARG, got 0x%08x\n", hr
);
1434 hr
= ScriptGetGlyphABCWidth(NULL
, &sc
, 'a', NULL
);
1435 ok(broken(hr
== E_PENDING
) ||
1436 hr
== E_INVALIDARG
, /* WIN7 */
1437 "expected E_INVALIDARG, got 0x%08x\n", hr
);
1439 hr
= ScriptGetGlyphABCWidth(NULL
, &sc
, 'a', &abc
);
1440 ok(hr
== E_PENDING
, "expected E_PENDING, got 0x%08x\n", hr
);
1442 if (0) { /* crashes on WinXP */
1443 hr
= ScriptGetGlyphABCWidth(hdc
, &sc
, 'a', NULL
);
1444 ok(hr
== E_INVALIDARG
, "expected E_INVALIDARG, got 0x%08x\n", hr
);
1447 hr
= ScriptGetGlyphABCWidth(hdc
, &sc
, 'a', &abc
);
1448 ok(hr
== S_OK
, "expected S_OK, got 0x%08x\n", hr
);
1450 ScriptFreeCache(&sc
);
1453 static void test_ScriptLayout(void)
1456 static const BYTE levels
[][10] =
1458 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1459 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1460 { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
1461 { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
1463 { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1},
1464 { 1, 1, 1, 2, 2, 2, 1, 1, 1, 1 },
1465 { 2, 2, 2, 1, 1, 1, 2, 2, 2, 2 },
1466 { 0, 0, 1, 1, 2, 2, 1, 1, 0, 0 },
1467 { 1, 1, 2, 2, 3, 3, 2, 2, 1, 1 },
1469 { 0, 0, 1, 1, 2, 2, 1, 1, 0, 1 },
1470 { 1, 0, 1, 2, 2, 1, 2, 1, 0, 1 },
1472 static const int expect_l2v
[][10] =
1474 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
1475 { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
1476 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
1477 { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
1479 { 0, 1, 2, 3, 4, 9, 8 ,7 ,6, 5},
1480 /**/ { 9, 8, 7, 4, 5, 6, 3 ,2 ,1, 0},
1481 /**/ { 7, 8, 9, 6, 5, 4, 0 ,1 ,2, 3},
1482 { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1483 { 9, 8, 2, 3, 5, 4, 6 ,7 ,1, 0},
1485 { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1486 /**/ { 0, 1, 7, 5, 6, 4, 3 ,2 ,8, 9},
1488 static const int expect_v2l
[][10] =
1490 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
1491 { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
1492 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
1493 { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
1495 { 0, 1, 2, 3, 4, 9, 8 ,7 ,6, 5},
1496 { 9, 8, 7, 6, 3, 4, 5 ,2 ,1, 0},
1497 { 6, 7, 8, 9, 5, 4, 3 ,0 ,1, 2},
1498 { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1499 { 9, 8, 2, 3, 5, 4, 6 ,7 ,1, 0},
1501 { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1502 { 0, 1, 7, 6, 5, 3, 4 ,2 ,8, 9},
1505 int i
, j
, vistolog
[sizeof(levels
[0])], logtovis
[sizeof(levels
[0])];
1507 hr
= ScriptLayout(sizeof(levels
[0]), NULL
, vistolog
, logtovis
);
1508 ok(hr
== E_INVALIDARG
, "expected E_INVALIDARG, got 0x%08x\n", hr
);
1510 hr
= ScriptLayout(sizeof(levels
[0]), levels
[0], NULL
, NULL
);
1511 ok(hr
== E_INVALIDARG
, "expected E_INVALIDARG, got 0x%08x\n", hr
);
1513 for (i
= 0; i
< sizeof(levels
)/sizeof(levels
[0]); i
++)
1515 hr
= ScriptLayout(sizeof(levels
[0]), levels
[i
], vistolog
, logtovis
);
1516 ok(hr
== S_OK
, "expected S_OK, got 0x%08x\n", hr
);
1518 for (j
= 0; j
< sizeof(levels
[i
]); j
++)
1520 ok(expect_v2l
[i
][j
] == vistolog
[j
],
1521 "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n",
1522 i
, j
, levels
[i
][j
], j
, vistolog
[j
] );
1525 for (j
= 0; j
< sizeof(levels
[i
]); j
++)
1527 ok(expect_l2v
[i
][j
] == logtovis
[j
],
1528 "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n",
1529 i
, j
, levels
[i
][j
], j
, logtovis
[j
] );
1534 static BOOL CALLBACK
enum_proc(LGRPID group
, LCID lcid
, LPSTR locale
, LONG_PTR lparam
)
1537 SCRIPT_DIGITSUBSTITUTE sds
;
1542 if (!IsValidLocale(lcid
, LCID_INSTALLED
)) return TRUE
;
1544 memset(&sds
, 0, sizeof(sds
));
1545 memset(&sc
, 0, sizeof(sc
));
1546 memset(&ss
, 0, sizeof(ss
));
1548 lcid_old
= GetThreadLocale();
1549 if (!SetThreadLocale(lcid
)) return TRUE
;
1551 hr
= ScriptRecordDigitSubstitution(lcid
, &sds
);
1552 ok(hr
== S_OK
, "ScriptRecordDigitSubstitution failed: 0x%08x\n", hr
);
1554 hr
= ScriptApplyDigitSubstitution(&sds
, &sc
, &ss
);
1555 ok(hr
== S_OK
, "ScriptApplyDigitSubstitution failed: 0x%08x\n", hr
);
1557 SetThreadLocale(lcid_old
);
1561 static void test_digit_substitution(void)
1565 static const LGRPID groups
[] =
1567 LGRPID_WESTERN_EUROPE
,
1568 LGRPID_CENTRAL_EUROPE
,
1575 LGRPID_TRADITIONAL_CHINESE
,
1576 LGRPID_SIMPLIFIED_CHINESE
,
1586 static BOOL (WINAPI
* pEnumLanguageGroupLocalesA
)(LANGGROUPLOCALE_ENUMPROCA
,LGRPID
,DWORD
,LONG_PTR
);
1588 hKernel32
= GetModuleHandleA("kernel32.dll");
1589 pEnumLanguageGroupLocalesA
= (void*)GetProcAddress(hKernel32
, "EnumLanguageGroupLocalesA");
1591 if (!pEnumLanguageGroupLocalesA
)
1593 win_skip("EnumLanguageGroupLocalesA not available on this platform\n");
1597 for (i
= 0; i
< sizeof(groups
)/sizeof(groups
[0]); i
++)
1599 ret
= pEnumLanguageGroupLocalesA(enum_proc
, groups
[i
], 0, 0);
1600 if (!ret
&& GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
1602 win_skip("EnumLanguageGroupLocalesA not implemented on this platform\n");
1606 ok(ret
, "EnumLanguageGroupLocalesA failed unexpectedly: %u\n", GetLastError());
1610 static void test_ScriptGetProperties(void)
1612 const SCRIPT_PROPERTIES
**props
;
1616 hr
= ScriptGetProperties(NULL
, NULL
);
1617 ok(hr
== E_INVALIDARG
, "ScriptGetProperties succeeded\n");
1619 hr
= ScriptGetProperties(NULL
, &num
);
1620 ok(hr
== S_OK
, "ScriptGetProperties failed: 0x%08x\n", hr
);
1622 hr
= ScriptGetProperties(&props
, NULL
);
1623 ok(hr
== S_OK
, "ScriptGetProperties failed: 0x%08x\n", hr
);
1625 hr
= ScriptGetProperties(&props
, &num
);
1626 ok(hr
== S_OK
, "ScriptGetProperties failed: 0x%08x\n", hr
);
1629 static void test_ScriptBreak(void)
1631 static const WCHAR test
[] = {' ','\r','\n',0};
1632 SCRIPT_ITEM items
[4];
1636 hr
= ScriptItemize(test
, 3, 4, NULL
, NULL
, items
, NULL
);
1637 ok(!hr
, "ScriptItemize should return S_OK not %08x\n", hr
);
1639 memset(&la
, 0, sizeof(la
));
1640 hr
= ScriptBreak(test
, 1, &items
[0].a
, &la
);
1641 ok(!hr
, "ScriptBreak should return S_OK not %08x\n", hr
);
1643 ok(!la
.fSoftBreak
, "fSoftBreak set\n");
1644 ok(la
.fWhiteSpace
, "fWhiteSpace not set\n");
1645 ok(la
.fCharStop
, "fCharStop not set\n");
1646 ok(!la
.fWordStop
, "fWordStop set\n");
1647 ok(!la
.fInvalid
, "fInvalid set\n");
1648 ok(!la
.fReserved
, "fReserved set\n");
1650 memset(&la
, 0, sizeof(la
));
1651 hr
= ScriptBreak(test
+ 1, 1, &items
[1].a
, &la
);
1652 ok(!hr
, "ScriptBreak should return S_OK not %08x\n", hr
);
1654 ok(!la
.fSoftBreak
, "fSoftBreak set\n");
1655 ok(!la
.fWhiteSpace
, "fWhiteSpace set\n");
1656 ok(la
.fCharStop
, "fCharStop not set\n");
1657 ok(!la
.fWordStop
, "fWordStop set\n");
1658 ok(!la
.fInvalid
, "fInvalid set\n");
1659 ok(!la
.fReserved
, "fReserved set\n");
1661 memset(&la
, 0, sizeof(la
));
1662 hr
= ScriptBreak(test
+ 2, 1, &items
[2].a
, &la
);
1663 ok(!hr
, "ScriptBreak should return S_OK not %08x\n", hr
);
1665 ok(!la
.fSoftBreak
, "fSoftBreak set\n");
1666 ok(!la
.fWhiteSpace
, "fWhiteSpace set\n");
1667 ok(la
.fCharStop
, "fCharStop not set\n");
1668 ok(!la
.fWordStop
, "fWordStop set\n");
1669 ok(!la
.fInvalid
, "fInvalid set\n");
1670 ok(!la
.fReserved
, "fReserved set\n");
1673 static void test_newlines(void)
1675 static const WCHAR test1
[] = {'t','e','x','t','\r','t','e','x','t',0};
1676 static const WCHAR test2
[] = {'t','e','x','t','\n','t','e','x','t',0};
1677 static const WCHAR test3
[] = {'t','e','x','t','\r','\n','t','e','x','t',0};
1678 static const WCHAR test4
[] = {'t','e','x','t','\n','\r','t','e','x','t',0};
1679 static const WCHAR test5
[] = {'1','2','3','4','\n','\r','1','2','3','4',0};
1680 SCRIPT_ITEM items
[5];
1685 hr
= ScriptItemize(test1
, lstrlenW(test1
), 5, NULL
, NULL
, items
, &count
);
1686 ok(hr
== S_OK
, "ScriptItemize failed: 0x%08x\n", hr
);
1687 ok(count
== 3, "got %d expected 3\n", count
);
1690 hr
= ScriptItemize(test2
, lstrlenW(test2
), 5, NULL
, NULL
, items
, &count
);
1691 ok(hr
== S_OK
, "ScriptItemize failed: 0x%08x\n", hr
);
1692 ok(count
== 3, "got %d expected 3\n", count
);
1695 hr
= ScriptItemize(test3
, lstrlenW(test3
), 5, NULL
, NULL
, items
, &count
);
1696 ok(hr
== S_OK
, "ScriptItemize failed: 0x%08x\n", hr
);
1697 ok(count
== 4, "got %d expected 4\n", count
);
1700 hr
= ScriptItemize(test4
, lstrlenW(test4
), 5, NULL
, NULL
, items
, &count
);
1701 ok(hr
== S_OK
, "ScriptItemize failed: 0x%08x\n", hr
);
1702 ok(count
== 4, "got %d expected 4\n", count
);
1705 hr
= ScriptItemize(test5
, lstrlenW(test5
), 5, NULL
, NULL
, items
, &count
);
1706 ok(hr
== S_OK
, "ScriptItemize failed: 0x%08x\n", hr
);
1707 ok(count
== 4, "got %d expected 4\n", count
);
1717 unsigned short pwOutGlyphs
[256];
1719 /* We need a valid HDC to drive a lot of Script functions which requires the following *
1720 * to set up for the tests. */
1721 hwnd
= CreateWindowExA(0, "static", "", WS_POPUP
, 0,0,100,100,
1724 ShowWindow(hwnd
, SW_SHOW
);
1727 hdc
= GetDC(hwnd
); /* We now have a hdc */
1728 ok( hdc
!= NULL
, "HDC failed to be created %p\n", hdc
);
1730 memset(&lf
, 0, sizeof(LOGFONTA
));
1731 lstrcpyA(lf
.lfFaceName
, "Tahoma");
1736 hfont
= SelectObject(hdc
, CreateFontIndirectA(&lf
));
1737 ok(hfont
!= NULL
, "SelectObject failed: %p\n", hfont
);
1739 test_ScriptItemize();
1740 test_ScriptItemIzeShapePlace(hdc
,pwOutGlyphs
);
1741 test_ScriptGetCMap(hdc
, pwOutGlyphs
);
1742 test_ScriptCacheGetHeight(hdc
);
1743 test_ScriptGetGlyphABCWidth(hdc
);
1744 test_ScriptShape(hdc
);
1745 test_ScriptPlace(hdc
);
1747 test_ScriptGetFontProperties(hdc
);
1748 test_ScriptTextOut(hdc
);
1749 test_ScriptTextOut2(hdc
);
1750 test_ScriptTextOut3(hdc
);
1752 test_ScriptString(hdc
);
1753 test_ScriptStringXtoCP_CPtoX(hdc
);
1755 test_ScriptLayout();
1756 test_digit_substitution();
1757 test_ScriptGetProperties();
1761 ReleaseDC(hwnd
, hdc
);
1762 DestroyWindow(hwnd
);