usp10: Add Thai shaping test.
[wine] / dlls / usp10 / tests / usp10.c
1 /*
2  * Tests for usp10 dll
3  *
4  * Copyright 2006 Jeff Latimer
5  * Copyright 2006 Hans Leidekker
6  * Copyright 2010 CodeWeavers, Aric Stewart
7  *
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.
12  *
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.
17  *
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
21  *
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.
25  */
26
27 #include <assert.h>
28 #include <stdio.h>
29
30 #include <wine/test.h>
31 #include <windows.h>
32 #include <usp10.h>
33
34 typedef struct _itemTest {
35     char todo_flag[5];
36     int iCharPos;
37     int fRTL;
38     int fLayoutRTL;
39     int uBidiLevel;
40     ULONG scriptTag;
41 } itemTest;
42
43 typedef struct _shapeTest_char {
44     WORD wLogClust;
45     SCRIPT_CHARPROP CharProp;
46 } shapeTest_char;
47
48 typedef struct _shapeTest_glyph {
49     int Glyph;
50     SCRIPT_GLYPHPROP GlyphProp;
51 } shapeTest_glyph;
52
53 /* Uniscribe 1.6 calls */
54 static HRESULT (WINAPI *pScriptItemizeOpenType)( const WCHAR *pwcInChars, int cInChars, int cMaxItems, const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState, SCRIPT_ITEM *pItems, ULONG *pScriptTags, int *pcItems);
55
56 static HRESULT (WINAPI *pScriptShapeOpenType)( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties, int cRanges, const WCHAR *pwcChars, int cChars, int cMaxGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs, SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs);
57
58 static inline void _test_items_ok(LPCWSTR string, DWORD cchString,
59                          SCRIPT_CONTROL *Control, SCRIPT_STATE *State,
60                          DWORD nItems, const itemTest* items, BOOL nItemsToDo,
61                          INT nItemsBroken)
62 {
63     HRESULT hr;
64     int x, outnItems;
65     SCRIPT_ITEM outpItems[15];
66     ULONG tags[15] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
67
68     if (pScriptItemizeOpenType)
69         hr = pScriptItemizeOpenType(string, cchString, 15, Control, State, outpItems, tags, &outnItems);
70     else
71         hr = ScriptItemize(string, cchString, 15, Control, State, outpItems, &outnItems);
72
73     winetest_ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
74     if (nItemsBroken && broken(nItemsBroken == outnItems))
75     {
76         winetest_win_skip("This test broken on this platform\n");
77         return;
78     }
79     if (nItemsToDo)
80         todo_wine winetest_ok(outnItems == nItems, "Wrong number of items\n");
81     else
82         winetest_ok(outnItems == nItems, "Wrong number of items\n");
83     for (x = 0; x <= outnItems; x++)
84     {
85         if (items[x].todo_flag[0])
86             todo_wine winetest_ok(outpItems[x].iCharPos == items[x].iCharPos, "%i:Wrong CharPos\n",x);
87         else
88             winetest_ok(outpItems[x].iCharPos == items[x].iCharPos, "%i:Wrong CharPos (%i)\n",x,outpItems[x].iCharPos);
89
90         if (items[x].todo_flag[1])
91             todo_wine winetest_ok(outpItems[x].a.fRTL == items[x].fRTL, "%i:Wrong fRTL\n",x);
92         else
93             winetest_ok(outpItems[x].a.fRTL == items[x].fRTL, "%i:Wrong fRTL(%i)\n",x,outpItems[x].a.fRTL);
94         if (items[x].todo_flag[2])
95             todo_wine winetest_ok(outpItems[x].a.fLayoutRTL == items[x].fLayoutRTL, "%i:Wrong fLayoutRTL\n",x);
96         else
97             winetest_ok(outpItems[x].a.fLayoutRTL == items[x].fLayoutRTL, "%i:Wrong fLayoutRTL(%i)\n",x,outpItems[x].a.fLayoutRTL);
98         if (items[x].todo_flag[3])
99             todo_wine winetest_ok(outpItems[x].a.s.uBidiLevel == items[x].uBidiLevel, "%i:Wrong BidiLevel\n",x);
100         else
101             winetest_ok(outpItems[x].a.s.uBidiLevel == items[x].uBidiLevel, "%i:Wrong BidiLevel(%i)\n",x,outpItems[x].a.s.uBidiLevel);
102         if (x != outnItems)
103             winetest_ok(outpItems[x].a.eScript != SCRIPT_UNDEFINED, "%i: Undefined script\n",x);
104         if (pScriptItemizeOpenType)
105         {
106             if (items[x].todo_flag[4])
107                 todo_wine winetest_ok(tags[x] == items[x].scriptTag,"%i:Incorrect Script Tag %x != %x\n",x,tags[x],items[x].scriptTag);
108             else
109                 winetest_ok(tags[x] == items[x].scriptTag,"%i:Incorrect Script Tag %x != %x\n",x,tags[x],items[x].scriptTag);
110         }
111     }
112 }
113
114 #define test_items_ok(a,b,c,d,e,f,g,h) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _test_items_ok(a,b,c,d,e,f,g,h)
115
116 #define MS_MAKE_TAG( _x1, _x2, _x3, _x4 ) \
117           ( ( (ULONG)_x4 << 24 ) |     \
118             ( (ULONG)_x3 << 16 ) |     \
119             ( (ULONG)_x2 <<  8 ) |     \
120               (ULONG)_x1         )
121
122 #define latn_tag MS_MAKE_TAG('l','a','t','n')
123 #define arab_tag MS_MAKE_TAG('a','r','a','b')
124 #define thai_tag MS_MAKE_TAG('t','h','a','i')
125 #define hebr_tag MS_MAKE_TAG('h','e','b','r')
126 #define syrc_tag MS_MAKE_TAG('s','y','r','c')
127
128 static void test_ScriptItemize( void )
129 {
130     static const WCHAR test1[] = {'t', 'e', 's', 't',0};
131     static const itemTest t11[2] = {{{0,0,0,0,0},0,0,0,0,latn_tag},{{0,0,0,0,0},4,0,0,0,-1}};
132     static const itemTest t12[2] = {{{0,0,0,0,0},0,0,0,2,latn_tag},{{0,0,0,0,0},4,0,0,0,-1}};
133
134     static const WCHAR test1b[] = {' ', ' ', ' ', ' ',0};
135     static const itemTest t1b1[2] = {{{0,0,0,0,0},0,0,0,0,0},{{0,0,0,0,0},4,0,0,0,-1}};
136     static const itemTest t1b2[2] = {{{0,0,0,0,0},0,1,1,1,0},{{0,0,0,0,0},4,0,0,0,-1}};
137
138     /* Arabic, English*/
139     static const WCHAR test2[] = {'1','2','3','-','5','2',0x064a,0x064f,0x0633,0x0627,0x0648,0x0650,0x064a,'7','1','.',0};
140     static const itemTest t21[7] = {{{0,0,0,0,0},0,0,0,0,0},{{0,0,0,0,0},3,0,0,0,0},{{0,0,0,0,0},4,0,0,0,0},{{0,0,0,0,0},6,1,1,1,arab_tag},{{0,0,0,0,0},13,0,0,0,0},{{0,0,0,0,0},15,0,0,0,0},{{0,0,0,0,0},16,0,0,0,-1}};
141     static const itemTest t22[5] = {{{0,0,0,1,0},0,0,0,2,0},{{0,0,0,0,0},6,1,1,1,arab_tag},{{0,0,1,0,0},13,0,1,2,0},{{0,0,0,0,0},15,0,0,0,0},{{0,0,0,0,0},16,0,0,0,-1}};
142     static const itemTest t23[5] = {{{0,0,1,0,0},0,0,1,2,0},{{0,0,0,0,0},6,1,1,1,arab_tag},{{0,0,1,0,0},13,0,1,2,0},{{0,0,0,0,0},15,1,1,1,0},{{0,0,0,0,0},16,0,0,0,-1}};
143
144     static const WCHAR test2b[] = {'A','B','C','-','D','E','F',' ',0x0621,0x0623,0x0624,0};
145     static const itemTest t2b1[5] = {{{0,0,0,0,0},0,0,0,0,latn_tag},{{0,0,0,0,0},3,0,0,0,0},{{0,0,0,0,0},4,0,0,0,latn_tag},{{0,0,0,0,0},8,1,1,1,arab_tag},{{0,0,0,0,0},11,0,0,0,-1}};
146     static const itemTest t2b2[5] = {{{0,0,0,0,0},0,0,0,2,latn_tag},{{0,0,0,0,0},3,0,0,2,0},{{0,0,0,0,0},4,0,0,2,latn_tag},{{0,0,0,0,0},7,1,1,1,arab_tag},{{0,0,0,0,0},11,0,0,0,-1}};
147     static const itemTest t2b3[3] = {{{0,0,0,0,0},0,0,0,2,latn_tag},{{0,0,0,0,0},7,1,1,1,arab_tag},{{0,0,0,0,0},11,0,0,0,-1}};
148
149     /* leading space */
150     static const WCHAR test2c[] = {' ',0x0621,0x0623,0x0624,'A','B','C','-','D','E','F',0};
151     static const itemTest t2c1[5] = {{{0,0,0,0,0},0,1,1,1,arab_tag},{{0,0,0,0,0},4,0,0,0,latn_tag},{{0,0,0,0,0},7,0,0,0,0},{{0,0,0,0,0},8,0,0,0,latn_tag},{{0,0,0,0,0},11,0,0,0,-1}};
152     static const itemTest t2c2[6] = {{{0,0,0,0,1},0,0,0,0,0},{{0,0,0,0,0},1,1,1,1,arab_tag},{{0,0,0,0,0},4,0,0,0,latn_tag},{{0,0,0,0,0},7,0,0,0,0},{{0,0,0,0,0},8,0,0,0,latn_tag},{{0,0,0,0,0},11,0,0,0,-1}};
153     static const itemTest t2c3[5] = {{{0,0,0,0,0},0,1,1,1,arab_tag},{{0,0,0,0,0},4,0,0,2,latn_tag},{{0,0,0,0,0},7,0,0,2,0},{{0,0,0,0,0},8,0,0,2,latn_tag},{{0,0,0,0,0},11,0,0,0,-1}};
154     static const itemTest t2c4[3] = {{{0,0,0,0,0},0,1,1,1,arab_tag},{{0,0,0,0,0},4,0,0,2,latn_tag},{{0,0,0,0,0},11,0,0,0,-1}};
155
156     /* trailing space */
157     static const WCHAR test2d[] = {'A','B','C','-','D','E','F',0x0621,0x0623,0x0624,' ',0};
158     static const itemTest t2d1[5] = {{{0,0,0,0,0},0,0,0,0,latn_tag},{{0,0,0,0,0},3,0,0,0,0},{{0,0,0,0,0},4,0,0,0,latn_tag},{{0,0,0,0,0},7,1,1,1,arab_tag},{{0,0,0,0,0},11,0,0,0,-1}};
159     static const itemTest t2d2[6] = {{{0,0,0,0,0},0,0,0,0,latn_tag},{{0,0,0,0,0},3,0,0,0,0},{{0,0,0,0,0},4,0,0,0,latn_tag},{{0,0,0,0,0},7,1,1,1,arab_tag},{{0,0,0,0,0},10,0,0,0,0},{{0,0,0,0,0},11,0,0,0,-1}};
160     static const itemTest t2d3[5] = {{{0,0,0,0,0},0,0,0,2,latn_tag},{{0,0,0,0,0},3,0,0,2,0},{{0,0,0,0,0},4,0,0,2,latn_tag},{{0,0,0,0,0},7,1,1,1,arab_tag},{{0,0,0,0,0},11,0,0,0,-1}};
161     static const itemTest t2d4[3] = {{{0,0,0,0,0},0,0,0,2,latn_tag},{{0,0,0,0,0},7,1,1,1,arab_tag},{{0,0,0,0,0},11,0,0,0,-1}};
162
163     /* Thai */
164     static const WCHAR test3[] =
165 {0x0e04,0x0e27,0x0e32,0x0e21,0x0e1e,0x0e22,0x0e32,0x0e22,0x0e32, 0x0e21
166 ,0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e44,0x0e2b,0x0e19
167 ,0x0e04,0x0e27,0x0e32,0x0e21,0x0e2a, 0x0e33,0x0e40,0x0e23,0x0e47,0x0e08,
168  0x0e2d,0x0e22,0x0e39,0x0e48,0x0e17,0x0e35,0x0e48,0x0e19,0x0e31,0x0e48,0x0e19,0};
169
170     static const itemTest t31[2] = {{{0,0,0,0,0},0,0,0,0,thai_tag},{{0,0,0,0,0},41,0,0,0,-1}};
171     static const itemTest t32[2] = {{{0,0,0,0,0},0,0,0,2,thai_tag},{{0,0,0,0,0},41,0,0,0,-1}};
172
173     static const WCHAR test4[]  = {'1','2','3','-','5','2',' ','i','s',' ','7','1','.',0};
174
175     static const itemTest t41[6] = {{{0,0,0,0,0},0,0,0,0,0},{{0,0,0,0,0},3,0,0,0,0},{{0,0,0,0,0},4,0,0,0,0},{{0,0,0,0,0},7,0,0,0,latn_tag},{{0,0,0,0,0},10,0,0,0,0},{{0,0,0,0,0},12,0,0,0,-1}};
176     static const itemTest t42[5] = {{{0,0,1,0,0},0,0,1,2,0},{{0,0,0,0,1},6,1,1,1,0},{{0,0,0,0,0},7,0,0,2,latn_tag},{{0,0,0,0,0},10,0,0,2,0},{{0,0,0,0,0},12,0,0,0,-1}};
177     static const itemTest t43[4] = {{{0,0,1,0,0},0,0,1,2,0},{{0,0,0,0,1},6,1,1,1,0},{{0,0,0,0,0},7,0,0,2,latn_tag},{{0,0,0,0,0},12,0,0,0,-1}};
178
179     /* Arabic */
180     static const WCHAR test5[]  =
181 {0x0627,0x0644,0x0635,0x0651,0x0650,0x062d,0x0629,0x064f,' ',0x062a,0x064e,
182 0x0627,0x062c,0x064c,' ',0x0639,0x064e,0x0644,0x0649,' ',
183 0x0631,0x064f,0x0624,0x0648,0x0633,0x0650,' ',0x0627,0x0644
184 ,0x0623,0x0635,0x0650,0x062d,0x0651,0x064e,0x0627,0x0621,0x0650,0};
185     static const itemTest t51[2] = {{{0,0,0,0,0},0,1,1,1,arab_tag},{{0,0,0,0,0},38,0,0,0,-1}};
186
187     /* Hebrew */
188     static const WCHAR test6[]  = {0x05e9, 0x05dc, 0x05d5, 0x05dd, '.',0};
189     static const itemTest t61[3] = {{{0,0,0,0,0},0,1,1,1,hebr_tag},{{0,0,0,0,0},4,0,0,0,0},{{0,0,0,0,0},5,0,0,0,-1}};
190     static const itemTest t62[3] = {{{0,0,0,0,0},0,1,1,1,hebr_tag},{{0,0,0,0,0},4,1,1,1,0},{{0,0,0,0,0},5,0,0,0,-1}};
191     static const itemTest t63[2] = {{{0,0,0,0,0},0,1,1,1,hebr_tag},{{0,0,0,0,0},5,0,0,0,-1}};
192     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};
193     static const itemTest t71[4] = {{{0,0,0,0,0},0,0,0,0,latn_tag},{{0,0,0,0,0},9,1,1,1,hebr_tag},{{0,0,0,0,0},19,0,0,0,latn_tag},{{0,0,0,0,0},29,0,0,0,-1}};
194     static const itemTest t72[4] = {{{0,0,0,0,0},0,0,0,0,latn_tag},{{0,0,0,0,0},9,1,1,1,hebr_tag},{{0,0,0,0,0},18,0,0,0,latn_tag},{{0,0,0,0,0},29,0,0,0,-1}};
195     static const itemTest t73[4] = {{{0,0,0,0,0},0,0,0,2,latn_tag},{{0,0,0,0,0},8,1,1,1,hebr_tag},{{0,0,0,0,0},19,0,0,2,latn_tag},{{0,0,0,0,0},29,0,0,0,-1}};
196     static const WCHAR test8[] = {0x0633, 0x0644, 0x0627, 0x0645,0};
197     static const itemTest t81[2] = {{{0,0,0,0,0},0,1,1,1,arab_tag},{{0,0,0,0,0},4,0,0,0,-1}};
198
199     /* Syriac  (Like Arabic )*/
200     static const WCHAR test9[] = {0x0710, 0x0712, 0x0712, 0x0714, '.',0};
201     static const itemTest t91[3] = {{{0,0,0,0,0},0,1,1,1,syrc_tag},{{0,0,0,0,0},4,0,0,0,0},{{0,0,0,0,0},5,0,0,0,-1}};
202     static const itemTest t92[3] = {{{0,0,0,0,0},0,1,1,1,syrc_tag},{{0,0,0,0,0},4,1,1,1,0},{{0,0,0,0,0},5,0,0,0,-1}};
203     static const itemTest t93[2] = {{{0,0,0,0,0},0,1,1,1,syrc_tag},{{0,0,0,0,0},5,0,0,0,-1}};
204
205     static const WCHAR test10[] = {0x0717, 0x0718, 0x071a, 0x071b,0};
206     static const itemTest t101[2] = {{{0,0,0,0,0},0,1,1,1,syrc_tag},{{0,0,0,0,0},4,0,0,0,-1}};
207
208     SCRIPT_ITEM items[15];
209     SCRIPT_CONTROL  Control;
210     SCRIPT_STATE    State;
211     HRESULT hr;
212     HMODULE usp10;
213     int nItems;
214
215     usp10 = LoadLibraryA("usp10.dll");
216     ok (usp10 != 0,"Unable to LoadLibrary on usp10.dll\n");
217     pScriptItemizeOpenType = (void*)GetProcAddress(usp10, "ScriptItemizeOpenType");
218     pScriptShapeOpenType = (void*)GetProcAddress(usp10, "ScriptShapeOpenType");
219
220     memset(&Control, 0, sizeof(Control));
221     memset(&State, 0, sizeof(State));
222
223     hr = ScriptItemize(NULL, 4, 10, &Control, &State, items, NULL);
224     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pwcInChars is NULL\n");
225
226     hr = ScriptItemize(test1, 4, 10, &Control, &State, NULL, NULL);
227     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if pItems is NULL\n");
228
229     hr = ScriptItemize(test1, 4, 1, &Control, &State, items, NULL);
230     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cMaxItems < 2.\n");
231
232     hr = ScriptItemize(test1, 0, 10, NULL, NULL, items, &nItems);
233     ok (hr == E_INVALIDARG, "ScriptItemize should return E_INVALIDARG if cInChars is 0\n");
234
235     test_items_ok(test1,4,NULL,NULL,1,t11,FALSE,0);
236     test_items_ok(test1b,4,NULL,NULL,1,t1b1,FALSE,0);
237     test_items_ok(test2,16,NULL,NULL,6,t21,FALSE,0);
238     test_items_ok(test2b,11,NULL,NULL,4,t2b1,FALSE,0);
239     test_items_ok(test2c,11,NULL,NULL,4,t2c1,FALSE,0);
240     test_items_ok(test2d,11,NULL,NULL,4,t2d1,FALSE,0);
241     test_items_ok(test3,41,NULL,NULL,1,t31,FALSE,0);
242     test_items_ok(test4,12,NULL,NULL,5,t41,FALSE,0);
243     test_items_ok(test5,38,NULL,NULL,1,t51,FALSE,0);
244     test_items_ok(test6,5,NULL,NULL,2,t61,FALSE,0);
245     test_items_ok(test7,29,NULL,NULL,3,t71,FALSE,0);
246     test_items_ok(test8,4,NULL,NULL,1,t81,FALSE,0);
247     test_items_ok(test9,5,NULL,NULL,2,t91,FALSE,0);
248     test_items_ok(test10,4,NULL,NULL,1,t101,FALSE,0);
249
250     State.uBidiLevel = 0;
251     test_items_ok(test1,4,&Control,&State,1,t11,FALSE,0);
252     test_items_ok(test1b,4,&Control,&State,1,t1b1,FALSE,0);
253     test_items_ok(test2,16,&Control,&State,4,t22,FALSE,0);
254     test_items_ok(test2b,11,&Control,&State,4,t2b1,FALSE,0);
255     test_items_ok(test2c,11,&Control,&State,5,t2c2,FALSE,0);
256     test_items_ok(test2d,11,&Control,&State,5,t2d2,FALSE,0);
257     test_items_ok(test3,41,&Control,&State,1,t31,FALSE,0);
258     test_items_ok(test4,12,&Control,&State,5,t41,FALSE,0);
259     test_items_ok(test5,38,&Control,&State,1,t51,FALSE,0);
260     test_items_ok(test6,5,&Control,&State,2,t61,FALSE,0);
261     test_items_ok(test7,29,&Control,&State,3,t72,FALSE,0);
262     test_items_ok(test8,4,&Control,&State,1,t81,FALSE,0);
263     test_items_ok(test9,5,&Control,&State,2,t91,FALSE,0);
264     test_items_ok(test10,4,&Control,&State,1,t101,FALSE,0);
265
266     State.uBidiLevel = 1;
267     test_items_ok(test1,4,&Control,&State,1,t12,FALSE,0);
268     test_items_ok(test1b,4,&Control,&State,1,t1b2,FALSE,0);
269     test_items_ok(test2,16,&Control,&State,4,t23,FALSE,0);
270     test_items_ok(test2b,11,&Control,&State,4,t2b2,FALSE,0);
271     test_items_ok(test2c,11,&Control,&State,4,t2c3,FALSE,0);
272     test_items_ok(test2d,11,&Control,&State,4,t2d3,FALSE,0);
273     test_items_ok(test3,41,&Control,&State,1,t32,FALSE,0);
274     test_items_ok(test4,12,&Control,&State,4,t42,FALSE,0);
275     test_items_ok(test5,38,&Control,&State,1,t51,FALSE,0);
276     test_items_ok(test6,5,&Control,&State,2,t62,FALSE,0);
277     test_items_ok(test7,29,&Control,&State,3,t73,FALSE,0);
278     test_items_ok(test8,4,&Control,&State,1,t81,FALSE,0);
279     test_items_ok(test9,5,&Control,&State,2,t92,FALSE,0);
280     test_items_ok(test10,4,&Control,&State,1,t101,FALSE,0);
281
282     State.uBidiLevel = 1;
283     Control.fMergeNeutralItems = TRUE;
284     test_items_ok(test1,4,&Control,&State,1,t12,FALSE,0);
285     test_items_ok(test1b,4,&Control,&State,1,t1b2,FALSE,0);
286     test_items_ok(test2,16,&Control,&State,4,t23,FALSE,0);
287     test_items_ok(test2b,11,&Control,&State,2,t2b3,FALSE,4);
288     test_items_ok(test2c,11,&Control,&State,2,t2c4,FALSE,4);
289     test_items_ok(test2d,11,&Control,&State,2,t2d4,FALSE,4);
290     test_items_ok(test3,41,&Control,&State,1,t32,FALSE,0);
291     test_items_ok(test4,12,&Control,&State,3,t43,FALSE,4);
292     test_items_ok(test5,38,&Control,&State,1,t51,FALSE,0);
293     test_items_ok(test6,5,&Control,&State,1,t63,FALSE,2);
294     test_items_ok(test7,29,&Control,&State,3,t73,FALSE,0);
295     test_items_ok(test8,4,&Control,&State,1,t81,FALSE,0);
296     test_items_ok(test9,5,&Control,&State,1,t93,FALSE,2);
297     test_items_ok(test10,4,&Control,&State,1,t101,FALSE,0);
298 }
299
300 static inline void _test_shape_ok(int valid, HDC hdc, LPCWSTR string,
301                          DWORD cchString, SCRIPT_CONTROL *Control,
302                          SCRIPT_STATE *State, DWORD item, DWORD nGlyphs,
303                          const shapeTest_char* charItems,
304                          const shapeTest_glyph* glyphItems)
305 {
306     HRESULT hr;
307     int x, outnItems=0, outnGlyphs=0;
308     SCRIPT_ITEM outpItems[15];
309     SCRIPT_CACHE sc = NULL;
310     WORD *glyphs;
311     WORD *logclust;
312     int maxGlyphs = cchString * 1.5;
313     SCRIPT_GLYPHPROP *glyphProp;
314     SCRIPT_CHARPROP  *charProp;
315     ULONG tags[15];
316
317     hr = pScriptItemizeOpenType(string, cchString, 15, Control, State, outpItems, tags, &outnItems);
318     if (hr == USP_E_SCRIPT_NOT_IN_FONT)
319     {
320         if (valid > 0)
321             winetest_win_skip("Select font does not support script\n");
322         else
323             winetest_trace("Select font does not support script\n");
324         return;
325     }
326     if (valid > 0)
327         winetest_ok(!hr, "ScriptItemizeOpenType should return S_OK not %08x\n", hr);
328     else if (hr)
329         winetest_trace("ScriptItemizeOpenType should return S_OK not %08x\n", hr);
330
331
332     if (outnItems <= item)
333     {
334         if (valid > 0)
335             winetest_win_skip("Did not get enough items\n");
336         else
337             winetest_trace("Did not get enough items\n");
338         return;
339     }
340
341     logclust = HeapAlloc(GetProcessHeap(), 0, sizeof(WORD) * cchString);
342     memset(logclust,'a',sizeof(WORD) * cchString);
343     charProp = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPT_CHARPROP) * cchString);
344     memset(charProp,'a',sizeof(SCRIPT_CHARPROP) * cchString);
345     glyphs = HeapAlloc(GetProcessHeap(), 0, sizeof(WORD) * maxGlyphs);
346     memset(glyphs,'a',sizeof(WORD) * cchString);
347     glyphProp = HeapAlloc(GetProcessHeap(), 0, sizeof(SCRIPT_GLYPHPROP) * maxGlyphs);
348     memset(glyphProp,'a',sizeof(SCRIPT_GLYPHPROP) * cchString);
349
350     hr = pScriptShapeOpenType(hdc, &sc, &outpItems[item].a, tags[item], 0x00000000, NULL, NULL, 0, string, cchString, maxGlyphs, logclust, charProp, glyphs, glyphProp, &outnGlyphs);
351     if (valid > 0)
352         winetest_ok(hr == S_OK, "ScriptShapeOpenType failed (%x)\n",hr);
353     else if (hr != S_OK)
354         winetest_trace("ScriptShapeOpenType failed (%x)\n",hr);
355     if (FAILED(hr))
356         return;
357
358     for (x = 0; x < cchString; x++)
359     {
360         if (valid > 0)
361             winetest_ok(logclust[x] == charItems[x].wLogClust, "%i: invalid LogClust(%i)\n",x,logclust[x]);
362         else if (logclust[x] != charItems[x].wLogClust)
363             winetest_trace("%i: invalid LogClust(%i)\n",x,logclust[x]);
364         if (valid > 0)
365             winetest_ok(charProp[x].fCanGlyphAlone == charItems[x].CharProp.fCanGlyphAlone, "%i: invalid fCanGlyphAlone\n",x);
366         else if (charProp[x].fCanGlyphAlone != charItems[x].CharProp.fCanGlyphAlone)
367             winetest_trace("%i: invalid fCanGlyphAlone\n",x);
368     }
369
370     if(valid)
371         winetest_ok(nGlyphs == outnGlyphs, "got incorrect number of glyphs (%i)\n",outnGlyphs);
372     else if (nGlyphs != outnGlyphs)
373         winetest_trace("got incorrect number of glyphs (%i)\n",outnGlyphs);
374     for (x = 0; x < outnGlyphs; x++)
375     {
376         if (glyphItems[x].Glyph)
377         {
378             if (valid > 0)
379                 winetest_ok(glyphs[x]!=0, "%i: Glyph not present when it should be\n",x);
380             else if (glyphs[x]==0)
381                 winetest_trace("%i: Glyph not present when it should be\n",x);
382         }
383         else
384         {
385             if (valid > 0)
386                 winetest_ok(glyphs[x]==0, "%i: Glyph present when it should not be\n",x);
387             else if (glyphs[x]!=0)
388                 winetest_trace("%i: Glyph present when it should not be\n",x);
389         }
390         if (valid > 0)
391             winetest_ok(glyphProp[x].sva.uJustification == glyphItems[x].GlyphProp.sva.uJustification, "%i: uJustification incorrect (%i)\n",x,glyphProp[x].sva.uJustification);
392         else if (glyphProp[x].sva.uJustification != glyphItems[x].GlyphProp.sva.uJustification)
393             winetest_trace("%i: uJustification incorrect (%i)\n",x,glyphProp[x].sva.uJustification);
394         if (valid > 0)
395             winetest_ok(glyphProp[x].sva.fClusterStart == glyphItems[x].GlyphProp.sva.fClusterStart, "%i: fClusterStart incorrect (%i)\n",x,glyphProp[x].sva.fClusterStart);
396         else if (glyphProp[x].sva.fClusterStart != glyphItems[x].GlyphProp.sva.fClusterStart)
397             winetest_trace("%i: fClusterStart incorrect (%i)\n",x,glyphProp[x].sva.fClusterStart);
398         if (valid > 0)
399             winetest_ok(glyphProp[x].sva.fDiacritic == glyphItems[x].GlyphProp.sva.fDiacritic, "%i: fDiacritic incorrect (%i)\n",x,glyphProp[x].sva.fDiacritic);
400         else if (glyphProp[x].sva.fDiacritic != glyphItems[x].GlyphProp.sva.fDiacritic)
401             winetest_trace("%i: fDiacritic incorrect (%i)\n",x,glyphProp[x].sva.fDiacritic);
402         if (valid > 0)
403             winetest_ok(glyphProp[x].sva.fZeroWidth == glyphItems[x].GlyphProp.sva.fZeroWidth, "%i: fZeroWidth incorrect (%i)\n",x,glyphProp[x].sva.fZeroWidth);
404         else if (glyphProp[x].sva.fZeroWidth != glyphItems[x].GlyphProp.sva.fZeroWidth)
405             winetest_trace("%i: fZeroWidth incorrect (%i)\n",x,glyphProp[x].sva.fZeroWidth);
406     }
407
408     HeapFree(GetProcessHeap(),0,logclust);
409     HeapFree(GetProcessHeap(),0,charProp);
410     HeapFree(GetProcessHeap(),0,glyphs);
411     HeapFree(GetProcessHeap(),0,glyphProp);
412     ScriptFreeCache(&sc);
413 }
414
415 #define test_shape_ok(a,b,c,d,e,f,g,h,i) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _test_shape_ok(1,a,b,c,d,e,f,g,h,i)
416
417 #define test_shape_ok_valid(v,a,b,c,d,e,f,g,h,i) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _test_shape_ok(v,a,b,c,d,e,f,g,h,i)
418
419 typedef struct tagRangeP {
420     BYTE range;
421     LOGFONTA lf;
422 } fontEnumParam;
423
424 int CALLBACK enumFontProc( const LOGFONT *lpelfe, const TEXTMETRIC *lpntme,
425                            DWORD FontType, LPARAM lParam)
426 {
427     NEWTEXTMETRICEX *ntme = (NEWTEXTMETRICEX*)lpntme;
428     fontEnumParam *rp = (fontEnumParam*) lParam;
429     int idx = 0;
430     DWORD i;
431     DWORD mask = 0;
432
433     if (FontType != TRUETYPE_FONTTYPE)
434         return 1;
435
436     i = rp->range;
437     while (i > sizeof(DWORD)*8)
438     {
439         idx++;
440         i -= (sizeof(DWORD)*8);
441     }
442     if (idx > 3)
443         return 0;
444
445     mask = 1 << i;
446
447     if (ntme->ntmFontSig.fsUsb[idx] & mask)
448     {
449         memcpy(&(rp->lf),lpelfe,sizeof(LOGFONT));
450         return 0;
451     }
452     return 1;
453 }
454
455 static int _find_font_for_range(HDC hdc, const CHAR *recommended, BYTE range, const WCHAR check, HFONT *hfont, HFONT *origFont)
456 {
457     int rc = 0;
458     fontEnumParam lParam;
459
460     lParam.range = range;
461     memset(&lParam.lf,0,sizeof(LOGFONT));
462     *hfont = NULL;
463
464     if (recommended)
465     {
466         lstrcpyA(lParam.lf.lfFaceName, recommended);
467         if (!EnumFontFamiliesExA(hdc, &lParam.lf, enumFontProc, (LPARAM)&lParam, 0))
468         {
469             *hfont = CreateFontIndirectA(&lParam.lf);
470             if (*hfont)
471             {
472                 winetest_trace("using font %s\n",lParam.lf.lfFaceName);
473                 rc = 1;
474             }
475         }
476     }
477
478     if (!*hfont)
479     {
480         memset(&lParam.lf,0,sizeof(LOGFONT));
481         lParam.lf.lfCharSet = DEFAULT_CHARSET;
482
483         if (!EnumFontFamiliesExA(hdc, &lParam.lf, enumFontProc, (LPARAM)&lParam, 0) && lParam.lf.lfFaceName[0])
484         {
485             *hfont = CreateFontIndirectA(&lParam.lf);
486             if (*hfont)
487                 winetest_trace("trying font %s: failures will only be warnings\n",lParam.lf.lfFaceName);
488         }
489     }
490
491     if (*hfont)
492     {
493         WORD glyph = 0;
494
495         *origFont = SelectObject(hdc,*hfont);
496         if (GetGlyphIndicesW(hdc, &check, 1, &glyph, 0) == GDI_ERROR || glyph ==0)
497         {
498             winetest_trace("    Font fails to contain required glyphs\n");
499             SelectObject(hdc,*origFont);
500             DeleteObject(*hfont);
501             *hfont=NULL;
502             rc = 0;
503         }
504         else if (!rc)
505             rc = -1;
506     }
507     else
508         winetest_trace("Failed to find usable font\n");
509
510     return rc;
511 }
512
513 #define find_font_for_range(a,b,c,d,e,f) (winetest_set_location(__FILE__,__LINE__), 0) ? 0 : _find_font_for_range(a,b,c,d,e,f)
514
515 static void test_ScriptShapeOpenType(HDC hdc)
516 {
517     HRESULT hr;
518     SCRIPT_CACHE sc = NULL;
519     WORD glyphs[4], logclust[4];
520     SCRIPT_GLYPHPROP glyphProp[4];
521     SCRIPT_ITEM items[2];
522     ULONG tags[2];
523     SCRIPT_CONTROL  Control;
524     SCRIPT_STATE    State;
525     int nb, outnItems;
526     HFONT hfont, hfont_orig;
527     int test_valid;
528
529     static const WCHAR test1[] = {'w', 'i', 'n', 'e',0};
530     static const shapeTest_char t1_c[] = {{0,{0,0}},{1,{0,0}},{2,{0,0}},{3,{0,0}}};
531     static const shapeTest_glyph t1_g[] = {
532                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
533                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
534                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
535                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}} };
536
537     static const WCHAR test2[] = {0x202B, 'i', 'n', 0x202C,0};
538     static const shapeTest_char t2_c[] = {{0,{0,0}},{1,{0,0}},{2,{0,0}},{3,{0,0}}};
539     static const shapeTest_glyph t2_g[] = {
540                             {0,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
541                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
542                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
543                             {0,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}} };
544
545     /* Hebrew */
546     static const WCHAR test_hebrew[]  = {0x05e9, 0x05dc, 0x05d5, 0x05dd,0};
547     static const shapeTest_char hebrew_c[] = {{3,{0,0}},{2,{0,0}},{1,{0,0}},{0,{0,0}}};
548     static const shapeTest_glyph hebrew_g[] = {
549                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
550                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
551                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
552                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}} };
553
554     /* Arabic */
555     static const WCHAR test_arabic[] = {0x0633,0x0644,0x0627,0x0645,0};
556     static const shapeTest_char arabic_c[] = {{2,{0,0}},{1,{0,0}},{1,{0,0}},{0,{0,0}}};
557     static const shapeTest_glyph arabic_g[] = {
558                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
559                             {1,{{SCRIPT_JUSTIFY_ARABIC_NORMAL,1,0,0,0,0},0}},
560                             {1,{{SCRIPT_JUSTIFY_ARABIC_SEEN,1,0,0,0,0},0}} };
561
562     /* Thai */
563     static const WCHAR test_thai[] = {0x0e2a, 0x0e04, 0x0e23, 0x0e34, 0x0e1b, 0x0e15, 0x0e4c, 0x0e44, 0x0e17, 0x0e22,};
564     static const shapeTest_char thai_c[] = {{0,{0,0}},{1,{0,0}},{2,{0,0}},{2,{0,0}},{4,{0,0}},{5,{0,0}},{5,{0,0}},{7,{0,0}},{8,{0,0}},{9,{0,0}}};
565     static const shapeTest_glyph thai_g[] = {
566                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
567                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
568                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
569                             {1,{{SCRIPT_JUSTIFY_CHARACTER,0,1,1,0,0},0}},
570                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
571                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
572                             {1,{{SCRIPT_JUSTIFY_CHARACTER,0,1,1,0,0},0}},
573                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
574                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
575                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}}};
576
577     if (!pScriptItemizeOpenType || !pScriptShapeOpenType)
578     {
579         win_skip("ScriptShapeOpenType not available on this platform\n");
580         return;
581     }
582
583     memset(&Control, 0 , sizeof(Control));
584     memset(&State, 0 , sizeof(State));
585
586     hr = pScriptItemizeOpenType(test1, 4, 2, &Control, &State, items, tags, &outnItems);
587     ok(!hr, "ScriptItemizeOpenType should return S_OK not %08x\n", hr);
588     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
589
590     hr = pScriptShapeOpenType(hdc, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, NULL, NULL, glyphs, NULL, &nb);
591     ok(hr == E_INVALIDARG, "ScriptShapeOpenType should return E_INVALIDARG not %08x\n", hr);
592
593     hr = pScriptShapeOpenType(hdc, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, NULL, NULL, glyphs, glyphProp, NULL);
594     ok(hr == E_INVALIDARG, "ScriptShapeOpenType should return E_INVALIDARG not %08x\n", hr);
595
596     hr = pScriptShapeOpenType(NULL, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, NULL, NULL, glyphs, glyphProp, &nb);
597     ok(hr == E_INVALIDARG, "ScriptShapeOpenType should return E_PENDING not %08x\n", hr);
598
599     hr = pScriptShapeOpenType(hdc, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, NULL, NULL, glyphs, glyphProp, &nb);
600     ok( hr == E_INVALIDARG,
601        "ScriptShapeOpenType should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
602     hr = pScriptShapeOpenType(hdc, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, logclust, NULL, glyphs, glyphProp, &nb);
603     ok(hr == E_INVALIDARG, "ScriptShapeOpenType should return E_INVALIDARG not %08x\n", hr);
604
605     ScriptFreeCache(&sc);
606
607     test_shape_ok(hdc, test1, 4, &Control, &State, 0, 4, t1_c, t1_g);
608     test_shape_ok(hdc, test2, 4, &Control, &State, 1, 4, t2_c, t2_g);
609
610     test_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 11, test_hebrew[0], &hfont, &hfont_orig);
611     if (hfont != NULL)
612     {
613         test_shape_ok_valid(test_valid, hdc, test_hebrew, 4, &Control, &State, 0, 4, hebrew_c, hebrew_g);
614         SelectObject(hdc, hfont_orig);
615         DeleteObject(hfont);
616     }
617
618     test_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 13, test_arabic[0], &hfont, &hfont_orig);
619     if (hfont != NULL)
620     {
621         test_shape_ok_valid(test_valid, hdc, test_arabic, 4, &Control, &State, 0, 3, arabic_c, arabic_g);
622         SelectObject(hdc, hfont_orig);
623         DeleteObject(hfont);
624     }
625
626     test_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 24, test_thai[0], &hfont, &hfont_orig);
627     if (hfont != NULL)
628     {
629         test_shape_ok_valid(test_valid, hdc, test_thai, 10, &Control, &State, 0, 10, thai_c, thai_g);
630         SelectObject(hdc, hfont_orig);
631         DeleteObject(hfont);
632     }
633 }
634
635 static void test_ScriptShape(HDC hdc)
636 {
637     static const WCHAR test1[] = {'w', 'i', 'n', 'e',0};
638     static const WCHAR test2[] = {0x202B, 'i', 'n', 0x202C,0};
639     HRESULT hr;
640     SCRIPT_CACHE sc = NULL;
641     WORD glyphs[4], glyphs2[4], logclust[4];
642     SCRIPT_VISATTR attrs[4];
643     SCRIPT_ITEM items[2];
644     int nb;
645
646     hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL);
647     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
648     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
649
650     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, NULL, &nb);
651     ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr);
652
653     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, NULL);
654     ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr);
655
656     hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb);
657     ok(hr == E_PENDING, "ScriptShape should return E_PENDING not %08x\n", hr);
658
659     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb);
660     ok(broken(hr == S_OK) ||
661        hr == E_INVALIDARG || /* Vista, W2K8 */
662        hr == E_FAIL, /* WIN7 */
663        "ScriptShape should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
664     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
665
666     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
667     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
668     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
669
670
671     memset(glyphs,-1,sizeof(glyphs));
672     memset(logclust,-1,sizeof(logclust));
673     memset(attrs,-1,sizeof(attrs));
674     hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
675     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
676     ok(nb == 4, "Wrong number of items\n");
677     ok(logclust[0] == 0, "clusters out of order\n");
678     ok(logclust[1] == 1, "clusters out of order\n");
679     ok(logclust[2] == 2, "clusters out of order\n");
680     ok(logclust[3] == 3, "clusters out of order\n");
681     ok(attrs[0].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
682     ok(attrs[1].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
683     ok(attrs[2].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
684     ok(attrs[3].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
685     ok(attrs[0].fClusterStart == 1, "fClusterStart incorrect\n");
686     ok(attrs[1].fClusterStart == 1, "fClusterStart incorrect\n");
687     ok(attrs[2].fClusterStart == 1, "fClusterStart incorrect\n");
688     ok(attrs[3].fClusterStart == 1, "fClusterStart incorrect\n");
689     ok(attrs[0].fDiacritic == 0, "fDiacritic incorrect\n");
690     ok(attrs[1].fDiacritic == 0, "fDiacritic incorrect\n");
691     ok(attrs[2].fDiacritic == 0, "fDiacritic incorrect\n");
692     ok(attrs[3].fDiacritic == 0, "fDiacritic incorrect\n");
693     ok(attrs[0].fZeroWidth == 0, "fZeroWidth incorrect\n");
694     ok(attrs[1].fZeroWidth == 0, "fZeroWidth incorrect\n");
695     ok(attrs[2].fZeroWidth == 0, "fZeroWidth incorrect\n");
696     ok(attrs[3].fZeroWidth == 0, "fZeroWidth incorrect\n");
697
698     ScriptFreeCache(&sc);
699     sc = NULL;
700
701     memset(glyphs2,-1,sizeof(glyphs2));
702     memset(logclust,-1,sizeof(logclust));
703     memset(attrs,-1,sizeof(attrs));
704     hr = ScriptShape(hdc, &sc, test2, 4, 4, &items[0].a, glyphs2, logclust, attrs, &nb);
705     ok(hr == S_OK, "ScriptShape should return S_OK not %08x\n", hr);
706     ok(nb == 4, "Wrong number of items\n");
707     ok(glyphs2[0] == 0 || broken(glyphs2[0] == 0x80), "Incorrect glyph for 0x202B\n");
708     ok(glyphs2[3] == 0 || broken(glyphs2[3] == 0x80), "Incorrect glyph for 0x202C\n");
709     ok(logclust[0] == 0, "clusters out of order\n");
710     ok(logclust[1] == 1, "clusters out of order\n");
711     ok(logclust[2] == 2, "clusters out of order\n");
712     ok(logclust[3] == 3, "clusters out of order\n");
713     ok(attrs[0].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
714     ok(attrs[1].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
715     ok(attrs[2].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
716     ok(attrs[3].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
717     ok(attrs[0].fClusterStart == 1, "fClusterStart incorrect\n");
718     ok(attrs[1].fClusterStart == 1, "fClusterStart incorrect\n");
719     ok(attrs[2].fClusterStart == 1, "fClusterStart incorrect\n");
720     ok(attrs[3].fClusterStart == 1, "fClusterStart incorrect\n");
721     ok(attrs[0].fDiacritic == 0, "fDiacritic incorrect\n");
722     ok(attrs[1].fDiacritic == 0, "fDiacritic incorrect\n");
723     ok(attrs[2].fDiacritic == 0, "fDiacritic incorrect\n");
724     ok(attrs[3].fDiacritic == 0, "fDiacritic incorrect\n");
725     ok(attrs[0].fZeroWidth == 0, "fZeroWidth incorrect\n");
726     ok(attrs[1].fZeroWidth == 0, "fZeroWidth incorrect\n");
727     ok(attrs[2].fZeroWidth == 0, "fZeroWidth incorrect\n");
728     ok(attrs[3].fZeroWidth == 0, "fZeroWidth incorrect\n");
729
730     /* modify LTR to RTL */
731     items[0].a.fRTL = 1;
732     memset(glyphs2,-1,sizeof(glyphs2));
733     memset(logclust,-1,sizeof(logclust));
734     memset(attrs,-1,sizeof(attrs));
735     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs2, logclust, attrs, &nb);
736     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
737     ok(nb == 4, "Wrong number of items\n");
738     ok(glyphs2[0] == glyphs[3], "Glyphs not reordered properly\n");
739     ok(glyphs2[1] == glyphs[2], "Glyphs not reordered properly\n");
740     ok(glyphs2[2] == glyphs[1], "Glyphs not reordered properly\n");
741     ok(glyphs2[3] == glyphs[0], "Glyphs not reordered properly\n");
742     ok(logclust[0] == 3, "clusters out of order\n");
743     ok(logclust[1] == 2, "clusters out of order\n");
744     ok(logclust[2] == 1, "clusters out of order\n");
745     ok(logclust[3] == 0, "clusters out of order\n");
746     ok(attrs[0].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
747     ok(attrs[1].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
748     ok(attrs[2].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
749     ok(attrs[3].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
750     ok(attrs[0].fClusterStart == 1, "fClusterStart incorrect\n");
751     ok(attrs[1].fClusterStart == 1, "fClusterStart incorrect\n");
752     ok(attrs[2].fClusterStart == 1, "fClusterStart incorrect\n");
753     ok(attrs[3].fClusterStart == 1, "fClusterStart incorrect\n");
754     ok(attrs[0].fDiacritic == 0, "fDiacritic incorrect\n");
755     ok(attrs[1].fDiacritic == 0, "fDiacritic incorrect\n");
756     ok(attrs[2].fDiacritic == 0, "fDiacritic incorrect\n");
757     ok(attrs[3].fDiacritic == 0, "fDiacritic incorrect\n");
758     ok(attrs[0].fZeroWidth == 0, "fZeroWidth incorrect\n");
759     ok(attrs[1].fZeroWidth == 0, "fZeroWidth incorrect\n");
760     ok(attrs[2].fZeroWidth == 0, "fZeroWidth incorrect\n");
761     ok(attrs[3].fZeroWidth == 0, "fZeroWidth incorrect\n");
762
763     ScriptFreeCache(&sc);
764 }
765
766 static void test_ScriptPlace(HDC hdc)
767 {
768     static const WCHAR test1[] = {'t', 'e', 's', 't',0};
769     BOOL ret;
770     HRESULT hr;
771     SCRIPT_CACHE sc = NULL;
772     WORD glyphs[4], logclust[4];
773     SCRIPT_VISATTR attrs[4];
774     SCRIPT_ITEM items[2];
775     int nb, widths[4];
776     GOFFSET offset[4];
777     ABC abc[4];
778
779     hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL);
780     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
781     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
782
783     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
784     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
785     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
786
787     hr = ScriptPlace(hdc, &sc, glyphs, 4, NULL, &items[0].a, widths, NULL, NULL);
788     ok(hr == E_INVALIDARG, "ScriptPlace should return E_INVALIDARG not %08x\n", hr);
789
790     hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, NULL);
791     ok(broken(hr == E_PENDING) ||
792        hr == E_INVALIDARG || /* Vista, W2K8 */
793        hr == E_FAIL, /* WIN7 */
794        "ScriptPlace should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
795
796     hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, offset, NULL);
797     ok(hr == E_PENDING, "ScriptPlace should return E_PENDING not %08x\n", hr);
798
799     hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, abc);
800     ok(broken(hr == E_PENDING) ||
801        hr == E_INVALIDARG || /* Vista, W2K8 */
802        hr == E_FAIL, /* WIN7 */
803        "ScriptPlace should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
804
805     hr = ScriptPlace(hdc, &sc, glyphs, 4, attrs, &items[0].a, widths, offset, NULL);
806     ok(!hr, "ScriptPlace should return S_OK not %08x\n", hr);
807     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
808
809     ret = ExtTextOutW(hdc, 1, 1, 0, NULL, glyphs, 4, widths);
810     ok(ret, "ExtTextOutW should return TRUE\n");
811
812     ScriptFreeCache(&sc);
813 }
814
815 static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256])
816 {
817     HRESULT         hr;
818     int             iMaxProps;
819     const SCRIPT_PROPERTIES **ppSp;
820
821     int             cInChars;
822     int             cMaxItems;
823     SCRIPT_ITEM     pItem[255];
824     int             pcItems;
825     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
826     WCHAR           TestItem2[] = {'T', 'e', 's', 't', 'b', 0}; 
827     WCHAR           TestItem3[] = {'T', 'e', 's', 't', 'c',' ','1','2','3',' ',' ','e','n','d',0};
828     WCHAR           TestItem4[] = {'T', 'e', 's', 't', 'd',' ',0x0684,0x0694,0x06a4,' ',' ','\r','\n','e','n','d',0};
829     WCHAR           TestItem5[] = {0x0684,'T','e','s','t','e',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0};
830     WCHAR           TestItem6[] = {'T', 'e', 's', 't', 'f',' ',' ',' ','\r','\n','e','n','d',0};
831
832     SCRIPT_CACHE    psc;
833     int             cChars;
834     int             cMaxGlyphs;
835     unsigned short  pwOutGlyphs1[256];
836     unsigned short  pwOutGlyphs2[256];
837     unsigned short  pwLogClust[256];
838     SCRIPT_VISATTR  psva[256];
839     int             pcGlyphs;
840     int             piAdvance[256];
841     GOFFSET         pGoffset[256];
842     ABC             pABC[256];
843     int             cnt;
844
845     /* Start testing usp10 functions                                                         */
846     /* This test determines that the pointer returned by ScriptGetProperties is valid
847      * by checking a known value in the table                                                */
848     hr = ScriptGetProperties(&ppSp, &iMaxProps);
849     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
850     trace("number of script properties %d\n", iMaxProps);
851     ok (iMaxProps > 0, "Number of scripts returned should not be 0\n");
852     if  (iMaxProps > 0)
853          ok( ppSp[0]->langid == 0, "Langid[0] not = to 0\n"); /* Check a known value to ensure   */
854                                                               /* ptrs work                       */
855
856     /* This is a valid test that will cause parsing to take place                             */
857     cInChars = 5;
858     cMaxItems = 255;
859     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
860     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
861     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
862      *  returned.                                                                             */
863     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
864     if (pcItems > 0)
865         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
866             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
867             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
868
869     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
870      * ie. ScriptItemize has succeeded and that pItem has been set                            */
871     cInChars = 5;
872     if (hr == 0) {
873         psc = NULL;                                   /* must be null on first call           */
874         cChars = cInChars;
875         cMaxGlyphs = cInChars;
876         hr = ScriptShape(NULL, &psc, TestItem1, cChars,
877                          cMaxGlyphs, &pItem[0].a,
878                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
879         ok (hr == E_PENDING, "If psc is NULL (%08x) the E_PENDING should be returned\n", hr);
880         cMaxGlyphs = 4;
881         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
882                          cMaxGlyphs, &pItem[0].a,
883                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
884         ok (hr == E_OUTOFMEMORY, "If not enough output area cChars (%d) is > than CMaxGlyphs "
885                                  "(%d) but not E_OUTOFMEMORY\n",
886                                  cChars, cMaxGlyphs);
887         cMaxGlyphs = 256;
888         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
889                          cMaxGlyphs, &pItem[0].a,
890                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
891         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
892         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
893         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
894         if (hr ==0) {
895             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
896                              pGoffset, pABC);
897             ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
898             hr = ScriptPlace(NULL, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
899                              pGoffset, pABC);
900             ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
901             for (cnt=0; cnt < pcGlyphs; cnt++)
902                 pwOutGlyphs[cnt] = pwOutGlyphs1[cnt];                 /* Send to next function */
903         }
904
905         /* This test will check to make sure that SCRIPT_CACHE is reused and that not translation   *
906          * takes place if fNoGlyphIndex is set.                                                     */
907
908         cInChars = 5;
909         cMaxItems = 255;
910         hr = ScriptItemize(TestItem2, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
911         ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
912         /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is   *
913          *  returned.                                                                               */
914         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
915                             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
916                              pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
917         /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue                    */
918         if (hr == 0) {
919              cChars = cInChars;
920              cMaxGlyphs = 256;
921              pItem[0].a.fNoGlyphIndex = 1;                /* say no translate                     */
922              hr = ScriptShape(NULL, &psc, TestItem2, cChars,
923                               cMaxGlyphs, &pItem[0].a,
924                               pwOutGlyphs2, pwLogClust, psva, &pcGlyphs);
925              ok (hr != E_PENDING, "If psc should not be NULL (%08x) and the E_PENDING should be returned\n", hr);
926              ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
927              ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
928              ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
929              for (cnt=0; cnt < cChars && TestItem2[cnt] == pwOutGlyphs2[cnt]; cnt++) {}
930              ok (cnt == cChars, "Translation to place when told not to. WCHAR %d - %04x != %04x\n",
931                            cnt, TestItem2[cnt], pwOutGlyphs2[cnt]);
932              if (hr ==0) {
933                  hr = ScriptPlace(hdc, &psc, pwOutGlyphs2, pcGlyphs, psva, &pItem[0].a, piAdvance,
934                                   pGoffset, pABC);
935                  ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
936              }
937         }
938         ScriptFreeCache( &psc);
939         ok (!psc, "psc is not null after ScriptFreeCache\n");
940
941     }
942
943     /* This is a valid test that will cause parsing to take place and create 3 script_items   */
944     cInChars = (sizeof(TestItem3)/2)-1;
945     cMaxItems = 255;
946     hr = ScriptItemize(TestItem3, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
947     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
948     if  (hr == 0)
949         {
950         ok (pcItems == 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems);
951         if (pcItems > 2)
952         {
953             ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
954                 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
955                 pItem[0].iCharPos, pItem[1].iCharPos);
956             ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
957                 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
958                 pItem[1].iCharPos, pItem[2].iCharPos);
959             ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == cInChars,
960                 "Start pos [2] not = 11 (%d) or end [3] pos not = 14 (%d), cInChars = %d\n",
961                 pItem[2].iCharPos, pItem[3].iCharPos, cInChars);
962         }
963     }
964
965     /* This is a valid test that will cause parsing to take place and create 5 script_items   */
966     cInChars = (sizeof(TestItem4)/2)-1;
967     cMaxItems = 255;
968     hr = ScriptItemize(TestItem4, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
969     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
970     if  (hr == 0)
971         {
972         ok (pcItems == 5, "The number of SCRIPT_ITEMS should be 5 not %d\n", pcItems);
973         if (pcItems > 4)
974         {
975             ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
976                 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
977                 pItem[0].iCharPos, pItem[1].iCharPos);
978             ok (pItem[0].a.s.uBidiLevel == 0, "Should have been bidi=0 not %d\n",
979                                                pItem[0].a.s.uBidiLevel);
980             ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
981                 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
982                 pItem[1].iCharPos, pItem[2].iCharPos);
983             ok (pItem[1].a.s.uBidiLevel == 1, "Should have been bidi=1 not %d\n",
984                                               pItem[1].a.s.uBidiLevel);
985             ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == 12,
986                 "Start pos [2] not = 11 (%d) or end [3] pos not = 12 (%d)\n",
987                 pItem[2].iCharPos, pItem[3].iCharPos);
988             ok (pItem[2].a.s.uBidiLevel == 0, "Should have been bidi=0 not %d\n",
989                                                pItem[2].a.s.uBidiLevel);
990             ok (pItem[3].iCharPos == 12 && pItem[4].iCharPos == 13,
991                 "Start pos [3] not = 12 (%d) or end [4] pos not = 13 (%d)\n",
992                 pItem[3].iCharPos, pItem[4].iCharPos);
993             ok (pItem[3].a.s.uBidiLevel == 0, "Should have been bidi=0 not %d\n",
994                                                pItem[3].a.s.uBidiLevel);
995             ok (pItem[4].iCharPos == 13 && pItem[5].iCharPos == cInChars,
996                 "Start pos [4] not = 13 (%d) or end [5] pos not = 16 (%d), cInChars = %d\n",
997                 pItem[4].iCharPos, pItem[5].iCharPos, cInChars);
998         }
999     }
1000
1001     /*
1002      * This test is for when the first unicode character requires bidi support
1003      */
1004     cInChars = (sizeof(TestItem5)-1)/sizeof(WCHAR);
1005     hr = ScriptItemize(TestItem5, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1006     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
1007     ok (pcItems == 4, "There should have been 4 items, found %d\n", pcItems);
1008     ok (pItem[0].a.s.uBidiLevel == 1, "The first character should have been bidi=1 not %d\n",
1009                                        pItem[0].a.s.uBidiLevel);
1010
1011     /* This test checks to make sure that the test to see if there are sufficient buffers to store  *
1012      * the pointer to the last char works.  Note that windows often needs a greater number of       *
1013      * SCRIPT_ITEMS to process a string than is returned in pcItems.                                */
1014     cInChars = (sizeof(TestItem6)/2)-1;
1015     cMaxItems = 4;
1016     hr = ScriptItemize(TestItem6, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1017     ok (hr == E_OUTOFMEMORY, "ScriptItemize should return E_OUTOFMEMORY, returned %08x\n", hr);
1018
1019 }
1020
1021 static void test_ScriptGetCMap(HDC hdc, unsigned short pwOutGlyphs[256])
1022 {
1023     HRESULT         hr;
1024     SCRIPT_CACHE    psc = NULL;
1025     int             cInChars;
1026     int             cChars;
1027     unsigned short  pwOutGlyphs2[256];
1028     unsigned short  pwOutGlyphs3[256];
1029     DWORD           dwFlags;
1030     int             cnt;
1031
1032     static const WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
1033     static const WCHAR TestItem2[] = {0x202B, 'i', 'n', 0x202C,0};
1034     static const WCHAR TestItem3[] = {'a','b','c','d','(','<','{','[',0x2039,0};
1035     static const WCHAR TestItem3b[] = {'a','b','c','d',')','>','}',']',0x203A,0};
1036
1037     /*  Check to make sure that SCRIPT_CACHE gets allocated ok                     */
1038     dwFlags = 0;
1039     cInChars = cChars = 5;
1040     /* Some sanity checks for ScriptGetCMap */
1041
1042     hr = ScriptGetCMap(NULL, NULL, NULL, 0, 0, NULL);
1043     ok( hr == E_INVALIDARG, "(NULL,NULL,NULL,0,0,NULL), "
1044                             "expected E_INVALIDARG, got %08x\n", hr);
1045
1046     hr = ScriptGetCMap(NULL, NULL, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
1047     ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
1048                             "expected E_INVALIDARG, got %08x\n", hr);
1049
1050     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1051     psc = NULL;
1052     hr = ScriptGetCMap(NULL, &psc, TestItem1, cInChars, 0, pwOutGlyphs3);
1053     ok( hr == E_PENDING, "(NULL,&psc,NULL,0,0,NULL), expected E_PENDING, "
1054                          "got %08x\n", hr);
1055     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1056
1057     /* Set psc to NULL but add hdc, to be able to check if a pointer is returned in psc */
1058     psc = NULL;
1059     hr = ScriptGetCMap(hdc, &psc, TestItem1, cInChars, 0, pwOutGlyphs3);
1060     ok( hr == S_OK, "ScriptGetCMap(NULL,&psc,NULL,0,0,NULL), expected S_OK, "
1061                     "got %08x\n", hr);
1062     ok( psc != NULL, "ScritpGetCMap expected psc to be not NULL\n");
1063     ScriptFreeCache( &psc);
1064
1065     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1066     psc = NULL;
1067     hr = ScriptGetCMap(NULL, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
1068     ok( hr == E_PENDING, "(NULL,&psc,), expected E_PENDING, got %08x\n", hr);
1069     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1070     /*  Check to see if the results are the same as those returned by ScriptShape  */
1071     hr = ScriptGetCMap(hdc, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
1072     ok (hr == 0, "ScriptGetCMap should return 0 not (%08x)\n", hr);
1073     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1074     for (cnt=0; cnt < cChars && pwOutGlyphs[cnt] == pwOutGlyphs3[cnt]; cnt++) {}
1075     ok (cnt == cInChars, "Translation not correct. WCHAR %d - %04x != %04x\n",
1076                          cnt, pwOutGlyphs[cnt], pwOutGlyphs3[cnt]);
1077
1078     ScriptFreeCache( &psc);
1079     ok (!psc, "psc is not null after ScriptFreeCache\n");
1080
1081     cInChars = cChars = 4;
1082     hr = ScriptGetCMap(hdc, &psc, TestItem2, cInChars, dwFlags, pwOutGlyphs3);
1083     ok (hr == S_FALSE, "ScriptGetCMap should return S_FALSE not (%08x)\n", hr);
1084     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1085     ok(pwOutGlyphs3[0] == 0 || broken(pwOutGlyphs3[0] == 0x80), "Glyph 0 should be default glyph\n");
1086     ok(pwOutGlyphs3[3] == 0 || broken(pwOutGlyphs3[0] == 0x80), "Glyph 0 should be default glyph\n");
1087
1088
1089     cInChars = cChars = 9;
1090     hr = ScriptGetCMap(hdc, &psc, TestItem3b, cInChars, dwFlags, pwOutGlyphs2);
1091     ok (hr == S_OK, "ScriptGetCMap should return S_OK not (%08x)\n", hr);
1092     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1093
1094     cInChars = cChars = 9;
1095     dwFlags = SGCM_RTL;
1096     hr = ScriptGetCMap(hdc, &psc, TestItem3, cInChars, dwFlags, pwOutGlyphs3);
1097     ok (hr == S_OK, "ScriptGetCMap should return S_OK not (%08x)\n", hr);
1098     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1099     ok(pwOutGlyphs3[0] == pwOutGlyphs2[0], "glyph incorrectly altered\n");
1100     ok(pwOutGlyphs3[1] == pwOutGlyphs2[1], "glyph incorreclty altered\n");
1101     ok(pwOutGlyphs3[2] == pwOutGlyphs2[2], "glyph incorreclty altered\n");
1102     ok(pwOutGlyphs3[3] == pwOutGlyphs2[3], "glyph incorreclty altered\n");
1103     ok(pwOutGlyphs3[4] == pwOutGlyphs2[4], "glyph not mirrored correctly\n");
1104     ok(pwOutGlyphs3[5] == pwOutGlyphs2[5], "glyph not mirrored correctly\n");
1105     ok(pwOutGlyphs3[6] == pwOutGlyphs2[6], "glyph not mirrored correctly\n");
1106     ok(pwOutGlyphs3[7] == pwOutGlyphs2[7], "glyph not mirrored correctly\n");
1107     ok(pwOutGlyphs3[8] == pwOutGlyphs2[8], "glyph not mirrored correctly\n");
1108
1109     ScriptFreeCache( &psc);
1110     ok (!psc, "psc is not null after ScriptFreeCache\n");
1111 }
1112
1113 static void test_ScriptGetFontProperties(HDC hdc)
1114 {
1115     HRESULT         hr;
1116     SCRIPT_CACHE    psc,old_psc;
1117     SCRIPT_FONTPROPERTIES sfp;
1118
1119     /* Some sanity checks for ScriptGetFontProperties */
1120
1121     hr = ScriptGetFontProperties(NULL,NULL,NULL);
1122     ok( hr == E_INVALIDARG, "(NULL,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
1123
1124     hr = ScriptGetFontProperties(NULL,NULL,&sfp);
1125     ok( hr == E_INVALIDARG, "(NULL,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
1126
1127     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1128     psc = NULL;
1129     hr = ScriptGetFontProperties(NULL,&psc,NULL);
1130     ok( hr == E_INVALIDARG, "(NULL,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr);
1131     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1132
1133     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1134     psc = NULL;
1135     hr = ScriptGetFontProperties(NULL,&psc,&sfp);
1136     ok( hr == E_PENDING, "(NULL,&psc,&sfp), expected E_PENDING, got %08x\n", hr);
1137     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1138
1139     hr = ScriptGetFontProperties(hdc,NULL,NULL);
1140     ok( hr == E_INVALIDARG, "(hdc,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
1141
1142     hr = ScriptGetFontProperties(hdc,NULL,&sfp);
1143     ok( hr == E_INVALIDARG, "(hdc,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
1144
1145     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1146     psc = NULL;
1147     hr = ScriptGetFontProperties(hdc,&psc,NULL);
1148     ok( hr == E_INVALIDARG, "(hdc,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr);
1149     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1150
1151     /* Pass an invalid sfp */
1152     psc = NULL;
1153     sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES) - 1;
1154     hr = ScriptGetFontProperties(hdc,&psc,&sfp);
1155     ok( hr == E_INVALIDARG, "(hdc,&psc,&sfp) invalid, expected E_INVALIDARG, got %08x\n", hr);
1156     ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
1157     ScriptFreeCache(&psc);
1158     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1159
1160     /* Give it the correct cBytes, we don't care about what's coming back */
1161     sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES);
1162     psc = NULL;
1163     hr = ScriptGetFontProperties(hdc,&psc,&sfp);
1164     ok( hr == S_OK, "(hdc,&psc,&sfp) partly initialized, expected S_OK, got %08x\n", hr);
1165     ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
1166
1167     /* Save the psc pointer */
1168     old_psc = psc;
1169     /* Now a NULL hdc again */
1170     hr = ScriptGetFontProperties(NULL,&psc,&sfp);
1171     ok( hr == S_OK, "(NULL,&psc,&sfp), expected S_OK, got %08x\n", hr);
1172     ok( psc == old_psc, "Expected psc not to be changed, was %p is now %p\n", old_psc, psc);
1173     ScriptFreeCache(&psc);
1174     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1175 }
1176
1177 static void test_ScriptTextOut(HDC hdc)
1178 {
1179     HRESULT         hr;
1180
1181     int             cInChars;
1182     int             cMaxItems;
1183     SCRIPT_ITEM     pItem[255];
1184     int             pcItems;
1185     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
1186
1187     SCRIPT_CACHE    psc;
1188     int             cChars;
1189     int             cMaxGlyphs;
1190     unsigned short  pwOutGlyphs1[256];
1191     WORD            pwLogClust[256];
1192     SCRIPT_VISATTR  psva[256];
1193     int             pcGlyphs;
1194     int             piAdvance[256];
1195     GOFFSET         pGoffset[256];
1196     ABC             pABC[256];
1197     RECT            rect;
1198     int             piX;
1199     int             iCP = 1;
1200     BOOL            fTrailing = FALSE;
1201     SCRIPT_LOGATTR  *psla;
1202     SCRIPT_LOGATTR  sla[256];
1203
1204     /* This is a valid test that will cause parsing to take place                             */
1205     cInChars = 5;
1206     cMaxItems = 255;
1207     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1208     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
1209     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
1210      *  returned.                                                                             */
1211     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
1212     if (pcItems > 0)
1213         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
1214             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
1215             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
1216
1217     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
1218      * ie. ScriptItemize has succeeded and that pItem has been set                            */
1219     cInChars = 5;
1220     if (hr == 0) {
1221         psc = NULL;                                   /* must be null on first call           */
1222         cChars = cInChars;
1223         cMaxGlyphs = 256;
1224         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
1225                          cMaxGlyphs, &pItem[0].a,
1226                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
1227         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
1228         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1229         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
1230         if (hr ==0) {
1231             /* Note hdc is needed as glyph info is not yet in psc                  */
1232             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
1233                              pGoffset, pABC);
1234             ok (hr == 0, "Should return 0 not (%08x)\n", hr);
1235             ScriptFreeCache(&psc);              /* Get rid of psc for next test set */
1236             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1237
1238             hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL);
1239             ok (hr == E_INVALIDARG, "Should return 0 not (%08x)\n", hr);
1240
1241             hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1242                                piAdvance, NULL, pGoffset);
1243             ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
1244                                     "expected E_INVALIDARG, got %08x\n", hr);
1245
1246             /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1247             psc = NULL;
1248             hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0,
1249                                NULL, NULL, NULL);
1250             ok( hr == E_INVALIDARG, "(NULL,&psc,NULL,0,0,0,NULL,), expected E_INVALIDARG, "
1251                                     "got %08x\n", hr);
1252             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1253
1254             /* hdc is required for this one rather than the usual optional          */
1255             psc = NULL;
1256             hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1257                                piAdvance, NULL, pGoffset);
1258             ok( hr == E_INVALIDARG, "(NULL,&psc,), expected E_INVALIDARG, got %08x\n", hr);
1259             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1260
1261             /* Set that it returns 0 status */
1262             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1263                                piAdvance, NULL, pGoffset);
1264             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
1265
1266             /* Test Rect Rgn is acceptable */
1267             rect.top = 10;
1268             rect.bottom = 20;
1269             rect.left = 10;
1270             rect.right = 40;
1271             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, &rect, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1272                                piAdvance, NULL, pGoffset);
1273             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
1274
1275             iCP = 1;
1276             hr = ScriptCPtoX(iCP, fTrailing, cChars, pcGlyphs, (const WORD *) &pwLogClust,
1277                             (const SCRIPT_VISATTR *) &psva, (const int *)&piAdvance, &pItem[0].a, &piX);
1278             ok(hr == S_OK, "ScriptCPtoX Stub should return S_OK not %08x\n", hr);
1279
1280             psla = (SCRIPT_LOGATTR *)&sla;
1281             hr = ScriptBreak(TestItem1, cChars, &pItem[0].a, psla);
1282             ok(hr == S_OK, "ScriptBreak Stub should return S_OK not %08x\n", hr);
1283
1284             /* Clean up and go   */
1285             ScriptFreeCache(&psc);
1286             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1287         }
1288     }
1289 }
1290
1291 static void test_ScriptTextOut2(HDC hdc)
1292 {
1293 /*  Intent is to validate that the HDC passed into ScriptTextOut is
1294  *  used instead of the (possibly) invalid cached one
1295  */
1296     HRESULT         hr;
1297
1298     HDC             hdc1, hdc2;
1299     int             cInChars;
1300     int             cMaxItems;
1301     SCRIPT_ITEM     pItem[255];
1302     int             pcItems;
1303     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
1304
1305     SCRIPT_CACHE    psc;
1306     int             cChars;
1307     int             cMaxGlyphs;
1308     unsigned short  pwOutGlyphs1[256];
1309     WORD            pwLogClust[256];
1310     SCRIPT_VISATTR  psva[256];
1311     int             pcGlyphs;
1312     int             piAdvance[256];
1313     GOFFSET         pGoffset[256];
1314     ABC             pABC[256];
1315
1316     /* Create an extra DC that will be used until the ScriptTextOut */
1317     hdc1 = CreateCompatibleDC(hdc);
1318     ok (hdc1 != 0, "CreateCompatibleDC failed to create a DC\n");
1319     hdc2 = CreateCompatibleDC(hdc);
1320     ok (hdc2 != 0, "CreateCompatibleDC failed to create a DC\n");
1321
1322     /* This is a valid test that will cause parsing to take place                             */
1323     cInChars = 5;
1324     cMaxItems = 255;
1325     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1326     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
1327     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
1328      *  returned.                                                                             */
1329     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
1330     if (pcItems > 0)
1331         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
1332             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
1333             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
1334
1335     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
1336      * ie. ScriptItemize has succeeded and that pItem has been set                            */
1337     cInChars = 5;
1338     if (hr == 0) {
1339         psc = NULL;                                   /* must be null on first call           */
1340         cChars = cInChars;
1341         cMaxGlyphs = 256;
1342         hr = ScriptShape(hdc2, &psc, TestItem1, cChars,
1343                          cMaxGlyphs, &pItem[0].a,
1344                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
1345         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
1346         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1347         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
1348         if (hr ==0) {
1349             /* Note hdc is needed as glyph info is not yet in psc                  */
1350             hr = ScriptPlace(hdc2, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
1351                              pGoffset, pABC);
1352             ok (hr == 0, "Should return 0 not (%08x)\n", hr);
1353
1354             /*   key part!!!   cached dc is being deleted  */
1355             hr = DeleteDC(hdc2);
1356             ok(hr == 1, "DeleteDC should return 1 not %08x\n", hr);
1357
1358             /* At this point the cached hdc (hdc2) has been destroyed,
1359              * however, we are passing in a *real* hdc (the original hdc).
1360              * The text should be written to that DC
1361              */
1362             hr = ScriptTextOut(hdc1, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1363                                piAdvance, NULL, pGoffset);
1364             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
1365             ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1366
1367             DeleteDC(hdc1);
1368
1369             /* Clean up and go   */
1370             ScriptFreeCache(&psc);
1371             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1372         }
1373     }
1374 }
1375
1376 static void test_ScriptTextOut3(HDC hdc)
1377 {
1378     HRESULT         hr;
1379
1380     int             cInChars;
1381     int             cMaxItems;
1382     SCRIPT_ITEM     pItem[255];
1383     int             pcItems;
1384     WCHAR           TestItem1[] = {' ','\r', 0};
1385
1386     SCRIPT_CACHE    psc;
1387     int             cChars;
1388     int             cMaxGlyphs;
1389     unsigned short  pwOutGlyphs1[256];
1390     WORD            pwLogClust[256];
1391     SCRIPT_VISATTR  psva[256];
1392     int             pcGlyphs;
1393     int             piAdvance[256];
1394     GOFFSET         pGoffset[256];
1395     ABC             pABC[256];
1396     RECT            rect;
1397
1398     /* This is to ensure that non exisiting glyphs are translated into a valid glyph number */
1399     cInChars = 2;
1400     cMaxItems = 255;
1401     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1402     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
1403     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
1404      *  returned.                                                                             */
1405     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
1406     if (pcItems > 0)
1407         ok (pItem[0].iCharPos == 0 && pItem[2].iCharPos == cInChars,
1408             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
1409             pItem[0].iCharPos, cInChars, pItem[2].iCharPos);
1410
1411     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
1412      * ie. ScriptItemize has succeeded and that pItem has been set                            */
1413     cInChars = 2;
1414     if (hr == 0) {
1415         psc = NULL;                                   /* must be null on first call           */
1416         cChars = cInChars;
1417         cMaxGlyphs = 256;
1418         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
1419                          cMaxGlyphs, &pItem[0].a,
1420                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
1421         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
1422         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1423         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
1424         if (hr ==0) {
1425             /* Note hdc is needed as glyph info is not yet in psc                  */
1426             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
1427                              pGoffset, pABC);
1428             ok (hr == 0, "Should return 0 not (%08x)\n", hr);
1429
1430             /* Test Rect Rgn is acceptable */
1431             rect.top = 10;
1432             rect.bottom = 20;
1433             rect.left = 10;
1434             rect.right = 40;
1435             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, &rect, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1436                                piAdvance, NULL, pGoffset);
1437             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
1438
1439         }
1440         /* Clean up and go   */
1441         ScriptFreeCache(&psc);
1442         ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1443     }
1444 }
1445
1446 static void test_ScriptXtoX(void)
1447 /****************************************************************************************
1448  *  This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables *
1449  ****************************************************************************************/
1450 {
1451     static const WCHAR test[] = {'t', 'e', 's', 't',0};
1452     SCRIPT_ITEM items[2];
1453     int iX, iCP;
1454     int cChars;
1455     int cGlyphs;
1456     WORD pwLogClust[10] = {0, 0, 0, 1, 1, 2, 2, 3, 3, 3};
1457     WORD pwLogClust_RTL[10] = {3, 3, 3, 2, 2, 1, 1, 0, 0, 0};
1458     SCRIPT_VISATTR psva[10];
1459     int piAdvance[10] = {200, 190, 210, 180, 170, 204, 189, 195, 212, 203};
1460     int piCP, piX;
1461     int piTrailing;
1462     BOOL fTrailing;
1463     HRESULT hr;
1464     static const int offsets[13] = {0, 66, 133, 200, 295, 390, 495, 600, 1051, 1502, 1953, 1953, 1953};
1465     static const int offsets_RTL[13] = {780, 720, 660, 600, 495, 390, 295, 200, 133, 66, 0, 0, 0};
1466
1467     hr = ScriptItemize(test, lstrlenW(test), sizeof(items)/sizeof(items[0]), NULL, NULL, items, NULL);
1468     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
1469
1470     iX = -1;
1471     cChars = 10;
1472     cGlyphs = 10;
1473     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1474     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1475     if (piTrailing)
1476         ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
1477     else /* win2k3 */
1478         ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
1479
1480     for(iCP = 0; iCP < 10; iCP++)
1481     {
1482         iX = offsets[iCP]+1;
1483         cChars = 10;
1484         cGlyphs = 10;
1485         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1486         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1487         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1488         ok(piTrailing == 0, "iX=%d should return piTrailing=0 not %d\n", iX, piTrailing);
1489     }
1490
1491     for(iCP = 0; iCP < 10; iCP++)
1492     {
1493         iX = offsets[iCP+1]-1;
1494         cChars = 10;
1495         cGlyphs = 10;
1496         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1497         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1498         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1499         ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
1500     }
1501
1502     /* 0,1,2 are actually fractional offsets meaning that they will not be reporting the same iCP as comes in so don't test those */
1503     for(iCP = 3; iCP < 10; iCP++)
1504     {
1505         iX = offsets[iCP];
1506         cChars = 10;
1507         cGlyphs = 10;
1508         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1509         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1510         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1511         ok(piTrailing == 0, "iX=%d should return piTrailing=0 not %d\n", iX, piTrailing);
1512     }
1513
1514     items[0].a.fRTL = TRUE;
1515
1516     iX = -1;
1517     cChars = 10;
1518     cGlyphs = 10;
1519     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1520     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1521     if (piTrailing)
1522         ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
1523     else /* win2k3 */
1524         ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
1525
1526     iX = 1954;
1527     cChars = 10;
1528     cGlyphs = 10;
1529     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1530     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1531     ok(piCP == -1, "iX=%d should return piCP=-1 not %d\n", iX, piCP);
1532     ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
1533
1534     for(iCP = 0; iCP < 10; iCP++)
1535     {
1536         iX = offsets_RTL[iCP]-1;
1537         cChars = 10;
1538         cGlyphs = 10;
1539         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1540         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1541         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1542         ok(piTrailing == 0, "iX=%d should return piTrailing=0 not %d\n", iX, piTrailing);
1543     }
1544
1545     for(iCP = 0; iCP < 10; iCP++)
1546     {
1547         iX = offsets_RTL[iCP+1]+1;
1548         cChars = 10;
1549         cGlyphs = 10;
1550         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1551         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1552         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1553         ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
1554     }
1555
1556     for(iCP = 0; iCP < 10; iCP++)
1557     {
1558         iX = offsets_RTL[iCP];
1559         cChars = 10;
1560         cGlyphs = 10;
1561         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1562         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1563         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1564         ok(piTrailing == 0, "iX=%d should return piTrailing=0 not %d\n", iX, piTrailing);
1565     }
1566
1567     items[0].a.fRTL = FALSE;
1568
1569     for(iCP = 0; iCP <= 11; iCP++)
1570     {
1571         fTrailing = FALSE;
1572         cChars = 10;
1573         cGlyphs = 10;
1574         hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
1575         ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
1576         ok(piX == offsets[iCP],
1577            "iCP=%d should return piX=%d not %d\n", iCP, offsets[iCP], piX);
1578     }
1579
1580     for(iCP = 0; iCP <= 11; iCP++)
1581     {
1582         fTrailing = TRUE;
1583         cChars = 10;
1584         cGlyphs = 10;
1585         hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
1586         ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
1587         ok(piX == offsets[iCP+1],
1588            "iCP=%d should return piX=%d not %d\n", iCP, offsets[iCP+1], piX);
1589     }
1590
1591     items[0].a.fRTL = TRUE;
1592
1593     for(iCP = 0; iCP <= 11; iCP++)
1594     {
1595         fTrailing = FALSE;
1596         cChars = 10;
1597         cGlyphs = 10;
1598         hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piX);
1599         ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
1600         ok(piX == offsets_RTL[iCP],
1601            "iCP=%d should return piX=%d not %d\n", iCP, offsets_RTL[iCP], piX);
1602     }
1603
1604     for(iCP = 0; iCP <= 11; iCP++)
1605     {
1606         fTrailing = TRUE;
1607         cChars = 10;
1608         cGlyphs = 10;
1609         hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piX);
1610         ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
1611         ok(piX == offsets_RTL[iCP+1],
1612            "iCP=%d should return piX=%d not %d\n", iCP, offsets_RTL[iCP+1], piX);
1613     }
1614 }
1615
1616 static void test_ScriptString(HDC hdc)
1617 {
1618 /*******************************************************************************************
1619  *
1620  * This set of tests are for the string functions of uniscribe.  The ScriptStringAnalyse
1621  * function allocates memory pointed to by the SCRIPT_STRING_ANALYSIS ssa pointer.  This
1622  * memory is freed by ScriptStringFree.  There needs to be a valid hdc for this as
1623  * ScriptStringAnalyse calls ScriptSItemize, ScriptShape and ScriptPlace which require it.
1624  *
1625  */
1626
1627     HRESULT         hr;
1628     WCHAR           teststr[] = {'T','e','s','t','1',' ','a','2','b','3', '\0'};
1629     int             len = (sizeof(teststr) / sizeof(WCHAR)) - 1;
1630     int             Glyphs = len * 2 + 16;
1631     int             Charset;
1632     DWORD           Flags = SSA_GLYPHS;
1633     int             ReqWidth = 100;
1634     const int       Dx[5] = {10, 10, 10, 10, 10};
1635     const BYTE      InClass = 0;
1636     SCRIPT_STRING_ANALYSIS ssa = NULL;
1637
1638     int             X = 10; 
1639     int             Y = 100;
1640     UINT            Options = 0; 
1641     const RECT      rc = {0, 50, 100, 100}; 
1642     int             MinSel = 0;
1643     int             MaxSel = 0;
1644     BOOL            Disabled = FALSE;
1645     const int      *clip_len;
1646     int            i;
1647     UINT           *order;
1648
1649
1650     Charset = -1;     /* this flag indicates unicode input */
1651     /* Test without hdc to get E_PENDING */
1652     hr = ScriptStringAnalyse( NULL, teststr, len, Glyphs, Charset, Flags,
1653                               ReqWidth, NULL, NULL, Dx, NULL,
1654                               &InClass, &ssa);
1655     ok(hr == E_PENDING, "ScriptStringAnalyse Stub should return E_PENDING not %08x\n", hr);
1656
1657     /* test with hdc, this should be a valid test  */
1658     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
1659                               ReqWidth, NULL, NULL, Dx, NULL,
1660                               &InClass, &ssa);
1661     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
1662     ScriptStringFree(&ssa);
1663
1664     /* test makes sure that a call with a valid pssa still works */
1665     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
1666                               ReqWidth, NULL, NULL, Dx, NULL,
1667                               &InClass, &ssa);
1668     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
1669     ok(ssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
1670
1671     if (hr == S_OK)
1672     {
1673         hr = ScriptStringOut(ssa, X, Y, Options, &rc, MinSel, MaxSel, Disabled);
1674         ok(hr == S_OK, "ScriptStringOut should return S_OK not %08x\n", hr);
1675     }
1676
1677      clip_len = ScriptString_pcOutChars(ssa);
1678      ok(*clip_len == len, "ScriptString_pcOutChars failed, got %d, expected %d\n", *clip_len, len);
1679
1680      order = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *clip_len * sizeof(UINT));
1681      hr = ScriptStringGetOrder(ssa, order);
1682      ok(hr == S_OK, "ScriptStringGetOrder failed, got %08x, expected S_OK\n", hr);
1683
1684      for (i = 0; i < *clip_len; i++) ok(order[i] == i, "%d: got %d expected %d\n", i, order[i], i);
1685      HeapFree(GetProcessHeap(), 0, order);
1686
1687      hr = ScriptStringFree(&ssa);
1688      ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
1689 }
1690
1691 static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
1692 {
1693 /*****************************************************************************************
1694  *
1695  * This test is for the ScriptStringXtoCP and ScriptStringXtoCP functions.  Due to the
1696  * nature of the fonts between Windows and Wine, the test is implemented by generating
1697  * values using one one function then checking the output of the second.  In this way
1698  * the validity of the functions is established using Windows as a base and confirming
1699  * similar behaviour in wine.
1700  */
1701
1702     HRESULT         hr;
1703     static const WCHAR teststr1[]  = {0x05e9, 'i', 0x05dc, 'n', 0x05d5, 'e', 0x05dd, '.',0};
1704     static const BOOL rtl[] = {1, 0, 1, 0, 1, 0, 1, 0};
1705     void            *String = (WCHAR *) &teststr1;      /* ScriptStringAnalysis needs void */
1706     int             String_len = (sizeof(teststr1)/sizeof(WCHAR))-1;
1707     int             Glyphs = String_len * 2 + 16;       /* size of buffer as recommended  */
1708     int             Charset = -1;                       /* unicode                        */
1709     DWORD           Flags = SSA_GLYPHS;
1710     int             ReqWidth = 100;
1711     const BYTE      InClass = 0;
1712     SCRIPT_STRING_ANALYSIS ssa = NULL;
1713
1714     int             Ch;                                  /* Character position in string */
1715     int             iTrailing;
1716     int             Cp;                                  /* Character position in string */
1717     int             X;
1718     int             trail,lead;
1719     BOOL            fTrailing;
1720
1721     /* Test with hdc, this should be a valid test
1722      * Here we generate an SCRIPT_STRING_ANALYSIS that will be used as input to the
1723      * following character positions to X and X to character position functions.
1724      */
1725
1726     hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
1727                               ReqWidth, NULL, NULL, NULL, NULL,
1728                               &InClass, &ssa);
1729     ok(hr == S_OK ||
1730        hr == E_INVALIDARG, /* NT */
1731        "ScriptStringAnalyse should return S_OK or E_INVALIDARG not %08x\n", hr);
1732
1733     if  (hr == S_OK)
1734     {
1735         ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
1736
1737         /*
1738          * Loop to generate character positions to provide starting positions for the
1739          * ScriptStringCPtoX and ScriptStringXtoCP functions
1740          */
1741         for (Cp = 0; Cp < String_len; Cp++)
1742         {
1743             /* The fTrailing flag is used to indicate whether the X being returned is at
1744              * the beginning or the end of the character. What happens here is that if
1745              * fTrailing indicates the end of the character, ie. FALSE, then ScriptStringXtoCP
1746              * returns the beginning of the next character and iTrailing is FALSE.  So for this
1747              * loop iTrailing will be FALSE in both cases.
1748              */
1749             hr = ScriptStringCPtoX(ssa, Cp, TRUE, &trail);
1750             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1751             hr = ScriptStringCPtoX(ssa, Cp, FALSE, &lead);
1752             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1753             if (rtl[Cp])
1754                 ok(lead > trail, "Leading values should be after trialing for rtl chracters(%i)\n",Cp);
1755             else
1756                 ok(lead < trail, "Trailing values should be after leading for ltr chracters(%i)\n",Cp);
1757
1758             /* move by 1 pixel so that we are not inbetween 2 characters.  That could result in being the lead of a rtl and
1759                at the same time the trail of an ltr */
1760
1761             /* inside the leading edge */
1762             X = lead;
1763             if (rtl[Cp]) X--; else X++;
1764             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1765             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1766             ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, trail);
1767             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
1768                                   iTrailing, X);
1769
1770             /* inside the trailing edge */
1771             X = trail;
1772             if (rtl[Cp]) X++; else X--;
1773             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1774             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1775             ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, trail);
1776             ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
1777                                   iTrailing, X);
1778
1779             /* outside the "trailing" edge */
1780             if (Cp < String_len-1)
1781             {
1782                 if (rtl[Cp]) X = lead; else X = trail;
1783                 X++;
1784                 hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1785                 ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1786                 ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, trail);
1787                 if (rtl[Cp+1])
1788                     ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
1789                                           iTrailing, X);
1790                 else
1791                     ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
1792                                           iTrailing, X);
1793             }
1794
1795             /* outside the "leading" edge */
1796             if (Cp != 0)
1797             {
1798                 if (rtl[Cp]) X = trail; else X = lead;
1799                 X--;
1800                 hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1801                 ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1802                 ok(Cp - 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp - 1, Ch, trail);
1803                 if (Cp != 0  && rtl[Cp-1])
1804                     ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
1805                                           iTrailing, X);
1806                 else
1807                     ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
1808                                           iTrailing, X);
1809             }
1810         }
1811
1812         /* Check beyond the leading boundary of the whole string */
1813         if (rtl[0])
1814         {
1815             /* having a leading rtl character seems to confuse usp */
1816             /* this looks to be a windows bug we should emulate */
1817             hr = ScriptStringCPtoX(ssa, 0, TRUE, &X);
1818             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1819             X--;
1820             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1821             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1822             ok(Ch == 1, "ScriptStringXtoCP should return Ch = 1 not %d for X outside leading edge when rtl\n", Ch);
1823             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = outside leading edge when rtl\n",
1824                                        iTrailing);
1825         }
1826         else
1827         {
1828             hr = ScriptStringCPtoX(ssa, 0, FALSE, &X);
1829             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1830             X--;
1831             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1832             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1833             ok(Ch == -1, "ScriptStringXtoCP should return Ch = -1 not %d for X outside leading edge\n", Ch);
1834             ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = outside leading edge\n",
1835                                        iTrailing);
1836         }
1837
1838         /* Check beyond the end boundary of the whole string */
1839         if (rtl[String_len-1])
1840         {
1841             hr = ScriptStringCPtoX(ssa, String_len-1, FALSE, &X);
1842             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1843         }
1844         else
1845         {
1846             hr = ScriptStringCPtoX(ssa, String_len-1, TRUE, &X);
1847             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1848         }
1849         X++;
1850         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1851         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1852         ok(Ch == String_len, "ScriptStringXtoCP should return Ch = %i not %d for X outside trailing edge\n", String_len, Ch);
1853         ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = outside traling edge\n",
1854                                    iTrailing);
1855
1856         /*
1857          * Cleanup the SSA for the next round of tests
1858          */
1859         hr = ScriptStringFree(&ssa);
1860         ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
1861
1862         /*
1863          * Test to see that exceeding the number of chars returns E_INVALIDARG.  First
1864          * generate an SSA for the subsequent tests.
1865          */
1866         hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
1867                                   ReqWidth, NULL, NULL, NULL, NULL,
1868                                   &InClass, &ssa);
1869         ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
1870
1871         /*
1872          * When ScriptStringCPtoX is called with a character position Cp that exceeds the
1873          * string length, return E_INVALIDARG.  This also invalidates the ssa so a
1874          * ScriptStringFree should also fail.
1875          */
1876         fTrailing = FALSE;
1877         Cp = String_len + 1;
1878         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
1879         ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr);
1880
1881         ScriptStringFree(&ssa);
1882     }
1883 }
1884
1885 static void test_ScriptCacheGetHeight(HDC hdc)
1886 {
1887     HRESULT hr;
1888     SCRIPT_CACHE sc = NULL;
1889     LONG height;
1890
1891     hr = ScriptCacheGetHeight(NULL, NULL, NULL);
1892     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1893
1894     hr = ScriptCacheGetHeight(NULL, &sc, NULL);
1895     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1896
1897     hr = ScriptCacheGetHeight(NULL, &sc, &height);
1898     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1899
1900     height = 0;
1901
1902     hr = ScriptCacheGetHeight(hdc, &sc, &height);
1903     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1904     ok(height > 0, "expected height > 0\n");
1905
1906     ScriptFreeCache(&sc);
1907 }
1908
1909 static void test_ScriptGetGlyphABCWidth(HDC hdc)
1910 {
1911     HRESULT hr;
1912     SCRIPT_CACHE sc = NULL;
1913     ABC abc;
1914
1915     hr = ScriptGetGlyphABCWidth(NULL, NULL, 'a', NULL);
1916     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1917
1918     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', NULL);
1919     ok(broken(hr == E_PENDING) ||
1920        hr == E_INVALIDARG, /* WIN7 */
1921        "expected E_INVALIDARG, got 0x%08x\n", hr);
1922
1923     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', &abc);
1924     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1925
1926     if (0) {    /* crashes on WinXP */
1927     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', NULL);
1928     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1929     }
1930
1931     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', &abc);
1932     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1933
1934     ScriptFreeCache(&sc);
1935 }
1936
1937 static void test_ScriptLayout(void)
1938 {
1939     HRESULT hr;
1940     static const BYTE levels[][10] =
1941     {
1942         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1943         { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1944         { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
1945         { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
1946
1947         { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1},
1948         { 1, 1, 1, 2, 2, 2, 1, 1, 1, 1 },
1949         { 2, 2, 2, 1, 1, 1, 2, 2, 2, 2 },
1950         { 0, 0, 1, 1, 2, 2, 1, 1, 0, 0 },
1951         { 1, 1, 2, 2, 3, 3, 2, 2, 1, 1 },
1952
1953         { 0, 0, 1, 1, 2, 2, 1, 1, 0, 1 },
1954         { 1, 0, 1, 2, 2, 1, 2, 1, 0, 1 },
1955     };
1956     static const int expect_l2v[][10] =
1957     {
1958         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
1959         { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
1960         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
1961         { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
1962
1963         { 0, 1, 2, 3, 4, 9, 8 ,7 ,6, 5},
1964 /**/    { 9, 8, 7, 4, 5, 6, 3 ,2 ,1, 0},
1965 /**/    { 7, 8, 9, 6, 5, 4, 0 ,1 ,2, 3},
1966         { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1967         { 9, 8, 2, 3, 5, 4, 6 ,7 ,1, 0},
1968
1969         { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1970 /**/    { 0, 1, 7, 5, 6, 4, 3 ,2 ,8, 9},
1971     };
1972     static const int expect_v2l[][10] =
1973     {
1974         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
1975         { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
1976         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
1977         { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
1978
1979         { 0, 1, 2, 3, 4, 9, 8 ,7 ,6, 5},
1980         { 9, 8, 7, 6, 3, 4, 5 ,2 ,1, 0},
1981         { 6, 7, 8, 9, 5, 4, 3 ,0 ,1, 2},
1982         { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1983         { 9, 8, 2, 3, 5, 4, 6 ,7 ,1, 0},
1984
1985         { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
1986         { 0, 1, 7, 6, 5, 3, 4 ,2 ,8, 9},
1987     };
1988
1989     int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])];
1990
1991     hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis);
1992     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1993
1994     hr = ScriptLayout(sizeof(levels[0]), levels[0], NULL, NULL);
1995     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1996
1997     for (i = 0; i < sizeof(levels)/sizeof(levels[0]); i++)
1998     {
1999         hr = ScriptLayout(sizeof(levels[0]), levels[i], vistolog, logtovis);
2000         ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2001
2002         for (j = 0; j < sizeof(levels[i]); j++)
2003         {
2004             ok(expect_v2l[i][j] == vistolog[j],
2005                "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n",
2006                i, j, levels[i][j], j, vistolog[j] );
2007         }
2008
2009         for (j = 0; j < sizeof(levels[i]); j++)
2010         {
2011             ok(expect_l2v[i][j] == logtovis[j],
2012                "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n",
2013                i, j, levels[i][j], j, logtovis[j] );
2014         }
2015     }
2016 }
2017
2018 static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR lparam)
2019 {
2020     HRESULT hr;
2021     SCRIPT_DIGITSUBSTITUTE sds;
2022     SCRIPT_CONTROL sc;
2023     SCRIPT_STATE ss;
2024     LCID lcid_old;
2025
2026     if (!IsValidLocale(lcid, LCID_INSTALLED)) return TRUE;
2027
2028     memset(&sds, 0, sizeof(sds));
2029     memset(&sc, 0, sizeof(sc));
2030     memset(&ss, 0, sizeof(ss));
2031
2032     lcid_old = GetThreadLocale();
2033     if (!SetThreadLocale(lcid)) return TRUE;
2034
2035     hr = ScriptRecordDigitSubstitution(lcid, &sds);
2036     ok(hr == S_OK, "ScriptRecordDigitSubstitution failed: 0x%08x\n", hr);
2037
2038     hr = ScriptApplyDigitSubstitution(&sds, &sc, &ss);
2039     ok(hr == S_OK, "ScriptApplyDigitSubstitution failed: 0x%08x\n", hr);
2040
2041     SetThreadLocale(lcid_old);
2042     return TRUE;
2043 }
2044
2045 static void test_digit_substitution(void)
2046 {
2047     BOOL ret;
2048     unsigned int i;
2049     static const LGRPID groups[] =
2050     {
2051         LGRPID_WESTERN_EUROPE,
2052         LGRPID_CENTRAL_EUROPE,
2053         LGRPID_BALTIC,
2054         LGRPID_GREEK,
2055         LGRPID_CYRILLIC,
2056         LGRPID_TURKISH,
2057         LGRPID_JAPANESE,
2058         LGRPID_KOREAN,
2059         LGRPID_TRADITIONAL_CHINESE,
2060         LGRPID_SIMPLIFIED_CHINESE,
2061         LGRPID_THAI,
2062         LGRPID_HEBREW,
2063         LGRPID_ARABIC,
2064         LGRPID_VIETNAMESE,
2065         LGRPID_INDIC,
2066         LGRPID_GEORGIAN,
2067         LGRPID_ARMENIAN
2068     };
2069     HMODULE hKernel32;
2070     static BOOL (WINAPI * pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA,LGRPID,DWORD,LONG_PTR);
2071
2072     hKernel32 = GetModuleHandleA("kernel32.dll");
2073     pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
2074
2075     if (!pEnumLanguageGroupLocalesA)
2076     {
2077         win_skip("EnumLanguageGroupLocalesA not available on this platform\n");
2078         return;
2079     }
2080
2081     for (i = 0; i < sizeof(groups)/sizeof(groups[0]); i++)
2082     {
2083         ret = pEnumLanguageGroupLocalesA(enum_proc, groups[i], 0, 0);
2084         if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2085         {
2086             win_skip("EnumLanguageGroupLocalesA not implemented on this platform\n");
2087             break;
2088         }
2089         
2090         ok(ret, "EnumLanguageGroupLocalesA failed unexpectedly: %u\n", GetLastError());
2091     }
2092 }
2093
2094 static void test_ScriptGetProperties(void)
2095 {
2096     const SCRIPT_PROPERTIES **props;
2097     HRESULT hr;
2098     int num;
2099
2100     hr = ScriptGetProperties(NULL, NULL);
2101     ok(hr == E_INVALIDARG, "ScriptGetProperties succeeded\n");
2102
2103     hr = ScriptGetProperties(NULL, &num);
2104     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
2105
2106     hr = ScriptGetProperties(&props, NULL);
2107     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
2108
2109     hr = ScriptGetProperties(&props, &num);
2110     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
2111 }
2112
2113 static void test_ScriptBreak(void)
2114 {
2115     static const WCHAR test[] = {' ','\r','\n',0};
2116     SCRIPT_ITEM items[4];
2117     SCRIPT_LOGATTR la;
2118     HRESULT hr;
2119
2120     hr = ScriptItemize(test, 3, 4, NULL, NULL, items, NULL);
2121     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
2122
2123     memset(&la, 0, sizeof(la));
2124     hr = ScriptBreak(test, 1, &items[0].a, &la);
2125     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
2126
2127     ok(!la.fSoftBreak, "fSoftBreak set\n");
2128     ok(la.fWhiteSpace, "fWhiteSpace not set\n");
2129     ok(la.fCharStop, "fCharStop not set\n");
2130     ok(!la.fWordStop, "fWordStop set\n");
2131     ok(!la.fInvalid, "fInvalid set\n");
2132     ok(!la.fReserved, "fReserved set\n");
2133
2134     memset(&la, 0, sizeof(la));
2135     hr = ScriptBreak(test + 1, 1, &items[1].a, &la);
2136     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
2137
2138     ok(!la.fSoftBreak, "fSoftBreak set\n");
2139     ok(!la.fWhiteSpace, "fWhiteSpace set\n");
2140     ok(la.fCharStop, "fCharStop not set\n");
2141     ok(!la.fWordStop, "fWordStop set\n");
2142     ok(!la.fInvalid, "fInvalid set\n");
2143     ok(!la.fReserved, "fReserved set\n");
2144
2145     memset(&la, 0, sizeof(la));
2146     hr = ScriptBreak(test + 2, 1, &items[2].a, &la);
2147     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
2148
2149     ok(!la.fSoftBreak, "fSoftBreak set\n");
2150     ok(!la.fWhiteSpace, "fWhiteSpace set\n");
2151     ok(la.fCharStop, "fCharStop not set\n");
2152     ok(!la.fWordStop, "fWordStop set\n");
2153     ok(!la.fInvalid, "fInvalid set\n");
2154     ok(!la.fReserved, "fReserved set\n");
2155 }
2156
2157 static void test_newlines(void)
2158 {
2159     static const WCHAR test1[] = {'t','e','x','t','\r','t','e','x','t',0};
2160     static const WCHAR test2[] = {'t','e','x','t','\n','t','e','x','t',0};
2161     static const WCHAR test3[] = {'t','e','x','t','\r','\n','t','e','x','t',0};
2162     static const WCHAR test4[] = {'t','e','x','t','\n','\r','t','e','x','t',0};
2163     static const WCHAR test5[] = {'1','2','3','4','\n','\r','1','2','3','4',0};
2164     SCRIPT_ITEM items[5];
2165     HRESULT hr;
2166     int count;
2167
2168     count = 0;
2169     hr = ScriptItemize(test1, lstrlenW(test1), 5, NULL, NULL, items, &count);
2170     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2171     ok(count == 3, "got %d expected 3\n", count);
2172
2173     count = 0;
2174     hr = ScriptItemize(test2, lstrlenW(test2), 5, NULL, NULL, items, &count);
2175     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2176     ok(count == 3, "got %d expected 3\n", count);
2177
2178     count = 0;
2179     hr = ScriptItemize(test3, lstrlenW(test3), 5, NULL, NULL, items, &count);
2180     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2181     ok(count == 4, "got %d expected 4\n", count);
2182
2183     count = 0;
2184     hr = ScriptItemize(test4, lstrlenW(test4), 5, NULL, NULL, items, &count);
2185     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2186     ok(count == 4, "got %d expected 4\n", count);
2187
2188     count = 0;
2189     hr = ScriptItemize(test5, lstrlenW(test5), 5, NULL, NULL, items, &count);
2190     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2191     ok(count == 4, "got %d expected 4\n", count);
2192 }
2193
2194 START_TEST(usp10)
2195 {
2196     HWND            hwnd;
2197     HDC             hdc;
2198     LOGFONTA        lf;
2199     HFONT           hfont;
2200
2201     unsigned short  pwOutGlyphs[256];
2202
2203     /* We need a valid HDC to drive a lot of Script functions which requires the following    *
2204      * to set up for the tests.                                                               */
2205     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
2206                            0, 0, 0, NULL);
2207     assert(hwnd != 0);
2208     ShowWindow(hwnd, SW_SHOW);
2209     UpdateWindow(hwnd);
2210
2211     hdc = GetDC(hwnd);                                      /* We now have a hdc             */
2212     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
2213
2214     memset(&lf, 0, sizeof(LOGFONTA));
2215     lstrcpyA(lf.lfFaceName, "Tahoma");
2216     lf.lfHeight = 10;
2217     lf.lfWeight = 3;
2218     lf.lfWidth = 10;
2219
2220     hfont = SelectObject(hdc, CreateFontIndirectA(&lf));
2221     ok(hfont != NULL, "SelectObject failed: %p\n", hfont);
2222
2223     test_ScriptItemize();
2224     test_ScriptItemIzeShapePlace(hdc,pwOutGlyphs);
2225     test_ScriptGetCMap(hdc, pwOutGlyphs);
2226     test_ScriptCacheGetHeight(hdc);
2227     test_ScriptGetGlyphABCWidth(hdc);
2228     test_ScriptShape(hdc);
2229     test_ScriptShapeOpenType(hdc);
2230     test_ScriptPlace(hdc);
2231
2232     test_ScriptGetFontProperties(hdc);
2233     test_ScriptTextOut(hdc);
2234     test_ScriptTextOut2(hdc);
2235     test_ScriptTextOut3(hdc);
2236     test_ScriptXtoX();
2237     test_ScriptString(hdc);
2238     test_ScriptStringXtoCP_CPtoX(hdc);
2239
2240     test_ScriptLayout();
2241     test_digit_substitution();
2242     test_ScriptGetProperties();
2243     test_ScriptBreak();
2244     test_newlines();
2245
2246     ReleaseDC(hwnd, hdc);
2247     DestroyWindow(hwnd);
2248 }