usp10/test: Add Thaana 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     /* Syriac */
578     static const WCHAR test_syriac[] = {0x0710, 0x0710, 0x0710, 0x0728, 0x0718, 0x0723,0};
579     static const shapeTest_char syriac_c[] = {{5,{0,0}},{4,{0,0}},{3,{0,0}},{2,{0,0}},{1,{0,0}},{0,{0,0}}};
580     static const shapeTest_glyph syriac_g[] = {
581                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
582                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
583                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
584                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
585                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
586                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}} };
587
588     /* Thaana */
589     static const WCHAR test_thaana[] = {0x078a, 0x07ae, 0x0792, 0x07b0, 0x0020, 0x0796, 0x07aa, 0x0789, 0x07b0, 0x0795, 0x07ac, 0x0791, 0x07b0};
590     static const shapeTest_char thaana_c[] = {{12,{0,0}},{12,{0,0}},{10,{0,0}},{10,{0,0}},{8,{1,0}},{7,{0,0}},{7,{0,0}},{5,{0,0}},{5,{0,0}},{3,{0,0}},{3,{0,0}},{1,{0,0}},{1,{0,0}}};
591     static const shapeTest_glyph thaana_g[] = {
592                             {1,{{SCRIPT_JUSTIFY_NONE,0,1,1,0,0},0}},
593                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
594                             {1,{{SCRIPT_JUSTIFY_NONE,0,1,1,0,0},0}},
595                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
596                             {1,{{SCRIPT_JUSTIFY_NONE,0,1,1,0,0},0}},
597                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
598                             {1,{{SCRIPT_JUSTIFY_NONE,0,1,1,0,0},0}},
599                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
600                             {1,{{SCRIPT_JUSTIFY_CHARACTER,1,0,0,0,0},0}},
601                             {1,{{SCRIPT_JUSTIFY_NONE,0,1,1,0,0},0}},
602                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}},
603                             {1,{{SCRIPT_JUSTIFY_NONE,0,1,1,0,0},0}},
604                             {1,{{SCRIPT_JUSTIFY_NONE,1,0,0,0,0},0}} };
605
606     if (!pScriptItemizeOpenType || !pScriptShapeOpenType)
607     {
608         win_skip("ScriptShapeOpenType not available on this platform\n");
609         return;
610     }
611
612     memset(&Control, 0 , sizeof(Control));
613     memset(&State, 0 , sizeof(State));
614
615     hr = pScriptItemizeOpenType(test1, 4, 2, &Control, &State, items, tags, &outnItems);
616     ok(!hr, "ScriptItemizeOpenType should return S_OK not %08x\n", hr);
617     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
618
619     hr = pScriptShapeOpenType(hdc, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, NULL, NULL, glyphs, NULL, &nb);
620     ok(hr == E_INVALIDARG, "ScriptShapeOpenType should return E_INVALIDARG not %08x\n", hr);
621
622     hr = pScriptShapeOpenType(hdc, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, NULL, NULL, glyphs, glyphProp, NULL);
623     ok(hr == E_INVALIDARG, "ScriptShapeOpenType should return E_INVALIDARG not %08x\n", hr);
624
625     hr = pScriptShapeOpenType(NULL, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, NULL, NULL, glyphs, glyphProp, &nb);
626     ok(hr == E_INVALIDARG, "ScriptShapeOpenType should return E_PENDING not %08x\n", hr);
627
628     hr = pScriptShapeOpenType(hdc, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, NULL, NULL, glyphs, glyphProp, &nb);
629     ok( hr == E_INVALIDARG,
630        "ScriptShapeOpenType should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
631     hr = pScriptShapeOpenType(hdc, &sc, &items[0].a, tags[0], 0x00000000, NULL, NULL, 0, test1, 4, 4, logclust, NULL, glyphs, glyphProp, &nb);
632     ok(hr == E_INVALIDARG, "ScriptShapeOpenType should return E_INVALIDARG not %08x\n", hr);
633
634     ScriptFreeCache(&sc);
635
636     test_shape_ok(hdc, test1, 4, &Control, &State, 0, 4, t1_c, t1_g);
637     test_shape_ok(hdc, test2, 4, &Control, &State, 1, 4, t2_c, t2_g);
638
639     test_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 11, test_hebrew[0], &hfont, &hfont_orig);
640     if (hfont != NULL)
641     {
642         test_shape_ok_valid(test_valid, hdc, test_hebrew, 4, &Control, &State, 0, 4, hebrew_c, hebrew_g);
643         SelectObject(hdc, hfont_orig);
644         DeleteObject(hfont);
645     }
646
647     test_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 13, test_arabic[0], &hfont, &hfont_orig);
648     if (hfont != NULL)
649     {
650         test_shape_ok_valid(test_valid, hdc, test_arabic, 4, &Control, &State, 0, 3, arabic_c, arabic_g);
651         SelectObject(hdc, hfont_orig);
652         DeleteObject(hfont);
653     }
654
655     test_valid = find_font_for_range(hdc, "Microsoft Sans Serif", 24, test_thai[0], &hfont, &hfont_orig);
656     if (hfont != NULL)
657     {
658         test_shape_ok_valid(test_valid, hdc, test_thai, 10, &Control, &State, 0, 10, thai_c, thai_g);
659         SelectObject(hdc, hfont_orig);
660         DeleteObject(hfont);
661     }
662
663     test_valid = find_font_for_range(hdc, "Estrangelo Edessa", 71, test_syriac[0], &hfont, &hfont_orig);
664     if (hfont != NULL)
665     {
666         test_shape_ok_valid(test_valid, hdc, test_syriac, 6, &Control, &State, 0, 6, syriac_c, syriac_g);
667         SelectObject(hdc, hfont_orig);
668         DeleteObject(hfont);
669     }
670
671     test_valid = find_font_for_range(hdc, "MV Boli", 72, test_thaana[0], &hfont, &hfont_orig);
672     if (hfont != NULL)
673     {
674         test_shape_ok_valid(test_valid, hdc, test_thaana, 13, &Control, &State, 0, 13, thaana_c, thaana_g);
675         SelectObject(hdc, hfont_orig);
676         DeleteObject(hfont);
677     }
678 }
679
680 static void test_ScriptShape(HDC hdc)
681 {
682     static const WCHAR test1[] = {'w', 'i', 'n', 'e',0};
683     static const WCHAR test2[] = {0x202B, 'i', 'n', 0x202C,0};
684     HRESULT hr;
685     SCRIPT_CACHE sc = NULL;
686     WORD glyphs[4], glyphs2[4], logclust[4];
687     SCRIPT_VISATTR attrs[4];
688     SCRIPT_ITEM items[2];
689     int nb;
690
691     hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL);
692     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
693     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
694
695     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, NULL, &nb);
696     ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr);
697
698     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, NULL);
699     ok(hr == E_INVALIDARG, "ScriptShape should return E_INVALIDARG not %08x\n", hr);
700
701     hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb);
702     ok(hr == E_PENDING, "ScriptShape should return E_PENDING not %08x\n", hr);
703
704     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, NULL, attrs, &nb);
705     ok(broken(hr == S_OK) ||
706        hr == E_INVALIDARG || /* Vista, W2K8 */
707        hr == E_FAIL, /* WIN7 */
708        "ScriptShape should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
709     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
710
711     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
712     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
713     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
714
715
716     memset(glyphs,-1,sizeof(glyphs));
717     memset(logclust,-1,sizeof(logclust));
718     memset(attrs,-1,sizeof(attrs));
719     hr = ScriptShape(NULL, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
720     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
721     ok(nb == 4, "Wrong number of items\n");
722     ok(logclust[0] == 0, "clusters out of order\n");
723     ok(logclust[1] == 1, "clusters out of order\n");
724     ok(logclust[2] == 2, "clusters out of order\n");
725     ok(logclust[3] == 3, "clusters out of order\n");
726     ok(attrs[0].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
727     ok(attrs[1].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
728     ok(attrs[2].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
729     ok(attrs[3].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
730     ok(attrs[0].fClusterStart == 1, "fClusterStart incorrect\n");
731     ok(attrs[1].fClusterStart == 1, "fClusterStart incorrect\n");
732     ok(attrs[2].fClusterStart == 1, "fClusterStart incorrect\n");
733     ok(attrs[3].fClusterStart == 1, "fClusterStart incorrect\n");
734     ok(attrs[0].fDiacritic == 0, "fDiacritic incorrect\n");
735     ok(attrs[1].fDiacritic == 0, "fDiacritic incorrect\n");
736     ok(attrs[2].fDiacritic == 0, "fDiacritic incorrect\n");
737     ok(attrs[3].fDiacritic == 0, "fDiacritic incorrect\n");
738     ok(attrs[0].fZeroWidth == 0, "fZeroWidth incorrect\n");
739     ok(attrs[1].fZeroWidth == 0, "fZeroWidth incorrect\n");
740     ok(attrs[2].fZeroWidth == 0, "fZeroWidth incorrect\n");
741     ok(attrs[3].fZeroWidth == 0, "fZeroWidth incorrect\n");
742
743     ScriptFreeCache(&sc);
744     sc = NULL;
745
746     memset(glyphs2,-1,sizeof(glyphs2));
747     memset(logclust,-1,sizeof(logclust));
748     memset(attrs,-1,sizeof(attrs));
749     hr = ScriptShape(hdc, &sc, test2, 4, 4, &items[0].a, glyphs2, logclust, attrs, &nb);
750     ok(hr == S_OK, "ScriptShape should return S_OK not %08x\n", hr);
751     ok(nb == 4, "Wrong number of items\n");
752     ok(glyphs2[0] == 0 || broken(glyphs2[0] == 0x80), "Incorrect glyph for 0x202B\n");
753     ok(glyphs2[3] == 0 || broken(glyphs2[3] == 0x80), "Incorrect glyph for 0x202C\n");
754     ok(logclust[0] == 0, "clusters out of order\n");
755     ok(logclust[1] == 1, "clusters out of order\n");
756     ok(logclust[2] == 2, "clusters out of order\n");
757     ok(logclust[3] == 3, "clusters out of order\n");
758     ok(attrs[0].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
759     ok(attrs[1].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
760     ok(attrs[2].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
761     ok(attrs[3].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
762     ok(attrs[0].fClusterStart == 1, "fClusterStart incorrect\n");
763     ok(attrs[1].fClusterStart == 1, "fClusterStart incorrect\n");
764     ok(attrs[2].fClusterStart == 1, "fClusterStart incorrect\n");
765     ok(attrs[3].fClusterStart == 1, "fClusterStart incorrect\n");
766     ok(attrs[0].fDiacritic == 0, "fDiacritic incorrect\n");
767     ok(attrs[1].fDiacritic == 0, "fDiacritic incorrect\n");
768     ok(attrs[2].fDiacritic == 0, "fDiacritic incorrect\n");
769     ok(attrs[3].fDiacritic == 0, "fDiacritic incorrect\n");
770     ok(attrs[0].fZeroWidth == 0, "fZeroWidth incorrect\n");
771     ok(attrs[1].fZeroWidth == 0, "fZeroWidth incorrect\n");
772     ok(attrs[2].fZeroWidth == 0, "fZeroWidth incorrect\n");
773     ok(attrs[3].fZeroWidth == 0, "fZeroWidth incorrect\n");
774
775     /* modify LTR to RTL */
776     items[0].a.fRTL = 1;
777     memset(glyphs2,-1,sizeof(glyphs2));
778     memset(logclust,-1,sizeof(logclust));
779     memset(attrs,-1,sizeof(attrs));
780     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs2, logclust, attrs, &nb);
781     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
782     ok(nb == 4, "Wrong number of items\n");
783     ok(glyphs2[0] == glyphs[3], "Glyphs not reordered properly\n");
784     ok(glyphs2[1] == glyphs[2], "Glyphs not reordered properly\n");
785     ok(glyphs2[2] == glyphs[1], "Glyphs not reordered properly\n");
786     ok(glyphs2[3] == glyphs[0], "Glyphs not reordered properly\n");
787     ok(logclust[0] == 3, "clusters out of order\n");
788     ok(logclust[1] == 2, "clusters out of order\n");
789     ok(logclust[2] == 1, "clusters out of order\n");
790     ok(logclust[3] == 0, "clusters out of order\n");
791     ok(attrs[0].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
792     ok(attrs[1].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
793     ok(attrs[2].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
794     ok(attrs[3].uJustification == SCRIPT_JUSTIFY_CHARACTER, "uJustification incorrect\n");
795     ok(attrs[0].fClusterStart == 1, "fClusterStart incorrect\n");
796     ok(attrs[1].fClusterStart == 1, "fClusterStart incorrect\n");
797     ok(attrs[2].fClusterStart == 1, "fClusterStart incorrect\n");
798     ok(attrs[3].fClusterStart == 1, "fClusterStart incorrect\n");
799     ok(attrs[0].fDiacritic == 0, "fDiacritic incorrect\n");
800     ok(attrs[1].fDiacritic == 0, "fDiacritic incorrect\n");
801     ok(attrs[2].fDiacritic == 0, "fDiacritic incorrect\n");
802     ok(attrs[3].fDiacritic == 0, "fDiacritic incorrect\n");
803     ok(attrs[0].fZeroWidth == 0, "fZeroWidth incorrect\n");
804     ok(attrs[1].fZeroWidth == 0, "fZeroWidth incorrect\n");
805     ok(attrs[2].fZeroWidth == 0, "fZeroWidth incorrect\n");
806     ok(attrs[3].fZeroWidth == 0, "fZeroWidth incorrect\n");
807
808     ScriptFreeCache(&sc);
809 }
810
811 static void test_ScriptPlace(HDC hdc)
812 {
813     static const WCHAR test1[] = {'t', 'e', 's', 't',0};
814     BOOL ret;
815     HRESULT hr;
816     SCRIPT_CACHE sc = NULL;
817     WORD glyphs[4], logclust[4];
818     SCRIPT_VISATTR attrs[4];
819     SCRIPT_ITEM items[2];
820     int nb, widths[4];
821     GOFFSET offset[4];
822     ABC abc[4];
823
824     hr = ScriptItemize(test1, 4, 2, NULL, NULL, items, NULL);
825     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
826     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
827
828     hr = ScriptShape(hdc, &sc, test1, 4, 4, &items[0].a, glyphs, logclust, attrs, &nb);
829     ok(!hr, "ScriptShape should return S_OK not %08x\n", hr);
830     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
831
832     hr = ScriptPlace(hdc, &sc, glyphs, 4, NULL, &items[0].a, widths, NULL, NULL);
833     ok(hr == E_INVALIDARG, "ScriptPlace should return E_INVALIDARG not %08x\n", hr);
834
835     hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, NULL);
836     ok(broken(hr == E_PENDING) ||
837        hr == E_INVALIDARG || /* Vista, W2K8 */
838        hr == E_FAIL, /* WIN7 */
839        "ScriptPlace should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
840
841     hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, offset, NULL);
842     ok(hr == E_PENDING, "ScriptPlace should return E_PENDING not %08x\n", hr);
843
844     hr = ScriptPlace(NULL, &sc, glyphs, 4, attrs, &items[0].a, widths, NULL, abc);
845     ok(broken(hr == E_PENDING) ||
846        hr == E_INVALIDARG || /* Vista, W2K8 */
847        hr == E_FAIL, /* WIN7 */
848        "ScriptPlace should return E_FAIL or E_INVALIDARG, not %08x\n", hr);
849
850     hr = ScriptPlace(hdc, &sc, glyphs, 4, attrs, &items[0].a, widths, offset, NULL);
851     ok(!hr, "ScriptPlace should return S_OK not %08x\n", hr);
852     ok(items[0].a.fNoGlyphIndex == FALSE, "fNoGlyphIndex TRUE\n");
853
854     ret = ExtTextOutW(hdc, 1, 1, 0, NULL, glyphs, 4, widths);
855     ok(ret, "ExtTextOutW should return TRUE\n");
856
857     ScriptFreeCache(&sc);
858 }
859
860 static void test_ScriptItemIzeShapePlace(HDC hdc, unsigned short pwOutGlyphs[256])
861 {
862     HRESULT         hr;
863     int             iMaxProps;
864     const SCRIPT_PROPERTIES **ppSp;
865
866     int             cInChars;
867     int             cMaxItems;
868     SCRIPT_ITEM     pItem[255];
869     int             pcItems;
870     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
871     WCHAR           TestItem2[] = {'T', 'e', 's', 't', 'b', 0}; 
872     WCHAR           TestItem3[] = {'T', 'e', 's', 't', 'c',' ','1','2','3',' ',' ','e','n','d',0};
873     WCHAR           TestItem4[] = {'T', 'e', 's', 't', 'd',' ',0x0684,0x0694,0x06a4,' ',' ','\r','\n','e','n','d',0};
874     WCHAR           TestItem5[] = {0x0684,'T','e','s','t','e',' ',0x0684,0x0694,0x06a4,' ',' ','e','n','d',0};
875     WCHAR           TestItem6[] = {'T', 'e', 's', 't', 'f',' ',' ',' ','\r','\n','e','n','d',0};
876
877     SCRIPT_CACHE    psc;
878     int             cChars;
879     int             cMaxGlyphs;
880     unsigned short  pwOutGlyphs1[256];
881     unsigned short  pwOutGlyphs2[256];
882     unsigned short  pwLogClust[256];
883     SCRIPT_VISATTR  psva[256];
884     int             pcGlyphs;
885     int             piAdvance[256];
886     GOFFSET         pGoffset[256];
887     ABC             pABC[256];
888     int             cnt;
889
890     /* Start testing usp10 functions                                                         */
891     /* This test determines that the pointer returned by ScriptGetProperties is valid
892      * by checking a known value in the table                                                */
893     hr = ScriptGetProperties(&ppSp, &iMaxProps);
894     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
895     trace("number of script properties %d\n", iMaxProps);
896     ok (iMaxProps > 0, "Number of scripts returned should not be 0\n");
897     if  (iMaxProps > 0)
898          ok( ppSp[0]->langid == 0, "Langid[0] not = to 0\n"); /* Check a known value to ensure   */
899                                                               /* ptrs work                       */
900
901     /* This is a valid test that will cause parsing to take place                             */
902     cInChars = 5;
903     cMaxItems = 255;
904     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
905     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
906     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
907      *  returned.                                                                             */
908     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
909     if (pcItems > 0)
910         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
911             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
912             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
913
914     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
915      * ie. ScriptItemize has succeeded and that pItem has been set                            */
916     cInChars = 5;
917     if (hr == 0) {
918         psc = NULL;                                   /* must be null on first call           */
919         cChars = cInChars;
920         cMaxGlyphs = cInChars;
921         hr = ScriptShape(NULL, &psc, TestItem1, cChars,
922                          cMaxGlyphs, &pItem[0].a,
923                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
924         ok (hr == E_PENDING, "If psc is NULL (%08x) the E_PENDING should be returned\n", hr);
925         cMaxGlyphs = 4;
926         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
927                          cMaxGlyphs, &pItem[0].a,
928                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
929         ok (hr == E_OUTOFMEMORY, "If not enough output area cChars (%d) is > than CMaxGlyphs "
930                                  "(%d) but not E_OUTOFMEMORY\n",
931                                  cChars, cMaxGlyphs);
932         cMaxGlyphs = 256;
933         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
934                          cMaxGlyphs, &pItem[0].a,
935                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
936         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
937         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
938         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
939         if (hr ==0) {
940             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
941                              pGoffset, pABC);
942             ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
943             hr = ScriptPlace(NULL, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
944                              pGoffset, pABC);
945             ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
946             for (cnt=0; cnt < pcGlyphs; cnt++)
947                 pwOutGlyphs[cnt] = pwOutGlyphs1[cnt];                 /* Send to next function */
948         }
949
950         /* This test will check to make sure that SCRIPT_CACHE is reused and that not translation   *
951          * takes place if fNoGlyphIndex is set.                                                     */
952
953         cInChars = 5;
954         cMaxItems = 255;
955         hr = ScriptItemize(TestItem2, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
956         ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
957         /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is   *
958          *  returned.                                                                               */
959         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
960                             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
961                              pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
962         /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue                    */
963         if (hr == 0) {
964              cChars = cInChars;
965              cMaxGlyphs = 256;
966              pItem[0].a.fNoGlyphIndex = 1;                /* say no translate                     */
967              hr = ScriptShape(NULL, &psc, TestItem2, cChars,
968                               cMaxGlyphs, &pItem[0].a,
969                               pwOutGlyphs2, pwLogClust, psva, &pcGlyphs);
970              ok (hr != E_PENDING, "If psc should not be NULL (%08x) and the E_PENDING should be returned\n", hr);
971              ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
972              ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
973              ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
974              for (cnt=0; cnt < cChars && TestItem2[cnt] == pwOutGlyphs2[cnt]; cnt++) {}
975              ok (cnt == cChars, "Translation to place when told not to. WCHAR %d - %04x != %04x\n",
976                            cnt, TestItem2[cnt], pwOutGlyphs2[cnt]);
977              if (hr ==0) {
978                  hr = ScriptPlace(hdc, &psc, pwOutGlyphs2, pcGlyphs, psva, &pItem[0].a, piAdvance,
979                                   pGoffset, pABC);
980                  ok (hr == 0, "ScriptPlace should return 0 not (%08x)\n", hr);
981              }
982         }
983         ScriptFreeCache( &psc);
984         ok (!psc, "psc is not null after ScriptFreeCache\n");
985
986     }
987
988     /* This is a valid test that will cause parsing to take place and create 3 script_items   */
989     cInChars = (sizeof(TestItem3)/2)-1;
990     cMaxItems = 255;
991     hr = ScriptItemize(TestItem3, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
992     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
993     if  (hr == 0)
994         {
995         ok (pcItems == 3, "The number of SCRIPT_ITEMS should be 3 not %d\n", pcItems);
996         if (pcItems > 2)
997         {
998             ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
999                 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
1000                 pItem[0].iCharPos, pItem[1].iCharPos);
1001             ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
1002                 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
1003                 pItem[1].iCharPos, pItem[2].iCharPos);
1004             ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == cInChars,
1005                 "Start pos [2] not = 11 (%d) or end [3] pos not = 14 (%d), cInChars = %d\n",
1006                 pItem[2].iCharPos, pItem[3].iCharPos, cInChars);
1007         }
1008     }
1009
1010     /* This is a valid test that will cause parsing to take place and create 5 script_items   */
1011     cInChars = (sizeof(TestItem4)/2)-1;
1012     cMaxItems = 255;
1013     hr = ScriptItemize(TestItem4, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1014     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
1015     if  (hr == 0)
1016         {
1017         ok (pcItems == 5, "The number of SCRIPT_ITEMS should be 5 not %d\n", pcItems);
1018         if (pcItems > 4)
1019         {
1020             ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == 6,
1021                 "Start pos [0] not = 0 (%d) or end pos [1] not = %d\n",
1022                 pItem[0].iCharPos, pItem[1].iCharPos);
1023             ok (pItem[0].a.s.uBidiLevel == 0, "Should have been bidi=0 not %d\n",
1024                                                pItem[0].a.s.uBidiLevel);
1025             ok (pItem[1].iCharPos == 6 && pItem[2].iCharPos == 11,
1026                 "Start pos [1] not = 6 (%d) or end pos [2] not = 11 (%d)\n",
1027                 pItem[1].iCharPos, pItem[2].iCharPos);
1028             ok (pItem[1].a.s.uBidiLevel == 1, "Should have been bidi=1 not %d\n",
1029                                               pItem[1].a.s.uBidiLevel);
1030             ok (pItem[2].iCharPos == 11 && pItem[3].iCharPos == 12,
1031                 "Start pos [2] not = 11 (%d) or end [3] pos not = 12 (%d)\n",
1032                 pItem[2].iCharPos, pItem[3].iCharPos);
1033             ok (pItem[2].a.s.uBidiLevel == 0, "Should have been bidi=0 not %d\n",
1034                                                pItem[2].a.s.uBidiLevel);
1035             ok (pItem[3].iCharPos == 12 && pItem[4].iCharPos == 13,
1036                 "Start pos [3] not = 12 (%d) or end [4] pos not = 13 (%d)\n",
1037                 pItem[3].iCharPos, pItem[4].iCharPos);
1038             ok (pItem[3].a.s.uBidiLevel == 0, "Should have been bidi=0 not %d\n",
1039                                                pItem[3].a.s.uBidiLevel);
1040             ok (pItem[4].iCharPos == 13 && pItem[5].iCharPos == cInChars,
1041                 "Start pos [4] not = 13 (%d) or end [5] pos not = 16 (%d), cInChars = %d\n",
1042                 pItem[4].iCharPos, pItem[5].iCharPos, cInChars);
1043         }
1044     }
1045
1046     /*
1047      * This test is for when the first unicode character requires bidi support
1048      */
1049     cInChars = (sizeof(TestItem5)-1)/sizeof(WCHAR);
1050     hr = ScriptItemize(TestItem5, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1051     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
1052     ok (pcItems == 4, "There should have been 4 items, found %d\n", pcItems);
1053     ok (pItem[0].a.s.uBidiLevel == 1, "The first character should have been bidi=1 not %d\n",
1054                                        pItem[0].a.s.uBidiLevel);
1055
1056     /* This test checks to make sure that the test to see if there are sufficient buffers to store  *
1057      * the pointer to the last char works.  Note that windows often needs a greater number of       *
1058      * SCRIPT_ITEMS to process a string than is returned in pcItems.                                */
1059     cInChars = (sizeof(TestItem6)/2)-1;
1060     cMaxItems = 4;
1061     hr = ScriptItemize(TestItem6, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1062     ok (hr == E_OUTOFMEMORY, "ScriptItemize should return E_OUTOFMEMORY, returned %08x\n", hr);
1063
1064 }
1065
1066 static void test_ScriptGetCMap(HDC hdc, unsigned short pwOutGlyphs[256])
1067 {
1068     HRESULT         hr;
1069     SCRIPT_CACHE    psc = NULL;
1070     int             cInChars;
1071     int             cChars;
1072     unsigned short  pwOutGlyphs2[256];
1073     unsigned short  pwOutGlyphs3[256];
1074     DWORD           dwFlags;
1075     int             cnt;
1076
1077     static const WCHAR TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
1078     static const WCHAR TestItem2[] = {0x202B, 'i', 'n', 0x202C,0};
1079     static const WCHAR TestItem3[] = {'a','b','c','d','(','<','{','[',0x2039,0};
1080     static const WCHAR TestItem3b[] = {'a','b','c','d',')','>','}',']',0x203A,0};
1081
1082     /*  Check to make sure that SCRIPT_CACHE gets allocated ok                     */
1083     dwFlags = 0;
1084     cInChars = cChars = 5;
1085     /* Some sanity checks for ScriptGetCMap */
1086
1087     hr = ScriptGetCMap(NULL, NULL, NULL, 0, 0, NULL);
1088     ok( hr == E_INVALIDARG, "(NULL,NULL,NULL,0,0,NULL), "
1089                             "expected E_INVALIDARG, got %08x\n", hr);
1090
1091     hr = ScriptGetCMap(NULL, NULL, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
1092     ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
1093                             "expected E_INVALIDARG, got %08x\n", hr);
1094
1095     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1096     psc = NULL;
1097     hr = ScriptGetCMap(NULL, &psc, TestItem1, cInChars, 0, pwOutGlyphs3);
1098     ok( hr == E_PENDING, "(NULL,&psc,NULL,0,0,NULL), expected E_PENDING, "
1099                          "got %08x\n", hr);
1100     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1101
1102     /* Set psc to NULL but add hdc, to be able to check if a pointer is returned in psc */
1103     psc = NULL;
1104     hr = ScriptGetCMap(hdc, &psc, TestItem1, cInChars, 0, pwOutGlyphs3);
1105     ok( hr == S_OK, "ScriptGetCMap(NULL,&psc,NULL,0,0,NULL), expected S_OK, "
1106                     "got %08x\n", hr);
1107     ok( psc != NULL, "ScritpGetCMap expected psc to be not NULL\n");
1108     ScriptFreeCache( &psc);
1109
1110     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1111     psc = NULL;
1112     hr = ScriptGetCMap(NULL, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
1113     ok( hr == E_PENDING, "(NULL,&psc,), expected E_PENDING, got %08x\n", hr);
1114     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1115     /*  Check to see if the results are the same as those returned by ScriptShape  */
1116     hr = ScriptGetCMap(hdc, &psc, TestItem1, cInChars, dwFlags, pwOutGlyphs3);
1117     ok (hr == 0, "ScriptGetCMap should return 0 not (%08x)\n", hr);
1118     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1119     for (cnt=0; cnt < cChars && pwOutGlyphs[cnt] == pwOutGlyphs3[cnt]; cnt++) {}
1120     ok (cnt == cInChars, "Translation not correct. WCHAR %d - %04x != %04x\n",
1121                          cnt, pwOutGlyphs[cnt], pwOutGlyphs3[cnt]);
1122
1123     ScriptFreeCache( &psc);
1124     ok (!psc, "psc is not null after ScriptFreeCache\n");
1125
1126     cInChars = cChars = 4;
1127     hr = ScriptGetCMap(hdc, &psc, TestItem2, cInChars, dwFlags, pwOutGlyphs3);
1128     ok (hr == S_FALSE, "ScriptGetCMap should return S_FALSE not (%08x)\n", hr);
1129     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1130     ok(pwOutGlyphs3[0] == 0 || broken(pwOutGlyphs3[0] == 0x80), "Glyph 0 should be default glyph\n");
1131     ok(pwOutGlyphs3[3] == 0 || broken(pwOutGlyphs3[0] == 0x80), "Glyph 0 should be default glyph\n");
1132
1133
1134     cInChars = cChars = 9;
1135     hr = ScriptGetCMap(hdc, &psc, TestItem3b, cInChars, dwFlags, pwOutGlyphs2);
1136     ok (hr == S_OK, "ScriptGetCMap should return S_OK not (%08x)\n", hr);
1137     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1138
1139     cInChars = cChars = 9;
1140     dwFlags = SGCM_RTL;
1141     hr = ScriptGetCMap(hdc, &psc, TestItem3, cInChars, dwFlags, pwOutGlyphs3);
1142     ok (hr == S_OK, "ScriptGetCMap should return S_OK not (%08x)\n", hr);
1143     ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1144     ok(pwOutGlyphs3[0] == pwOutGlyphs2[0], "glyph incorrectly altered\n");
1145     ok(pwOutGlyphs3[1] == pwOutGlyphs2[1], "glyph incorreclty altered\n");
1146     ok(pwOutGlyphs3[2] == pwOutGlyphs2[2], "glyph incorreclty altered\n");
1147     ok(pwOutGlyphs3[3] == pwOutGlyphs2[3], "glyph incorreclty altered\n");
1148     ok(pwOutGlyphs3[4] == pwOutGlyphs2[4], "glyph not mirrored correctly\n");
1149     ok(pwOutGlyphs3[5] == pwOutGlyphs2[5], "glyph not mirrored correctly\n");
1150     ok(pwOutGlyphs3[6] == pwOutGlyphs2[6], "glyph not mirrored correctly\n");
1151     ok(pwOutGlyphs3[7] == pwOutGlyphs2[7], "glyph not mirrored correctly\n");
1152     ok(pwOutGlyphs3[8] == pwOutGlyphs2[8], "glyph not mirrored correctly\n");
1153
1154     ScriptFreeCache( &psc);
1155     ok (!psc, "psc is not null after ScriptFreeCache\n");
1156 }
1157
1158 static void test_ScriptGetFontProperties(HDC hdc)
1159 {
1160     HRESULT         hr;
1161     SCRIPT_CACHE    psc,old_psc;
1162     SCRIPT_FONTPROPERTIES sfp;
1163
1164     /* Some sanity checks for ScriptGetFontProperties */
1165
1166     hr = ScriptGetFontProperties(NULL,NULL,NULL);
1167     ok( hr == E_INVALIDARG, "(NULL,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
1168
1169     hr = ScriptGetFontProperties(NULL,NULL,&sfp);
1170     ok( hr == E_INVALIDARG, "(NULL,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
1171
1172     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1173     psc = NULL;
1174     hr = ScriptGetFontProperties(NULL,&psc,NULL);
1175     ok( hr == E_INVALIDARG, "(NULL,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr);
1176     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1177
1178     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1179     psc = NULL;
1180     hr = ScriptGetFontProperties(NULL,&psc,&sfp);
1181     ok( hr == E_PENDING, "(NULL,&psc,&sfp), expected E_PENDING, got %08x\n", hr);
1182     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1183
1184     hr = ScriptGetFontProperties(hdc,NULL,NULL);
1185     ok( hr == E_INVALIDARG, "(hdc,NULL,NULL), expected E_INVALIDARG, got %08x\n", hr);
1186
1187     hr = ScriptGetFontProperties(hdc,NULL,&sfp);
1188     ok( hr == E_INVALIDARG, "(hdc,NULL,&sfp), expected E_INVALIDARG, got %08x\n", hr);
1189
1190     /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1191     psc = NULL;
1192     hr = ScriptGetFontProperties(hdc,&psc,NULL);
1193     ok( hr == E_INVALIDARG, "(hdc,&psc,NULL), expected E_INVALIDARG, got %08x\n", hr);
1194     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1195
1196     /* Pass an invalid sfp */
1197     psc = NULL;
1198     sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES) - 1;
1199     hr = ScriptGetFontProperties(hdc,&psc,&sfp);
1200     ok( hr == E_INVALIDARG, "(hdc,&psc,&sfp) invalid, expected E_INVALIDARG, got %08x\n", hr);
1201     ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
1202     ScriptFreeCache(&psc);
1203     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1204
1205     /* Give it the correct cBytes, we don't care about what's coming back */
1206     sfp.cBytes = sizeof(SCRIPT_FONTPROPERTIES);
1207     psc = NULL;
1208     hr = ScriptGetFontProperties(hdc,&psc,&sfp);
1209     ok( hr == S_OK, "(hdc,&psc,&sfp) partly initialized, expected S_OK, got %08x\n", hr);
1210     ok( psc != NULL, "Expected a pointer in psc, got NULL\n");
1211
1212     /* Save the psc pointer */
1213     old_psc = psc;
1214     /* Now a NULL hdc again */
1215     hr = ScriptGetFontProperties(NULL,&psc,&sfp);
1216     ok( hr == S_OK, "(NULL,&psc,&sfp), expected S_OK, got %08x\n", hr);
1217     ok( psc == old_psc, "Expected psc not to be changed, was %p is now %p\n", old_psc, psc);
1218     ScriptFreeCache(&psc);
1219     ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1220 }
1221
1222 static void test_ScriptTextOut(HDC hdc)
1223 {
1224     HRESULT         hr;
1225
1226     int             cInChars;
1227     int             cMaxItems;
1228     SCRIPT_ITEM     pItem[255];
1229     int             pcItems;
1230     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0}; 
1231
1232     SCRIPT_CACHE    psc;
1233     int             cChars;
1234     int             cMaxGlyphs;
1235     unsigned short  pwOutGlyphs1[256];
1236     WORD            pwLogClust[256];
1237     SCRIPT_VISATTR  psva[256];
1238     int             pcGlyphs;
1239     int             piAdvance[256];
1240     GOFFSET         pGoffset[256];
1241     ABC             pABC[256];
1242     RECT            rect;
1243     int             piX;
1244     int             iCP = 1;
1245     BOOL            fTrailing = FALSE;
1246     SCRIPT_LOGATTR  *psla;
1247     SCRIPT_LOGATTR  sla[256];
1248
1249     /* This is a valid test that will cause parsing to take place                             */
1250     cInChars = 5;
1251     cMaxItems = 255;
1252     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1253     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
1254     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
1255      *  returned.                                                                             */
1256     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
1257     if (pcItems > 0)
1258         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
1259             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
1260             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
1261
1262     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
1263      * ie. ScriptItemize has succeeded and that pItem has been set                            */
1264     cInChars = 5;
1265     if (hr == 0) {
1266         psc = NULL;                                   /* must be null on first call           */
1267         cChars = cInChars;
1268         cMaxGlyphs = 256;
1269         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
1270                          cMaxGlyphs, &pItem[0].a,
1271                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
1272         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
1273         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1274         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
1275         if (hr ==0) {
1276             /* Note hdc is needed as glyph info is not yet in psc                  */
1277             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
1278                              pGoffset, pABC);
1279             ok (hr == 0, "Should return 0 not (%08x)\n", hr);
1280             ScriptFreeCache(&psc);              /* Get rid of psc for next test set */
1281             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1282
1283             hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0, NULL, NULL, NULL);
1284             ok (hr == E_INVALIDARG, "Should return 0 not (%08x)\n", hr);
1285
1286             hr = ScriptTextOut(NULL, NULL, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1287                                piAdvance, NULL, pGoffset);
1288             ok( hr == E_INVALIDARG, "(NULL,NULL,TestItem1, cInChars, dwFlags, pwOutGlyphs3), "
1289                                     "expected E_INVALIDARG, got %08x\n", hr);
1290
1291             /* Set psc to NULL, to be able to check if a pointer is returned in psc */
1292             psc = NULL;
1293             hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, NULL, NULL, 0, NULL, 0,
1294                                NULL, NULL, NULL);
1295             ok( hr == E_INVALIDARG, "(NULL,&psc,NULL,0,0,0,NULL,), expected E_INVALIDARG, "
1296                                     "got %08x\n", hr);
1297             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1298
1299             /* hdc is required for this one rather than the usual optional          */
1300             psc = NULL;
1301             hr = ScriptTextOut(NULL, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1302                                piAdvance, NULL, pGoffset);
1303             ok( hr == E_INVALIDARG, "(NULL,&psc,), expected E_INVALIDARG, got %08x\n", hr);
1304             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1305
1306             /* Set that it returns 0 status */
1307             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1308                                piAdvance, NULL, pGoffset);
1309             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
1310
1311             /* Test Rect Rgn is acceptable */
1312             rect.top = 10;
1313             rect.bottom = 20;
1314             rect.left = 10;
1315             rect.right = 40;
1316             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, &rect, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1317                                piAdvance, NULL, pGoffset);
1318             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
1319
1320             iCP = 1;
1321             hr = ScriptCPtoX(iCP, fTrailing, cChars, pcGlyphs, (const WORD *) &pwLogClust,
1322                             (const SCRIPT_VISATTR *) &psva, (const int *)&piAdvance, &pItem[0].a, &piX);
1323             ok(hr == S_OK, "ScriptCPtoX Stub should return S_OK not %08x\n", hr);
1324
1325             psla = (SCRIPT_LOGATTR *)&sla;
1326             hr = ScriptBreak(TestItem1, cChars, &pItem[0].a, psla);
1327             ok(hr == S_OK, "ScriptBreak Stub should return S_OK not %08x\n", hr);
1328
1329             /* Clean up and go   */
1330             ScriptFreeCache(&psc);
1331             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1332         }
1333     }
1334 }
1335
1336 static void test_ScriptTextOut2(HDC hdc)
1337 {
1338 /*  Intent is to validate that the HDC passed into ScriptTextOut is
1339  *  used instead of the (possibly) invalid cached one
1340  */
1341     HRESULT         hr;
1342
1343     HDC             hdc1, hdc2;
1344     int             cInChars;
1345     int             cMaxItems;
1346     SCRIPT_ITEM     pItem[255];
1347     int             pcItems;
1348     WCHAR           TestItem1[] = {'T', 'e', 's', 't', 'a', 0};
1349
1350     SCRIPT_CACHE    psc;
1351     int             cChars;
1352     int             cMaxGlyphs;
1353     unsigned short  pwOutGlyphs1[256];
1354     WORD            pwLogClust[256];
1355     SCRIPT_VISATTR  psva[256];
1356     int             pcGlyphs;
1357     int             piAdvance[256];
1358     GOFFSET         pGoffset[256];
1359     ABC             pABC[256];
1360
1361     /* Create an extra DC that will be used until the ScriptTextOut */
1362     hdc1 = CreateCompatibleDC(hdc);
1363     ok (hdc1 != 0, "CreateCompatibleDC failed to create a DC\n");
1364     hdc2 = CreateCompatibleDC(hdc);
1365     ok (hdc2 != 0, "CreateCompatibleDC failed to create a DC\n");
1366
1367     /* This is a valid test that will cause parsing to take place                             */
1368     cInChars = 5;
1369     cMaxItems = 255;
1370     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1371     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
1372     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
1373      *  returned.                                                                             */
1374     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
1375     if (pcItems > 0)
1376         ok (pItem[0].iCharPos == 0 && pItem[1].iCharPos == cInChars,
1377             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
1378             pItem[0].iCharPos, cInChars, pItem[1].iCharPos);
1379
1380     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
1381      * ie. ScriptItemize has succeeded and that pItem has been set                            */
1382     cInChars = 5;
1383     if (hr == 0) {
1384         psc = NULL;                                   /* must be null on first call           */
1385         cChars = cInChars;
1386         cMaxGlyphs = 256;
1387         hr = ScriptShape(hdc2, &psc, TestItem1, cChars,
1388                          cMaxGlyphs, &pItem[0].a,
1389                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
1390         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
1391         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1392         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
1393         if (hr ==0) {
1394             /* Note hdc is needed as glyph info is not yet in psc                  */
1395             hr = ScriptPlace(hdc2, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
1396                              pGoffset, pABC);
1397             ok (hr == 0, "Should return 0 not (%08x)\n", hr);
1398
1399             /*   key part!!!   cached dc is being deleted  */
1400             hr = DeleteDC(hdc2);
1401             ok(hr == 1, "DeleteDC should return 1 not %08x\n", hr);
1402
1403             /* At this point the cached hdc (hdc2) has been destroyed,
1404              * however, we are passing in a *real* hdc (the original hdc).
1405              * The text should be written to that DC
1406              */
1407             hr = ScriptTextOut(hdc1, &psc, 0, 0, 0, NULL, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1408                                piAdvance, NULL, pGoffset);
1409             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
1410             ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1411
1412             DeleteDC(hdc1);
1413
1414             /* Clean up and go   */
1415             ScriptFreeCache(&psc);
1416             ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1417         }
1418     }
1419 }
1420
1421 static void test_ScriptTextOut3(HDC hdc)
1422 {
1423     HRESULT         hr;
1424
1425     int             cInChars;
1426     int             cMaxItems;
1427     SCRIPT_ITEM     pItem[255];
1428     int             pcItems;
1429     WCHAR           TestItem1[] = {' ','\r', 0};
1430
1431     SCRIPT_CACHE    psc;
1432     int             cChars;
1433     int             cMaxGlyphs;
1434     unsigned short  pwOutGlyphs1[256];
1435     WORD            pwLogClust[256];
1436     SCRIPT_VISATTR  psva[256];
1437     int             pcGlyphs;
1438     int             piAdvance[256];
1439     GOFFSET         pGoffset[256];
1440     ABC             pABC[256];
1441     RECT            rect;
1442
1443     /* This is to ensure that non exisiting glyphs are translated into a valid glyph number */
1444     cInChars = 2;
1445     cMaxItems = 255;
1446     hr = ScriptItemize(TestItem1, cInChars, cMaxItems, NULL, NULL, pItem, &pcItems);
1447     ok (hr == 0, "ScriptItemize should return 0, returned %08x\n", hr);
1448     /*  This test is for the interim operation of ScriptItemize where only one SCRIPT_ITEM is *
1449      *  returned.                                                                             */
1450     ok (pcItems > 0, "The number of SCRIPT_ITEMS should be greater than 0\n");
1451     if (pcItems > 0)
1452         ok (pItem[0].iCharPos == 0 && pItem[2].iCharPos == cInChars,
1453             "Start pos not = 0 (%d) or end pos not = %d (%d)\n",
1454             pItem[0].iCharPos, cInChars, pItem[2].iCharPos);
1455
1456     /* It would appear that we have a valid SCRIPT_ANALYSIS and can continue
1457      * ie. ScriptItemize has succeeded and that pItem has been set                            */
1458     cInChars = 2;
1459     if (hr == 0) {
1460         psc = NULL;                                   /* must be null on first call           */
1461         cChars = cInChars;
1462         cMaxGlyphs = 256;
1463         hr = ScriptShape(hdc, &psc, TestItem1, cChars,
1464                          cMaxGlyphs, &pItem[0].a,
1465                          pwOutGlyphs1, pwLogClust, psva, &pcGlyphs);
1466         ok (hr == 0, "ScriptShape should return 0 not (%08x)\n", hr);
1467         ok (psc != NULL, "psc should not be null and have SCRIPT_CACHE buffer address\n");
1468         ok (pcGlyphs == cChars, "Chars in (%d) should equal Glyphs out (%d)\n", cChars, pcGlyphs);
1469         if (hr ==0) {
1470             /* Note hdc is needed as glyph info is not yet in psc                  */
1471             hr = ScriptPlace(hdc, &psc, pwOutGlyphs1, pcGlyphs, psva, &pItem[0].a, piAdvance,
1472                              pGoffset, pABC);
1473             ok (hr == 0, "Should return 0 not (%08x)\n", hr);
1474
1475             /* Test Rect Rgn is acceptable */
1476             rect.top = 10;
1477             rect.bottom = 20;
1478             rect.left = 10;
1479             rect.right = 40;
1480             hr = ScriptTextOut(hdc, &psc, 0, 0, 0, &rect, &pItem[0].a, NULL, 0, pwOutGlyphs1, pcGlyphs,
1481                                piAdvance, NULL, pGoffset);
1482             ok (hr == 0, "ScriptTextOut should return 0 not (%08x)\n", hr);
1483
1484         }
1485         /* Clean up and go   */
1486         ScriptFreeCache(&psc);
1487         ok( psc == NULL, "Expected psc to be NULL, got %p\n", psc);
1488     }
1489 }
1490
1491 static void test_ScriptXtoX(void)
1492 /****************************************************************************************
1493  *  This routine tests the ScriptXtoCP and ScriptCPtoX functions using static variables *
1494  ****************************************************************************************/
1495 {
1496     static const WCHAR test[] = {'t', 'e', 's', 't',0};
1497     SCRIPT_ITEM items[2];
1498     int iX, iCP;
1499     int cChars;
1500     int cGlyphs;
1501     WORD pwLogClust[10] = {0, 0, 0, 1, 1, 2, 2, 3, 3, 3};
1502     WORD pwLogClust_RTL[10] = {3, 3, 3, 2, 2, 1, 1, 0, 0, 0};
1503     SCRIPT_VISATTR psva[10];
1504     int piAdvance[10] = {200, 190, 210, 180, 170, 204, 189, 195, 212, 203};
1505     int piCP, piX;
1506     int piTrailing;
1507     BOOL fTrailing;
1508     HRESULT hr;
1509     static const int offsets[13] = {0, 66, 133, 200, 295, 390, 495, 600, 1051, 1502, 1953, 1953, 1953};
1510     static const int offsets_RTL[13] = {780, 720, 660, 600, 495, 390, 295, 200, 133, 66, 0, 0, 0};
1511
1512     hr = ScriptItemize(test, lstrlenW(test), sizeof(items)/sizeof(items[0]), NULL, NULL, items, NULL);
1513     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
1514
1515     iX = -1;
1516     cChars = 10;
1517     cGlyphs = 10;
1518     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1519     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1520     if (piTrailing)
1521         ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
1522     else /* win2k3 */
1523         ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
1524
1525     for(iCP = 0; iCP < 10; iCP++)
1526     {
1527         iX = offsets[iCP]+1;
1528         cChars = 10;
1529         cGlyphs = 10;
1530         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1531         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1532         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1533         ok(piTrailing == 0, "iX=%d should return piTrailing=0 not %d\n", iX, piTrailing);
1534     }
1535
1536     for(iCP = 0; iCP < 10; iCP++)
1537     {
1538         iX = offsets[iCP+1]-1;
1539         cChars = 10;
1540         cGlyphs = 10;
1541         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1542         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1543         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1544         ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
1545     }
1546
1547     /* 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 */
1548     for(iCP = 3; iCP < 10; iCP++)
1549     {
1550         iX = offsets[iCP];
1551         cChars = 10;
1552         cGlyphs = 10;
1553         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1554         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1555         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1556         ok(piTrailing == 0, "iX=%d should return piTrailing=0 not %d\n", iX, piTrailing);
1557     }
1558
1559     items[0].a.fRTL = TRUE;
1560
1561     iX = -1;
1562     cChars = 10;
1563     cGlyphs = 10;
1564     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1565     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1566     if (piTrailing)
1567         ok(piCP == -1, "Negative iX should return piCP=-1 not %d\n", piCP);
1568     else /* win2k3 */
1569         ok(piCP == 10, "Negative iX should return piCP=10 not %d\n", piCP);
1570
1571     iX = 1954;
1572     cChars = 10;
1573     cGlyphs = 10;
1574     hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1575     ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1576     ok(piCP == -1, "iX=%d should return piCP=-1 not %d\n", iX, piCP);
1577     ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
1578
1579     for(iCP = 0; iCP < 10; iCP++)
1580     {
1581         iX = offsets_RTL[iCP]-1;
1582         cChars = 10;
1583         cGlyphs = 10;
1584         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1585         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1586         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1587         ok(piTrailing == 0, "iX=%d should return piTrailing=0 not %d\n", iX, piTrailing);
1588     }
1589
1590     for(iCP = 0; iCP < 10; iCP++)
1591     {
1592         iX = offsets_RTL[iCP+1]+1;
1593         cChars = 10;
1594         cGlyphs = 10;
1595         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1596         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1597         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1598         ok(piTrailing == 1, "iX=%d should return piTrailing=1 not %d\n", iX, piTrailing);
1599     }
1600
1601     for(iCP = 0; iCP < 10; iCP++)
1602     {
1603         iX = offsets_RTL[iCP];
1604         cChars = 10;
1605         cGlyphs = 10;
1606         hr = ScriptXtoCP(iX, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piCP, &piTrailing);
1607         ok(hr == S_OK, "ScriptXtoCP should return S_OK not %08x\n", hr);
1608         ok(piCP == iCP, "iX=%d should return piCP=%d not %d\n", iX, iCP, piCP);
1609         ok(piTrailing == 0, "iX=%d should return piTrailing=0 not %d\n", iX, piTrailing);
1610     }
1611
1612     items[0].a.fRTL = FALSE;
1613
1614     for(iCP = 0; iCP <= 11; iCP++)
1615     {
1616         fTrailing = FALSE;
1617         cChars = 10;
1618         cGlyphs = 10;
1619         hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
1620         ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
1621         ok(piX == offsets[iCP],
1622            "iCP=%d should return piX=%d not %d\n", iCP, offsets[iCP], piX);
1623     }
1624
1625     for(iCP = 0; iCP <= 11; iCP++)
1626     {
1627         fTrailing = TRUE;
1628         cChars = 10;
1629         cGlyphs = 10;
1630         hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance, &items[0].a, &piX);
1631         ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
1632         ok(piX == offsets[iCP+1],
1633            "iCP=%d should return piX=%d not %d\n", iCP, offsets[iCP+1], piX);
1634     }
1635
1636     items[0].a.fRTL = TRUE;
1637
1638     for(iCP = 0; iCP <= 11; iCP++)
1639     {
1640         fTrailing = FALSE;
1641         cChars = 10;
1642         cGlyphs = 10;
1643         hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piX);
1644         ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
1645         ok(piX == offsets_RTL[iCP],
1646            "iCP=%d should return piX=%d not %d\n", iCP, offsets_RTL[iCP], piX);
1647     }
1648
1649     for(iCP = 0; iCP <= 11; iCP++)
1650     {
1651         fTrailing = TRUE;
1652         cChars = 10;
1653         cGlyphs = 10;
1654         hr = ScriptCPtoX(iCP, fTrailing, cChars, cGlyphs, pwLogClust_RTL, psva, piAdvance, &items[0].a, &piX);
1655         ok(hr == S_OK, "ScriptCPtoX should return S_OK not %08x\n", hr);
1656         ok(piX == offsets_RTL[iCP+1],
1657            "iCP=%d should return piX=%d not %d\n", iCP, offsets_RTL[iCP+1], piX);
1658     }
1659 }
1660
1661 static void test_ScriptString(HDC hdc)
1662 {
1663 /*******************************************************************************************
1664  *
1665  * This set of tests are for the string functions of uniscribe.  The ScriptStringAnalyse
1666  * function allocates memory pointed to by the SCRIPT_STRING_ANALYSIS ssa pointer.  This
1667  * memory is freed by ScriptStringFree.  There needs to be a valid hdc for this as
1668  * ScriptStringAnalyse calls ScriptSItemize, ScriptShape and ScriptPlace which require it.
1669  *
1670  */
1671
1672     HRESULT         hr;
1673     WCHAR           teststr[] = {'T','e','s','t','1',' ','a','2','b','3', '\0'};
1674     int             len = (sizeof(teststr) / sizeof(WCHAR)) - 1;
1675     int             Glyphs = len * 2 + 16;
1676     int             Charset;
1677     DWORD           Flags = SSA_GLYPHS;
1678     int             ReqWidth = 100;
1679     const int       Dx[5] = {10, 10, 10, 10, 10};
1680     const BYTE      InClass = 0;
1681     SCRIPT_STRING_ANALYSIS ssa = NULL;
1682
1683     int             X = 10; 
1684     int             Y = 100;
1685     UINT            Options = 0; 
1686     const RECT      rc = {0, 50, 100, 100}; 
1687     int             MinSel = 0;
1688     int             MaxSel = 0;
1689     BOOL            Disabled = FALSE;
1690     const int      *clip_len;
1691     int            i;
1692     UINT           *order;
1693
1694
1695     Charset = -1;     /* this flag indicates unicode input */
1696     /* Test without hdc to get E_PENDING */
1697     hr = ScriptStringAnalyse( NULL, teststr, len, Glyphs, Charset, Flags,
1698                               ReqWidth, NULL, NULL, Dx, NULL,
1699                               &InClass, &ssa);
1700     ok(hr == E_PENDING, "ScriptStringAnalyse Stub should return E_PENDING not %08x\n", hr);
1701
1702     /* test with hdc, this should be a valid test  */
1703     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
1704                               ReqWidth, NULL, NULL, Dx, NULL,
1705                               &InClass, &ssa);
1706     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
1707     ScriptStringFree(&ssa);
1708
1709     /* test makes sure that a call with a valid pssa still works */
1710     hr = ScriptStringAnalyse( hdc, teststr, len, Glyphs, Charset, Flags,
1711                               ReqWidth, NULL, NULL, Dx, NULL,
1712                               &InClass, &ssa);
1713     ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
1714     ok(ssa != NULL, "ScriptStringAnalyse pssa should not be NULL\n");
1715
1716     if (hr == S_OK)
1717     {
1718         hr = ScriptStringOut(ssa, X, Y, Options, &rc, MinSel, MaxSel, Disabled);
1719         ok(hr == S_OK, "ScriptStringOut should return S_OK not %08x\n", hr);
1720     }
1721
1722      clip_len = ScriptString_pcOutChars(ssa);
1723      ok(*clip_len == len, "ScriptString_pcOutChars failed, got %d, expected %d\n", *clip_len, len);
1724
1725      order = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *clip_len * sizeof(UINT));
1726      hr = ScriptStringGetOrder(ssa, order);
1727      ok(hr == S_OK, "ScriptStringGetOrder failed, got %08x, expected S_OK\n", hr);
1728
1729      for (i = 0; i < *clip_len; i++) ok(order[i] == i, "%d: got %d expected %d\n", i, order[i], i);
1730      HeapFree(GetProcessHeap(), 0, order);
1731
1732      hr = ScriptStringFree(&ssa);
1733      ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
1734 }
1735
1736 static void test_ScriptStringXtoCP_CPtoX(HDC hdc)
1737 {
1738 /*****************************************************************************************
1739  *
1740  * This test is for the ScriptStringXtoCP and ScriptStringXtoCP functions.  Due to the
1741  * nature of the fonts between Windows and Wine, the test is implemented by generating
1742  * values using one one function then checking the output of the second.  In this way
1743  * the validity of the functions is established using Windows as a base and confirming
1744  * similar behaviour in wine.
1745  */
1746
1747     HRESULT         hr;
1748     static const WCHAR teststr1[]  = {0x05e9, 'i', 0x05dc, 'n', 0x05d5, 'e', 0x05dd, '.',0};
1749     static const BOOL rtl[] = {1, 0, 1, 0, 1, 0, 1, 0};
1750     void            *String = (WCHAR *) &teststr1;      /* ScriptStringAnalysis needs void */
1751     int             String_len = (sizeof(teststr1)/sizeof(WCHAR))-1;
1752     int             Glyphs = String_len * 2 + 16;       /* size of buffer as recommended  */
1753     int             Charset = -1;                       /* unicode                        */
1754     DWORD           Flags = SSA_GLYPHS;
1755     int             ReqWidth = 100;
1756     const BYTE      InClass = 0;
1757     SCRIPT_STRING_ANALYSIS ssa = NULL;
1758
1759     int             Ch;                                  /* Character position in string */
1760     int             iTrailing;
1761     int             Cp;                                  /* Character position in string */
1762     int             X;
1763     int             trail,lead;
1764     BOOL            fTrailing;
1765
1766     /* Test with hdc, this should be a valid test
1767      * Here we generate an SCRIPT_STRING_ANALYSIS that will be used as input to the
1768      * following character positions to X and X to character position functions.
1769      */
1770
1771     hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
1772                               ReqWidth, NULL, NULL, NULL, NULL,
1773                               &InClass, &ssa);
1774     ok(hr == S_OK ||
1775        hr == E_INVALIDARG, /* NT */
1776        "ScriptStringAnalyse should return S_OK or E_INVALIDARG not %08x\n", hr);
1777
1778     if  (hr == S_OK)
1779     {
1780         ok(ssa != NULL, "ScriptStringAnalyse ssa should not be NULL\n");
1781
1782         /*
1783          * Loop to generate character positions to provide starting positions for the
1784          * ScriptStringCPtoX and ScriptStringXtoCP functions
1785          */
1786         for (Cp = 0; Cp < String_len; Cp++)
1787         {
1788             /* The fTrailing flag is used to indicate whether the X being returned is at
1789              * the beginning or the end of the character. What happens here is that if
1790              * fTrailing indicates the end of the character, ie. FALSE, then ScriptStringXtoCP
1791              * returns the beginning of the next character and iTrailing is FALSE.  So for this
1792              * loop iTrailing will be FALSE in both cases.
1793              */
1794             hr = ScriptStringCPtoX(ssa, Cp, TRUE, &trail);
1795             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1796             hr = ScriptStringCPtoX(ssa, Cp, FALSE, &lead);
1797             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1798             if (rtl[Cp])
1799                 ok(lead > trail, "Leading values should be after trialing for rtl chracters(%i)\n",Cp);
1800             else
1801                 ok(lead < trail, "Trailing values should be after leading for ltr chracters(%i)\n",Cp);
1802
1803             /* move by 1 pixel so that we are not inbetween 2 characters.  That could result in being the lead of a rtl and
1804                at the same time the trail of an ltr */
1805
1806             /* inside the leading edge */
1807             X = lead;
1808             if (rtl[Cp]) X--; else X++;
1809             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1810             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1811             ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, trail);
1812             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
1813                                   iTrailing, X);
1814
1815             /* inside the trailing edge */
1816             X = trail;
1817             if (rtl[Cp]) X++; else X--;
1818             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1819             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1820             ok(Cp == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp, Ch, trail);
1821             ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
1822                                   iTrailing, X);
1823
1824             /* outside the "trailing" edge */
1825             if (Cp < String_len-1)
1826             {
1827                 if (rtl[Cp]) X = lead; else X = trail;
1828                 X++;
1829                 hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1830                 ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1831                 ok(Cp + 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp + 1, Ch, trail);
1832                 if (rtl[Cp+1])
1833                     ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
1834                                           iTrailing, X);
1835                 else
1836                     ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
1837                                           iTrailing, X);
1838             }
1839
1840             /* outside the "leading" edge */
1841             if (Cp != 0)
1842             {
1843                 if (rtl[Cp]) X = trail; else X = lead;
1844                 X--;
1845                 hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1846                 ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1847                 ok(Cp - 1 == Ch, "ScriptStringXtoCP should return Ch = %d not %d for X = %d\n", Cp - 1, Ch, trail);
1848                 if (Cp != 0  && rtl[Cp-1])
1849                     ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = %d\n",
1850                                           iTrailing, X);
1851                 else
1852                     ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = %d\n",
1853                                           iTrailing, X);
1854             }
1855         }
1856
1857         /* Check beyond the leading boundary of the whole string */
1858         if (rtl[0])
1859         {
1860             /* having a leading rtl character seems to confuse usp */
1861             /* this looks to be a windows bug we should emulate */
1862             hr = ScriptStringCPtoX(ssa, 0, TRUE, &X);
1863             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1864             X--;
1865             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1866             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1867             ok(Ch == 1, "ScriptStringXtoCP should return Ch = 1 not %d for X outside leading edge when rtl\n", Ch);
1868             ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = outside leading edge when rtl\n",
1869                                        iTrailing);
1870         }
1871         else
1872         {
1873             hr = ScriptStringCPtoX(ssa, 0, FALSE, &X);
1874             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1875             X--;
1876             hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1877             ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1878             ok(Ch == -1, "ScriptStringXtoCP should return Ch = -1 not %d for X outside leading edge\n", Ch);
1879             ok(iTrailing == TRUE, "ScriptStringXtoCP should return iTrailing = 1 not %d for X = outside leading edge\n",
1880                                        iTrailing);
1881         }
1882
1883         /* Check beyond the end boundary of the whole string */
1884         if (rtl[String_len-1])
1885         {
1886             hr = ScriptStringCPtoX(ssa, String_len-1, FALSE, &X);
1887             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1888         }
1889         else
1890         {
1891             hr = ScriptStringCPtoX(ssa, String_len-1, TRUE, &X);
1892             ok(hr == S_OK, "ScriptStringCPtoX should return S_OK not %08x\n", hr);
1893         }
1894         X++;
1895         hr = ScriptStringXtoCP(ssa, X, &Ch, &iTrailing);
1896         ok(hr == S_OK, "ScriptStringXtoCP should return S_OK not %08x\n", hr);
1897         ok(Ch == String_len, "ScriptStringXtoCP should return Ch = %i not %d for X outside trailing edge\n", String_len, Ch);
1898         ok(iTrailing == FALSE, "ScriptStringXtoCP should return iTrailing = 0 not %d for X = outside traling edge\n",
1899                                    iTrailing);
1900
1901         /*
1902          * Cleanup the SSA for the next round of tests
1903          */
1904         hr = ScriptStringFree(&ssa);
1905         ok(hr == S_OK, "ScriptStringFree should return S_OK not %08x\n", hr);
1906
1907         /*
1908          * Test to see that exceeding the number of chars returns E_INVALIDARG.  First
1909          * generate an SSA for the subsequent tests.
1910          */
1911         hr = ScriptStringAnalyse( hdc, String, String_len, Glyphs, Charset, Flags,
1912                                   ReqWidth, NULL, NULL, NULL, NULL,
1913                                   &InClass, &ssa);
1914         ok(hr == S_OK, "ScriptStringAnalyse should return S_OK not %08x\n", hr);
1915
1916         /*
1917          * When ScriptStringCPtoX is called with a character position Cp that exceeds the
1918          * string length, return E_INVALIDARG.  This also invalidates the ssa so a
1919          * ScriptStringFree should also fail.
1920          */
1921         fTrailing = FALSE;
1922         Cp = String_len + 1;
1923         hr = ScriptStringCPtoX(ssa, Cp, fTrailing, &X);
1924         ok(hr == E_INVALIDARG, "ScriptStringCPtoX should return E_INVALIDARG not %08x\n", hr);
1925
1926         ScriptStringFree(&ssa);
1927     }
1928 }
1929
1930 static void test_ScriptCacheGetHeight(HDC hdc)
1931 {
1932     HRESULT hr;
1933     SCRIPT_CACHE sc = NULL;
1934     LONG height;
1935
1936     hr = ScriptCacheGetHeight(NULL, NULL, NULL);
1937     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1938
1939     hr = ScriptCacheGetHeight(NULL, &sc, NULL);
1940     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1941
1942     hr = ScriptCacheGetHeight(NULL, &sc, &height);
1943     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1944
1945     height = 0;
1946
1947     hr = ScriptCacheGetHeight(hdc, &sc, &height);
1948     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1949     ok(height > 0, "expected height > 0\n");
1950
1951     ScriptFreeCache(&sc);
1952 }
1953
1954 static void test_ScriptGetGlyphABCWidth(HDC hdc)
1955 {
1956     HRESULT hr;
1957     SCRIPT_CACHE sc = NULL;
1958     ABC abc;
1959
1960     hr = ScriptGetGlyphABCWidth(NULL, NULL, 'a', NULL);
1961     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1962
1963     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', NULL);
1964     ok(broken(hr == E_PENDING) ||
1965        hr == E_INVALIDARG, /* WIN7 */
1966        "expected E_INVALIDARG, got 0x%08x\n", hr);
1967
1968     hr = ScriptGetGlyphABCWidth(NULL, &sc, 'a', &abc);
1969     ok(hr == E_PENDING, "expected E_PENDING, got 0x%08x\n", hr);
1970
1971     if (0) {    /* crashes on WinXP */
1972     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', NULL);
1973     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
1974     }
1975
1976     hr = ScriptGetGlyphABCWidth(hdc, &sc, 'a', &abc);
1977     ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
1978
1979     ScriptFreeCache(&sc);
1980 }
1981
1982 static void test_ScriptLayout(void)
1983 {
1984     HRESULT hr;
1985     static const BYTE levels[][10] =
1986     {
1987         { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
1988         { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 },
1989         { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
1990         { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
1991
1992         { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1},
1993         { 1, 1, 1, 2, 2, 2, 1, 1, 1, 1 },
1994         { 2, 2, 2, 1, 1, 1, 2, 2, 2, 2 },
1995         { 0, 0, 1, 1, 2, 2, 1, 1, 0, 0 },
1996         { 1, 1, 2, 2, 3, 3, 2, 2, 1, 1 },
1997
1998         { 0, 0, 1, 1, 2, 2, 1, 1, 0, 1 },
1999         { 1, 0, 1, 2, 2, 1, 2, 1, 0, 1 },
2000     };
2001     static const int expect_l2v[][10] =
2002     {
2003         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
2004         { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
2005         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
2006         { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
2007
2008         { 0, 1, 2, 3, 4, 9, 8 ,7 ,6, 5},
2009 /**/    { 9, 8, 7, 4, 5, 6, 3 ,2 ,1, 0},
2010 /**/    { 7, 8, 9, 6, 5, 4, 0 ,1 ,2, 3},
2011         { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
2012         { 9, 8, 2, 3, 5, 4, 6 ,7 ,1, 0},
2013
2014         { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
2015 /**/    { 0, 1, 7, 5, 6, 4, 3 ,2 ,8, 9},
2016     };
2017     static const int expect_v2l[][10] =
2018     {
2019         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
2020         { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
2021         { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
2022         { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 },
2023
2024         { 0, 1, 2, 3, 4, 9, 8 ,7 ,6, 5},
2025         { 9, 8, 7, 6, 3, 4, 5 ,2 ,1, 0},
2026         { 6, 7, 8, 9, 5, 4, 3 ,0 ,1, 2},
2027         { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
2028         { 9, 8, 2, 3, 5, 4, 6 ,7 ,1, 0},
2029
2030         { 0, 1, 7, 6, 4, 5, 3 ,2 ,8, 9},
2031         { 0, 1, 7, 6, 5, 3, 4 ,2 ,8, 9},
2032     };
2033
2034     int i, j, vistolog[sizeof(levels[0])], logtovis[sizeof(levels[0])];
2035
2036     hr = ScriptLayout(sizeof(levels[0]), NULL, vistolog, logtovis);
2037     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
2038
2039     hr = ScriptLayout(sizeof(levels[0]), levels[0], NULL, NULL);
2040     ok(hr == E_INVALIDARG, "expected E_INVALIDARG, got 0x%08x\n", hr);
2041
2042     for (i = 0; i < sizeof(levels)/sizeof(levels[0]); i++)
2043     {
2044         hr = ScriptLayout(sizeof(levels[0]), levels[i], vistolog, logtovis);
2045         ok(hr == S_OK, "expected S_OK, got 0x%08x\n", hr);
2046
2047         for (j = 0; j < sizeof(levels[i]); j++)
2048         {
2049             ok(expect_v2l[i][j] == vistolog[j],
2050                "failure: levels[%d][%d] = %d, vistolog[%d] = %d\n",
2051                i, j, levels[i][j], j, vistolog[j] );
2052         }
2053
2054         for (j = 0; j < sizeof(levels[i]); j++)
2055         {
2056             ok(expect_l2v[i][j] == logtovis[j],
2057                "failure: levels[%d][%d] = %d, logtovis[%d] = %d\n",
2058                i, j, levels[i][j], j, logtovis[j] );
2059         }
2060     }
2061 }
2062
2063 static BOOL CALLBACK enum_proc(LGRPID group, LCID lcid, LPSTR locale, LONG_PTR lparam)
2064 {
2065     HRESULT hr;
2066     SCRIPT_DIGITSUBSTITUTE sds;
2067     SCRIPT_CONTROL sc;
2068     SCRIPT_STATE ss;
2069     LCID lcid_old;
2070
2071     if (!IsValidLocale(lcid, LCID_INSTALLED)) return TRUE;
2072
2073     memset(&sds, 0, sizeof(sds));
2074     memset(&sc, 0, sizeof(sc));
2075     memset(&ss, 0, sizeof(ss));
2076
2077     lcid_old = GetThreadLocale();
2078     if (!SetThreadLocale(lcid)) return TRUE;
2079
2080     hr = ScriptRecordDigitSubstitution(lcid, &sds);
2081     ok(hr == S_OK, "ScriptRecordDigitSubstitution failed: 0x%08x\n", hr);
2082
2083     hr = ScriptApplyDigitSubstitution(&sds, &sc, &ss);
2084     ok(hr == S_OK, "ScriptApplyDigitSubstitution failed: 0x%08x\n", hr);
2085
2086     SetThreadLocale(lcid_old);
2087     return TRUE;
2088 }
2089
2090 static void test_digit_substitution(void)
2091 {
2092     BOOL ret;
2093     unsigned int i;
2094     static const LGRPID groups[] =
2095     {
2096         LGRPID_WESTERN_EUROPE,
2097         LGRPID_CENTRAL_EUROPE,
2098         LGRPID_BALTIC,
2099         LGRPID_GREEK,
2100         LGRPID_CYRILLIC,
2101         LGRPID_TURKISH,
2102         LGRPID_JAPANESE,
2103         LGRPID_KOREAN,
2104         LGRPID_TRADITIONAL_CHINESE,
2105         LGRPID_SIMPLIFIED_CHINESE,
2106         LGRPID_THAI,
2107         LGRPID_HEBREW,
2108         LGRPID_ARABIC,
2109         LGRPID_VIETNAMESE,
2110         LGRPID_INDIC,
2111         LGRPID_GEORGIAN,
2112         LGRPID_ARMENIAN
2113     };
2114     HMODULE hKernel32;
2115     static BOOL (WINAPI * pEnumLanguageGroupLocalesA)(LANGGROUPLOCALE_ENUMPROCA,LGRPID,DWORD,LONG_PTR);
2116
2117     hKernel32 = GetModuleHandleA("kernel32.dll");
2118     pEnumLanguageGroupLocalesA = (void*)GetProcAddress(hKernel32, "EnumLanguageGroupLocalesA");
2119
2120     if (!pEnumLanguageGroupLocalesA)
2121     {
2122         win_skip("EnumLanguageGroupLocalesA not available on this platform\n");
2123         return;
2124     }
2125
2126     for (i = 0; i < sizeof(groups)/sizeof(groups[0]); i++)
2127     {
2128         ret = pEnumLanguageGroupLocalesA(enum_proc, groups[i], 0, 0);
2129         if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2130         {
2131             win_skip("EnumLanguageGroupLocalesA not implemented on this platform\n");
2132             break;
2133         }
2134         
2135         ok(ret, "EnumLanguageGroupLocalesA failed unexpectedly: %u\n", GetLastError());
2136     }
2137 }
2138
2139 static void test_ScriptGetProperties(void)
2140 {
2141     const SCRIPT_PROPERTIES **props;
2142     HRESULT hr;
2143     int num;
2144
2145     hr = ScriptGetProperties(NULL, NULL);
2146     ok(hr == E_INVALIDARG, "ScriptGetProperties succeeded\n");
2147
2148     hr = ScriptGetProperties(NULL, &num);
2149     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
2150
2151     hr = ScriptGetProperties(&props, NULL);
2152     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
2153
2154     hr = ScriptGetProperties(&props, &num);
2155     ok(hr == S_OK, "ScriptGetProperties failed: 0x%08x\n", hr);
2156 }
2157
2158 static void test_ScriptBreak(void)
2159 {
2160     static const WCHAR test[] = {' ','\r','\n',0};
2161     SCRIPT_ITEM items[4];
2162     SCRIPT_LOGATTR la;
2163     HRESULT hr;
2164
2165     hr = ScriptItemize(test, 3, 4, NULL, NULL, items, NULL);
2166     ok(!hr, "ScriptItemize should return S_OK not %08x\n", hr);
2167
2168     memset(&la, 0, sizeof(la));
2169     hr = ScriptBreak(test, 1, &items[0].a, &la);
2170     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
2171
2172     ok(!la.fSoftBreak, "fSoftBreak set\n");
2173     ok(la.fWhiteSpace, "fWhiteSpace not set\n");
2174     ok(la.fCharStop, "fCharStop not set\n");
2175     ok(!la.fWordStop, "fWordStop set\n");
2176     ok(!la.fInvalid, "fInvalid set\n");
2177     ok(!la.fReserved, "fReserved set\n");
2178
2179     memset(&la, 0, sizeof(la));
2180     hr = ScriptBreak(test + 1, 1, &items[1].a, &la);
2181     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
2182
2183     ok(!la.fSoftBreak, "fSoftBreak set\n");
2184     ok(!la.fWhiteSpace, "fWhiteSpace set\n");
2185     ok(la.fCharStop, "fCharStop not set\n");
2186     ok(!la.fWordStop, "fWordStop set\n");
2187     ok(!la.fInvalid, "fInvalid set\n");
2188     ok(!la.fReserved, "fReserved set\n");
2189
2190     memset(&la, 0, sizeof(la));
2191     hr = ScriptBreak(test + 2, 1, &items[2].a, &la);
2192     ok(!hr, "ScriptBreak should return S_OK not %08x\n", hr);
2193
2194     ok(!la.fSoftBreak, "fSoftBreak set\n");
2195     ok(!la.fWhiteSpace, "fWhiteSpace set\n");
2196     ok(la.fCharStop, "fCharStop not set\n");
2197     ok(!la.fWordStop, "fWordStop set\n");
2198     ok(!la.fInvalid, "fInvalid set\n");
2199     ok(!la.fReserved, "fReserved set\n");
2200 }
2201
2202 static void test_newlines(void)
2203 {
2204     static const WCHAR test1[] = {'t','e','x','t','\r','t','e','x','t',0};
2205     static const WCHAR test2[] = {'t','e','x','t','\n','t','e','x','t',0};
2206     static const WCHAR test3[] = {'t','e','x','t','\r','\n','t','e','x','t',0};
2207     static const WCHAR test4[] = {'t','e','x','t','\n','\r','t','e','x','t',0};
2208     static const WCHAR test5[] = {'1','2','3','4','\n','\r','1','2','3','4',0};
2209     SCRIPT_ITEM items[5];
2210     HRESULT hr;
2211     int count;
2212
2213     count = 0;
2214     hr = ScriptItemize(test1, lstrlenW(test1), 5, NULL, NULL, items, &count);
2215     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2216     ok(count == 3, "got %d expected 3\n", count);
2217
2218     count = 0;
2219     hr = ScriptItemize(test2, lstrlenW(test2), 5, NULL, NULL, items, &count);
2220     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2221     ok(count == 3, "got %d expected 3\n", count);
2222
2223     count = 0;
2224     hr = ScriptItemize(test3, lstrlenW(test3), 5, NULL, NULL, items, &count);
2225     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2226     ok(count == 4, "got %d expected 4\n", count);
2227
2228     count = 0;
2229     hr = ScriptItemize(test4, lstrlenW(test4), 5, NULL, NULL, items, &count);
2230     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2231     ok(count == 4, "got %d expected 4\n", count);
2232
2233     count = 0;
2234     hr = ScriptItemize(test5, lstrlenW(test5), 5, NULL, NULL, items, &count);
2235     ok(hr == S_OK, "ScriptItemize failed: 0x%08x\n", hr);
2236     ok(count == 4, "got %d expected 4\n", count);
2237 }
2238
2239 START_TEST(usp10)
2240 {
2241     HWND            hwnd;
2242     HDC             hdc;
2243     LOGFONTA        lf;
2244     HFONT           hfont;
2245
2246     unsigned short  pwOutGlyphs[256];
2247
2248     /* We need a valid HDC to drive a lot of Script functions which requires the following    *
2249      * to set up for the tests.                                                               */
2250     hwnd = CreateWindowExA(0, "static", "", WS_POPUP, 0,0,100,100,
2251                            0, 0, 0, NULL);
2252     assert(hwnd != 0);
2253     ShowWindow(hwnd, SW_SHOW);
2254     UpdateWindow(hwnd);
2255
2256     hdc = GetDC(hwnd);                                      /* We now have a hdc             */
2257     ok( hdc != NULL, "HDC failed to be created %p\n", hdc);
2258
2259     memset(&lf, 0, sizeof(LOGFONTA));
2260     lstrcpyA(lf.lfFaceName, "Tahoma");
2261     lf.lfHeight = 10;
2262     lf.lfWeight = 3;
2263     lf.lfWidth = 10;
2264
2265     hfont = SelectObject(hdc, CreateFontIndirectA(&lf));
2266     ok(hfont != NULL, "SelectObject failed: %p\n", hfont);
2267
2268     test_ScriptItemize();
2269     test_ScriptItemIzeShapePlace(hdc,pwOutGlyphs);
2270     test_ScriptGetCMap(hdc, pwOutGlyphs);
2271     test_ScriptCacheGetHeight(hdc);
2272     test_ScriptGetGlyphABCWidth(hdc);
2273     test_ScriptShape(hdc);
2274     test_ScriptShapeOpenType(hdc);
2275     test_ScriptPlace(hdc);
2276
2277     test_ScriptGetFontProperties(hdc);
2278     test_ScriptTextOut(hdc);
2279     test_ScriptTextOut2(hdc);
2280     test_ScriptTextOut3(hdc);
2281     test_ScriptXtoX();
2282     test_ScriptString(hdc);
2283     test_ScriptStringXtoCP_CPtoX(hdc);
2284
2285     test_ScriptLayout();
2286     test_digit_substitution();
2287     test_ScriptGetProperties();
2288     test_ScriptBreak();
2289     test_newlines();
2290
2291     ReleaseDC(hwnd, hdc);
2292     DestroyWindow(hwnd);
2293 }