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