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