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