usp10: Add Phags-pa Script.
[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  * Copyright 2010 CodeWeavers, Aric Stewart
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  * Notes:
23  * Uniscribe allows for processing of complex scripts such as joining
24  * and filtering characters and bi-directional text with custom line breaks.
25  */
26
27 #include <stdarg.h>
28
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "usp10.h"
35
36 #include "usp10_internal.h"
37
38 #include "wine/debug.h"
39 #include "wine/unicode.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
42
43 typedef struct _scriptRange
44 {
45     WORD script;
46     WORD rangeFirst;
47     WORD rangeLast;
48     WORD numericScript;
49     WORD punctScript;
50 } scriptRange;
51
52 static const scriptRange scriptRanges[] = {
53     /* Basic Latin: U+0000–U+007A */
54     /* Latin-1 Supplement: U+0080–U+00FF */
55     /* Latin Extended-A: U+0100–U+017F */
56     /* Latin Extended-B: U+0180–U+024F */
57     /* IPA Extensions: U+0250–U+02AF */
58     { Script_Latin,      0x00,   0x2af ,  Script_Numeric, Script_Punctuation},
59     /* Greek: U+0370–U+03FF */
60     { Script_Greek,      0x370,  0x3ff,  0, 0},
61     /* Cyrillic: U+0400–U+04FF */
62     /* Cyrillic Supplement: U+0500–U+052F */
63     { Script_Cyrillic,   0x400,  0x52f,  0, 0},
64     /* Armenian: U+0530–U+058F */
65     { Script_Armenian,   0x530,  0x58f,  0, 0},
66     /* Hebrew: U+0590–U+05FF */
67     { Script_Hebrew,     0x590,  0x5ff,  0, 0},
68     /* Arabic: U+0600–U+06FF */
69     { Script_Arabic,     0x600,  0x6ef,  Script_Arabic_Numeric, 0},
70     /* Defined by Windows */
71     { Script_Persian,    0x6f0,  0x6f9,  0, 0},
72     /* Continue Arabic: U+0600–U+06FF */
73     { Script_Arabic,     0x6fa,  0x6ff,  0, 0},
74     /* Syriac: U+0700–U+074F*/
75     { Script_Syriac,     0x700,  0x74f,  0, 0},
76     /* Arabic Supplement: U+0750–U+077F */
77     { Script_Arabic,     0x750,  0x77f,  0, 0},
78     /* Thaana: U+0780–U+07BF */
79     { Script_Thaana,     0x780,  0x7bf,  0, 0},
80     /* Sinhala: U+0D80–U+0DFF */
81     { Script_Sinhala,   0xd80,  0xdff,  0, 0},
82     /* Tibetan: U+0F00–U+0FFF */
83     { Script_Tibetan,   0xf00,  0xfff,  Script_Tibetan_Numeric, 0},
84     /* Georgian: U+10A0–U+10FF */
85     { Script_Georgian,   0x10a0,  0x10ff,  0, 0},
86     /* Phonetic Extensions: U+1D00–U+1DBF */
87     { Script_Latin,      0x1d00, 0x1dbf, 0, 0},
88     /* Latin Extended Additional: U+1E00–U+1EFF */
89     { Script_Latin,      0x1e00, 0x1eff, 0, 0},
90     /* Greek Extended: U+1F00–U+1FFF */
91     { Script_Greek,      0x1f00, 0x1fff, 0, 0},
92     /* Latin Extended-C: U+2C60–U+2C7F */
93     { Script_Latin,      0x2c60, 0x2c7f, 0, 0},
94     /* Georgian: U+2D00–U+2D2F */
95     { Script_Georgian,   0x2d00,  0x2d2f,  0, 0},
96     /* Cyrillic Extended-A: U+2DE0–U+2DFF */
97     { Script_Cyrillic,   0x2de0, 0x2dff,  0, 0},
98     /* Cyrillic Extended-B: U+A640–U+A69F */
99     { Script_Cyrillic,   0xa640, 0xa69f,  0, 0},
100     /* Modifier Tone Letters: U+A700–U+A71F */
101     /* Latin Extended-D: U+A720–U+A7FF */
102     { Script_Latin,      0xa700, 0xa7ff, 0, 0},
103     /* Phags-pa: U+A840–U+A87F */
104     { Script_Phags_pa,   0xa840, 0xa87f, 0, 0},
105     /* Latin Ligatures: U+FB00–U+FB06 */
106     { Script_Latin,      0xfb00, 0xfb06, 0, 0},
107     /* Armenian ligatures U+FB13..U+FB17 */
108     { Script_Armenian,   0xfb13, 0xfb17,  0, 0},
109     /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
110     { Script_Hebrew,     0xfb1d, 0xfb4f, 0, 0},
111     /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
112     { Script_Arabic,     0xfb50, 0xfdff, 0, 0},
113     /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
114     { Script_Arabic,     0xfe70, 0xfeff, 0, 0},
115     /* END */
116     { SCRIPT_UNDEFINED,  0, 0, 0}
117 };
118
119 typedef struct _scriptData
120 {
121     SCRIPT_ANALYSIS a;
122     SCRIPT_PROPERTIES props;
123 } scriptData;
124
125 /* the must be in order so that the index matches the Script value */
126 static const scriptData scriptInformation[] = {
127     {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
128      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
129     {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
130      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0}},
131     {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
132      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
133     {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
134      {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
135     {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
136      {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0}},
137     {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
138      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
139     {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
140      {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0}},
141     {{Script_Arabic_Numeric, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
142      {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0}},
143     {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
144      {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
145     {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
146      {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0}},
147     {{Script_Persian, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
148      {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
149     {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
150      {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
151     {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
152      {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
153     {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
154      {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
155     {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
156      {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0}},
157     {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
158      {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0}},
159     {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
160      {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
161     {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
162      {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0}},
163     {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
164      {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
165     {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
166      {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
167 };
168
169 static const SCRIPT_PROPERTIES *script_props[] =
170 {
171     &scriptInformation[0].props, &scriptInformation[1].props,
172     &scriptInformation[2].props, &scriptInformation[3].props,
173     &scriptInformation[4].props, &scriptInformation[5].props,
174     &scriptInformation[6].props, &scriptInformation[7].props,
175     &scriptInformation[8].props, &scriptInformation[9].props,
176     &scriptInformation[10].props, &scriptInformation[11].props,
177     &scriptInformation[12].props, &scriptInformation[13].props,
178     &scriptInformation[14].props, &scriptInformation[15].props,
179     &scriptInformation[16].props, &scriptInformation[17].props,
180     &scriptInformation[18].props, &scriptInformation[19].props
181 };
182
183 typedef struct {
184     int numGlyphs;
185     WORD* glyphs;
186     WORD* pwLogClust;
187     int* piAdvance;
188     SCRIPT_VISATTR* psva;
189     GOFFSET* pGoffset;
190     ABC* abc;
191 } StringGlyphs;
192
193 typedef struct {
194     HDC hdc;
195     BOOL invalid;
196     int clip_len;
197     ScriptCache *sc;
198     int cItems;
199     int cMaxGlyphs;
200     SCRIPT_ITEM* pItem;
201     int numItems;
202     StringGlyphs* glyphs;
203     SCRIPT_LOGATTR* logattrs;
204     SIZE* sz;
205 } StringAnalysis;
206
207 static inline void *heap_alloc(SIZE_T size)
208 {
209     return HeapAlloc(GetProcessHeap(), 0, size);
210 }
211
212 static inline void *heap_alloc_zero(SIZE_T size)
213 {
214     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
215 }
216
217 static inline void *heap_realloc_zero(LPVOID mem, SIZE_T size)
218 {
219     return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
220 }
221
222 static inline BOOL heap_free(LPVOID mem)
223 {
224     return HeapFree(GetProcessHeap(), 0, mem);
225 }
226
227 static inline WCHAR get_cache_default_char(SCRIPT_CACHE *psc)
228 {
229     return ((ScriptCache *)*psc)->tm.tmDefaultChar;
230 }
231
232 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
233 {
234     return ((ScriptCache *)*psc)->tm.tmHeight;
235 }
236
237 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
238 {
239     return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
240 }
241
242 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, WCHAR c)
243 {
244     WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
245
246     if (!block) return 0;
247     return block[c & GLYPH_BLOCK_MASK];
248 }
249
250 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
251 {
252     WORD **block = &((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
253
254     if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
255     return ((*block)[c & GLYPH_BLOCK_MASK] = glyph);
256 }
257
258 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
259 {
260     static const ABC nil;
261     ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
262
263     if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
264     memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
265     return TRUE;
266 }
267
268 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
269 {
270     ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
271
272     if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
273     memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
274     return TRUE;
275 }
276
277 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
278 {
279     ScriptCache *sc;
280
281     if (!psc) return E_INVALIDARG;
282     if (*psc) return S_OK;
283     if (!hdc) return E_PENDING;
284
285     if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
286     if (!GetTextMetricsW(hdc, &sc->tm))
287     {
288         heap_free(sc);
289         return E_INVALIDARG;
290     }
291     if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
292     {
293         heap_free(sc);
294         return E_INVALIDARG;
295     }
296     *psc = sc;
297     TRACE("<- %p\n", sc);
298     return S_OK;
299 }
300
301 static WCHAR mirror_char( WCHAR ch )
302 {
303     extern const WCHAR wine_mirror_map[];
304     return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
305 }
306
307 static WORD get_char_script( WCHAR ch)
308 {
309     WORD type = 0;
310     int i;
311
312     if (ch == 0xc || ch == 0x20 || ch == 0x202f)
313         return Script_CR;
314
315     GetStringTypeW(CT_CTYPE1, &ch, 1, &type);
316
317     if (type == 0)
318         return SCRIPT_UNDEFINED;
319
320     if (type & C1_CNTRL)
321         return Script_Control;
322
323     i = 0;
324     do
325     {
326         if (ch < scriptRanges[i].rangeFirst || scriptRanges[i].script == SCRIPT_UNDEFINED)
327             break;
328
329         if (ch >= scriptRanges[i].rangeFirst && ch <= scriptRanges[i].rangeLast)
330         {
331             if (scriptRanges[i].numericScript && type & C1_DIGIT)
332                 return scriptRanges[i].numericScript;
333             if (scriptRanges[i].punctScript && type & C1_PUNCT)
334                 return scriptRanges[i].punctScript;
335             return scriptRanges[i].script;
336         }
337         i++;
338     } while (1);
339
340     return SCRIPT_UNDEFINED;
341 }
342
343 /***********************************************************************
344  *      DllMain
345  *
346  */
347 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
348 {
349     switch(fdwReason)
350     {
351     case DLL_PROCESS_ATTACH:
352         DisableThreadLibraryCalls(hInstDLL);
353         break;
354     case DLL_PROCESS_DETACH:
355         break;
356     }
357     return TRUE;
358 }
359
360 /***********************************************************************
361  *      ScriptFreeCache (USP10.@)
362  *
363  * Free a script cache.
364  *
365  * PARAMS
366  *   psc [I/O] Script cache.
367  *
368  * RETURNS
369  *  Success: S_OK
370  *  Failure: Non-zero HRESULT value.
371  */
372 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
373 {
374     TRACE("%p\n", psc);
375
376     if (psc && *psc)
377     {
378         unsigned int i;
379         for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
380         {
381             heap_free(((ScriptCache *)*psc)->glyphs[i]);
382             heap_free(((ScriptCache *)*psc)->widths[i]);
383         }
384         heap_free(((ScriptCache *)*psc)->GSUB_Table);
385         heap_free(((ScriptCache *)*psc)->features);
386         heap_free(*psc);
387         *psc = NULL;
388     }
389     return S_OK;
390 }
391
392 /***********************************************************************
393  *      ScriptGetProperties (USP10.@)
394  *
395  * Retrieve a list of script properties.
396  *
397  * PARAMS
398  *  props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
399  *  num   [I] Pointer to the number of scripts.
400  *
401  * RETURNS
402  *  Success: S_OK
403  *  Failure: Non-zero HRESULT value.
404  *
405  * NOTES
406  *  Behaviour matches WinXP.
407  */
408 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
409 {
410     TRACE("(%p,%p)\n", props, num);
411
412     if (!props && !num) return E_INVALIDARG;
413
414     if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
415     if (props) *props = script_props;
416
417     return S_OK;
418 }
419
420 /***********************************************************************
421  *      ScriptGetFontProperties (USP10.@)
422  *
423  * Get information on special glyphs.
424  *
425  * PARAMS
426  *  hdc [I]   Device context.
427  *  psc [I/O] Opaque pointer to a script cache.
428  *  sfp [O]   Font properties structure.
429  */
430 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
431 {
432     HRESULT hr;
433
434     TRACE("%p,%p,%p\n", hdc, psc, sfp);
435
436     if (!sfp) return E_INVALIDARG;
437     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
438
439     if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
440         return E_INVALIDARG;
441
442     /* return something sensible? */
443     sfp->wgBlank = 0;
444     sfp->wgDefault = get_cache_default_char(psc);
445     sfp->wgInvalid = 0;
446     sfp->wgKashida = 0xffff;
447     sfp->iKashidaWidth = 0;
448
449     return S_OK;
450 }
451
452 /***********************************************************************
453  *      ScriptRecordDigitSubstitution (USP10.@)
454  *
455  *  Record digit substitution settings for a given locale.
456  *
457  *  PARAMS
458  *   locale [I] Locale identifier.
459  *   sds    [I] Structure to record substitution settings.
460  *
461  *  RETURNS
462  *   Success: S_OK
463  *   Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
464  *
465  *  SEE ALSO
466  *   http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
467  */
468 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
469 {
470     DWORD plgid, sub;
471
472     TRACE("0x%x, %p\n", locale, sds);
473
474     /* This implementation appears to be correct for all languages, but it's
475      * not clear if sds->DigitSubstitute is ever set to anything except 
476      * CONTEXT or NONE in reality */
477
478     if (!sds) return E_POINTER;
479
480     locale = ConvertDefaultLocale(locale);
481
482     if (!IsValidLocale(locale, LCID_INSTALLED))
483         return E_INVALIDARG;
484
485     plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
486     sds->TraditionalDigitLanguage = plgid;
487
488     if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
489         sds->NationalDigitLanguage = plgid;
490     else
491         sds->NationalDigitLanguage = LANG_ENGLISH;
492
493     if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
494                         (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
495
496     switch (sub)
497     {
498     case 0: 
499         if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
500             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
501         else
502             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
503         break;
504     case 1:
505         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
506         break;
507     case 2:
508         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
509         break;
510     default:
511         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
512         break;
513     }
514
515     sds->dwReserved = 0;
516     return S_OK;
517 }
518
519 /***********************************************************************
520  *      ScriptApplyDigitSubstitution (USP10.@)
521  *
522  *  Apply digit substitution settings.
523  *
524  *  PARAMS
525  *   sds [I] Structure with recorded substitution settings.
526  *   sc  [I] Script control structure.
527  *   ss  [I] Script state structure.
528  *
529  *  RETURNS
530  *   Success: S_OK
531  *   Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
532  */
533 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds, 
534                                             SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
535 {
536     SCRIPT_DIGITSUBSTITUTE psds;
537
538     TRACE("%p, %p, %p\n", sds, sc, ss);
539
540     if (!sc || !ss) return E_POINTER;
541     if (!sds)
542     {
543         sds = &psds;
544         if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
545             return E_INVALIDARG;
546     }
547
548     sc->uDefaultLanguage = LANG_ENGLISH;
549     sc->fContextDigits = 0;
550     ss->fDigitSubstitute = 0;
551
552     switch (sds->DigitSubstitute) {
553         case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
554         case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
555         case SCRIPT_DIGITSUBSTITUTE_NONE:
556         case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
557             return S_OK;
558         default:
559             return E_INVALIDARG;
560     }
561 }
562
563 /***********************************************************************
564  *      ScriptItemize (USP10.@)
565  *
566  * Split a Unicode string into shapeable parts.
567  *
568  * PARAMS
569  *  pwcInChars [I] String to split.
570  *  cInChars   [I] Number of characters in pwcInChars.
571  *  cMaxItems  [I] Maximum number of items to return.
572  *  psControl  [I] Pointer to a SCRIPT_CONTROL structure.
573  *  psState    [I] Pointer to a SCRIPT_STATE structure.
574  *  pItems     [O] Buffer to receive SCRIPT_ITEM structures.
575  *  pcItems    [O] Number of script items returned.
576  *
577  * RETURNS
578  *  Success: S_OK
579  *  Failure: Non-zero HRESULT value.
580  */
581 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
582                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
583                              SCRIPT_ITEM *pItems, int *pcItems)
584 {
585
586 #define Numeric_space 0x0020
587
588     int   cnt = 0, index = 0;
589     int   New_Script = SCRIPT_UNDEFINED;
590     WORD  *levels = NULL;
591     WORD  baselevel = 0;
592
593     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
594           psControl, psState, pItems, pcItems);
595
596     if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
597         return E_INVALIDARG;
598
599     if (psState && psControl)
600     {
601         int i;
602         levels = heap_alloc_zero(cInChars * sizeof(WORD));
603         if (!levels)
604             return E_OUTOFMEMORY;
605
606         BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
607         baselevel = levels[0];
608         for (i = 0; i < cInChars; i++)
609             if (levels[i]!=levels[0])
610                 break;
611         if (i >= cInChars)
612         {
613             heap_free(levels);
614             levels = NULL;
615         }
616     }
617
618     pItems[index].iCharPos = 0;
619     pItems[index].a = scriptInformation[get_char_script(pwcInChars[cnt])].a;
620
621     if (levels)
622     {
623         pItems[index].a.fRTL = odd(levels[cnt]);
624         pItems[index].a.fLayoutRTL = odd(levels[cnt]);
625         pItems[index].a.s.uBidiLevel = levels[cnt];
626     }
627     else if (!pItems[index].a.s.uBidiLevel)
628     {
629         pItems[index].a.s.uBidiLevel = baselevel;
630         pItems[index].a.fLayoutRTL = odd(baselevel);
631         pItems[index].a.fRTL = odd(baselevel);
632     }
633
634     TRACE("New_Level=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
635           levels?levels[cnt]:-1, New_Script, pItems[index].a.eScript, index, cnt,
636           pItems[index].iCharPos);
637
638     for (cnt=1; cnt < cInChars; cnt++)
639     {
640         if (levels && (levels[cnt] == pItems[index].a.s.uBidiLevel))
641             continue;
642
643         if(pwcInChars[cnt] != Numeric_space)
644             New_Script = get_char_script(pwcInChars[cnt]);
645
646         if ((levels && (levels[cnt] != pItems[index].a.s.uBidiLevel)) || New_Script != pItems[index].a.eScript || New_Script == Script_Control)
647         {
648             TRACE("New_Level = %i, New_Script=%d, eScript=%d ", levels?levels[cnt]:-1, New_Script, pItems[index].a.eScript);
649             index++;
650             if  (index+1 > cMaxItems)
651                 return E_OUTOFMEMORY;
652
653             pItems[index].iCharPos = cnt;
654             memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
655
656             pItems[index].a = scriptInformation[New_Script].a;
657             if (levels)
658             {
659                 pItems[index].a.fRTL = odd(levels[cnt]);
660                 pItems[index].a.fLayoutRTL = odd(levels[cnt]);
661                 pItems[index].a.s.uBidiLevel = levels[cnt];
662             }
663             else if (!pItems[index].a.s.uBidiLevel)
664             {
665                 pItems[index].a.s.uBidiLevel = baselevel;
666                 pItems[index].a.fLayoutRTL = odd(baselevel);
667                 pItems[index].a.fRTL = odd(baselevel);
668             }
669
670             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
671         }
672     }
673
674     /* While not strictly necessary according to the spec, make sure the n+1
675      * item is set up to prevent random behaviour if the caller erroneously
676      * checks the n+1 structure                                              */
677     index++;
678     memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
679
680     TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
681
682     /*  Set one SCRIPT_STATE item being returned  */
683     if  (index + 1 > cMaxItems) return E_OUTOFMEMORY;
684     if (pcItems) *pcItems = index;
685
686     /*  Set SCRIPT_ITEM                                     */
687     pItems[index].iCharPos = cnt;         /* the last item contains the ptr to the lastchar */
688     heap_free(levels);
689     return S_OK;
690 }
691
692 /***********************************************************************
693  *      ScriptStringAnalyse (USP10.@)
694  *
695  */
696 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
697                                    int cGlyphs, int iCharset, DWORD dwFlags,
698                                    int iReqWidth, SCRIPT_CONTROL *psControl,
699                                    SCRIPT_STATE *psState, const int *piDx,
700                                    SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
701                                    SCRIPT_STRING_ANALYSIS *pssa)
702 {
703     HRESULT hr = E_OUTOFMEMORY;
704     StringAnalysis *analysis = NULL;
705     int i, num_items = 255;
706
707     TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
708           hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
709           psControl, psState, piDx, pTabdef, pbInClass, pssa);
710
711     if (iCharset != -1)
712     {
713         FIXME("Only Unicode strings are supported\n");
714         return E_INVALIDARG;
715     }
716     if (cString < 1 || !pString) return E_INVALIDARG;
717     if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
718
719     if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
720     if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
721
722     /* FIXME: handle clipping */
723     analysis->clip_len = cString;
724     analysis->hdc = hdc;
725
726     hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
727                        &analysis->numItems);
728
729     while (hr == E_OUTOFMEMORY)
730     {
731         SCRIPT_ITEM *tmp;
732
733         num_items *= 2;
734         if (!(tmp = heap_realloc_zero(analysis->pItem, num_items * sizeof(SCRIPT_ITEM) + 1)))
735             goto error;
736
737         analysis->pItem = tmp;
738         hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
739                            &analysis->numItems);
740     }
741     if (hr != S_OK) goto error;
742
743     if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
744         ScriptBreak(pString, cString, (SCRIPT_STRING_ANALYSIS)analysis, analysis->logattrs);
745     else
746         goto error;
747
748     if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
749         goto error;
750
751     for (i = 0; i < analysis->numItems; i++)
752     {
753         SCRIPT_CACHE *sc = (SCRIPT_CACHE *)&analysis->sc;
754         int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
755         int numGlyphs = 1.5 * cChar + 16;
756         WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
757         WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
758         int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
759         SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * cChar);
760         GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
761         ABC *abc = heap_alloc_zero(sizeof(ABC));
762         int numGlyphsReturned;
763
764         /* FIXME: non unicode strings */
765         const WCHAR* pStr = (const WCHAR*)pString;
766         hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
767                          cChar, numGlyphs, &analysis->pItem[i].a,
768                          glyphs, pwLogClust, psva, &numGlyphsReturned);
769         hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
770                          piAdvance, pGoffset, abc);
771
772         analysis->glyphs[i].numGlyphs = numGlyphsReturned;
773         analysis->glyphs[i].glyphs = glyphs;
774         analysis->glyphs[i].pwLogClust = pwLogClust;
775         analysis->glyphs[i].piAdvance = piAdvance;
776         analysis->glyphs[i].psva = psva;
777         analysis->glyphs[i].pGoffset = pGoffset;
778         analysis->glyphs[i].abc = abc;
779     }
780
781     *pssa = analysis;
782     return S_OK;
783
784 error:
785     heap_free(analysis->glyphs);
786     heap_free(analysis->logattrs);
787     heap_free(analysis->pItem);
788     heap_free(analysis->sc);
789     heap_free(analysis);
790     return hr;
791 }
792
793 /***********************************************************************
794  *      ScriptStringOut (USP10.@)
795  *
796  * This function takes the output of ScriptStringAnalyse and joins the segments
797  * of glyphs and passes the resulting string to ScriptTextOut.  ScriptStringOut
798  * only processes glyphs.
799  *
800  * Parameters:
801  *  ssa       [I] buffer to hold the analysed string components
802  *  iX        [I] X axis displacement for output
803  *  iY        [I] Y axis displacement for output
804  *  uOptions  [I] flags controling output processing
805  *  prc       [I] rectangle coordinates
806  *  iMinSel   [I] starting pos for substringing output string
807  *  iMaxSel   [I] ending pos for substringing output string
808  *  fDisabled [I] controls text highlighting
809  *
810  *  RETURNS
811  *   Success: S_OK
812  *   Failure: is the value returned by ScriptTextOut
813  */
814 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
815                                int iX,
816                                int iY, 
817                                UINT uOptions, 
818                                const RECT *prc, 
819                                int iMinSel, 
820                                int iMaxSel,
821                                BOOL fDisabled)
822 {
823     StringAnalysis *analysis;
824     WORD *glyphs;
825     int   item, cnt, x;
826     HRESULT hr;
827
828     TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
829          ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
830
831     if (!(analysis = ssa)) return E_INVALIDARG;
832
833     /*
834      * Get storage for the output buffer for the consolidated strings
835      */
836     cnt = 0;
837     for (item = 0; item < analysis->numItems; item++)
838     {
839         cnt += analysis->glyphs[item].numGlyphs;
840     }
841     if (!(glyphs = heap_alloc(sizeof(WCHAR) * cnt))) return E_OUTOFMEMORY;
842
843     /*
844      * ScriptStringOut only processes glyphs hence set ETO_GLYPH_INDEX
845      */
846     uOptions |= ETO_GLYPH_INDEX;
847     analysis->pItem[0].a.fNoGlyphIndex = FALSE; /* say that we have glyphs */
848
849     /*
850      * Copy the string items into the output buffer
851      */
852
853     TRACE("numItems %d\n", analysis->numItems);
854
855     cnt = 0;
856     for (item = 0; item < analysis->numItems; item++)
857     {
858         memcpy(&glyphs[cnt], analysis->glyphs[item].glyphs,
859               sizeof(WCHAR) * analysis->glyphs[item].numGlyphs);
860
861         TRACE("Item %d, Glyphs %d ", item, analysis->glyphs[item].numGlyphs);
862         for (x = cnt; x < analysis->glyphs[item].numGlyphs + cnt; x ++)
863             TRACE("%04x", glyphs[x]);
864         TRACE("\n");
865
866         cnt += analysis->glyphs[item].numGlyphs; /* point to the end of the copied text */
867     }
868
869     hr = ScriptTextOut(analysis->hdc, (SCRIPT_CACHE *)&analysis->sc, iX, iY,
870                        uOptions, prc, &analysis->pItem->a, NULL, 0, glyphs, cnt,
871                        analysis->glyphs->piAdvance, NULL, analysis->glyphs->pGoffset);
872     TRACE("ScriptTextOut hr=%08x\n", hr);
873
874     /*
875      * Free the output buffer and script cache
876      */
877     heap_free(glyphs);
878     return hr;
879 }
880
881 /***********************************************************************
882  *      ScriptStringCPtoX (USP10.@)
883  *
884  */
885 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
886 {
887     int i, j;
888     int runningX = 0;
889     int runningCp = 0;
890     StringAnalysis* analysis = ssa;
891
892     TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
893
894     if (!ssa || !pX) return S_FALSE;
895
896     /* icp out of range */
897     if(icp < 0)
898     {
899         analysis->invalid = TRUE;
900         return E_INVALIDARG;
901     }
902
903     for(i=0; i<analysis->numItems; i++)
904     {
905         for(j=0; j<analysis->glyphs[i].numGlyphs; j++)
906         {
907             if(runningCp == icp && fTrailing == FALSE)
908             {
909                 *pX = runningX;
910                 return S_OK;
911             }
912             runningX += analysis->glyphs[i].piAdvance[j];
913             if(runningCp == icp && fTrailing == TRUE)
914             {
915                 *pX = runningX;
916                 return S_OK;
917             }
918             runningCp++;
919         }
920     }
921
922     /* icp out of range */
923     analysis->invalid = TRUE;
924     return E_INVALIDARG;
925 }
926
927 /***********************************************************************
928  *      ScriptStringXtoCP (USP10.@)
929  *
930  */
931 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing) 
932 {
933     StringAnalysis* analysis = ssa;
934     int i;
935     int j;
936     int runningX = 0;
937     int runningCp = 0;
938     int width;
939
940     TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
941
942     if (!ssa || !piCh || !piTrailing) return S_FALSE;
943
944     /* out of range */
945     if(iX < 0)
946     {
947         *piCh = -1;
948         *piTrailing = TRUE;
949         return S_OK;
950     }
951
952     for(i=0; i<analysis->numItems; i++)
953     {
954         for(j=0; j<analysis->glyphs[i].numGlyphs; j++)
955         {
956             width = analysis->glyphs[i].piAdvance[j];
957             if(iX < (runningX + width))
958             {
959                 *piCh = runningCp;
960                 if((iX - runningX) > width/2)
961                     *piTrailing = TRUE;
962                 else
963                     *piTrailing = FALSE;
964                 return S_OK;
965             }
966             runningX += width;
967             runningCp++;
968         }
969     }
970
971     /* out of range */
972     *piCh = analysis->pItem[analysis->numItems].iCharPos;
973     *piTrailing = FALSE;
974
975     return S_OK;
976 }
977
978
979 /***********************************************************************
980  *      ScriptStringFree (USP10.@)
981  *
982  * Free a string analysis.
983  *
984  * PARAMS
985  *  pssa [I] string analysis.
986  *
987  * RETURNS
988  *  Success: S_OK
989  *  Failure: Non-zero HRESULT value.
990  */
991 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
992 {
993     StringAnalysis* analysis;
994     BOOL invalid;
995     int i;
996
997     TRACE("(%p)\n", pssa);
998
999     if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
1000
1001     invalid = analysis->invalid;
1002     ScriptFreeCache((SCRIPT_CACHE *)&analysis->sc);
1003
1004     for (i = 0; i < analysis->numItems; i++)
1005     {
1006         heap_free(analysis->glyphs[i].glyphs);
1007         heap_free(analysis->glyphs[i].pwLogClust);
1008         heap_free(analysis->glyphs[i].piAdvance);
1009         heap_free(analysis->glyphs[i].psva);
1010         heap_free(analysis->glyphs[i].pGoffset);
1011         heap_free(analysis->glyphs[i].abc);
1012     }
1013
1014     heap_free(analysis->glyphs);
1015     heap_free(analysis->pItem);
1016     heap_free(analysis->logattrs);
1017     heap_free(analysis->sz);
1018     heap_free(analysis->sc);
1019     heap_free(analysis);
1020
1021     if (invalid) return E_INVALIDARG;
1022     return S_OK;
1023 }
1024
1025 /***********************************************************************
1026  *      ScriptCPtoX (USP10.@)
1027  *
1028  */
1029 HRESULT WINAPI ScriptCPtoX(int iCP,
1030                            BOOL fTrailing,
1031                            int cChars,
1032                            int cGlyphs,
1033                            const WORD *pwLogClust,
1034                            const SCRIPT_VISATTR *psva,
1035                            const int *piAdvance,
1036                            const SCRIPT_ANALYSIS *psa,
1037                            int *piX)
1038 {
1039     int  item;
1040     int  iPosX;
1041     float  fMaxPosX = 0;
1042     TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
1043           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1044           psa, piX);
1045     for (item=0; item < cGlyphs; item++)            /* total piAdvance           */
1046         fMaxPosX += piAdvance[item];
1047     iPosX = (fMaxPosX/cGlyphs)*(iCP+fTrailing);
1048     if  (iPosX > fMaxPosX)
1049         iPosX = fMaxPosX;
1050     *piX = iPosX;                                    /* Return something in range */
1051
1052     TRACE("*piX=%d\n", *piX);
1053     return S_OK;
1054 }
1055
1056 /***********************************************************************
1057  *      ScriptXtoCP (USP10.@)
1058  *
1059  */
1060 HRESULT WINAPI ScriptXtoCP(int iX,
1061                            int cChars,
1062                            int cGlyphs,
1063                            const WORD *pwLogClust,
1064                            const SCRIPT_VISATTR *psva,
1065                            const int *piAdvance,
1066                            const SCRIPT_ANALYSIS *psa,
1067                            int *piCP,
1068                            int *piTrailing)
1069 {
1070     int item;
1071     int iPosX;
1072     float fMaxPosX = 1;
1073     float fAvePosX;
1074     TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
1075           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1076           psa, piCP, piTrailing);
1077     if  (iX < 0)                                    /* iX is before start of run */
1078     {
1079         *piCP = -1;
1080         *piTrailing = TRUE;
1081         return S_OK;
1082     }
1083
1084     for (item=0; item < cGlyphs; item++)            /* total piAdvance           */
1085         fMaxPosX += piAdvance[item];
1086
1087     if  (iX >= fMaxPosX)                            /* iX too large              */
1088     {
1089         *piCP = cChars;
1090         *piTrailing = FALSE;
1091         return S_OK;
1092     }
1093
1094     fAvePosX = fMaxPosX / cGlyphs;
1095     iPosX = fAvePosX;
1096     for (item = 1; item < cGlyphs  && iPosX < iX; item++)
1097         iPosX += fAvePosX;
1098     if  (iPosX - iX > fAvePosX/2)
1099         *piTrailing = 0;
1100     else
1101         *piTrailing = 1;                            /* yep we are over halfway */
1102
1103     *piCP = item -1;                                /* Return character position */
1104     TRACE("*piCP=%d iPposX=%d\n", *piCP, iPosX);
1105     return S_OK;
1106 }
1107
1108 /***********************************************************************
1109  *      ScriptBreak (USP10.@)
1110  *
1111  *  Retrieve line break information.
1112  *
1113  *  PARAMS
1114  *   chars [I] Array of characters.
1115  *   sa    [I] String analysis.
1116  *   la    [I] Array of logical attribute structures.
1117  *
1118  *  RETURNS
1119  *   Success: S_OK
1120  *   Failure: S_FALSE
1121  */
1122 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
1123 {
1124     int i;
1125
1126     TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
1127
1128     if (!la) return S_FALSE;
1129
1130     for (i = 0; i < count; i++)
1131     {
1132         memset(&la[i], 0, sizeof(SCRIPT_LOGATTR));
1133
1134         /* FIXME: set the other flags */
1135         la[i].fWhiteSpace = (chars[i] == ' ');
1136         la[i].fCharStop = 1;
1137
1138         if (i > 0 && la[i - 1].fWhiteSpace)
1139         {
1140             la[i].fSoftBreak = 1;
1141             la[i].fWordStop = 1;
1142         }
1143     }
1144     return S_OK;
1145 }
1146
1147 /***********************************************************************
1148  *      ScriptIsComplex (USP10.@)
1149  *
1150  *  Determine if a string is complex.
1151  *
1152  *  PARAMS
1153  *   chars [I] Array of characters to test.
1154  *   len   [I] Length in characters.
1155  *   flag  [I] Flag.
1156  *
1157  *  RETURNS
1158  *   Success: S_OK
1159  *   Failure: S_FALSE
1160  *
1161  */
1162 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
1163 {
1164     int i;
1165
1166     TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
1167
1168     for (i = 0; i < len; i++)
1169     {
1170         int script;
1171
1172         if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
1173             return S_OK;
1174
1175         script = get_char_script(chars[i]);
1176         if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
1177             (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
1178             return S_OK;
1179     }
1180     return S_FALSE;
1181 }
1182
1183 /***********************************************************************
1184  *      ScriptShape (USP10.@)
1185  *
1186  * Produce glyphs and visual attributes for a run.
1187  *
1188  * PARAMS
1189  *  hdc         [I]   Device context.
1190  *  psc         [I/O] Opaque pointer to a script cache.
1191  *  pwcChars    [I]   Array of characters specifying the run.
1192  *  cChars      [I]   Number of characters in pwcChars.
1193  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
1194  *  psa         [I/O] Script analysis.
1195  *  pwOutGlyphs [O]   Array of glyphs.
1196  *  pwLogClust  [O]   Array of logical cluster info.
1197  *  psva        [O]   Array of visual attributes.
1198  *  pcGlyphs    [O]   Number of glyphs returned.
1199  *
1200  * RETURNS
1201  *  Success: S_OK
1202  *  Failure: Non-zero HRESULT value.
1203  */
1204 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars, 
1205                            int cChars, int cMaxGlyphs,
1206                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
1207                            SCRIPT_VISATTR *psva, int *pcGlyphs)
1208 {
1209     HRESULT hr;
1210     unsigned int i;
1211     BOOL rtl;
1212
1213     TRACE("(%p, %p, %s, %d, %d, %p, %p, %p, %p, %p)\n", hdc, psc, debugstr_wn(pwcChars, cChars),
1214           cChars, cMaxGlyphs, psa, pwOutGlyphs, pwLogClust, psva, pcGlyphs);
1215
1216     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
1217                    psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
1218
1219     if (!psva || !pcGlyphs) return E_INVALIDARG;
1220     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
1221     rtl = (!psa->fLogicalOrder && psa->fRTL);
1222
1223     *pcGlyphs = cChars;
1224     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1225     if (!pwLogClust) return E_FAIL;
1226
1227     /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
1228     for (i = 0; i < cChars; i++)
1229     {
1230         int idx = i;
1231         if (rtl) idx = cChars - 1 - i;
1232         /* FIXME: set to better values */
1233         psva[i].uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
1234         psva[i].fClusterStart  = 1;
1235         psva[i].fDiacritic     = 0;
1236         psva[i].fZeroWidth     = 0;
1237         psva[i].fReserved      = 0;
1238         psva[i].fShapeReserved = 0;
1239
1240         pwLogClust[i] = idx;
1241     }
1242
1243     if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
1244     {
1245         WCHAR *rChars = heap_alloc(sizeof(WCHAR) * cChars);
1246         if (!rChars) return E_OUTOFMEMORY;
1247         for (i = 0; i < cChars; i++)
1248         {
1249             int idx = i;
1250             WCHAR chInput;
1251             if (rtl) idx = cChars - 1 - i;
1252             if (psa->fRTL)
1253                 chInput = mirror_char(pwcChars[idx]);
1254             else
1255                 chInput = pwcChars[idx];
1256             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, chInput)))
1257             {
1258                 WORD glyph;
1259                 if (!hdc) return E_PENDING;
1260                 if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR) return S_FALSE;
1261                 pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph);
1262             }
1263             rChars[i] = chInput;
1264         }
1265         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
1266         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
1267         heap_free(rChars);
1268     }
1269     else
1270     {
1271         TRACE("no glyph translation\n");
1272         for (i = 0; i < cChars; i++)
1273         {
1274             int idx = i;
1275             /* No mirroring done here */
1276             if (rtl) idx = cChars - 1 - i;
1277             pwOutGlyphs[i] = pwcChars[idx];
1278         }
1279     }
1280
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     HRESULT hr;
1309     int i;
1310
1311     TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n",  hdc, psc, pwGlyphs, cGlyphs, psva, psa,
1312           piAdvance, pGoffset, pABC);
1313
1314     if (!psva) return E_INVALIDARG;
1315     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1316     if (!pGoffset) return E_FAIL;
1317
1318     if (pABC) memset(pABC, 0, sizeof(ABC));
1319     for (i = 0; i < cGlyphs; i++)
1320     {
1321         ABC abc;
1322         if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
1323         {
1324             if (!hdc) return E_PENDING;
1325             if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
1326             {
1327                 if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
1328             }
1329             else
1330             {
1331                 INT width;
1332                 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
1333                 abc.abcB = width;
1334                 abc.abcA = abc.abcC = 0;
1335             }
1336             set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
1337         }
1338         if (pABC)
1339         {
1340             pABC->abcA += abc.abcA;
1341             pABC->abcB += abc.abcB;
1342             pABC->abcC += abc.abcC;
1343         }
1344         /* FIXME: set to more reasonable values */
1345         pGoffset[i].du = pGoffset[i].dv = 0;
1346         if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
1347     }
1348
1349     if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
1350     return S_OK;
1351 }
1352
1353 /***********************************************************************
1354  *      ScriptGetCMap (USP10.@)
1355  *
1356  * Retrieve glyph indices.
1357  *
1358  * PARAMS
1359  *  hdc         [I]   Device context.
1360  *  psc         [I/O] Opaque pointer to a script cache.
1361  *  pwcInChars  [I]   Array of Unicode characters.
1362  *  cChars      [I]   Number of characters in pwcInChars.
1363  *  dwFlags     [I]   Flags.
1364  *  pwOutGlyphs [O]   Buffer to receive the array of glyph indices.
1365  *
1366  * RETURNS
1367  *  Success: S_OK
1368  *  Failure: Non-zero HRESULT value.
1369  */
1370 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
1371                              int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
1372 {
1373     HRESULT hr;
1374     int i;
1375
1376     TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
1377           cChars, dwFlags, pwOutGlyphs);
1378
1379     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1380
1381     hr = S_OK;
1382
1383     if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
1384     {
1385         for (i = 0; i < cChars; i++)
1386         {
1387             WCHAR inChar;
1388             if (dwFlags == SGCM_RTL)
1389                 inChar = mirror_char(pwcInChars[i]);
1390             else
1391                 inChar = pwcInChars[i];
1392             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
1393             {
1394                 WORD glyph;
1395                 if (!hdc) return E_PENDING;
1396                 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
1397                 if (glyph == 0xffff)
1398                 {
1399                     hr = S_FALSE;
1400                     glyph = 0x0;
1401                 }
1402                 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
1403             }
1404         }
1405     }
1406     else
1407     {
1408         TRACE("no glyph translation\n");
1409         for (i = 0; i < cChars; i++)
1410         {
1411             WCHAR inChar;
1412             if (dwFlags == SGCM_RTL)
1413                 inChar = mirror_char(pwcInChars[i]);
1414             else
1415                 inChar = pwcInChars[i];
1416             pwOutGlyphs[i] = inChar;
1417         }
1418     }
1419     return hr;
1420 }
1421
1422 /***********************************************************************
1423  *      ScriptTextOut (USP10.@)
1424  *
1425  */
1426 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
1427                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
1428                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
1429                              const int *piJustify, const GOFFSET *pGoffset)
1430 {
1431     HRESULT hr = S_OK;
1432
1433     TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
1434          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
1435          piAdvance, piJustify, pGoffset);
1436
1437     if (!hdc || !psc) return E_INVALIDARG;
1438     if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
1439
1440     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
1441     fuOptions |= ETO_IGNORELANGUAGE;
1442     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
1443         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do translation to glyph */
1444
1445     if (psa->fRTL && psa->fLogicalOrder)
1446     {
1447         int i;
1448         WORD *rtlGlyphs;
1449
1450         rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD));
1451         if (!rtlGlyphs)
1452             return E_OUTOFMEMORY;
1453
1454         for (i = 0; i < cGlyphs; i++)
1455             rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i];
1456
1457         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL))
1458             hr = S_FALSE;
1459         heap_free(rtlGlyphs);
1460     }
1461     else
1462         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
1463             hr = S_FALSE;
1464
1465     return hr;
1466 }
1467
1468 /***********************************************************************
1469  *      ScriptCacheGetHeight (USP10.@)
1470  *
1471  * Retrieve the height of the font in the cache.
1472  *
1473  * PARAMS
1474  *  hdc    [I]    Device context.
1475  *  psc    [I/O]  Opaque pointer to a script cache.
1476  *  height [O]    Receives font height.
1477  *
1478  * RETURNS
1479  *  Success: S_OK
1480  *  Failure: Non-zero HRESULT value.
1481  */
1482 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
1483 {
1484     HRESULT hr;
1485
1486     TRACE("(%p, %p, %p)\n", hdc, psc, height);
1487
1488     if (!height) return E_INVALIDARG;
1489     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1490
1491     *height = get_cache_height(psc);
1492     return S_OK;
1493 }
1494
1495 /***********************************************************************
1496  *      ScriptGetGlyphABCWidth (USP10.@)
1497  *
1498  * Retrieve the width of a glyph.
1499  *
1500  * PARAMS
1501  *  hdc    [I]    Device context.
1502  *  psc    [I/O]  Opaque pointer to a script cache.
1503  *  glyph  [I]    Glyph to retrieve the width for.
1504  *  abc    [O]    ABC widths of the glyph.
1505  *
1506  * RETURNS
1507  *  Success: S_OK
1508  *  Failure: Non-zero HRESULT value.
1509  */
1510 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
1511 {
1512     HRESULT hr;
1513
1514     TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
1515
1516     if (!abc) return E_INVALIDARG;
1517     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1518
1519     if (!get_cache_glyph_widths(psc, glyph, abc))
1520     {
1521         if (!hdc) return E_PENDING;
1522         if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
1523         {
1524             if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
1525         }
1526         else
1527         {
1528             INT width;
1529             if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
1530             abc->abcB = width;
1531             abc->abcA = abc->abcC = 0;
1532         }
1533         set_cache_glyph_widths(psc, glyph, abc);
1534     }
1535     return S_OK;
1536 }
1537
1538 /***********************************************************************
1539  *      ScriptLayout (USP10.@)
1540  *
1541  * Map embedding levels to visual and/or logical order.
1542  *
1543  * PARAMS
1544  *  runs     [I] Size of level array.
1545  *  level    [I] Array of embedding levels.
1546  *  vistolog [O] Map of embedding levels from visual to logical order.
1547  *  logtovis [O] Map of embedding levels from logical to visual order.
1548  *
1549  * RETURNS
1550  *  Success: S_OK
1551  *  Failure: Non-zero HRESULT value.
1552  *
1553  * BUGS
1554  *  This stub works correctly for any sequence of a single
1555  *  embedding level but not for sequences of different
1556  *  embedding levels, i.e. mixtures of RTL and LTR scripts.
1557  */
1558 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
1559 {
1560     int* indexs;
1561     int ich;
1562
1563     TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
1564
1565     if (!level || (!vistolog && !logtovis))
1566         return E_INVALIDARG;
1567
1568     indexs = heap_alloc(sizeof(int) * runs);
1569     if (!indexs)
1570         return E_OUTOFMEMORY;
1571
1572
1573     if (vistolog)
1574     {
1575         for( ich = 0; ich < runs; ich++)
1576             indexs[ich] = ich;
1577
1578         ich = 0;
1579         while (ich < runs)
1580             ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
1581         for (ich = 0; ich < runs; ich++)
1582             vistolog[ich] = indexs[ich];
1583     }
1584
1585
1586     if (logtovis)
1587     {
1588         for( ich = 0; ich < runs; ich++)
1589             indexs[ich] = ich;
1590
1591         ich = 0;
1592         while (ich < runs)
1593             ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
1594         for (ich = 0; ich < runs; ich++)
1595             logtovis[ich] = indexs[ich];
1596     }
1597     heap_free(indexs);
1598
1599     return S_OK;
1600 }
1601
1602 /***********************************************************************
1603  *      ScriptStringGetLogicalWidths (USP10.@)
1604  *
1605  * Returns logical widths from a string analysis.
1606  *
1607  * PARAMS
1608  *  ssa  [I] string analysis.
1609  *  piDx [O] logical widths returned.
1610  *
1611  * RETURNS
1612  *  Success: S_OK
1613  *  Failure: a non-zero HRESULT.
1614  */
1615 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
1616 {
1617     int i, j, next = 0;
1618     StringAnalysis *analysis = ssa;
1619
1620     TRACE("%p, %p\n", ssa, piDx);
1621
1622     if (!analysis) return S_FALSE;
1623
1624     for (i = 0; i < analysis->numItems; i++)
1625     {
1626         for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
1627         {
1628             piDx[next] = analysis->glyphs[i].piAdvance[j];
1629             next++;
1630         }
1631     }
1632     return S_OK;
1633 }
1634
1635 /***********************************************************************
1636  *      ScriptStringValidate (USP10.@)
1637  *
1638  * Validate a string analysis.
1639  *
1640  * PARAMS
1641  *  ssa [I] string analysis.
1642  *
1643  * RETURNS
1644  *  Success: S_OK
1645  *  Failure: S_FALSE if invalid sequences are found
1646  *           or a non-zero HRESULT if it fails.
1647  */
1648 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
1649 {
1650     StringAnalysis *analysis = ssa;
1651
1652     TRACE("(%p)\n", ssa);
1653
1654     if (!analysis) return E_INVALIDARG;
1655     return (analysis->invalid) ? S_FALSE : S_OK;
1656 }
1657
1658 /***********************************************************************
1659  *      ScriptString_pSize (USP10.@)
1660  *
1661  * Retrieve width and height of an analysed string.
1662  *
1663  * PARAMS
1664  *  ssa [I] string analysis.
1665  *
1666  * RETURNS
1667  *  Success: Pointer to a SIZE structure.
1668  *  Failure: NULL
1669  */
1670 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
1671 {
1672     int i, j;
1673     StringAnalysis *analysis = ssa;
1674
1675     TRACE("(%p)\n", ssa);
1676
1677     if (!analysis) return NULL;
1678
1679     if (!analysis->sz)
1680     {
1681         if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
1682         analysis->sz->cy = analysis->sc->tm.tmHeight;
1683
1684         analysis->sz->cx = 0;
1685         for (i = 0; i < analysis->numItems; i++)
1686             for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
1687                 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
1688     }
1689     return analysis->sz;
1690 }
1691
1692 /***********************************************************************
1693  *      ScriptString_pLogAttr (USP10.@)
1694  *
1695  * Retrieve logical attributes of an analysed string.
1696  *
1697  * PARAMS
1698  *  ssa [I] string analysis.
1699  *
1700  * RETURNS
1701  *  Success: Pointer to an array of SCRIPT_LOGATTR structures.
1702  *  Failure: NULL
1703  */
1704 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
1705 {
1706     StringAnalysis *analysis = ssa;
1707
1708     TRACE("(%p)\n", ssa);
1709
1710     if (!analysis) return NULL;
1711     return analysis->logattrs;
1712 }
1713
1714 /***********************************************************************
1715  *      ScriptString_pcOutChars (USP10.@)
1716  *
1717  * Retrieve the length of a string after clipping.
1718  *
1719  * PARAMS
1720  *  ssa [I] String analysis.
1721  *
1722  * RETURNS
1723  *  Success: Pointer to the length.
1724  *  Failure: NULL
1725  */
1726 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
1727 {
1728     StringAnalysis *analysis = ssa;
1729
1730     TRACE("(%p)\n", ssa);
1731
1732     if (!analysis) return NULL;
1733     return &analysis->clip_len;
1734 }
1735
1736 /***********************************************************************
1737  *      ScriptStringGetOrder (USP10.@)
1738  *
1739  * Retrieve a glyph order map.
1740  *
1741  * PARAMS
1742  *  ssa   [I]   String analysis.
1743  *  order [I/O] Array of glyph positions.
1744  *
1745  * RETURNS
1746  *  Success: S_OK
1747  *  Failure: a non-zero HRESULT.
1748  */
1749 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
1750 {
1751     int i, j;
1752     unsigned int k;
1753     StringAnalysis *analysis = ssa;
1754
1755     TRACE("(%p)\n", ssa);
1756
1757     if (!analysis) return S_FALSE;
1758
1759     /* FIXME: handle RTL scripts */
1760     for (i = 0, k = 0; i < analysis->numItems; i++)
1761         for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
1762             order[k] = k;
1763
1764     return S_OK;
1765 }
1766
1767 /***********************************************************************
1768  *      ScriptGetLogicalWidths (USP10.@)
1769  *
1770  * Convert advance widths to logical widths.
1771  *
1772  * PARAMS
1773  *  sa          [I] Script analysis.
1774  *  nbchars     [I] Number of characters.
1775  *  nbglyphs    [I] Number of glyphs.
1776  *  glyph_width [I] Array of glyph widths.
1777  *  log_clust   [I] Array of logical clusters.
1778  *  sva         [I] Visual attributes.
1779  *  widths      [O] Array of logical widths.
1780  *
1781  * RETURNS
1782  *  Success: S_OK
1783  *  Failure: a non-zero HRESULT.
1784  */
1785 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
1786                                       const int *glyph_width, const WORD *log_clust,
1787                                       const SCRIPT_VISATTR *sva, int *widths)
1788 {
1789     int i;
1790
1791     TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
1792           sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);
1793
1794     /* FIXME */
1795     for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
1796     return S_OK;
1797 }
1798
1799 /***********************************************************************
1800  *      ScriptApplyLogicalWidth (USP10.@)
1801  *
1802  * Generate glyph advance widths.
1803  *
1804  * PARAMS
1805  *  dx          [I]   Array of logical advance widths.
1806  *  num_chars   [I]   Number of characters.
1807  *  num_glyphs  [I]   Number of glyphs.
1808  *  log_clust   [I]   Array of logical clusters.
1809  *  sva         [I]   Visual attributes.
1810  *  advance     [I]   Array of glyph advance widths.
1811  *  sa          [I]   Script analysis.
1812  *  abc         [I/O] Summed ABC widths.
1813  *  justify     [O]   Array of glyph advance widths.
1814  *
1815  * RETURNS
1816  *  Success: S_OK
1817  *  Failure: a non-zero HRESULT.
1818  */
1819 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
1820                                        const WORD *log_clust, const SCRIPT_VISATTR *sva,
1821                                        const int *advance, const SCRIPT_ANALYSIS *sa,
1822                                        ABC *abc, int *justify)
1823 {
1824     int i;
1825
1826     FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
1827           dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
1828
1829     for (i = 0; i < num_chars; i++) justify[i] = advance[i];
1830     return S_OK;
1831 }
1832
1833 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
1834                              int num_glyphs, int dx, int min_kashida, int *justify)
1835 {
1836     int i;
1837
1838     FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
1839
1840     for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
1841     return S_OK;
1842 }