usp10: Document ScriptItemize. Get rid of the remaining tabs.
[wine] / dlls / usp10 / usp10.c
1 /*
2  * Implementation of Uniscribe Script Processor (usp10.dll)
3  *
4  * Copyright 2005 Steven Edwards for CodeWeavers
5  * Copyright 2006 Hans Leidekker
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * Notes:
22  * Uniscribe allows for processing of complex scripts such as joining
23  * and filtering characters and bi-directional text with custom line breaks.
24  */
25
26 #include <stdarg.h>
27
28 #include "windef.h"
29 #include "winbase.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "winnls.h"
33 #include "usp10.h"
34
35 #include "wine/debug.h"
36 #include "wine/unicode.h"
37
38 /**
39  * some documentation here:
40  *   http://www.microsoft.com/typography/developers/uniscribe/uniscribe.htm
41  */
42
43 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
44
45 static const SCRIPT_PROPERTIES props[] =
46 {
47     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
48     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
49     { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
50     { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
51     { 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
52     { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
53     { 9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
54     { 8, 0, 0, 0, 0, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
55     { 25, 0, 0, 0, 0, 204, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
56     { 43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
57     { 55, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
58     { 42, 0, 0, 0, 0, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
59     { 9, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
60     { 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0 },
61     { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
62     { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
63     { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
64     { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
65     { 18, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
66     { 18, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
67     { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
68     { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
69     { 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
70     { 9, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0 },
71     { 13, 0, 1, 0, 1, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
72     { 13, 0, 1, 0, 0, 177, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
73     { 1, 0, 1, 0, 0, 178, 0, 0, 0, 0, 0, 0, 1, 1, 0 },
74     { 1, 1, 1, 0, 0, 178, 0, 0, 0, 0, 0, 0, 1, 0, 0 },
75     { 41, 1, 1, 0, 0, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
76     { 32, 1, 1, 0, 0, 178, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
77     { 90, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0 },
78     { 30, 0, 1, 1, 1, 222, 0, 0, 1, 0, 1, 0, 0, 0, 1 },
79     { 30, 1, 1, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
80     { 30, 0, 1, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
81     { 57, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
82     { 57, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
83     { 73, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
84     { 73, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
85     { 69, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
86     { 69, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
87     { 69, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
88     { 70, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
89     { 70, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
90     { 71, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
91     { 71, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
92     { 72, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
93     { 72, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
94     { 74, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
95     { 74, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
96     { 75, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
97     { 75, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
98     { 76, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
99     { 76, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
100     { 81, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0 },
101     { 81, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
102     { 84, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0 },
103     { 84, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
104     { 83, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
105     { 83, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
106     { 85, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0 },
107     { 85, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
108     { 80, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
109     { 80, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
110     { 94, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
111     { 94, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
112     { 101, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
113     { 93, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
114     { 92, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
115     { 9, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
116     { 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
117     { 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
118     { 91, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
119     { 9, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 },
120     { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
121 };
122
123 static const SCRIPT_PROPERTIES *script_props[] =
124 {
125     &props[0], &props[1], &props[2], &props[3],
126     &props[4], &props[5], &props[6], &props[7],
127     &props[8], &props[9], &props[11], &props[12],
128     &props[13], &props[14], &props[15], &props[16],
129     &props[17], &props[18], &props[19], &props[20],
130     &props[21], &props[22], &props[23], &props[24],
131     &props[25], &props[26], &props[27], &props[28],
132     &props[29], &props[30], &props[31], &props[32],
133     &props[33], &props[34], &props[35], &props[36],
134     &props[37], &props[38], &props[39], &props[40],
135     &props[41], &props[42], &props[43], &props[44],
136     &props[45], &props[46], &props[47], &props[48],
137     &props[49], &props[50], &props[51], &props[52],
138     &props[53], &props[54], &props[55], &props[56],
139     &props[57], &props[58], &props[59], &props[60],
140     &props[61], &props[62], &props[63], &props[64],
141     &props[65], &props[66], &props[67], &props[68],
142     &props[69], &props[70], &props[71], &props[72],
143     &props[73]
144 };
145
146 typedef struct {
147     HDC hdc;
148 } ScriptCache;
149
150 typedef struct {
151     int numGlyphs;
152     WORD* glyphs;
153     WORD* pwLogClust;
154     int* piAdvance;
155     SCRIPT_VISATTR* psva;
156     GOFFSET* pGoffset;
157     ABC* abc;
158 } StringGlyphs;
159
160 typedef struct {
161     BOOL invalid;
162     int clip_len;
163     ScriptCache *sc;
164     int cItems;
165     int cMaxGlyphs;
166     SCRIPT_ITEM* pItem;
167     int numItems;
168     StringGlyphs* glyphs;
169     SCRIPT_LOGATTR* logattrs;
170     SIZE* sz;
171 } StringAnalysis;
172
173 static inline void *usp_alloc(SIZE_T size)
174 {
175     return HeapAlloc(GetProcessHeap(), 0, size);
176 }
177
178 static inline void *usp_zero_alloc(SIZE_T size)
179 {
180     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
181 }
182
183 static inline void *usp_zero_realloc(LPVOID mem, SIZE_T size)
184 {
185     return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
186 }
187
188 static inline void usp_free(LPVOID mem)
189 {
190     HeapFree(GetProcessHeap(), 0, mem);
191 }
192
193 static HRESULT get_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
194 {
195     if (!psc) return E_INVALIDARG;
196     if (!*psc)
197     {
198         if (!hdc) return E_PENDING;
199         if (!(*psc = usp_alloc(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
200         ((ScriptCache *)*psc)->hdc = hdc;
201     }
202     return S_OK;
203 }
204
205 /***********************************************************************
206  *      DllMain
207  *
208  */
209 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
210 {
211     switch(fdwReason)
212     {
213     case DLL_PROCESS_ATTACH:
214         DisableThreadLibraryCalls(hInstDLL);
215         break;
216     case DLL_PROCESS_DETACH:
217         break;
218     }
219     return TRUE;
220 }
221
222 /***********************************************************************
223  *      ScriptFreeCache (USP10.@)
224  *
225  * Free a script cache.
226  *
227  * PARAMS
228  *   psc [I/O] Script cache.
229  *
230  * RETURNS
231  *  Success: S_OK
232  *  Failure: Non-zero HRESULT value.
233  */
234 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
235 {
236     TRACE("%p\n", psc);
237
238     if (psc)
239     {
240        usp_free(*psc);
241        *psc = NULL;
242     }
243     return S_OK;
244 }
245
246 /***********************************************************************
247  *      ScriptGetProperties (USP10.@)
248  *
249  * Retrieve a list of script properties.
250  *
251  * PARAMS
252  *  props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
253  *  num   [I] Pointer to the number of scripts.
254  *
255  * RETURNS
256  *  Success: S_OK
257  *  Failure: Non-zero HRESULT value.
258  *
259  * NOTES
260  *  Behaviour matches WinXP.
261  */
262 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
263 {
264     TRACE("(%p,%p)\n", props, num);
265
266     if (!props && !num) return E_INVALIDARG;
267
268     if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
269     if (props) *props = script_props;
270
271     return S_OK;
272 }
273
274 /***********************************************************************
275  *      ScriptGetFontProperties (USP10.@)
276  *
277  * Get information on special glyphs.
278  *
279  * PARAMS
280  *  hdc [I]   Device context.
281  *  psc [I/O] Opaque pointer to a script cache.
282  *  sfp [O]   Font properties structure.
283  */
284 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
285 {
286     HRESULT hr;
287     TEXTMETRICW ptm;
288
289     TRACE("%p,%p,%p\n", hdc, psc, sfp);
290
291     if (!sfp) return E_INVALIDARG;
292     if ((hr = get_script_cache(hdc, psc))) return hr;
293
294     if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
295         return E_INVALIDARG;
296
297     /* return something sensible? */
298     sfp->wgBlank = 0;
299     if (GetTextMetricsW(((ScriptCache *)*psc)->hdc, &ptm))
300         sfp->wgDefault = ptm.tmDefaultChar;
301     else
302         sfp->wgDefault = 0;
303     sfp->wgInvalid = 0;
304     sfp->wgKashida = 0xffff;
305     sfp->iKashidaWidth = 0;
306
307     return S_OK;
308 }
309
310 /***********************************************************************
311  *      ScriptRecordDigitSubstitution (USP10.@)
312  *
313  *  Record digit substitution settings for a given locale.
314  *
315  *  PARAMS
316  *   locale [I] Locale identifier.
317  *   sds    [I] Structure to record substitution settings.
318  *
319  *  RETURNS
320  *   Success: S_OK
321  *   Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
322  *
323  *  SEE ALSO
324  *   http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
325  */
326 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
327 {
328     DWORD plgid, sub;
329
330     TRACE("0x%x, %p\n", locale, sds);
331
332     /* This implementation appears to be correct for all languages, but it's
333      * not clear if sds->DigitSubstitute is ever set to anything except 
334      * CONTEXT or NONE in reality */
335
336     if (!sds) return E_POINTER;
337
338     locale = ConvertDefaultLocale(locale);
339
340     if (!IsValidLocale(locale, LCID_INSTALLED))
341         return E_INVALIDARG;
342
343     plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
344     sds->TraditionalDigitLanguage = plgid;
345
346     if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
347         sds->NationalDigitLanguage = plgid;
348     else
349         sds->NationalDigitLanguage = LANG_ENGLISH;
350
351     if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
352                         (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
353
354     switch (sub)
355     {
356     case 0: 
357         if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
358             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
359         else
360             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
361         break;
362     case 1:
363         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
364         break;
365     case 2:
366         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
367         break;
368     default:
369         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
370         break;
371     }
372
373     sds->dwReserved = 0;
374     return S_OK;
375 }
376
377 /***********************************************************************
378  *      ScriptApplyDigitSubstitution (USP10.@)
379  *
380  *  Apply digit substitution settings.
381  *
382  *  PARAMS
383  *   sds [I] Structure with recorded substitution settings.
384  *   sc  [I] Script control structure.
385  *   ss  [I] Script state structure.
386  *
387  *  RETURNS
388  *   Success: S_OK
389  *   Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
390  */
391 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds, 
392                                             SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
393 {
394     SCRIPT_DIGITSUBSTITUTE psds;
395
396     TRACE("%p, %p, %p\n", sds, sc, ss);
397
398     if (!sc || !ss) return E_POINTER;
399     if (!sds)
400     {
401         sds = &psds;
402         if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
403             return E_INVALIDARG;
404     }
405
406     sc->uDefaultLanguage = LANG_ENGLISH;
407     sc->fContextDigits = 0;
408     ss->fDigitSubstitute = 0;
409
410     switch (sds->DigitSubstitute) {
411         case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
412         case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
413         case SCRIPT_DIGITSUBSTITUTE_NONE:
414         case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
415             return S_OK;
416         default:
417             return E_INVALIDARG;
418     }
419 }
420
421 /***********************************************************************
422  *      ScriptItemize (USP10.@)
423  *
424  * Split a Unicode string into shapeable parts.
425  *
426  * PARAMS
427  *  pwcInChars [I] String to split.
428  *  cInChars   [I] Number of characters in pwcInChars.
429  *  cMaxItems  [I] Maximum number of items to return.
430  *  psControl  [I] Pointer to a SCRIPT_CONTROL structure.
431  *  psState    [I] Pointer to a SCRIPT_STATE structure.
432  *  pItems     [O] Buffer to receive SCRIPT_ITEM structures.
433  *  pcItems    [O] Number of script items returned.
434  *
435  * RETURNS
436  *  Success: S_OK
437  *  Failure: Non-zero HRESULT value.
438  */
439 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
440                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
441                              SCRIPT_ITEM *pItems, int *pcItems)
442 {
443
444 #define Numeric_start 0x0030
445 #define Numeric_stop  0x0039
446 #define Numeric_space 0x0020
447 #define Arabic_start  0x0600
448 #define Arabic_stop   0x06ff
449 #define Latin_start   0x0001
450 #define Latin_stop    0x024f
451 #define Script_Arabic  6
452 #define Script_Latin   1
453 #define Script_Numeric 5
454
455     int   cnt = 0, index = 0;
456     int   New_Script = SCRIPT_UNDEFINED;
457
458     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
459           psControl, psState, pItems, pcItems);
460
461     if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
462         return E_INVALIDARG;
463
464     pItems[index].iCharPos = 0;
465     memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
466
467     if  (pwcInChars[cnt] >= Numeric_start && pwcInChars[cnt] <= Numeric_stop)
468         pItems[index].a.eScript = Script_Numeric;
469     else
470     if  (pwcInChars[cnt] >= Arabic_start && pwcInChars[cnt] <= Arabic_stop)
471         pItems[index].a.eScript = Script_Arabic;
472     else
473     if  (pwcInChars[cnt] >= Latin_start && pwcInChars[cnt] <= Latin_stop)
474         pItems[index].a.eScript = Script_Latin;
475
476     if  (pItems[index].a.eScript  == Script_Arabic)
477         pItems[index].a.s.uBidiLevel = 1;
478
479     TRACE("New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
480           New_Script, pItems[index].a.eScript, index, cnt,
481           pItems[index].iCharPos = cnt);
482
483     for (cnt=0; cnt < cInChars; cnt++)
484     {
485         if  ((pwcInChars[cnt] >= Numeric_start && pwcInChars[cnt] <= Numeric_stop)
486              || (New_Script == Script_Numeric && pwcInChars[cnt] == Numeric_space))
487             New_Script = Script_Numeric;
488         else
489         if  ((pwcInChars[cnt] >= Arabic_start && pwcInChars[cnt] <= Arabic_stop)
490              || (New_Script == Script_Arabic && pwcInChars[cnt] == Numeric_space))
491             New_Script = Script_Arabic;
492         else
493         if  ((WCHAR) pwcInChars[cnt] >= Latin_start && (WCHAR) pwcInChars[cnt] <= Latin_stop)
494             New_Script = Script_Latin;
495         else
496             New_Script = SCRIPT_UNDEFINED;
497
498         if  (New_Script != pItems[index].a.eScript)
499         {
500             TRACE("New_Script=%d, eScript=%d ", New_Script, pItems[index].a.eScript);
501             index++;
502             if  (index+1 > cMaxItems)
503                 return E_OUTOFMEMORY;
504
505             pItems[index].iCharPos = cnt;
506             memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
507
508             if  (New_Script == Script_Arabic)
509                 pItems[index].a.s.uBidiLevel = 1;
510
511             pItems[index].a.eScript = New_Script;
512             if  (New_Script == Script_Arabic)
513                 pItems[index].a.s.uBidiLevel = 1;
514
515             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos = cnt);
516         }
517     }
518
519     /* While not strictly necessary according to the spec, make sure the n+1
520      * item is set up to prevent random behaviour if the caller erroneously
521      * checks the n+1 structure                                              */
522     memset(&pItems[index+1].a, 0, sizeof(SCRIPT_ANALYSIS));
523
524     TRACE("index=%d cnt=%d iCharPos=%d\n", index+1, cnt, pItems[index+1].iCharPos = cnt);
525
526     /*  Set one SCRIPT_STATE item being returned  */
527     *pcItems = index + 1;
528
529     /*  Set SCRIPT_ITEM                                     */
530     pItems[index+1].iCharPos = cnt;       /* the last + 1 item
531                                              contains the ptr to the lastchar */
532     return S_OK;
533 }
534
535 /***********************************************************************
536  *      ScriptStringAnalyse (USP10.@)
537  *
538  */
539 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
540                                    int cGlyphs, int iCharset, DWORD dwFlags,
541                                    int iReqWidth, SCRIPT_CONTROL *psControl,
542                                    SCRIPT_STATE *psState, const int *piDx,
543                                    SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
544                                    SCRIPT_STRING_ANALYSIS *pssa)
545 {
546     HRESULT hr = E_OUTOFMEMORY;
547     StringAnalysis *analysis = NULL;
548     int i, num_items = 255;
549
550     TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
551           hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
552           psControl, psState, piDx, pTabdef, pbInClass, pssa);
553
554     if (iCharset != -1)
555     {
556         FIXME("Only Unicode strings are supported\n");
557         return E_INVALIDARG;
558     }
559     if (cString < 1 || !pString) return E_INVALIDARG;
560     if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
561
562     if (!(analysis = usp_zero_alloc(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
563     if (!(analysis->pItem = usp_zero_alloc(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
564
565     /* FIXME: handle clipping */
566     analysis->clip_len = cString;
567
568     hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
569                        &analysis->numItems);
570
571     while (hr == E_OUTOFMEMORY)
572     {
573         SCRIPT_ITEM *tmp;
574
575         num_items *= 2;
576         if (!(tmp = usp_zero_realloc(analysis->pItem, num_items * sizeof(SCRIPT_ITEM) + 1)))
577             goto error;
578
579         analysis->pItem = tmp;
580         hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
581                            &analysis->numItems);
582     }
583     if (hr) goto error;
584
585     if ((analysis->logattrs = usp_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
586         ScriptBreak(pString, cString, (SCRIPT_STRING_ANALYSIS)analysis, analysis->logattrs);
587     else
588         goto error;
589
590     if (!(analysis->glyphs = usp_zero_alloc(sizeof(StringGlyphs) * analysis->numItems)))
591         goto error;
592
593     for (i = 0; i < analysis->numItems; i++)
594     {
595         SCRIPT_CACHE *sc = (SCRIPT_CACHE *)&analysis->sc;
596         int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
597         int numGlyphs = 1.5 * cChar + 16;
598         WORD *glyphs = usp_zero_alloc(sizeof(WORD) * numGlyphs);
599         WORD *pwLogClust = usp_zero_alloc(sizeof(WORD) * cChar);
600         int *piAdvance = usp_zero_alloc(sizeof(int) * numGlyphs);
601         SCRIPT_VISATTR *psva = usp_zero_alloc(sizeof(SCRIPT_VISATTR) * cChar);
602         GOFFSET *pGoffset = usp_zero_alloc(sizeof(GOFFSET) * numGlyphs);
603         ABC *abc = usp_zero_alloc(sizeof(ABC));
604         int numGlyphsReturned;
605
606         /* FIXME: non unicode strings */
607         WCHAR* pStr = (WCHAR*)pString;
608         hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
609                          cChar, numGlyphs, &analysis->pItem[i].a,
610                          glyphs, pwLogClust, psva, &numGlyphsReturned);
611         hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
612                          piAdvance, pGoffset, abc);
613
614         analysis->glyphs[i].numGlyphs = numGlyphsReturned;
615         analysis->glyphs[i].glyphs = glyphs;
616         analysis->glyphs[i].pwLogClust = pwLogClust;
617         analysis->glyphs[i].piAdvance = piAdvance;
618         analysis->glyphs[i].psva = psva;
619         analysis->glyphs[i].pGoffset = pGoffset;
620         analysis->glyphs[i].abc = abc;
621     }
622
623     *pssa = analysis;
624     return S_OK;
625
626 error:
627     usp_free(analysis->glyphs);
628     usp_free(analysis->logattrs);
629     usp_free(analysis->pItem);
630     usp_free(analysis);
631     return hr;
632 }
633
634 /***********************************************************************
635  *      ScriptStringOut (USP10.@)
636  *
637  * This function takes the output of ScriptStringAnalyse and joins the segments
638  * of glyphs and passes the resulting string to ScriptTextOut.  ScriptStringOut
639  * only processes glyphs.
640  *
641  * Parameters:
642  *  ssa       [I] buffer to hold the analysed string components
643  *  iX        [I] X axis displacement for output
644  *  iY        [I] Y axis displacement for output
645  *  uOptions  [I] flags controling output processing
646  *  prc       [I] rectangle coordinates
647  *  iMinSel   [I] starting pos for substringing output string
648  *  iMaxSel   [I] ending pos for substringing output string
649  *  fDisabled [I] controls text highlighting
650  *
651  *  RETURNS
652  *   Success: S_OK
653  *   Failure: is the value returned by ScriptTextOut
654  */
655 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
656                                int iX,
657                                int iY, 
658                                UINT uOptions, 
659                                const RECT *prc, 
660                                int iMinSel, 
661                                int iMaxSel,
662                                BOOL fDisabled)
663 {
664     StringAnalysis *analysis;
665     WORD *glyphs;
666     int   item, cnt, x;
667     HRESULT hr;
668
669     TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
670          ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
671
672     if (!(analysis = ssa)) return E_INVALIDARG;
673
674     /*
675      * Get storage for the output buffer for the consolidated strings
676      */
677     cnt = 0;
678     for (item = 0; item < analysis->numItems; item++)
679     {
680         cnt += analysis->glyphs[item].numGlyphs;
681     }
682     if (!(glyphs = usp_alloc(sizeof(WCHAR) * cnt))) return E_OUTOFMEMORY;
683
684     /*
685      * ScriptStringOut only processes glyphs hence set ETO_GLYPH_INDEX
686      */
687     uOptions |= ETO_GLYPH_INDEX;
688     analysis->pItem[0].a.fNoGlyphIndex = FALSE; /* say that we have glyphs */
689
690     /*
691      * Copy the string items into the output buffer
692      */
693
694     TRACE("numItems %d\n", analysis->numItems);
695
696     cnt = 0;
697     for (item = 0; item < analysis->numItems; item++)
698     {
699         memcpy(&glyphs[cnt], analysis->glyphs[item].glyphs,
700               sizeof(WCHAR) * analysis->glyphs[item].numGlyphs);
701
702         TRACE("Item %d, Glyphs %d ", item, analysis->glyphs[item].numGlyphs);
703         for (x = cnt; x < analysis->glyphs[item].numGlyphs + cnt; x ++)
704             TRACE("%04x", glyphs[x]);
705         TRACE("\n");
706
707         cnt += analysis->glyphs[item].numGlyphs; /* point to the end of the copied text */
708     }
709
710     hr = ScriptTextOut(analysis->sc->hdc, (SCRIPT_CACHE *)&analysis->sc, iX, iY,
711                        uOptions, prc, &analysis->pItem->a, NULL, 0, glyphs, cnt,
712                        analysis->glyphs->piAdvance, NULL, analysis->glyphs->pGoffset);
713     TRACE("ScriptTextOut hr=%08x\n", hr);
714
715     /*
716      * Free the output buffer and script cache
717      */
718     usp_free(glyphs);
719     return hr;
720 }
721
722 /***********************************************************************
723  *      ScriptStringCPtoX (USP10.@)
724  *
725  */
726 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
727 {
728     int i, j;
729     int runningX = 0;
730     int runningCp = 0;
731     StringAnalysis* analysis = ssa;
732
733     TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
734
735     if (!ssa || !pX) return S_FALSE;
736
737     /* icp out of range */
738     if(icp < 0)
739     {
740         analysis->invalid = TRUE;
741         return E_INVALIDARG;
742     }
743
744     for(i=0; i<analysis->numItems; i++)
745     {
746         for(j=0; j<analysis->glyphs[i].numGlyphs; j++)
747         {
748             if(runningCp == icp && fTrailing == FALSE)
749             {
750                 *pX = runningX;
751                 return S_OK;
752             }
753             runningX += analysis->glyphs[i].piAdvance[j];
754             if(runningCp == icp && fTrailing == TRUE)
755             {
756                 *pX = runningX;
757                 return S_OK;
758             }
759             runningCp++;
760         }
761     }
762
763     /* icp out of range */
764     analysis->invalid = TRUE;
765     return E_INVALIDARG;
766 }
767
768 /***********************************************************************
769  *      ScriptStringXtoCP (USP10.@)
770  *
771  */
772 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing) 
773 {
774     StringAnalysis* analysis = ssa;
775     int i;
776     int j;
777     int runningX = 0;
778     int runningCp = 0;
779     int width;
780
781     TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
782
783     if (!ssa || !piCh || !piTrailing) return S_FALSE;
784
785     /* out of range */
786     if(iX < 0)
787     {
788         *piCh = -1;
789         *piTrailing = TRUE;
790         return S_OK;
791     }
792
793     for(i=0; i<analysis->numItems; i++)
794     {
795         for(j=0; j<analysis->glyphs[i].numGlyphs; j++)
796         {
797             width = analysis->glyphs[i].piAdvance[j];
798             if(iX < (runningX + width))
799             {
800                 *piCh = runningCp;
801                 if((iX - runningX) > width/2)
802                     *piTrailing = TRUE;
803                 else
804                     *piTrailing = FALSE;
805                 return S_OK;
806             }
807             runningX += width;
808             runningCp++;
809         }
810     }
811
812     /* out of range */
813     *piCh = analysis->pItem[analysis->numItems].iCharPos;
814     *piTrailing = FALSE;
815
816     return S_OK;
817 }
818
819
820 /***********************************************************************
821  *      ScriptStringFree (USP10.@)
822  *
823  * Free a string analysis.
824  *
825  * PARAMS
826  *  pssa [I] string analysis.
827  *
828  * RETURNS
829  *  Success: S_OK
830  *  Failure: Non-zero HRESULT value.
831  */
832 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
833 {
834     StringAnalysis* analysis;
835     BOOL invalid;
836     int i;
837
838     TRACE("(%p)\n", pssa);
839
840     if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
841     invalid = analysis->invalid;
842
843     for (i = 0; i < analysis->numItems; i++)
844     {
845         usp_free(analysis->glyphs[i].glyphs);
846         usp_free(analysis->glyphs[i].pwLogClust);
847         usp_free(analysis->glyphs[i].piAdvance);
848         usp_free(analysis->glyphs[i].psva);
849         usp_free(analysis->glyphs[i].pGoffset);
850         usp_free(analysis->glyphs[i].abc);
851     }
852
853     usp_free(analysis->glyphs);
854     usp_free(analysis->pItem);
855     usp_free(analysis->logattrs);
856     usp_free(analysis->sz);
857     usp_free(analysis);
858
859     if (invalid) return E_INVALIDARG;
860     return S_OK;
861 }
862
863 /***********************************************************************
864  *      ScriptCPtoX (USP10.@)
865  *
866  */
867 HRESULT WINAPI ScriptCPtoX(int iCP,
868                            BOOL fTrailing,
869                            int cChars,
870                            int cGlyphs,
871                            const WORD *pwLogClust,
872                            const SCRIPT_VISATTR *psva,
873                            const int *piAdvance,
874                            const SCRIPT_ANALYSIS *psa,
875                            int *piX)
876 {
877     int  item;
878     int  iPosX;
879     float  fMaxPosX = 0;
880     TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
881           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
882           psa, piX);
883     for (item=0; item < cGlyphs; item++)            /* total piAdvance           */
884         fMaxPosX += piAdvance[item];
885     iPosX = (fMaxPosX/cGlyphs)*(iCP+fTrailing);
886     if  (iPosX > fMaxPosX)
887         iPosX = fMaxPosX;
888     *piX = iPosX;                                    /* Return something in range */
889
890     TRACE("*piX=%d\n", *piX);
891     return S_OK;
892 }
893
894 /***********************************************************************
895  *      ScriptXtoCP (USP10.@)
896  *
897  */
898 HRESULT WINAPI ScriptXtoCP(int iX,
899                            int cChars,
900                            int cGlyphs,
901                            const WORD *pwLogClust,
902                            const SCRIPT_VISATTR *psva,
903                            const int *piAdvance,
904                            const SCRIPT_ANALYSIS *psa,
905                            int *piCP,
906                            int *piTrailing)
907 {
908     int item;
909     int iPosX;
910     float fMaxPosX = 1;
911     float fAvePosX;
912     TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
913           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
914           psa, piCP, piTrailing);
915     if  (iX < 0)                                    /* iX is before start of run */
916     {
917         *piCP = -1;
918         *piTrailing = TRUE;
919         return S_OK;
920     }
921
922     for (item=0; item < cGlyphs; item++)            /* total piAdvance           */
923         fMaxPosX += piAdvance[item];
924
925     if  (iX >= fMaxPosX)                            /* iX too large              */
926     {
927         *piCP = cChars;
928         *piTrailing = FALSE;
929         return S_OK;
930     }
931
932     fAvePosX = fMaxPosX / cGlyphs;
933     iPosX = fAvePosX;
934     for (item = 1; item < cGlyphs  && iPosX < iX; item++)
935         iPosX += fAvePosX;
936     if  (iPosX - iX > fAvePosX/2)
937         *piTrailing = 0;
938     else
939         *piTrailing = 1;                            /* yep we are over halfway */
940
941     *piCP = item -1;                                /* Return character position */
942     TRACE("*piCP=%d iPposX=%d\n", *piCP, iPosX);
943     return S_OK;
944 }
945
946 /***********************************************************************
947  *      ScriptBreak (USP10.@)
948  *
949  *  Retrieve line break information.
950  *
951  *  PARAMS
952  *   chars [I] Array of characters.
953  *   sa    [I] String analysis.
954  *   la    [I] Array of logical attribute structures.
955  *
956  *  RETURNS
957  *   Success: S_OK
958  *   Failure: S_FALSE
959  */
960 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
961 {
962     unsigned int i;
963
964     TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
965
966     if (!la) return S_FALSE;
967
968     for (i = 0; i < count; i++)
969     {
970         memset(&la[i], 0, sizeof(SCRIPT_LOGATTR));
971
972         /* FIXME: set the other flags */
973         la[i].fWhiteSpace = isspaceW(chars[i]);
974         la[i].fCharStop = 1;
975     }
976     return S_OK;
977 }
978
979 static const struct
980 {
981     WCHAR start;
982     WCHAR end;
983     DWORD flag;
984 }
985 complex_ranges[] =
986 {
987     { 0, 0x0b, SIC_COMPLEX },
988     { 0x0c, 0x0c, SIC_NEUTRAL },
989     { 0x0d, 0x1f, SIC_COMPLEX },
990     { 0x20, 0x2f, SIC_NEUTRAL },
991     { 0x30, 0x39, SIC_ASCIIDIGIT },
992     { 0x3a, 0x40, SIC_NEUTRAL },
993     { 0x5b, 0x60, SIC_NEUTRAL },
994     { 0x7b, 0x7e, SIC_NEUTRAL },
995     { 0x7f, 0x9f, SIC_COMPLEX },
996     { 0xa0, 0xa5, SIC_NEUTRAL },
997     { 0xa7, 0xa8, SIC_NEUTRAL },
998     { 0xab, 0xab, SIC_NEUTRAL },
999     { 0xad, 0xad, SIC_NEUTRAL },
1000     { 0xaf, 0xaf, SIC_NEUTRAL },
1001     { 0xb0, 0xb1, SIC_NEUTRAL },
1002     { 0xb4, 0xb4, SIC_NEUTRAL },
1003     { 0xb6, 0xb8, SIC_NEUTRAL },
1004     { 0xbb, 0xbf, SIC_NEUTRAL },
1005     { 0xd7, 0xd7, SIC_NEUTRAL },
1006     { 0xf7, 0xf7, SIC_NEUTRAL },
1007     { 0x2b9, 0x2ba, SIC_NEUTRAL },
1008     { 0x2c2, 0x2cf, SIC_NEUTRAL },
1009     { 0x2d2, 0x2df, SIC_NEUTRAL },
1010     { 0x2e5, 0x2e9, SIC_COMPLEX },
1011     { 0x2ea, 0x2ed, SIC_NEUTRAL },
1012     { 0x300, 0x362, SIC_COMPLEX },
1013     { 0x530, 0x60b, SIC_COMPLEX },
1014     { 0x60c, 0x60d, SIC_NEUTRAL },
1015     { 0x60e, 0x669, SIC_COMPLEX },
1016     { 0x66a, 0x66a, SIC_NEUTRAL },
1017     { 0x66b, 0x6e8, SIC_COMPLEX },
1018     { 0x6e9, 0x6e9, SIC_NEUTRAL },
1019     { 0x6ea, 0x7bf, SIC_COMPLEX },
1020     { 0x900, 0x1360, SIC_COMPLEX },
1021     { 0x137d, 0x137f, SIC_COMPLEX },
1022     { 0x1680, 0x1680, SIC_NEUTRAL },
1023     { 0x1780, 0x18af, SIC_COMPLEX },
1024     { 0x2000, 0x200a, SIC_NEUTRAL },
1025     { 0x200b, 0x200f, SIC_COMPLEX },
1026     { 0x2010, 0x2016, SIC_NEUTRAL },
1027     { 0x2018, 0x2022, SIC_NEUTRAL },
1028     { 0x2024, 0x2028, SIC_NEUTRAL },
1029     { 0x2029, 0x202e, SIC_COMPLEX },
1030     { 0x202f, 0x2037, SIC_NEUTRAL },
1031     { 0x2039, 0x203c, SIC_NEUTRAL },
1032     { 0x2044, 0x2046, SIC_NEUTRAL },
1033     { 0x206a, 0x206f, SIC_COMPLEX },
1034     { 0x207a, 0x207e, SIC_NEUTRAL },
1035     { 0x208a, 0x20aa, SIC_NEUTRAL },
1036     { 0x20ac, 0x20cf, SIC_NEUTRAL },
1037     { 0x20d0, 0x20ff, SIC_COMPLEX },
1038     { 0x2103, 0x2103, SIC_NEUTRAL },
1039     { 0x2105, 0x2105, SIC_NEUTRAL },
1040     { 0x2109, 0x2109, SIC_NEUTRAL },
1041     { 0x2116, 0x2116, SIC_NEUTRAL },
1042     { 0x2121, 0x2122, SIC_NEUTRAL },
1043     { 0x212e, 0x212e, SIC_NEUTRAL },
1044     { 0x2153, 0x2154, SIC_NEUTRAL },
1045     { 0x215b, 0x215e, SIC_NEUTRAL },
1046     { 0x2190, 0x2199, SIC_NEUTRAL },
1047     { 0x21b8, 0x21b9, SIC_NEUTRAL },
1048     { 0x21d2, 0x21d2, SIC_NEUTRAL },
1049     { 0x21d4, 0x21d4, SIC_NEUTRAL },
1050     { 0x21e7, 0x21e7, SIC_NEUTRAL },
1051     { 0x2200, 0x2200, SIC_NEUTRAL },
1052     { 0x2202, 0x2203, SIC_NEUTRAL },
1053     { 0x2207, 0x2208, SIC_NEUTRAL },
1054     { 0x220b, 0x220b, SIC_NEUTRAL },
1055     { 0x220f, 0x220f, SIC_NEUTRAL },
1056     { 0x2211, 0x2213, SIC_NEUTRAL },
1057     { 0x2215, 0x2215, SIC_NEUTRAL },
1058     { 0x221a, 0x221a, SIC_NEUTRAL },
1059     { 0x221d, 0x2220, SIC_NEUTRAL },
1060     { 0x2223, 0x2223, SIC_NEUTRAL },
1061     { 0x2225, 0x2225, SIC_NEUTRAL },
1062     { 0x2227, 0x222c, SIC_NEUTRAL },
1063     { 0x222e, 0x222e, SIC_NEUTRAL },
1064     { 0x2234, 0x2237, SIC_NEUTRAL },
1065     { 0x223c, 0x223d, SIC_NEUTRAL },
1066     { 0x2248, 0x2248, SIC_NEUTRAL },
1067     { 0x224c, 0x224c, SIC_NEUTRAL },
1068     { 0x2252, 0x2252, SIC_NEUTRAL },
1069     { 0x2260, 0x2261, SIC_NEUTRAL },
1070     { 0x2264, 0x2267, SIC_NEUTRAL },
1071     { 0x226a, 0x226b, SIC_NEUTRAL },
1072     { 0x226e, 0x226f, SIC_NEUTRAL },
1073     { 0x2282, 0x2283, SIC_NEUTRAL },
1074     { 0x2286, 0x2287, SIC_NEUTRAL },
1075     { 0x2295, 0x2295, SIC_NEUTRAL },
1076     { 0x2299, 0x2299, SIC_NEUTRAL },
1077     { 0x22a5, 0x22a5, SIC_NEUTRAL },
1078     { 0x22bf, 0x22bf, SIC_NEUTRAL },
1079     { 0x2312, 0x2312, SIC_NEUTRAL },
1080     { 0x24ea, 0x24ea, SIC_COMPLEX },
1081     { 0x2500, 0x254b, SIC_NEUTRAL },
1082     { 0x2550, 0x256d, SIC_NEUTRAL },
1083     { 0x256e, 0x2574, SIC_NEUTRAL },
1084     { 0x2581, 0x258f, SIC_NEUTRAL },
1085     { 0x2592, 0x2595, SIC_NEUTRAL },
1086     { 0x25a0, 0x25a1, SIC_NEUTRAL },
1087     { 0x25a3, 0x25a9, SIC_NEUTRAL },
1088     { 0x25b2, 0x25b3, SIC_NEUTRAL },
1089     { 0x25b6, 0x25b7, SIC_NEUTRAL },
1090     { 0x25bc, 0x25bd, SIC_NEUTRAL },
1091     { 0x25c0, 0x25c1, SIC_NEUTRAL },
1092     { 0x25c6, 0x25c8, SIC_NEUTRAL },
1093     { 0x25cb, 0x25cb, SIC_NEUTRAL },
1094     { 0x25ce, 0x25d1, SIC_NEUTRAL },
1095     { 0x25e2, 0x25e5, SIC_NEUTRAL },
1096     { 0x25ef, 0x25ef, SIC_NEUTRAL },
1097     { 0x2605, 0x2606, SIC_NEUTRAL },
1098     { 0x2609, 0x2609, SIC_NEUTRAL },
1099     { 0x260e, 0x260f, SIC_NEUTRAL },
1100     { 0x261c, 0x261c, SIC_NEUTRAL },
1101     { 0x261e, 0x261e, SIC_NEUTRAL },
1102     { 0x2640, 0x2640, SIC_NEUTRAL },
1103     { 0x2642, 0x2642, SIC_NEUTRAL },
1104     { 0x2660, 0x2661, SIC_NEUTRAL },
1105     { 0x2663, 0x2665, SIC_NEUTRAL },
1106     { 0x2667, 0x266a, SIC_NEUTRAL },
1107     { 0x266c, 0x266d, SIC_NEUTRAL },
1108     { 0x266f, 0x266f, SIC_NEUTRAL },
1109     { 0x273d, 0x273d, SIC_NEUTRAL },
1110     { 0x2e80, 0x312f, SIC_COMPLEX },
1111     { 0x3190, 0x31bf, SIC_COMPLEX },
1112     { 0x31f0, 0x31ff, SIC_COMPLEX },
1113     { 0x3220, 0x325f, SIC_COMPLEX },
1114     { 0x3280, 0xa4ff, SIC_COMPLEX },
1115     { 0xd800, 0xdfff, SIC_COMPLEX },
1116     { 0xe000, 0xf8ff, SIC_NEUTRAL },
1117     { 0xf900, 0xfaff, SIC_COMPLEX },
1118     { 0xfb13, 0xfb28, SIC_COMPLEX },
1119     { 0xfb29, 0xfb29, SIC_NEUTRAL },
1120     { 0xfb2a, 0xfb4f, SIC_COMPLEX },
1121     { 0xfd3e, 0xfd3f, SIC_NEUTRAL },
1122     { 0xfdd0, 0xfdef, SIC_COMPLEX },
1123     { 0xfe20, 0xfe6f, SIC_COMPLEX },
1124     { 0xfeff, 0xfeff, SIC_COMPLEX },
1125     { 0xff01, 0xff5e, SIC_COMPLEX },
1126     { 0xff61, 0xff9f, SIC_COMPLEX },
1127     { 0xffe0, 0xffe6, SIC_COMPLEX },
1128     { 0xffe8, 0xffee, SIC_COMPLEX },
1129     { 0xfff9, 0xfffb, SIC_COMPLEX },
1130     { 0xfffe, 0xfffe, SIC_COMPLEX }
1131 };
1132
1133 /***********************************************************************
1134  *      ScriptIsComplex (USP10.@)
1135  * 
1136  *  Determine if a string is complex.
1137  *
1138  *  PARAMS
1139  *   chars [I] Array of characters to test.
1140  *   len   [I] Length in characters.
1141  *   flag  [I] Flag.
1142  *
1143  *  RETURNS
1144  *   Success: S_OK
1145  *   Failure: S_FALSE
1146  *
1147  *  NOTES
1148  *   Behaviour matches that of WinXP.
1149  */
1150 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
1151 {
1152     unsigned int i, j;
1153
1154     TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
1155
1156     for (i = 0; i < len; i++)
1157     {
1158         for (j = 0; j < sizeof(complex_ranges)/sizeof(complex_ranges[0]); j++)
1159         {
1160             if (chars[i] >= complex_ranges[j].start &&
1161                 chars[i] <= complex_ranges[j].end &&
1162                 (flag & complex_ranges[j].flag)) return S_OK;
1163         }
1164     }
1165     return S_FALSE;
1166 }
1167
1168 /***********************************************************************
1169  *      ScriptShape (USP10.@)
1170  *
1171  */
1172 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars, 
1173                            int cChars, int cMaxGlyphs,
1174                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
1175                            SCRIPT_VISATTR *psva, int *pcGlyphs)
1176 {
1177     int cnt;
1178     HRESULT hr;
1179     *pcGlyphs = cChars;
1180
1181     TRACE("(%p, %p, %p, %d, %d, %p)\n",  hdc, psc, pwcChars, cChars, cMaxGlyphs, psa);
1182     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
1183                    psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
1184
1185     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
1186     if ((hr = get_script_cache(hdc, psc))) return hr;
1187
1188     TRACE("Before: ");
1189     for (cnt = 0; cnt < cChars; cnt++)
1190          TRACE("%4x",pwcChars[cnt]);
1191     TRACE("\n");
1192
1193     if  (!psa->fNoGlyphIndex) {                                         /* Glyph translate */
1194         if (!(GetGlyphIndicesW(((ScriptCache *)*psc)->hdc, pwcChars, cChars, pwOutGlyphs, 0)))
1195             return S_FALSE;
1196
1197         TRACE("After:  ");
1198         for (cnt = 0; cnt < cChars; cnt++) {
1199              TRACE("%04x",pwOutGlyphs[cnt]);
1200         }
1201         TRACE("\n");
1202     }
1203     else {
1204         TRACE("After:  ");
1205         for (cnt = 0; cnt < cChars; cnt++) {                           /* no translate so set up */
1206              pwOutGlyphs[cnt] = pwcChars[cnt];                         /* copy in to out and     */
1207              TRACE("%04x",pwOutGlyphs[cnt]);
1208         }
1209        TRACE("\n");
1210     }
1211
1212     /*  Set up a valid SCRIPT_VISATTR and LogClust for each char in this run */     
1213     for (cnt = 0;  cnt < cChars; cnt++) {
1214         /* FIXME:  set to better values */
1215          psva[cnt].uJustification = 2;
1216          psva[cnt].fClusterStart = 1;
1217          psva[cnt].fDiacritic = 0;
1218          psva[cnt].fZeroWidth = 0;
1219          pwLogClust[cnt] = cnt;
1220     }
1221     return S_OK;
1222 }
1223
1224 /***********************************************************************
1225  *      ScriptPlace (USP10.@)
1226  *
1227  */
1228 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs, 
1229                            int cGlyphs, const SCRIPT_VISATTR *psva,
1230                            SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
1231 {
1232     int wcnt;
1233     HRESULT hr;
1234     LPABC lpABC;
1235
1236     TRACE("(%p, %p, %p, %s, %d, %p, %p, %p)\n",  hdc, psc, pwGlyphs,
1237           debugstr_wn(pwGlyphs, cGlyphs), cGlyphs, psva, psa, piAdvance);
1238
1239     if ((hr = get_script_cache(hdc, psc))) return hr;
1240
1241     /*   Here we need to calculate the width of the run unit.  At this point the input string
1242      *   has been converted to glyphs and we still need to translate back to the original chars
1243      *   to get the correct ABC widths.   */
1244
1245      if (!(lpABC = usp_zero_alloc(sizeof(ABC) * cGlyphs))) return E_OUTOFMEMORY;
1246
1247     /* FIXME: set pGoffset to more reasonable values */
1248      if (!GetCharABCWidthsI(((ScriptCache *)*psc)->hdc, 0, cGlyphs, (WORD *) pwGlyphs, lpABC ))
1249      {
1250          WARN("Could not get ABC values\n");
1251          for (wcnt = 0; wcnt < cGlyphs; wcnt++) {
1252              piAdvance[wcnt] = 0;
1253              pGoffset[wcnt].du = 0;
1254              pGoffset[wcnt].dv = 0;
1255          }
1256      }
1257      else
1258      {
1259          for (wcnt = 0; wcnt < cGlyphs ; wcnt++) {          /* add up the char lengths  */
1260              TRACE("     Glyph=%04x,  abcA=%d,  abcB=%d,  abcC=%d  wcnt=%d\n",
1261                                   pwGlyphs[wcnt],  
1262                                   lpABC[wcnt].abcA,
1263                                   lpABC[wcnt].abcB,
1264                                   lpABC[wcnt].abcC, wcnt);
1265              pABC->abcA += lpABC[wcnt].abcA;
1266              pABC->abcB += lpABC[wcnt].abcB;
1267              pABC->abcC += lpABC[wcnt].abcC;
1268              piAdvance[wcnt] = lpABC[wcnt].abcA + lpABC[wcnt].abcB + lpABC[wcnt].abcC;
1269              pGoffset[wcnt].du = 0;
1270              pGoffset[wcnt].dv = 0;
1271          }
1272      }
1273      TRACE("Total for run:   abcA=%d,  abcB=%d,  abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
1274
1275      usp_free(lpABC);
1276      return S_OK;
1277 }
1278
1279 /***********************************************************************
1280  *      ScriptGetCMap (USP10.@)
1281  *
1282  * Retrieve glyph indices.
1283  *
1284  * PARAMS
1285  *  hdc         [I]   Device context.
1286  *  psc         [I/O] Opaque pointer to a script cache.
1287  *  pwcInChars  [I]   Array of Unicode characters.
1288  *  cChars      [I]   Number of characters in pwcInChars.
1289  *  dwFlags     [I]   Flags.
1290  *  pwOutGlyphs [O]   Buffer to receive the array of glyph indices.
1291  *
1292  * RETURNS
1293  *  Success: S_OK
1294  *  Failure: Non-zero HRESULT value.
1295  */
1296 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
1297                              int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
1298 {
1299     int cnt;
1300     HRESULT hr;
1301
1302     TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
1303           cChars, dwFlags, pwOutGlyphs);
1304
1305     if ((hr = get_script_cache(hdc, psc))) return hr;
1306
1307     TRACE("Before: ");
1308     for (cnt = 0; cnt < cChars; cnt++)
1309          TRACE("%4x",pwcInChars[cnt]);
1310     TRACE("\n");
1311
1312     GetGlyphIndicesW(((ScriptCache *)*psc)->hdc, pwcInChars, cChars, pwOutGlyphs, 0);
1313
1314     TRACE("After:  ");
1315     for (cnt = 0; cnt < cChars; cnt++) {
1316          TRACE("%04x",pwOutGlyphs[cnt]);
1317     }
1318     TRACE("\n");
1319
1320     return S_OK;
1321 }
1322
1323 /***********************************************************************
1324  *      ScriptTextOut (USP10.@)
1325  *
1326  */
1327 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
1328                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
1329                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
1330                              const int *piJustify, const GOFFSET *pGoffset)
1331 {
1332     HRESULT hr;
1333
1334     TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
1335          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
1336          piAdvance, piJustify, pGoffset);
1337
1338     if (!hdc && psc && !*psc) return E_INVALIDARG;
1339     if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
1340     if ((hr = get_script_cache(hdc, psc))) return hr;
1341
1342     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
1343     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
1344         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do translation to glyph */
1345
1346     if (!ExtTextOutW(((ScriptCache *)*psc)->hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
1347         return S_FALSE;
1348
1349     return S_OK;
1350 }
1351
1352 /***********************************************************************
1353  *      ScriptCacheGetHeight (USP10.@)
1354  *
1355  * Retrieve the height of the font in the cache.
1356  *
1357  * PARAMS
1358  *  hdc    [I]    Device context.
1359  *  psc    [I/O]  Opaque pointer to a script cache.
1360  *  height [O]    Receives font height.
1361  *
1362  * RETURNS
1363  *  Success: S_OK
1364  *  Failure: Non-zero HRESULT value.
1365  */
1366 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
1367 {
1368     HRESULT hr;
1369     TEXTMETRICW metric;
1370
1371     TRACE("(%p, %p, %p)\n", hdc, psc, height);
1372
1373     if (!height) return E_INVALIDARG;
1374     if ((hr = get_script_cache(hdc, psc))) return hr;
1375
1376     /* FIXME: get this from the cache */
1377     if (!GetTextMetricsW(((ScriptCache *)*psc)->hdc, &metric)) return E_INVALIDARG;
1378
1379     *height = metric.tmHeight;
1380     return S_OK;
1381 }
1382
1383 /***********************************************************************
1384  *      ScriptGetGlyphABCWidth (USP10.@)
1385  *
1386  * Retrieve the width of a glyph.
1387  *
1388  * PARAMS
1389  *  hdc    [I]    Device context.
1390  *  psc    [I/O]  Opaque pointer to a script cache.
1391  *  glyph  [I]    Glyph to retrieve the width for.
1392  *  abc    [O]    ABC widths of the glyph.
1393  *
1394  * RETURNS
1395  *  Success: S_OK
1396  *  Failure: Non-zero HRESULT value.
1397  */
1398 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
1399 {
1400     HRESULT hr;
1401
1402     TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
1403
1404     if ((hr = get_script_cache(hdc, psc))) return hr;
1405
1406     /* FIXME: get this from the cache */
1407     if (!GetCharABCWidthsW(((ScriptCache *)*psc)->hdc, glyph, glyph, abc)) return E_HANDLE;
1408     return S_OK;
1409 }
1410
1411 /***********************************************************************
1412  *      ScriptLayout (USP10.@)
1413  *
1414  * Map embedding levels to visual and/or logical order.
1415  *
1416  * PARAMS
1417  *  runs     [I] Size of level array.
1418  *  level    [I] Array of embedding levels.
1419  *  vistolog [O] Map of embedding levels from visual to logical order.
1420  *  logtovis [O] Map of embedding levels from logical to visual order.
1421  *
1422  * RETURNS
1423  *  Success: S_OK
1424  *  Failure: Non-zero HRESULT value.
1425  *
1426  * BUGS
1427  *  This stub works correctly for any sequence of a single
1428  *  embedding level but not for sequences of different
1429  *  embedding levels, i.e. mixtures of RTL and LTR scripts.
1430  */
1431 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
1432 {
1433     int i, j = runs - 1, k = 0;
1434
1435     TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
1436
1437     if (!level || (!vistolog && !logtovis))
1438         return E_INVALIDARG;
1439
1440     for (i = 0; i < runs; i++)
1441     {
1442         if (level[i] % 2)
1443         {
1444             if (vistolog) *vistolog++ = j;
1445             if (logtovis) *logtovis++ = j;
1446             j--;
1447         }
1448         else
1449         {
1450             if (vistolog) *vistolog++ = k;
1451             if (logtovis) *logtovis++ = k;
1452             k++;
1453         }
1454     }
1455     return S_OK;
1456 }
1457
1458 /***********************************************************************
1459  *      ScriptStringGetLogicalWidths (USP10.@)
1460  *
1461  * Returns logical widths from a string analysis.
1462  *
1463  * PARAMS
1464  *  ssa  [I] string analysis.
1465  *  piDx [O] logical widths returned.
1466  *
1467  * RETURNS
1468  *  Success: S_OK
1469  *  Failure: a non-zero HRESULT.
1470  */
1471 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
1472 {
1473     int i, j, next = 0;
1474     StringAnalysis *analysis = ssa;
1475
1476     TRACE("%p, %p\n", ssa, piDx);
1477
1478     if (!analysis) return S_FALSE;
1479
1480     for (i = 0; i < analysis->numItems; i++)
1481     {
1482         for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
1483         {
1484             piDx[next] = analysis->glyphs[i].piAdvance[j];
1485             next++;
1486         }
1487     }
1488     return S_OK;
1489 }
1490
1491 /***********************************************************************
1492  *      ScriptStringValidate (USP10.@)
1493  *
1494  * Validate a string analysis.
1495  *
1496  * PARAMS
1497  *  ssa [I] string analysis.
1498  *
1499  * RETURNS
1500  *  Success: S_OK
1501  *  Failure: S_FALSE if invalid sequences are found
1502  *           or a non-zero HRESULT if it fails.
1503  */
1504 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
1505 {
1506     StringAnalysis *analysis = ssa;
1507
1508     TRACE("(%p)\n", ssa);
1509
1510     if (!analysis) return E_INVALIDARG;
1511     return (analysis->invalid) ? S_FALSE : S_OK;
1512 }
1513
1514 /***********************************************************************
1515  *      ScriptString_pSize (USP10.@)
1516  *
1517  * Retrieve width and height of an analysed string.
1518  *
1519  * PARAMS
1520  *  ssa [I] string analysis.
1521  *
1522  * RETURNS
1523  *  Success: Pointer to a SIZE structure.
1524  *  Failure: NULL
1525  */
1526 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
1527 {
1528     unsigned int i, j;
1529     StringAnalysis *analysis = ssa;
1530     TEXTMETRICW metric;
1531
1532     TRACE("(%p)\n", ssa);
1533
1534     if (!analysis) return NULL;
1535
1536     if (!analysis->sz)
1537     {
1538         if (!(analysis->sz = usp_alloc(sizeof(SIZE))))
1539             return NULL;
1540
1541         /* FIXME: These values should be calculated at a more
1542          * appropriate place so that we can just pass cached
1543          * values here.
1544          */
1545         if (!GetTextMetricsW(analysis->sc->hdc, &metric))
1546         {
1547             usp_free(analysis->sz);
1548             analysis->sz = NULL;
1549             return NULL;
1550         }
1551         analysis->sz->cy = metric.tmHeight;
1552
1553         analysis->sz->cx = 0;
1554         for (i = 0; i < analysis->numItems; i++)
1555             for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
1556                 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
1557     }
1558     return analysis->sz;
1559 }
1560
1561 /***********************************************************************
1562  *      ScriptString_pLogAttr (USP10.@)
1563  *
1564  * Retrieve logical attributes of an analysed string.
1565  *
1566  * PARAMS
1567  *  ssa [I] string analysis.
1568  *
1569  * RETURNS
1570  *  Success: Pointer to an array of SCRIPT_LOGATTR structures.
1571  *  Failure: NULL
1572  */
1573 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
1574 {
1575     StringAnalysis *analysis = ssa;
1576
1577     TRACE("(%p)\n", ssa);
1578
1579     if (!analysis) return NULL;
1580     return analysis->logattrs;
1581 }
1582
1583 /***********************************************************************
1584  *      ScriptString_pcOutChars (USP10.@)
1585  *
1586  * Retrieve the length of a string after clipping.
1587  *
1588  * PARAMS
1589  *  ssa [I] String analysis.
1590  *
1591  * RETURNS
1592  *  Success: Pointer to the length.
1593  *  Failure: NULL
1594  */
1595 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
1596 {
1597     StringAnalysis *analysis = ssa;
1598
1599     TRACE("(%p)\n", ssa);
1600
1601     if (!analysis) return NULL;
1602     return &analysis->clip_len;
1603 }
1604
1605 /***********************************************************************
1606  *      ScriptStringGetOrder (USP10.@)
1607  *
1608  * Retrieve a glyph order map.
1609  *
1610  * PARAMS
1611  *  ssa   [I]   String analysis.
1612  *  order [I/O] Array of glyph positions.
1613  *
1614  * RETURNS
1615  *  Success: S_OK
1616  *  Failure: a non-zero HRESULT.
1617  */
1618 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
1619 {
1620     unsigned int i, j, k;
1621     StringAnalysis *analysis = ssa;
1622
1623     TRACE("(%p)\n", ssa);
1624
1625     if (!analysis) return S_FALSE;
1626
1627     /* FIXME: handle RTL scripts */
1628     for (i = 0, k = 0; i < analysis->numItems; i++)
1629         for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
1630             order[k] = k;
1631
1632     return S_OK;
1633 }