mshtml: Wine Gecko 1.4 release.
[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 "winreg.h"
35 #include "usp10.h"
36
37 #include "usp10_internal.h"
38
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
43
44 typedef struct _scriptRange
45 {
46     WORD script;
47     WORD rangeFirst;
48     WORD rangeLast;
49     WORD numericScript;
50     WORD punctScript;
51 } scriptRange;
52
53 static const scriptRange scriptRanges[] = {
54     /* Basic Latin: U+0000–U+007A */
55     /* Latin-1 Supplement: U+0080–U+00FF */
56     /* Latin Extended-A: U+0100–U+017F */
57     /* Latin Extended-B: U+0180–U+024F */
58     /* IPA Extensions: U+0250–U+02AF */
59     { Script_Latin,      0x00,   0x2af ,  Script_Numeric, Script_Punctuation},
60     /* Greek: U+0370–U+03FF */
61     { Script_Greek,      0x370,  0x3ff,  0, 0},
62     /* Cyrillic: U+0400–U+04FF */
63     /* Cyrillic Supplement: U+0500–U+052F */
64     { Script_Cyrillic,   0x400,  0x52f,  0, 0},
65     /* Armenian: U+0530–U+058F */
66     { Script_Armenian,   0x530,  0x58f,  0, 0},
67     /* Hebrew: U+0590–U+05FF */
68     { Script_Hebrew,     0x590,  0x5ff,  0, 0},
69     /* Arabic: U+0600–U+06FF */
70     { Script_Arabic,     0x600,  0x6ef,  Script_Arabic_Numeric, 0},
71     /* Defined by Windows */
72     { Script_Persian,    0x6f0,  0x6f9,  0, 0},
73     /* Continue Arabic: U+0600–U+06FF */
74     { Script_Arabic,     0x6fa,  0x6ff,  0, 0},
75     /* Syriac: U+0700–U+074F*/
76     { Script_Syriac,     0x700,  0x74f,  0, 0},
77     /* Arabic Supplement: U+0750–U+077F */
78     { Script_Arabic,     0x750,  0x77f,  0, 0},
79     /* Thaana: U+0780–U+07BF */
80     { Script_Thaana,     0x780,  0x7bf,  0, 0},
81     /* Devanagari: U+0900–U+097F */
82     { Script_Devanagari, 0x900,  0x97f,  Script_Devanagari_Numeric, 0},
83     /* Bengali: U+0980–U+09FF */
84     { Script_Bengali,    0x980,  0x9ff,  Script_Bengali_Numeric, 0},
85     /* Gurmukhi: U+0A00–U+0A7F*/
86     { Script_Gurmukhi,   0xa00,  0xa7f,  Script_Gurmukhi_Numeric, 0},
87     /* Gujarati: U+0A80–U+0AFF*/
88     { Script_Gujarati,   0xa80,  0xaff,  Script_Gujarati_Numeric, 0},
89     /* Oriya: U+0B00–U+0B7F */
90     { Script_Oriya,      0xb00,  0xb7f,  Script_Oriya_Numeric, 0},
91     /* Tamil: U+0B80–U+0BFF */
92     { Script_Tamil,      0xb80,  0xbff,  Script_Tamil_Numeric, 0},
93     /* Telugu: U+0C00–U+0C7F */
94     { Script_Telugu,     0xc00,  0xc7f,  Script_Telugu_Numeric, 0},
95     /* Kannada: U+0C80–U+0CFF */
96     { Script_Kannada,    0xc80,  0xcff,  Script_Kannada_Numeric, 0},
97     /* Malayalam: U+0D00–U+0D7F */
98     { Script_Malayalam,  0xd00,  0xd7f,  Script_Malayalam_Numeric, 0},
99     /* Sinhala: U+0D80–U+0DFF */
100     { Script_Sinhala,   0xd80,  0xdff,  0, 0},
101     /* Thai: U+0E00–U+0E7F */
102     { Script_Thai,      0xe00,  0xe7f,  Script_Thai_Numeric, 0},
103     /* Lao: U+0E80–U+0EFF */
104     { Script_Lao,       0xe80,  0xeff,  Script_Lao_Numeric, 0},
105     /* Tibetan: U+0F00–U+0FFF */
106     { Script_Tibetan,   0xf00,  0xfff,  Script_Tibetan_Numeric, 0},
107     /* Georgian: U+10A0–U+10FF */
108     { Script_Georgian,   0x10a0,  0x10ff,  0, 0},
109     /* Vedic Extensions: U+1CD0-U+1CFF */
110     { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
111     /* Phonetic Extensions: U+1D00–U+1DBF */
112     { Script_Latin,      0x1d00, 0x1dbf, 0, 0},
113     /* Latin Extended Additional: U+1E00–U+1EFF */
114     { Script_Latin,      0x1e00, 0x1eff, 0, 0},
115     /* Greek Extended: U+1F00–U+1FFF */
116     { Script_Greek,      0x1f00, 0x1fff, 0, 0},
117     /* Latin Extended-C: U+2C60–U+2C7F */
118     { Script_Latin,      0x2c60, 0x2c7f, 0, 0},
119     /* Georgian: U+2D00–U+2D2F */
120     { Script_Georgian,   0x2d00,  0x2d2f,  0, 0},
121     /* Cyrillic Extended-A: U+2DE0–U+2DFF */
122     { Script_Cyrillic,   0x2de0, 0x2dff,  0, 0},
123     /* Cyrillic Extended-B: U+A640–U+A69F */
124     { Script_Cyrillic,   0xa640, 0xa69f,  0, 0},
125     /* Modifier Tone Letters: U+A700–U+A71F */
126     /* Latin Extended-D: U+A720–U+A7FF */
127     { Script_Latin,      0xa700, 0xa7ff, 0, 0},
128     /* Phags-pa: U+A840–U+A87F */
129     { Script_Phags_pa,   0xa840, 0xa87f, 0, 0},
130     /* Devanagari Extended: U+A8E0-U+A8FF */
131     { Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
132     /* Latin Ligatures: U+FB00–U+FB06 */
133     { Script_Latin,      0xfb00, 0xfb06, 0, 0},
134     /* Armenian ligatures U+FB13..U+FB17 */
135     { Script_Armenian,   0xfb13, 0xfb17,  0, 0},
136     /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
137     { Script_Hebrew,     0xfb1d, 0xfb4f, 0, 0},
138     /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
139     { Script_Arabic,     0xfb50, 0xfdff, 0, 0},
140     /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
141     { Script_Arabic,     0xfe70, 0xfeff, 0, 0},
142     /* END */
143     { SCRIPT_UNDEFINED,  0, 0, 0}
144 };
145
146 typedef struct _scriptData
147 {
148     SCRIPT_ANALYSIS a;
149     SCRIPT_PROPERTIES props;
150     OPENTYPE_TAG scriptTag;
151     WCHAR fallbackFont[LF_FACESIZE];
152 } scriptData;
153
154 /* the must be in order so that the index matches the Script value */
155 static const scriptData scriptInformation[] = {
156     {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
157      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
158      0x00000000,
159      {0}},
160     {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
161      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
162      MS_MAKE_TAG('l','a','t','n'),
163      {0}},
164     {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
165      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
166      0x00000000,
167      {0}},
168     {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
169      {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
170      0x00000000,
171      {0}},
172     {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
173      {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
174      0x00000000,
175      {0}},
176     {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
177      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
178      0x00000000,
179      {0}},
180     {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
181      {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
182      MS_MAKE_TAG('a','r','a','b'),
183      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
184     {{Script_Arabic_Numeric, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
185      {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
186      MS_MAKE_TAG('a','r','a','b'),
187      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
188     {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
189      {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
190      MS_MAKE_TAG('h','e','b','r'),
191      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
192     {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
193      {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
194      MS_MAKE_TAG('s','y','r','c'),
195      {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
196     {{Script_Persian, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
197      {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
198      MS_MAKE_TAG('s','y','r','c'),
199      {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
200     {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
201      {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
202      MS_MAKE_TAG('t','h','a','a'),
203      {'M','V',' ','B','o','l','i',0}},
204     {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
205      {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
206      MS_MAKE_TAG('g','r','e','k'),
207      {0}},
208     {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
209      {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
210      MS_MAKE_TAG('c','y','r','l'),
211      {0}},
212     {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
213      {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
214      MS_MAKE_TAG('a','r','m','n'),
215      {'S','y','l','f','a','e','n',0}},
216     {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
217      {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
218      MS_MAKE_TAG('g','e','o','r'),
219      {'S','y','l','f','a','e','n',0}},
220     {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
221      {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
222      MS_MAKE_TAG('s','i','n','h'),
223      {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
224     {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
225      {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
226      MS_MAKE_TAG('t','i','b','t'),
227      {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
228     {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
229      {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
230      MS_MAKE_TAG('t','i','b','t'),
231      {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
232     {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
233      {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
234      MS_MAKE_TAG('p','h','a','g'),
235      {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
236     {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
237      {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
238      MS_MAKE_TAG('t','h','a','i'),
239      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
240     {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
241      {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
242      MS_MAKE_TAG('t','h','a','i'),
243      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
244     {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
245      {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
246      MS_MAKE_TAG('l','a','o',' '),
247      {'D','o','k','C','h','a','m','p','a',0}},
248     {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
249      {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
250      MS_MAKE_TAG('l','a','o',' '),
251      {'D','o','k','C','h','a','m','p','a',0}},
252     {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
253      {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
254      MS_MAKE_TAG('d','e','v','a'),
255      {'M','a','n','g','a','l',0}},
256     {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
257      {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
258      MS_MAKE_TAG('d','e','v','a'),
259      {'M','a','n','g','a','l',0}},
260     {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
261      {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
262      MS_MAKE_TAG('b','e','n','g'),
263      {'V','r','i','n','d','a',0}},
264     {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
265      {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
266      MS_MAKE_TAG('b','e','n','g'),
267      {'V','r','i','n','d','a',0}},
268     {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
269      {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
270      MS_MAKE_TAG('b','e','n','g'),
271      {'V','r','i','n','d','a',0}},
272     {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
273      {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
274      MS_MAKE_TAG('g','u','r','u'),
275      {'R','a','a','v','i',0}},
276     {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
277      {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
278      MS_MAKE_TAG('g','u','r','u'),
279      {'R','a','a','v','i',0}},
280     {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
281      {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
282      MS_MAKE_TAG('g','u','j','r'),
283      {'S','h','r','u','t','i',0}},
284     {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
285      {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
286      MS_MAKE_TAG('g','u','j','r'),
287      {'S','h','r','u','t','i',0}},
288     {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
289      {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
290      MS_MAKE_TAG('g','u','j','r'),
291      {'S','h','r','u','t','i',0}},
292     {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
293      {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
294      MS_MAKE_TAG('o','r','y','a'),
295      {'K','a','l','i','n','g','a',0}},
296     {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
297      {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
298      MS_MAKE_TAG('o','r','y','a'),
299      {'K','a','l','i','n','g','a',0}},
300     {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
301      {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
302      MS_MAKE_TAG('t','a','m','l'),
303      {'L','a','t','h','a',0}},
304     {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
305      {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
306      MS_MAKE_TAG('t','a','m','l'),
307      {'L','a','t','h','a',0}},
308     {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
309      {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
310      MS_MAKE_TAG('t','e','l','u'),
311      {'G','a','u','t','a','m','i',0}},
312     {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
313      {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
314      MS_MAKE_TAG('t','e','l','u'),
315      {'G','a','u','t','a','m','i',0}},
316     {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
317      {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
318      MS_MAKE_TAG('k','n','d','a'),
319      {'T','u','n','g','a',0}},
320     {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
321      {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
322      MS_MAKE_TAG('k','n','d','a'),
323      {'T','u','n','g','a',0}},
324     {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
325      {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
326      MS_MAKE_TAG('m','l','y','m'),
327      {'K','a','r','t','i','k','a',0}},
328     {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
329      {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
330      MS_MAKE_TAG('m','l','y','m'),
331      {'K','a','r','t','i','k','a',0}},
332 };
333
334 static const SCRIPT_PROPERTIES *script_props[] =
335 {
336     &scriptInformation[0].props, &scriptInformation[1].props,
337     &scriptInformation[2].props, &scriptInformation[3].props,
338     &scriptInformation[4].props, &scriptInformation[5].props,
339     &scriptInformation[6].props, &scriptInformation[7].props,
340     &scriptInformation[8].props, &scriptInformation[9].props,
341     &scriptInformation[10].props, &scriptInformation[11].props,
342     &scriptInformation[12].props, &scriptInformation[13].props,
343     &scriptInformation[14].props, &scriptInformation[15].props,
344     &scriptInformation[16].props, &scriptInformation[17].props,
345     &scriptInformation[18].props, &scriptInformation[19].props,
346     &scriptInformation[20].props, &scriptInformation[21].props,
347     &scriptInformation[22].props, &scriptInformation[23].props,
348     &scriptInformation[24].props, &scriptInformation[25].props,
349     &scriptInformation[26].props, &scriptInformation[27].props,
350     &scriptInformation[28].props, &scriptInformation[29].props,
351     &scriptInformation[30].props, &scriptInformation[31].props,
352     &scriptInformation[32].props, &scriptInformation[33].props,
353     &scriptInformation[34].props, &scriptInformation[35].props,
354     &scriptInformation[36].props, &scriptInformation[37].props,
355     &scriptInformation[38].props, &scriptInformation[39].props,
356     &scriptInformation[40].props, &scriptInformation[41].props,
357     &scriptInformation[42].props, &scriptInformation[43].props
358 };
359
360 typedef struct {
361     ScriptCache *sc;
362     int numGlyphs;
363     WORD* glyphs;
364     WORD* pwLogClust;
365     int* piAdvance;
366     SCRIPT_VISATTR* psva;
367     GOFFSET* pGoffset;
368     ABC* abc;
369     int iMaxPosX;
370     HFONT fallbackFont;
371 } StringGlyphs;
372
373 typedef struct {
374     HDC hdc;
375     DWORD dwFlags;
376     BOOL invalid;
377     int clip_len;
378     int cItems;
379     int cMaxGlyphs;
380     SCRIPT_ITEM* pItem;
381     int numItems;
382     StringGlyphs* glyphs;
383     SCRIPT_LOGATTR* logattrs;
384     SIZE* sz;
385     int* logical2visual;
386 } StringAnalysis;
387
388 static inline void *heap_alloc(SIZE_T size)
389 {
390     return HeapAlloc(GetProcessHeap(), 0, size);
391 }
392
393 static inline void *heap_alloc_zero(SIZE_T size)
394 {
395     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
396 }
397
398 static inline void *heap_realloc_zero(LPVOID mem, SIZE_T size)
399 {
400     return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
401 }
402
403 static inline BOOL heap_free(LPVOID mem)
404 {
405     return HeapFree(GetProcessHeap(), 0, mem);
406 }
407
408 static inline WCHAR get_cache_default_char(SCRIPT_CACHE *psc)
409 {
410     return ((ScriptCache *)*psc)->tm.tmDefaultChar;
411 }
412
413 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
414 {
415     return ((ScriptCache *)*psc)->tm.tmHeight;
416 }
417
418 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
419 {
420     return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
421 }
422
423 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, WCHAR c)
424 {
425     WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
426
427     if (!block) return 0;
428     return block[c & GLYPH_BLOCK_MASK];
429 }
430
431 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
432 {
433     WORD **block = &((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
434
435     if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
436     return ((*block)[c & GLYPH_BLOCK_MASK] = glyph);
437 }
438
439 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
440 {
441     static const ABC nil;
442     ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
443
444     if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
445     memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
446     return TRUE;
447 }
448
449 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
450 {
451     ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
452
453     if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
454     memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
455     return TRUE;
456 }
457
458 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
459 {
460     ScriptCache *sc;
461
462     if (!psc) return E_INVALIDARG;
463     if (*psc) return S_OK;
464     if (!hdc) return E_PENDING;
465
466     if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
467     if (!GetTextMetricsW(hdc, &sc->tm))
468     {
469         heap_free(sc);
470         return E_INVALIDARG;
471     }
472     if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
473     {
474         heap_free(sc);
475         return E_INVALIDARG;
476     }
477     sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
478     *psc = sc;
479     TRACE("<- %p\n", sc);
480     return S_OK;
481 }
482
483 static WCHAR mirror_char( WCHAR ch )
484 {
485     extern const WCHAR wine_mirror_map[];
486     return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
487 }
488
489 static WORD get_char_script( WCHAR ch)
490 {
491     WORD type = 0;
492     int i;
493
494     if (ch == 0xc || ch == 0x20 || ch == 0x202f)
495         return Script_CR;
496
497     /* These chars are itemized as Punctuation by Windows */
498     if (ch == 0x2212 || ch == 0x2044 || ch == 0x00a0)
499         return Script_Punctuation;
500
501     GetStringTypeW(CT_CTYPE1, &ch, 1, &type);
502
503     if (type == 0)
504         return SCRIPT_UNDEFINED;
505
506     if (type & C1_CNTRL)
507         return Script_Control;
508
509     i = 0;
510     do
511     {
512         if (ch < scriptRanges[i].rangeFirst || scriptRanges[i].script == SCRIPT_UNDEFINED)
513             break;
514
515         if (ch >= scriptRanges[i].rangeFirst && ch <= scriptRanges[i].rangeLast)
516         {
517             if (scriptRanges[i].numericScript && type & C1_DIGIT)
518                 return scriptRanges[i].numericScript;
519             if (scriptRanges[i].punctScript && type & C1_PUNCT)
520                 return scriptRanges[i].punctScript;
521             return scriptRanges[i].script;
522         }
523         i++;
524     } while (1);
525
526     return SCRIPT_UNDEFINED;
527 }
528
529 /***********************************************************************
530  *      DllMain
531  *
532  */
533 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
534 {
535     switch(fdwReason)
536     {
537     case DLL_PROCESS_ATTACH:
538         DisableThreadLibraryCalls(hInstDLL);
539         break;
540     case DLL_PROCESS_DETACH:
541         break;
542     }
543     return TRUE;
544 }
545
546 /***********************************************************************
547  *      ScriptFreeCache (USP10.@)
548  *
549  * Free a script cache.
550  *
551  * PARAMS
552  *   psc [I/O] Script cache.
553  *
554  * RETURNS
555  *  Success: S_OK
556  *  Failure: Non-zero HRESULT value.
557  */
558 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
559 {
560     TRACE("%p\n", psc);
561
562     if (psc && *psc)
563     {
564         unsigned int i;
565         for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
566         {
567             heap_free(((ScriptCache *)*psc)->glyphs[i]);
568             heap_free(((ScriptCache *)*psc)->widths[i]);
569         }
570         heap_free(((ScriptCache *)*psc)->GSUB_Table);
571         heap_free(((ScriptCache *)*psc)->GDEF_Table);
572         heap_free(((ScriptCache *)*psc)->features);
573         heap_free(*psc);
574         *psc = NULL;
575     }
576     return S_OK;
577 }
578
579 /***********************************************************************
580  *      ScriptGetProperties (USP10.@)
581  *
582  * Retrieve a list of script properties.
583  *
584  * PARAMS
585  *  props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
586  *  num   [I] Pointer to the number of scripts.
587  *
588  * RETURNS
589  *  Success: S_OK
590  *  Failure: Non-zero HRESULT value.
591  *
592  * NOTES
593  *  Behaviour matches WinXP.
594  */
595 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
596 {
597     TRACE("(%p,%p)\n", props, num);
598
599     if (!props && !num) return E_INVALIDARG;
600
601     if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
602     if (props) *props = script_props;
603
604     return S_OK;
605 }
606
607 /***********************************************************************
608  *      ScriptGetFontProperties (USP10.@)
609  *
610  * Get information on special glyphs.
611  *
612  * PARAMS
613  *  hdc [I]   Device context.
614  *  psc [I/O] Opaque pointer to a script cache.
615  *  sfp [O]   Font properties structure.
616  */
617 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
618 {
619     HRESULT hr;
620
621     TRACE("%p,%p,%p\n", hdc, psc, sfp);
622
623     if (!sfp) return E_INVALIDARG;
624     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
625
626     if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
627         return E_INVALIDARG;
628
629     /* return something sensible? */
630     sfp->wgBlank = 0;
631     sfp->wgDefault = get_cache_default_char(psc);
632     sfp->wgInvalid = 0;
633     sfp->wgKashida = 0xffff;
634     sfp->iKashidaWidth = 0;
635
636     return S_OK;
637 }
638
639 /***********************************************************************
640  *      ScriptRecordDigitSubstitution (USP10.@)
641  *
642  *  Record digit substitution settings for a given locale.
643  *
644  *  PARAMS
645  *   locale [I] Locale identifier.
646  *   sds    [I] Structure to record substitution settings.
647  *
648  *  RETURNS
649  *   Success: S_OK
650  *   Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
651  *
652  *  SEE ALSO
653  *   http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
654  */
655 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
656 {
657     DWORD plgid, sub;
658
659     TRACE("0x%x, %p\n", locale, sds);
660
661     /* This implementation appears to be correct for all languages, but it's
662      * not clear if sds->DigitSubstitute is ever set to anything except 
663      * CONTEXT or NONE in reality */
664
665     if (!sds) return E_POINTER;
666
667     locale = ConvertDefaultLocale(locale);
668
669     if (!IsValidLocale(locale, LCID_INSTALLED))
670         return E_INVALIDARG;
671
672     plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
673     sds->TraditionalDigitLanguage = plgid;
674
675     if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
676         sds->NationalDigitLanguage = plgid;
677     else
678         sds->NationalDigitLanguage = LANG_ENGLISH;
679
680     if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
681                         (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
682
683     switch (sub)
684     {
685     case 0: 
686         if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
687             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
688         else
689             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
690         break;
691     case 1:
692         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
693         break;
694     case 2:
695         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
696         break;
697     default:
698         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
699         break;
700     }
701
702     sds->dwReserved = 0;
703     return S_OK;
704 }
705
706 /***********************************************************************
707  *      ScriptApplyDigitSubstitution (USP10.@)
708  *
709  *  Apply digit substitution settings.
710  *
711  *  PARAMS
712  *   sds [I] Structure with recorded substitution settings.
713  *   sc  [I] Script control structure.
714  *   ss  [I] Script state structure.
715  *
716  *  RETURNS
717  *   Success: S_OK
718  *   Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
719  */
720 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds, 
721                                             SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
722 {
723     SCRIPT_DIGITSUBSTITUTE psds;
724
725     TRACE("%p, %p, %p\n", sds, sc, ss);
726
727     if (!sc || !ss) return E_POINTER;
728     if (!sds)
729     {
730         sds = &psds;
731         if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
732             return E_INVALIDARG;
733     }
734
735     sc->uDefaultLanguage = LANG_ENGLISH;
736     sc->fContextDigits = 0;
737     ss->fDigitSubstitute = 0;
738
739     switch (sds->DigitSubstitute) {
740         case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
741         case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
742         case SCRIPT_DIGITSUBSTITUTE_NONE:
743         case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
744             return S_OK;
745         default:
746             return E_INVALIDARG;
747     }
748 }
749
750 /***********************************************************************
751  *      ScriptItemizeOpenType (USP10.@)
752  *
753  * Split a Unicode string into shapeable parts.
754  *
755  * PARAMS
756  *  pwcInChars  [I] String to split.
757  *  cInChars    [I] Number of characters in pwcInChars.
758  *  cMaxItems   [I] Maximum number of items to return.
759  *  psControl   [I] Pointer to a SCRIPT_CONTROL structure.
760  *  psState     [I] Pointer to a SCRIPT_STATE structure.
761  *  pItems      [O] Buffer to receive SCRIPT_ITEM structures.
762  *  pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
763  *  pcItems     [O] Number of script items returned.
764  *
765  * RETURNS
766  *  Success: S_OK
767  *  Failure: Non-zero HRESULT value.
768  */
769 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
770                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
771                              SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
772 {
773
774 #define Numeric_space 0x0020
775 #define ZWNJ 0x200C
776 #define ZWJ  0x200D
777
778     int   cnt = 0, index = 0, str = 0;
779     int   New_Script = -1;
780     WORD  *levels = NULL;
781     WORD  *strength = NULL;
782     WORD  baselevel = 0;
783
784     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
785           psControl, psState, pItems, pcItems);
786
787     if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
788         return E_INVALIDARG;
789
790     if (psState && psControl)
791     {
792         int i;
793         levels = heap_alloc_zero(cInChars * sizeof(WORD));
794         if (!levels)
795             return E_OUTOFMEMORY;
796
797         BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
798         baselevel = levels[0];
799         for (i = 0; i < cInChars; i++)
800             if (levels[i]!=levels[0])
801                 break;
802         if (i >= cInChars && !odd(baselevel))
803         {
804             heap_free(levels);
805             levels = NULL;
806         }
807         else
808         {
809             BOOL inNumber = FALSE;
810             static WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
811
812             strength = heap_alloc_zero(cInChars * sizeof(WORD));
813             if (!strength)
814             {
815                 heap_free(levels);
816                 return E_OUTOFMEMORY;
817             }
818             BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
819
820             /* Script_Numeric and select puncuation at level 0 get bumped to level 2 */
821             for (i = 0; i < cInChars; i++)
822             {
823                 if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && inNumber && strchrW(math_punc,pwcInChars[i]))
824                     levels[i] = 2;
825                 else if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && get_char_script(pwcInChars[i]) == Script_Numeric)
826                 {
827                     levels[i] = 2;
828                     inNumber = TRUE;
829                 }
830                 else
831                     inNumber = FALSE;
832             }
833             if (psControl->fMergeNeutralItems)
834             {
835                 HeapFree(GetProcessHeap(),0,strength);
836                 strength = NULL;
837             }
838         }
839     }
840
841     while ((!levels || (levels && levels[cnt+1] == levels[0])) && (pwcInChars[cnt] == Numeric_space || pwcInChars[cnt] == ZWJ || pwcInChars[cnt] == ZWNJ) && cnt < cInChars)
842         cnt++;
843
844     if (cnt == cInChars) /* All Spaces */
845     {
846         cnt = 0;
847         New_Script = get_char_script(pwcInChars[cnt]);
848     }
849
850     pItems[index].iCharPos = 0;
851     pItems[index].a = scriptInformation[get_char_script(pwcInChars[cnt])].a;
852     pScriptTags[index] = scriptInformation[get_char_script(pwcInChars[cnt])].scriptTag;
853
854     if (strength)
855         str = strength[cnt];
856
857     cnt = 0;
858     if (levels)
859     {
860         pItems[index].a.fRTL = odd(levels[cnt]);
861         pItems[index].a.fLayoutRTL = odd(levels[cnt]);
862         pItems[index].a.s.uBidiLevel = levels[cnt];
863     }
864     else if (!pItems[index].a.s.uBidiLevel)
865     {
866         pItems[index].a.s.uBidiLevel = baselevel;
867         pItems[index].a.fLayoutRTL = odd(baselevel);
868         pItems[index].a.fRTL = odd(baselevel);
869     }
870
871     TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
872           levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
873           pItems[index].iCharPos);
874
875     for (cnt=1; cnt < cInChars; cnt++)
876     {
877         if (levels && (levels[cnt] == pItems[index].a.s.uBidiLevel && (!strength || (strength[cnt] == 0 || strength[cnt] == str))))
878             continue;
879
880         if(pwcInChars[cnt] != Numeric_space && pwcInChars[cnt] != ZWJ && pwcInChars[cnt] != ZWNJ)
881             New_Script = get_char_script(pwcInChars[cnt]);
882         else if (levels)
883         {
884             int j = 1;
885             while (cnt + j < cInChars - 1 && (pwcInChars[cnt+j] == Numeric_space || pwcInChars[cnt+j] == ZWJ || pwcInChars[cnt+j] == ZWNJ) && levels[cnt] == levels[cnt+j])
886                 j++;
887             if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
888                 New_Script = get_char_script(pwcInChars[cnt+j]);
889             else
890                 New_Script = get_char_script(pwcInChars[cnt]);
891         }
892
893         if ((levels && (levels[cnt] != pItems[index].a.s.uBidiLevel || (strength && (strength[cnt] != str)))) || (New_Script != -1 && New_Script != pItems[index].a.eScript) || New_Script == Script_Control)
894         {
895             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);
896
897             if (strength && strength[cnt] != 0)
898                 str = strength[cnt];
899
900             index++;
901             if  (index+1 > cMaxItems)
902                 return E_OUTOFMEMORY;
903
904             pItems[index].iCharPos = cnt;
905             memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
906
907             pItems[index].a = scriptInformation[New_Script].a;
908             pScriptTags[index] = scriptInformation[New_Script].scriptTag;
909             if (levels)
910             {
911                 pItems[index].a.fRTL = odd(levels[cnt]);
912                 pItems[index].a.fLayoutRTL = odd(levels[cnt]);
913                 pItems[index].a.s.uBidiLevel = levels[cnt];
914             }
915             else if (!pItems[index].a.s.uBidiLevel)
916             {
917                 pItems[index].a.s.uBidiLevel = baselevel;
918                 pItems[index].a.fLayoutRTL = odd(baselevel);
919                 pItems[index].a.fRTL = odd(baselevel);
920             }
921
922             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
923         }
924     }
925
926     /* While not strictly necessary according to the spec, make sure the n+1
927      * item is set up to prevent random behaviour if the caller erroneously
928      * checks the n+1 structure                                              */
929     index++;
930     memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
931
932     TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
933
934     /*  Set one SCRIPT_STATE item being returned  */
935     if  (index + 1 > cMaxItems) return E_OUTOFMEMORY;
936     if (pcItems) *pcItems = index;
937
938     /*  Set SCRIPT_ITEM                                     */
939     pItems[index].iCharPos = cnt;         /* the last item contains the ptr to the lastchar */
940     heap_free(levels);
941     heap_free(strength);
942     return S_OK;
943 }
944
945 /***********************************************************************
946  *      ScriptItemize (USP10.@)
947  *
948  * Split a Unicode string into shapeable parts.
949  *
950  * PARAMS
951  *  pwcInChars [I] String to split.
952  *  cInChars   [I] Number of characters in pwcInChars.
953  *  cMaxItems  [I] Maximum number of items to return.
954  *  psControl  [I] Pointer to a SCRIPT_CONTROL structure.
955  *  psState    [I] Pointer to a SCRIPT_STATE structure.
956  *  pItems     [O] Buffer to receive SCRIPT_ITEM structures.
957  *  pcItems    [O] Number of script items returned.
958  *
959  * RETURNS
960  *  Success: S_OK
961  *  Failure: Non-zero HRESULT value.
962  */
963 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
964                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
965                              SCRIPT_ITEM *pItems, int *pcItems)
966 {
967     OPENTYPE_TAG *discarded_tags;
968     HRESULT res;
969
970     discarded_tags = heap_alloc(cMaxItems * sizeof(OPENTYPE_TAG));
971     if (!discarded_tags)
972         return E_OUTOFMEMORY;
973     res = ScriptItemizeOpenType(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, discarded_tags, pcItems);
974     heap_free(discarded_tags);
975     return res;
976 }
977
978 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
979 {
980     int defWidth;
981     int cTabStops=0;
982     INT *lpTabPos = NULL;
983     INT nTabOrg = 0;
984     INT x = 0;
985
986     if (pTabdef)
987         lpTabPos = pTabdef->pTabStops;
988
989     if (pTabdef && pTabdef->iTabOrigin)
990     {
991         if (pTabdef->iScale)
992             nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
993         else
994             nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
995     }
996
997     if (pTabdef)
998         cTabStops = pTabdef->cTabStops;
999
1000     if (cTabStops == 1)
1001     {
1002         if (pTabdef->iScale)
1003             defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1004         else
1005             defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1006         cTabStops = 0;
1007     }
1008     else
1009         defWidth = 8 * psc->tm.tmAveCharWidth;
1010
1011     for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1012     {
1013         int position = *lpTabPos;
1014         if (position < 0)
1015             position = -1 * position;
1016         if (pTabdef->iScale)
1017             position = (position * pTabdef->iScale) / 4;
1018         else
1019             position = position * psc->tm.tmAveCharWidth;
1020
1021         if( nTabOrg + position > current_x)
1022         {
1023             if( *lpTabPos >= 0)
1024             {
1025                 /* a left aligned tab */
1026                 x = (nTabOrg + *lpTabPos) - current_x;
1027                 break;
1028             }
1029             else
1030             {
1031                 FIXME("Negative tabstop\n");
1032                 break;
1033             }
1034         }
1035     }
1036     if ((!cTabStops) && (defWidth > 0))
1037         x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1038     else if ((!cTabStops) && (defWidth < 0))
1039         FIXME("TODO: Negative defWidth\n");
1040
1041     return x;
1042 }
1043
1044 /***********************************************************************
1045  * Helper function for ScriptStringAnalyse
1046  */
1047 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1048                               const WCHAR *pwcInChars, int cChars )
1049 {
1050     /* FIXME: When to properly fallback is still a bit of a mystery */
1051     WORD *glyphs;
1052
1053     if (psa->fNoGlyphIndex)
1054         return FALSE;
1055
1056     if (init_script_cache(hdc, psc) != S_OK)
1057         return FALSE;
1058
1059     if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1060         return TRUE;
1061
1062     glyphs = heap_alloc(sizeof(WORD) * cChars);
1063     if (!glyphs)
1064         return FALSE;
1065     if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1066     {
1067         heap_free(glyphs);
1068         return TRUE;
1069     }
1070     heap_free(glyphs);
1071
1072     return FALSE;
1073 }
1074
1075 static void find_fallback_font(DWORD scriptid, LPWSTR FaceName)
1076 {
1077     HKEY hkey;
1078
1079     if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1080     {
1081         static const WCHAR szFmt[] = {'%','x',0};
1082         WCHAR value[10];
1083         DWORD count = LF_FACESIZE * sizeof(WCHAR);
1084         DWORD type;
1085
1086         sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1087         if (RegQueryValueExW(hkey, value, 0, &type, (LPBYTE)FaceName, &count))
1088             lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1089         RegCloseKey(hkey);
1090     }
1091     else
1092         lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1093 }
1094
1095 /***********************************************************************
1096  *      ScriptStringAnalyse (USP10.@)
1097  *
1098  */
1099 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1100                                    int cGlyphs, int iCharset, DWORD dwFlags,
1101                                    int iReqWidth, SCRIPT_CONTROL *psControl,
1102                                    SCRIPT_STATE *psState, const int *piDx,
1103                                    SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1104                                    SCRIPT_STRING_ANALYSIS *pssa)
1105 {
1106     HRESULT hr = E_OUTOFMEMORY;
1107     StringAnalysis *analysis = NULL;
1108     SCRIPT_CONTROL sControl;
1109     SCRIPT_STATE sState;
1110     int i, num_items = 255;
1111     BYTE   *BidiLevel;
1112     WCHAR *iString = NULL;
1113
1114     TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1115           hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1116           psControl, psState, piDx, pTabdef, pbInClass, pssa);
1117
1118     if (iCharset != -1)
1119     {
1120         FIXME("Only Unicode strings are supported\n");
1121         return E_INVALIDARG;
1122     }
1123     if (cString < 1 || !pString) return E_INVALIDARG;
1124     if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1125
1126     if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1127     if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1128
1129     /* FIXME: handle clipping */
1130     analysis->clip_len = cString;
1131     analysis->hdc = hdc;
1132     analysis->dwFlags = dwFlags;
1133
1134     if (psState)
1135         sState = *psState;
1136     else
1137         memset(&sState, 0, sizeof(SCRIPT_STATE));
1138
1139     if (psControl)
1140         sControl = *psControl;
1141     else
1142         memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1143
1144     if (dwFlags & SSA_PASSWORD)
1145     {
1146         iString = heap_alloc(sizeof(WCHAR)*cString);
1147         if (!iString)
1148         {
1149             hr = E_OUTOFMEMORY;
1150             goto error;
1151         }
1152         for (i = 0; i < cString; i++)
1153             iString[i] = *((const WCHAR *)pString);
1154         pString = iString;
1155     }
1156
1157     hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1158                        &analysis->numItems);
1159
1160     while (hr == E_OUTOFMEMORY)
1161     {
1162         SCRIPT_ITEM *tmp;
1163
1164         num_items *= 2;
1165         if (!(tmp = heap_realloc_zero(analysis->pItem, num_items * sizeof(SCRIPT_ITEM) + 1)))
1166             goto error;
1167
1168         analysis->pItem = tmp;
1169         hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
1170                            &analysis->numItems);
1171     }
1172     if (hr != S_OK) goto error;
1173
1174     /* set back to out of memory for default goto error behaviour */
1175     hr = E_OUTOFMEMORY;
1176
1177     if (dwFlags & SSA_BREAK)
1178     {
1179         if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
1180         {
1181             for (i = 0; i < analysis->numItems; i++)
1182                 ScriptBreak(&((LPWSTR)pString)[analysis->pItem[i].iCharPos], analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos, &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
1183         }
1184         else
1185             goto error;
1186     }
1187
1188     if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
1189         goto error;
1190     if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
1191         goto error;
1192
1193     if (dwFlags & SSA_GLYPHS)
1194     {
1195         int tab_x = 0;
1196         if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
1197             goto error;
1198
1199         for (i = 0; i < analysis->numItems; i++)
1200         {
1201             SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
1202             int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1203             int numGlyphs = 1.5 * cChar + 16;
1204             WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
1205             WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
1206             int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
1207             SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
1208             GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
1209             ABC *abc = heap_alloc_zero(sizeof(ABC));
1210             int numGlyphsReturned;
1211             HFONT originalFont = 0x0;
1212
1213             /* FIXME: non unicode strings */
1214             const WCHAR* pStr = (const WCHAR*)pString;
1215             analysis->glyphs[i].fallbackFont = NULL;
1216
1217             if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
1218             {
1219                 heap_free (glyphs);
1220                 heap_free (pwLogClust);
1221                 heap_free (piAdvance);
1222                 heap_free (psva);
1223                 heap_free (pGoffset);
1224                 heap_free (abc);
1225                 hr = E_OUTOFMEMORY;
1226                 goto error;
1227             }
1228
1229             if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
1230             {
1231                 LOGFONTW lf;
1232                 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
1233                 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
1234                 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
1235                 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
1236                 if (analysis->glyphs[i].fallbackFont)
1237                 {
1238                     ScriptFreeCache(sc);
1239                     originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
1240                 }
1241             }
1242
1243             hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
1244                              cChar, numGlyphs, &analysis->pItem[i].a,
1245                              glyphs, pwLogClust, psva, &numGlyphsReturned);
1246             hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
1247                              piAdvance, pGoffset, abc);
1248             if (originalFont)
1249                 SelectObject(hdc,originalFont);
1250
1251             if (dwFlags & SSA_TAB)
1252             {
1253                 int tabi = 0;
1254                 for (tabi = 0; tabi < cChar; tabi++)
1255                 {
1256                     if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
1257                         piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
1258                     tab_x+=piAdvance[tabi];
1259                 }
1260             }
1261
1262             analysis->glyphs[i].numGlyphs = numGlyphsReturned;
1263             analysis->glyphs[i].glyphs = glyphs;
1264             analysis->glyphs[i].pwLogClust = pwLogClust;
1265             analysis->glyphs[i].piAdvance = piAdvance;
1266             analysis->glyphs[i].psva = psva;
1267             analysis->glyphs[i].pGoffset = pGoffset;
1268             analysis->glyphs[i].abc = abc;
1269             analysis->glyphs[i].iMaxPosX= -1;
1270
1271             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1272         }
1273     }
1274     else
1275     {
1276         for (i = 0; i < analysis->numItems; i++)
1277             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1278     }
1279
1280     ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
1281     heap_free(BidiLevel);
1282
1283     *pssa = analysis;
1284     heap_free(iString);
1285     return S_OK;
1286
1287 error:
1288     heap_free(iString);
1289     heap_free(analysis->glyphs);
1290     heap_free(analysis->logattrs);
1291     heap_free(analysis->pItem);
1292     heap_free(analysis->logical2visual);
1293     heap_free(analysis);
1294     return hr;
1295 }
1296
1297 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
1298 {
1299     int i;
1300
1301     if (pva[glyph].fClusterStart)
1302         return TRUE;
1303     for (i = 0; i < cChars; i++)
1304         if (pwLogClust[i] == glyph) break;
1305     if (i != cChars)
1306         return TRUE;
1307
1308     return FALSE;
1309 }
1310
1311
1312 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
1313                            int iX,
1314                            int iY,
1315                            int iItem,
1316                            int cStart,
1317                            int cEnd,
1318                            UINT uOptions,
1319                            const RECT *prc,
1320                            BOOL fSelected,
1321                            BOOL fDisabled)
1322 {
1323     StringAnalysis *analysis;
1324     int off_x = 0;
1325     HRESULT hr;
1326     COLORREF BkColor = 0x0;
1327     COLORREF TextColor = 0x0;
1328     INT BkMode = 0;
1329     INT runStart, runEnd;
1330     INT iGlyph, cGlyphs;
1331     HFONT oldFont = 0x0;
1332
1333     TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
1334          ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
1335
1336     if (!(analysis = ssa)) return E_INVALIDARG;
1337
1338     if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
1339          (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
1340             return S_OK;
1341
1342     if (fSelected)
1343     {
1344         BkMode = GetBkMode(analysis->hdc);
1345         SetBkMode( analysis->hdc, OPAQUE);
1346         BkColor = GetBkColor(analysis->hdc);
1347         SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
1348         if (!fDisabled)
1349         {
1350             TextColor = GetTextColor(analysis->hdc);
1351             SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1352         }
1353     }
1354     if (analysis->glyphs[iItem].fallbackFont)
1355         oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
1356
1357     if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
1358         runStart = cStart - analysis->pItem[iItem].iCharPos;
1359     else
1360         runStart =  0;
1361     if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
1362         runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
1363     else
1364         runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
1365
1366     if (analysis->pItem[iItem].a.fRTL)
1367     {
1368         if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
1369             ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
1370         else
1371             ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
1372     }
1373     else
1374     {
1375         if (cStart >=0 && runStart)
1376             ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
1377         else
1378             ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
1379     }
1380
1381     if (analysis->pItem[iItem].a.fRTL)
1382         iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
1383     else
1384         iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
1385
1386     if (analysis->pItem[iItem].a.fRTL)
1387         cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
1388     else
1389         cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
1390
1391     cGlyphs++;
1392
1393     if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
1394     {
1395         INT direction;
1396         INT clust_glyph;
1397
1398         clust_glyph = iGlyph + cGlyphs;
1399         if (analysis->pItem[iItem].a.fRTL)
1400             direction = -1;
1401         else
1402             direction = 1;
1403
1404         while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
1405               !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
1406         {
1407             cGlyphs++;
1408             clust_glyph++;
1409         }
1410     }
1411
1412     hr = ScriptTextOut(analysis->hdc,
1413                        (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
1414                        iY, uOptions, prc, &analysis->pItem[iItem].a, NULL, 0,
1415                        &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
1416                        &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
1417                        &analysis->glyphs[iItem].pGoffset[iGlyph]);
1418
1419     TRACE("ScriptTextOut hr=%08x\n", hr);
1420
1421     if (fSelected)
1422     {
1423         SetBkColor(analysis->hdc, BkColor);
1424         SetBkMode( analysis->hdc, BkMode);
1425         if (!fDisabled)
1426             SetTextColor(analysis->hdc, TextColor);
1427     }
1428     if (analysis->glyphs[iItem].fallbackFont)
1429         SelectObject(analysis->hdc, oldFont);
1430
1431     return hr;
1432 }
1433
1434 /***********************************************************************
1435  *      ScriptStringOut (USP10.@)
1436  *
1437  * This function takes the output of ScriptStringAnalyse and joins the segments
1438  * of glyphs and passes the resulting string to ScriptTextOut.  ScriptStringOut
1439  * only processes glyphs.
1440  *
1441  * Parameters:
1442  *  ssa       [I] buffer to hold the analysed string components
1443  *  iX        [I] X axis displacement for output
1444  *  iY        [I] Y axis displacement for output
1445  *  uOptions  [I] flags controling output processing
1446  *  prc       [I] rectangle coordinates
1447  *  iMinSel   [I] starting pos for substringing output string
1448  *  iMaxSel   [I] ending pos for substringing output string
1449  *  fDisabled [I] controls text highlighting
1450  *
1451  *  RETURNS
1452  *   Success: S_OK
1453  *   Failure: is the value returned by ScriptTextOut
1454  */
1455 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
1456                                int iX,
1457                                int iY, 
1458                                UINT uOptions, 
1459                                const RECT *prc, 
1460                                int iMinSel, 
1461                                int iMaxSel,
1462                                BOOL fDisabled)
1463 {
1464     StringAnalysis *analysis;
1465     int   item;
1466     HRESULT hr;
1467
1468     TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
1469          ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
1470
1471     if (!(analysis = ssa)) return E_INVALIDARG;
1472     if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
1473
1474     for (item = 0; item < analysis->numItems; item++)
1475     {
1476         hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
1477         if (FAILED(hr))
1478             return hr;
1479     }
1480
1481     if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
1482     {
1483         if (iMaxSel > 0 &&  iMinSel < 0)
1484             iMinSel = 0;
1485         for (item = 0; item < analysis->numItems; item++)
1486         {
1487             hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
1488             if (FAILED(hr))
1489                 return hr;
1490         }
1491     }
1492
1493     return S_OK;
1494 }
1495
1496 /***********************************************************************
1497  *      ScriptStringCPtoX (USP10.@)
1498  *
1499  */
1500 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
1501 {
1502     int item;
1503     int runningX = 0;
1504     StringAnalysis* analysis = ssa;
1505
1506     TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
1507
1508     if (!ssa || !pX) return S_FALSE;
1509     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1510
1511     /* icp out of range */
1512     if(icp < 0)
1513     {
1514         analysis->invalid = TRUE;
1515         return E_INVALIDARG;
1516     }
1517
1518     for(item=0; item<analysis->numItems; item++)
1519     {
1520         int CP, i;
1521         int offset;
1522
1523         i = analysis->logical2visual[item];
1524         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1525         /* initialize max extents for uninitialized runs */
1526         if (analysis->glyphs[i].iMaxPosX == -1)
1527         {
1528             if (analysis->pItem[i].a.fRTL)
1529                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1530                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1531                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1532             else
1533                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1534                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1535                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1536         }
1537
1538         if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
1539         {
1540             runningX += analysis->glyphs[i].iMaxPosX;
1541             continue;
1542         }
1543
1544         icp -= analysis->pItem[i].iCharPos;
1545         ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1546                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1547                     &analysis->pItem[i].a, &offset);
1548         runningX += offset;
1549
1550         *pX = runningX;
1551         return S_OK;
1552     }
1553
1554     /* icp out of range */
1555     analysis->invalid = TRUE;
1556     return E_INVALIDARG;
1557 }
1558
1559 /***********************************************************************
1560  *      ScriptStringXtoCP (USP10.@)
1561  *
1562  */
1563 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
1564 {
1565     StringAnalysis* analysis = ssa;
1566     int item;
1567
1568     TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
1569
1570     if (!ssa || !piCh || !piTrailing) return S_FALSE;
1571     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1572
1573     /* out of range */
1574     if(iX < 0)
1575     {
1576         if (analysis->pItem[0].a.fRTL)
1577         {
1578             *piCh = 1;
1579             *piTrailing = FALSE;
1580         }
1581         else
1582         {
1583             *piCh = -1;
1584             *piTrailing = TRUE;
1585         }
1586         return S_OK;
1587     }
1588
1589     for(item=0; item<analysis->numItems; item++)
1590     {
1591         int i;
1592         int CP;
1593
1594         for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
1595         /* nothing */;
1596
1597         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1598         /* initialize max extents for uninitialized runs */
1599         if (analysis->glyphs[i].iMaxPosX == -1)
1600         {
1601             if (analysis->pItem[i].a.fRTL)
1602                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1603                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1604                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1605             else
1606                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1607                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1608                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1609         }
1610
1611         if (iX > analysis->glyphs[i].iMaxPosX)
1612         {
1613             iX -= analysis->glyphs[i].iMaxPosX;
1614             continue;
1615         }
1616
1617         ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1618                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1619                     &analysis->pItem[i].a, piCh, piTrailing);
1620         *piCh += analysis->pItem[i].iCharPos;
1621
1622         return S_OK;
1623     }
1624
1625     /* out of range */
1626     *piCh = analysis->pItem[analysis->numItems].iCharPos;
1627     *piTrailing = FALSE;
1628
1629     return S_OK;
1630 }
1631
1632
1633 /***********************************************************************
1634  *      ScriptStringFree (USP10.@)
1635  *
1636  * Free a string analysis.
1637  *
1638  * PARAMS
1639  *  pssa [I] string analysis.
1640  *
1641  * RETURNS
1642  *  Success: S_OK
1643  *  Failure: Non-zero HRESULT value.
1644  */
1645 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
1646 {
1647     StringAnalysis* analysis;
1648     BOOL invalid;
1649     int i;
1650
1651     TRACE("(%p)\n", pssa);
1652
1653     if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
1654
1655     invalid = analysis->invalid;
1656
1657     if (analysis->glyphs)
1658     {
1659         for (i = 0; i < analysis->numItems; i++)
1660         {
1661             heap_free(analysis->glyphs[i].glyphs);
1662             heap_free(analysis->glyphs[i].pwLogClust);
1663             heap_free(analysis->glyphs[i].piAdvance);
1664             heap_free(analysis->glyphs[i].psva);
1665             heap_free(analysis->glyphs[i].pGoffset);
1666             heap_free(analysis->glyphs[i].abc);
1667             if (analysis->glyphs[i].fallbackFont)
1668                 DeleteObject(analysis->glyphs[i].fallbackFont);
1669             ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
1670             heap_free(analysis->glyphs[i].sc);
1671         }
1672         heap_free(analysis->glyphs);
1673     }
1674
1675     heap_free(analysis->pItem);
1676     heap_free(analysis->logattrs);
1677     heap_free(analysis->sz);
1678     heap_free(analysis->logical2visual);
1679     heap_free(analysis);
1680
1681     if (invalid) return E_INVALIDARG;
1682     return S_OK;
1683 }
1684
1685 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
1686                                    int direction, int* iCluster, int *check_out)
1687 {
1688     int clust_size = 1;
1689     int check;
1690     WORD clust = pwLogClust[item];
1691
1692     for (check = item+direction; check < cChars && check >= 0; check+=direction)
1693     {
1694         if (pwLogClust[check] == clust)
1695         {
1696             clust_size ++;
1697             if (iCluster && *iCluster == -1)
1698                 *iCluster = item;
1699         }
1700         else break;
1701     }
1702
1703     if (check_out)
1704         *check_out = check;
1705
1706     return clust_size;
1707 }
1708
1709 static inline int get_glyph_cluster_advance(const int* piAdvance, const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cGlyphs, int cChars, int glyph, int direction)
1710 {
1711     int advance;
1712     int log_clust_max = 0;
1713     int i;
1714
1715     advance = piAdvance[glyph];
1716
1717     for (i = 0; i < cChars; i++)
1718     {
1719         if (pwLogClust[i] > log_clust_max)
1720             log_clust_max = pwLogClust[i];
1721     }
1722
1723     if (glyph > log_clust_max)
1724         return advance;
1725
1726     for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
1727     {
1728
1729         if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
1730             break;
1731         if (glyph > log_clust_max)
1732             break;
1733         advance += piAdvance[glyph];
1734     }
1735
1736     return advance;
1737 }
1738
1739 /***********************************************************************
1740  *      ScriptCPtoX (USP10.@)
1741  *
1742  */
1743 HRESULT WINAPI ScriptCPtoX(int iCP,
1744                            BOOL fTrailing,
1745                            int cChars,
1746                            int cGlyphs,
1747                            const WORD *pwLogClust,
1748                            const SCRIPT_VISATTR *psva,
1749                            const int *piAdvance,
1750                            const SCRIPT_ANALYSIS *psa,
1751                            int *piX)
1752 {
1753     int item;
1754     float iPosX;
1755     int iSpecial = -1;
1756     int iCluster = -1;
1757     int clust_size = 1;
1758     float special_size = 0.0;
1759     int iMaxPos = 0;
1760     int advance = 0;
1761     BOOL rtl = FALSE;
1762
1763     TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
1764           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1765           psa, piX);
1766
1767     if (psa->fRTL && ! psa->fLogicalOrder)
1768         rtl = TRUE;
1769
1770     if (fTrailing)
1771         iCP++;
1772
1773     if (rtl)
1774     {
1775         int max_clust = pwLogClust[0];
1776
1777         for (item=0; item < cGlyphs; item++)
1778             if (pwLogClust[item] > max_clust)
1779             {
1780                 ERR("We do not handle non reversed clusters properly\n");
1781                 break;
1782             }
1783
1784         iMaxPos = 0;
1785         for (item = max_clust; item >=0; item --)
1786             iMaxPos += piAdvance[item];
1787     }
1788
1789     iPosX = 0.0;
1790     for (item=0; item < iCP && item < cChars; item++)
1791     {
1792         if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
1793         {
1794             int check;
1795             int clust = pwLogClust[item];
1796
1797             iCluster = -1;
1798             clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
1799                                           &check);
1800
1801             advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
1802
1803             if (check >= cChars && !iMaxPos)
1804             {
1805                 for (check = clust; check < cChars; check++)
1806                     special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, 1);
1807                 iSpecial = item;
1808                 special_size /= (cChars - item);
1809                 iPosX += special_size;
1810             }
1811             else
1812             {
1813                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1814                 {
1815                     clust_size --;
1816                     if (clust_size == 0)
1817                         iPosX += advance;
1818                 }
1819                 else
1820                     iPosX += advance / (float)clust_size;
1821             }
1822         }
1823         else if (iSpecial != -1)
1824             iPosX += special_size;
1825         else /* (iCluster != -1) */
1826         {
1827             int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
1828             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1829             {
1830                 clust_size --;
1831                 if (clust_size == 0)
1832                     iPosX += adv;
1833             }
1834             else
1835                 iPosX += adv / (float)clust_size;
1836         }
1837     }
1838
1839     if (iMaxPos > 0)
1840     {
1841         iPosX = iMaxPos - iPosX;
1842         if (iPosX < 0)
1843             iPosX = 0;
1844     }
1845
1846     *piX = iPosX;
1847     TRACE("*piX=%d\n", *piX);
1848     return S_OK;
1849 }
1850
1851 /***********************************************************************
1852  *      ScriptXtoCP (USP10.@)
1853  *
1854  */
1855 HRESULT WINAPI ScriptXtoCP(int iX,
1856                            int cChars,
1857                            int cGlyphs,
1858                            const WORD *pwLogClust,
1859                            const SCRIPT_VISATTR *psva,
1860                            const int *piAdvance,
1861                            const SCRIPT_ANALYSIS *psa,
1862                            int *piCP,
1863                            int *piTrailing)
1864 {
1865     int item;
1866     float iPosX;
1867     float iLastPosX;
1868     int iSpecial = -1;
1869     int iCluster = -1;
1870     int clust_size = 1;
1871     int cjump = 0;
1872     int advance;
1873     float special_size = 0.0;
1874     int direction = 1;
1875
1876     TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
1877           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1878           psa, piCP, piTrailing);
1879
1880     if (psa->fRTL && ! psa->fLogicalOrder)
1881         direction = -1;
1882
1883     if (direction<0)
1884     {
1885         int max_clust = pwLogClust[0];
1886
1887         if (iX < 0)
1888         {
1889             *piCP = cChars;
1890             *piTrailing = 0;
1891             return S_OK;
1892         }
1893
1894         for (item=0; item < cChars; item++)
1895             if (pwLogClust[item] > max_clust)
1896             {
1897                 ERR("We do not handle non reversed clusters properly\n");
1898                 break;
1899             }
1900     }
1901
1902     if (iX < 0)
1903     {
1904         *piCP = -1;
1905         *piTrailing = 1;
1906         return S_OK;
1907     }
1908
1909     iPosX = iLastPosX = 0;
1910     if (direction > 0)
1911         item = 0;
1912     else
1913         item = cChars - 1;
1914     for (; iPosX <= iX && item < cChars && item >= 0; item+=direction)
1915     {
1916         iLastPosX = iPosX;
1917         if (iSpecial == -1 &&
1918              (iCluster == -1 ||
1919               (iCluster != -1 &&
1920                  ((direction > 0 && iCluster+clust_size <= item) ||
1921                   (direction < 0 && iCluster-clust_size >= item))
1922               )
1923              )
1924             )
1925         {
1926             int check;
1927             int clust = pwLogClust[item];
1928
1929             iCluster = -1;
1930             cjump = 0;
1931             clust_size = get_cluster_size(pwLogClust, cChars, item, direction,
1932                                           &iCluster, &check);
1933             advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, direction);
1934
1935             if (check >= cChars && direction > 0)
1936             {
1937                 for (check = clust; check < cChars; check++)
1938                     special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, direction);
1939                 iSpecial = item;
1940                 special_size /= (cChars - item);
1941                 iPosX += special_size;
1942             }
1943             else
1944             {
1945                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1946                 {
1947                     if (!cjump)
1948                         iPosX += advance;
1949                     cjump++;
1950                 }
1951                 else
1952                     iPosX += advance / (float)clust_size;
1953             }
1954         }
1955         else if (iSpecial != -1)
1956             iPosX += special_size;
1957         else /* (iCluster != -1) */
1958         {
1959             int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], direction);
1960             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1961             {
1962                 if (!cjump)
1963                     iPosX += adv;
1964                 cjump++;
1965             }
1966             else
1967                 iPosX += adv / (float)clust_size;
1968         }
1969     }
1970
1971     if (direction > 0)
1972     {
1973         if (iPosX > iX)
1974             item--;
1975         if (item < cChars && ((iPosX - iLastPosX) / 2.0) + iX >= iPosX)
1976         {
1977             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
1978                 item+=(clust_size-1);
1979             *piTrailing = 1;
1980         }
1981         else
1982             *piTrailing = 0;
1983     }
1984     else
1985     {
1986         if (iX == iLastPosX)
1987             item++;
1988         if (iX >= iLastPosX && iX <= iPosX)
1989             item++;
1990
1991         if (iLastPosX == iX)
1992             *piTrailing = 0;
1993         else if (item < 0 || ((iLastPosX - iPosX) / 2.0) + iX <= iLastPosX)
1994         {
1995             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
1996                 item-=(clust_size-1);
1997             *piTrailing = 1;
1998         }
1999         else
2000             *piTrailing = 0;
2001     }
2002
2003     *piCP = item;
2004
2005     TRACE("*piCP=%d\n", *piCP);
2006     TRACE("*piTrailing=%d\n", *piTrailing);
2007     return S_OK;
2008 }
2009
2010 /***********************************************************************
2011  *      ScriptBreak (USP10.@)
2012  *
2013  *  Retrieve line break information.
2014  *
2015  *  PARAMS
2016  *   chars [I] Array of characters.
2017  *   sa    [I] String analysis.
2018  *   la    [I] Array of logical attribute structures.
2019  *
2020  *  RETURNS
2021  *   Success: S_OK
2022  *   Failure: S_FALSE
2023  */
2024 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2025 {
2026     TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2027
2028     if (!la) return S_FALSE;
2029
2030     BREAK_line(chars, count, sa, la);
2031
2032     return S_OK;
2033 }
2034
2035 /***********************************************************************
2036  *      ScriptIsComplex (USP10.@)
2037  *
2038  *  Determine if a string is complex.
2039  *
2040  *  PARAMS
2041  *   chars [I] Array of characters to test.
2042  *   len   [I] Length in characters.
2043  *   flag  [I] Flag.
2044  *
2045  *  RETURNS
2046  *   Success: S_OK
2047  *   Failure: S_FALSE
2048  *
2049  */
2050 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
2051 {
2052     int i;
2053
2054     TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
2055
2056     for (i = 0; i < len; i++)
2057     {
2058         int script;
2059
2060         if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
2061             return S_OK;
2062
2063         script = get_char_script(chars[i]);
2064         if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
2065             (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
2066             return S_OK;
2067     }
2068     return S_FALSE;
2069 }
2070
2071 /***********************************************************************
2072  *      ScriptShapeOpenType (USP10.@)
2073  *
2074  * Produce glyphs and visual attributes for a run.
2075  *
2076  * PARAMS
2077  *  hdc         [I]   Device context.
2078  *  psc         [I/O] Opaque pointer to a script cache.
2079  *  psa         [I/O] Script analysis.
2080  *  tagScript   [I]   The OpenType tag for the Script
2081  *  tagLangSys  [I]   The OpenType tag for the Language
2082  *  rcRangeChars[I]   Array of Character counts in each range
2083  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2084  *  cRanges     [I]   Count of ranges
2085  *  pwcChars    [I]   Array of characters specifying the run.
2086  *  cChars      [I]   Number of characters in pwcChars.
2087  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
2088  *  pwLogClust  [O]   Array of logical cluster info.
2089  *  pCharProps  [O]   Array of character property values
2090  *  pwOutGlyphs [O]   Array of glyphs.
2091  *  pOutGlyphProps [O]  Array of attributes for the retrieved glyphs
2092  *  pcGlyphs    [O]   Number of glyphs returned.
2093  *
2094  * RETURNS
2095  *  Success: S_OK
2096  *  Failure: Non-zero HRESULT value.
2097  */
2098 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
2099                                     SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2100                                     OPENTYPE_TAG tagLangSys, int *rcRangeChars,
2101                                     TEXTRANGE_PROPERTIES **rpRangeProperties,
2102                                     int cRanges, const WCHAR *pwcChars, int cChars,
2103                                     int cMaxGlyphs, WORD *pwLogClust,
2104                                     SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
2105                                     SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
2106 {
2107     HRESULT hr;
2108     unsigned int i;
2109     BOOL rtl;
2110
2111     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
2112      hdc, psc, psa,
2113      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2114      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2115      cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
2116
2117     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
2118                    psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
2119
2120     if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
2121     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2122
2123     if (cRanges)
2124         FIXME("Ranges not supported yet\n");
2125
2126     rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
2127
2128     *pcGlyphs = cChars;
2129     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2130     if (!pwLogClust) return E_FAIL;
2131
2132     ((ScriptCache *)*psc)->userScript = tagScript;
2133     ((ScriptCache *)*psc)->userLang = tagLangSys;
2134
2135     /* set fNoGlyphIndex non truetype/opentype fonts */
2136     if (!psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
2137         psa->fNoGlyphIndex = TRUE;
2138
2139     /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
2140     for (i = 0; i < cChars; i++)
2141     {
2142         int idx = i;
2143         if (rtl) idx = cChars - 1 - i;
2144         /* FIXME: set to better values */
2145         pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
2146         pOutGlyphProps[i].sva.fClusterStart  = 1;
2147         pOutGlyphProps[i].sva.fDiacritic     = 0;
2148         pOutGlyphProps[i].sva.fZeroWidth     = 0;
2149         pOutGlyphProps[i].sva.fReserved      = 0;
2150         pOutGlyphProps[i].sva.fShapeReserved = 0;
2151
2152         /* FIXME: have the shaping engine set this */
2153         pCharProps[i].fCanGlyphAlone = 0;
2154
2155         pwLogClust[i] = idx;
2156     }
2157
2158     if (psa && !psa->fNoGlyphIndex)
2159     {
2160         WCHAR *rChars;
2161         if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
2162
2163         rChars = heap_alloc(sizeof(WCHAR) * cChars);
2164         if (!rChars) return E_OUTOFMEMORY;
2165         for (i = 0; i < cChars; i++)
2166         {
2167             int idx = i;
2168             WCHAR chInput;
2169             if (rtl) idx = cChars - 1 - i;
2170             if (psa->fRTL)
2171                 chInput = mirror_char(pwcChars[idx]);
2172             else
2173                 chInput = pwcChars[idx];
2174             /* special case for tabs */
2175             if (chInput == 0x0009)
2176                 chInput = 0x0020;
2177             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, chInput)))
2178             {
2179                 WORD glyph;
2180                 if (!hdc) return E_PENDING;
2181                 if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR) return S_FALSE;
2182                 pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph);
2183             }
2184             rChars[i] = chInput;
2185         }
2186
2187         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2188         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
2189         SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
2190         heap_free(rChars);
2191     }
2192     else
2193     {
2194         TRACE("no glyph translation\n");
2195         for (i = 0; i < cChars; i++)
2196         {
2197             int idx = i;
2198             /* No mirroring done here */
2199             if (rtl) idx = cChars - 1 - i;
2200             pwOutGlyphs[i] = pwcChars[idx];
2201         }
2202     }
2203
2204     return S_OK;
2205 }
2206
2207
2208 /***********************************************************************
2209  *      ScriptShape (USP10.@)
2210  *
2211  * Produce glyphs and visual attributes for a run.
2212  *
2213  * PARAMS
2214  *  hdc         [I]   Device context.
2215  *  psc         [I/O] Opaque pointer to a script cache.
2216  *  pwcChars    [I]   Array of characters specifying the run.
2217  *  cChars      [I]   Number of characters in pwcChars.
2218  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
2219  *  psa         [I/O] Script analysis.
2220  *  pwOutGlyphs [O]   Array of glyphs.
2221  *  pwLogClust  [O]   Array of logical cluster info.
2222  *  psva        [O]   Array of visual attributes.
2223  *  pcGlyphs    [O]   Number of glyphs returned.
2224  *
2225  * RETURNS
2226  *  Success: S_OK
2227  *  Failure: Non-zero HRESULT value.
2228  */
2229 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
2230                            int cChars, int cMaxGlyphs,
2231                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
2232                            SCRIPT_VISATTR *psva, int *pcGlyphs)
2233 {
2234     HRESULT hr;
2235     int i;
2236     SCRIPT_CHARPROP *charProps;
2237     SCRIPT_GLYPHPROP *glyphProps;
2238
2239     if (!psva || !pcGlyphs) return E_INVALIDARG;
2240     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2241
2242     charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
2243     if (!charProps) return E_OUTOFMEMORY;
2244     glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
2245     if (!glyphProps) return E_OUTOFMEMORY;
2246
2247     hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
2248
2249     if (SUCCEEDED(hr))
2250     {
2251         for (i = 0; i < *pcGlyphs; i++)
2252             psva[i] = glyphProps[i].sva;
2253     }
2254
2255     heap_free(charProps);
2256     heap_free(glyphProps);
2257
2258     return hr;
2259 }
2260
2261 /***********************************************************************
2262  *      ScriptPlaceOpenType (USP10.@)
2263  *
2264  * Produce advance widths for a run.
2265  *
2266  * PARAMS
2267  *  hdc       [I]   Device context.
2268  *  psc       [I/O] Opaque pointer to a script cache.
2269  *  psa       [I/O] String analysis.
2270  *  tagScript   [I]   The OpenType tag for the Script
2271  *  tagLangSys  [I]   The OpenType tag for the Language
2272  *  rcRangeChars[I]   Array of Character counts in each range
2273  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2274  *  cRanges     [I]   Count of ranges
2275  *  pwcChars    [I]   Array of characters specifying the run.
2276  *  pwLogClust  [I]   Array of logical cluster info
2277  *  pCharProps  [I]   Array of character property values
2278  *  cChars      [I]   Number of characters in pwcChars.
2279  *  pwGlyphs  [I]   Array of glyphs.
2280  *  pGlyphProps [I]  Array of attributes for the retrieved glyphs
2281  *  cGlyphs [I] Count of Glyphs
2282  *  piAdvance [O]   Array of advance widths.
2283  *  pGoffset  [O]   Glyph offsets.
2284  *  pABC      [O]   Combined ABC width.
2285  *
2286  * RETURNS
2287  *  Success: S_OK
2288  *  Failure: Non-zero HRESULT value.
2289  */
2290
2291 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
2292                                     OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
2293                                     int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
2294                                     int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
2295                                     SCRIPT_CHARPROP *pCharProps, int cChars,
2296                                     const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
2297                                     int cGlyphs, int *piAdvance,
2298                                     GOFFSET *pGoffset, ABC *pABC
2299 )
2300 {
2301     HRESULT hr;
2302     int i;
2303
2304     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
2305      hdc, psc, psa,
2306      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2307      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2308      pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
2309      pGoffset, pABC);
2310
2311     if (!pGlyphProps) return E_INVALIDARG;
2312     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2313     if (!pGoffset) return E_FAIL;
2314
2315     if (cRanges)
2316         FIXME("Ranges not supported yet\n");
2317
2318     ((ScriptCache *)*psc)->userScript = tagScript;
2319     ((ScriptCache *)*psc)->userLang = tagLangSys;
2320
2321     if (pABC) memset(pABC, 0, sizeof(ABC));
2322     for (i = 0; i < cGlyphs; i++)
2323     {
2324         ABC abc;
2325         if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
2326         {
2327             if (!hdc) return E_PENDING;
2328             if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
2329             {
2330                 if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
2331             }
2332             else
2333             {
2334                 INT width;
2335                 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
2336                 abc.abcB = width;
2337                 abc.abcA = abc.abcC = 0;
2338             }
2339             set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
2340         }
2341         if (pABC)
2342         {
2343             pABC->abcA += abc.abcA;
2344             pABC->abcB += abc.abcB;
2345             pABC->abcC += abc.abcC;
2346         }
2347         /* FIXME: set to more reasonable values */
2348         pGoffset[i].du = pGoffset[i].dv = 0;
2349         if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
2350     }
2351
2352     if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
2353     return S_OK;
2354 }
2355
2356 /***********************************************************************
2357  *      ScriptPlace (USP10.@)
2358  *
2359  * Produce advance widths for a run.
2360  *
2361  * PARAMS
2362  *  hdc       [I]   Device context.
2363  *  psc       [I/O] Opaque pointer to a script cache.
2364  *  pwGlyphs  [I]   Array of glyphs.
2365  *  cGlyphs   [I]   Number of glyphs in pwGlyphs.
2366  *  psva      [I]   Array of visual attributes.
2367  *  psa       [I/O] String analysis.
2368  *  piAdvance [O]   Array of advance widths.
2369  *  pGoffset  [O]   Glyph offsets.
2370  *  pABC      [O]   Combined ABC width.
2371  *
2372  * RETURNS
2373  *  Success: S_OK
2374  *  Failure: Non-zero HRESULT value.
2375  */
2376 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
2377                            int cGlyphs, const SCRIPT_VISATTR *psva,
2378                            SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
2379 {
2380     HRESULT hr;
2381     SCRIPT_GLYPHPROP *glyphProps;
2382     int i;
2383
2384     TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n",  hdc, psc, pwGlyphs, cGlyphs, psva, psa,
2385           piAdvance, pGoffset, pABC);
2386
2387     if (!psva) return E_INVALIDARG;
2388     if (!pGoffset) return E_FAIL;
2389
2390     glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
2391     if (!glyphProps) return E_OUTOFMEMORY;
2392
2393     for (i = 0; i < cGlyphs; i++)
2394         glyphProps[i].sva = psva[i];
2395
2396     hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
2397
2398     heap_free(glyphProps);
2399
2400     return hr;
2401 }
2402
2403 /***********************************************************************
2404  *      ScriptGetCMap (USP10.@)
2405  *
2406  * Retrieve glyph indices.
2407  *
2408  * PARAMS
2409  *  hdc         [I]   Device context.
2410  *  psc         [I/O] Opaque pointer to a script cache.
2411  *  pwcInChars  [I]   Array of Unicode characters.
2412  *  cChars      [I]   Number of characters in pwcInChars.
2413  *  dwFlags     [I]   Flags.
2414  *  pwOutGlyphs [O]   Buffer to receive the array of glyph indices.
2415  *
2416  * RETURNS
2417  *  Success: S_OK
2418  *  Failure: Non-zero HRESULT value.
2419  */
2420 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
2421                              int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
2422 {
2423     HRESULT hr;
2424     int i;
2425
2426     TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
2427           cChars, dwFlags, pwOutGlyphs);
2428
2429     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2430
2431     hr = S_OK;
2432
2433     if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2434     {
2435         for (i = 0; i < cChars; i++)
2436         {
2437             WCHAR inChar;
2438             if (dwFlags == SGCM_RTL)
2439                 inChar = mirror_char(pwcInChars[i]);
2440             else
2441                 inChar = pwcInChars[i];
2442             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
2443             {
2444                 WORD glyph;
2445                 if (!hdc) return E_PENDING;
2446                 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
2447                 if (glyph == 0xffff)
2448                 {
2449                     hr = S_FALSE;
2450                     glyph = 0x0;
2451                 }
2452                 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
2453             }
2454         }
2455     }
2456     else
2457     {
2458         TRACE("no glyph translation\n");
2459         for (i = 0; i < cChars; i++)
2460         {
2461             WCHAR inChar;
2462             if (dwFlags == SGCM_RTL)
2463                 inChar = mirror_char(pwcInChars[i]);
2464             else
2465                 inChar = pwcInChars[i];
2466             pwOutGlyphs[i] = inChar;
2467         }
2468     }
2469     return hr;
2470 }
2471
2472 /***********************************************************************
2473  *      ScriptTextOut (USP10.@)
2474  *
2475  */
2476 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
2477                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
2478                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
2479                              const int *piJustify, const GOFFSET *pGoffset)
2480 {
2481     HRESULT hr = S_OK;
2482
2483     TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
2484          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
2485          piAdvance, piJustify, pGoffset);
2486
2487     if (!hdc || !psc) return E_INVALIDARG;
2488     if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
2489
2490     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
2491     fuOptions |= ETO_IGNORELANGUAGE;
2492     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
2493         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do translation to glyph */
2494
2495     if (psa->fRTL && psa->fLogicalOrder)
2496     {
2497         int i;
2498         WORD *rtlGlyphs;
2499
2500         rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD));
2501         if (!rtlGlyphs)
2502             return E_OUTOFMEMORY;
2503
2504         for (i = 0; i < cGlyphs; i++)
2505             rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i];
2506
2507         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL))
2508             hr = S_FALSE;
2509         heap_free(rtlGlyphs);
2510     }
2511     else
2512         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
2513             hr = S_FALSE;
2514
2515     return hr;
2516 }
2517
2518 /***********************************************************************
2519  *      ScriptCacheGetHeight (USP10.@)
2520  *
2521  * Retrieve the height of the font in the cache.
2522  *
2523  * PARAMS
2524  *  hdc    [I]    Device context.
2525  *  psc    [I/O]  Opaque pointer to a script cache.
2526  *  height [O]    Receives font height.
2527  *
2528  * RETURNS
2529  *  Success: S_OK
2530  *  Failure: Non-zero HRESULT value.
2531  */
2532 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
2533 {
2534     HRESULT hr;
2535
2536     TRACE("(%p, %p, %p)\n", hdc, psc, height);
2537
2538     if (!height) return E_INVALIDARG;
2539     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2540
2541     *height = get_cache_height(psc);
2542     return S_OK;
2543 }
2544
2545 /***********************************************************************
2546  *      ScriptGetGlyphABCWidth (USP10.@)
2547  *
2548  * Retrieve the width of a glyph.
2549  *
2550  * PARAMS
2551  *  hdc    [I]    Device context.
2552  *  psc    [I/O]  Opaque pointer to a script cache.
2553  *  glyph  [I]    Glyph to retrieve the width for.
2554  *  abc    [O]    ABC widths of the glyph.
2555  *
2556  * RETURNS
2557  *  Success: S_OK
2558  *  Failure: Non-zero HRESULT value.
2559  */
2560 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
2561 {
2562     HRESULT hr;
2563
2564     TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
2565
2566     if (!abc) return E_INVALIDARG;
2567     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2568
2569     if (!get_cache_glyph_widths(psc, glyph, abc))
2570     {
2571         if (!hdc) return E_PENDING;
2572         if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2573         {
2574             if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
2575         }
2576         else
2577         {
2578             INT width;
2579             if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
2580             abc->abcB = width;
2581             abc->abcA = abc->abcC = 0;
2582         }
2583         set_cache_glyph_widths(psc, glyph, abc);
2584     }
2585     return S_OK;
2586 }
2587
2588 /***********************************************************************
2589  *      ScriptLayout (USP10.@)
2590  *
2591  * Map embedding levels to visual and/or logical order.
2592  *
2593  * PARAMS
2594  *  runs     [I] Size of level array.
2595  *  level    [I] Array of embedding levels.
2596  *  vistolog [O] Map of embedding levels from visual to logical order.
2597  *  logtovis [O] Map of embedding levels from logical to visual order.
2598  *
2599  * RETURNS
2600  *  Success: S_OK
2601  *  Failure: Non-zero HRESULT value.
2602  *
2603  * BUGS
2604  *  This stub works correctly for any sequence of a single
2605  *  embedding level but not for sequences of different
2606  *  embedding levels, i.e. mixtures of RTL and LTR scripts.
2607  */
2608 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
2609 {
2610     int* indexs;
2611     int ich;
2612
2613     TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
2614
2615     if (!level || (!vistolog && !logtovis))
2616         return E_INVALIDARG;
2617
2618     indexs = heap_alloc(sizeof(int) * runs);
2619     if (!indexs)
2620         return E_OUTOFMEMORY;
2621
2622
2623     if (vistolog)
2624     {
2625         for( ich = 0; ich < runs; ich++)
2626             indexs[ich] = ich;
2627
2628         ich = 0;
2629         while (ich < runs)
2630             ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2631         for (ich = 0; ich < runs; ich++)
2632             vistolog[ich] = indexs[ich];
2633     }
2634
2635
2636     if (logtovis)
2637     {
2638         for( ich = 0; ich < runs; ich++)
2639             indexs[ich] = ich;
2640
2641         ich = 0;
2642         while (ich < runs)
2643             ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2644         for (ich = 0; ich < runs; ich++)
2645             logtovis[ich] = indexs[ich];
2646     }
2647     heap_free(indexs);
2648
2649     return S_OK;
2650 }
2651
2652 /***********************************************************************
2653  *      ScriptStringGetLogicalWidths (USP10.@)
2654  *
2655  * Returns logical widths from a string analysis.
2656  *
2657  * PARAMS
2658  *  ssa  [I] string analysis.
2659  *  piDx [O] logical widths returned.
2660  *
2661  * RETURNS
2662  *  Success: S_OK
2663  *  Failure: a non-zero HRESULT.
2664  */
2665 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
2666 {
2667     int i, j, next = 0;
2668     StringAnalysis *analysis = ssa;
2669
2670     TRACE("%p, %p\n", ssa, piDx);
2671
2672     if (!analysis) return S_FALSE;
2673     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2674
2675     for (i = 0; i < analysis->numItems; i++)
2676     {
2677         int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2678         int direction = 1;
2679
2680         if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
2681             direction = -1;
2682
2683         for (j = 0; j < cChar; j++)
2684         {
2685             int k;
2686             int glyph = analysis->glyphs[i].pwLogClust[j];
2687             int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
2688                                               cChar, j, direction, NULL, NULL);
2689             int advance = get_glyph_cluster_advance(analysis->glyphs[i].piAdvance, analysis->glyphs[i].psva, analysis->glyphs[i].pwLogClust, analysis->glyphs[i].numGlyphs, cChar, glyph, direction);
2690
2691             for (k = 0; k < clust_size; k++)
2692             {
2693                 piDx[next] = advance / clust_size;
2694                 next++;
2695                 if (k) j++;
2696             }
2697         }
2698     }
2699     return S_OK;
2700 }
2701
2702 /***********************************************************************
2703  *      ScriptStringValidate (USP10.@)
2704  *
2705  * Validate a string analysis.
2706  *
2707  * PARAMS
2708  *  ssa [I] string analysis.
2709  *
2710  * RETURNS
2711  *  Success: S_OK
2712  *  Failure: S_FALSE if invalid sequences are found
2713  *           or a non-zero HRESULT if it fails.
2714  */
2715 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
2716 {
2717     StringAnalysis *analysis = ssa;
2718
2719     TRACE("(%p)\n", ssa);
2720
2721     if (!analysis) return E_INVALIDARG;
2722     return (analysis->invalid) ? S_FALSE : S_OK;
2723 }
2724
2725 /***********************************************************************
2726  *      ScriptString_pSize (USP10.@)
2727  *
2728  * Retrieve width and height of an analysed string.
2729  *
2730  * PARAMS
2731  *  ssa [I] string analysis.
2732  *
2733  * RETURNS
2734  *  Success: Pointer to a SIZE structure.
2735  *  Failure: NULL
2736  */
2737 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
2738 {
2739     int i, j;
2740     StringAnalysis *analysis = ssa;
2741
2742     TRACE("(%p)\n", ssa);
2743
2744     if (!analysis) return NULL;
2745     if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
2746
2747     if (!analysis->sz)
2748     {
2749         if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
2750         analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
2751
2752         analysis->sz->cx = 0;
2753         for (i = 0; i < analysis->numItems; i++)
2754         {
2755             if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
2756                 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
2757             for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
2758                 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
2759         }
2760     }
2761     return analysis->sz;
2762 }
2763
2764 /***********************************************************************
2765  *      ScriptString_pLogAttr (USP10.@)
2766  *
2767  * Retrieve logical attributes of an analysed string.
2768  *
2769  * PARAMS
2770  *  ssa [I] string analysis.
2771  *
2772  * RETURNS
2773  *  Success: Pointer to an array of SCRIPT_LOGATTR structures.
2774  *  Failure: NULL
2775  */
2776 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
2777 {
2778     StringAnalysis *analysis = ssa;
2779
2780     TRACE("(%p)\n", ssa);
2781
2782     if (!analysis) return NULL;
2783     if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
2784     return analysis->logattrs;
2785 }
2786
2787 /***********************************************************************
2788  *      ScriptString_pcOutChars (USP10.@)
2789  *
2790  * Retrieve the length of a string after clipping.
2791  *
2792  * PARAMS
2793  *  ssa [I] String analysis.
2794  *
2795  * RETURNS
2796  *  Success: Pointer to the length.
2797  *  Failure: NULL
2798  */
2799 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
2800 {
2801     StringAnalysis *analysis = ssa;
2802
2803     TRACE("(%p)\n", ssa);
2804
2805     if (!analysis) return NULL;
2806     return &analysis->clip_len;
2807 }
2808
2809 /***********************************************************************
2810  *      ScriptStringGetOrder (USP10.@)
2811  *
2812  * Retrieve a glyph order map.
2813  *
2814  * PARAMS
2815  *  ssa   [I]   String analysis.
2816  *  order [I/O] Array of glyph positions.
2817  *
2818  * RETURNS
2819  *  Success: S_OK
2820  *  Failure: a non-zero HRESULT.
2821  */
2822 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
2823 {
2824     int i, j;
2825     unsigned int k;
2826     StringAnalysis *analysis = ssa;
2827
2828     TRACE("(%p)\n", ssa);
2829
2830     if (!analysis) return S_FALSE;
2831     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2832
2833     /* FIXME: handle RTL scripts */
2834     for (i = 0, k = 0; i < analysis->numItems; i++)
2835         for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
2836             order[k] = k;
2837
2838     return S_OK;
2839 }
2840
2841 /***********************************************************************
2842  *      ScriptGetLogicalWidths (USP10.@)
2843  *
2844  * Convert advance widths to logical widths.
2845  *
2846  * PARAMS
2847  *  sa          [I] Script analysis.
2848  *  nbchars     [I] Number of characters.
2849  *  nbglyphs    [I] Number of glyphs.
2850  *  glyph_width [I] Array of glyph widths.
2851  *  log_clust   [I] Array of logical clusters.
2852  *  sva         [I] Visual attributes.
2853  *  widths      [O] Array of logical widths.
2854  *
2855  * RETURNS
2856  *  Success: S_OK
2857  *  Failure: a non-zero HRESULT.
2858  */
2859 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
2860                                       const int *glyph_width, const WORD *log_clust,
2861                                       const SCRIPT_VISATTR *sva, int *widths)
2862 {
2863     int i;
2864
2865     TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
2866           sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);
2867
2868     /* FIXME */
2869     for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
2870     return S_OK;
2871 }
2872
2873 /***********************************************************************
2874  *      ScriptApplyLogicalWidth (USP10.@)
2875  *
2876  * Generate glyph advance widths.
2877  *
2878  * PARAMS
2879  *  dx          [I]   Array of logical advance widths.
2880  *  num_chars   [I]   Number of characters.
2881  *  num_glyphs  [I]   Number of glyphs.
2882  *  log_clust   [I]   Array of logical clusters.
2883  *  sva         [I]   Visual attributes.
2884  *  advance     [I]   Array of glyph advance widths.
2885  *  sa          [I]   Script analysis.
2886  *  abc         [I/O] Summed ABC widths.
2887  *  justify     [O]   Array of glyph advance widths.
2888  *
2889  * RETURNS
2890  *  Success: S_OK
2891  *  Failure: a non-zero HRESULT.
2892  */
2893 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
2894                                        const WORD *log_clust, const SCRIPT_VISATTR *sva,
2895                                        const int *advance, const SCRIPT_ANALYSIS *sa,
2896                                        ABC *abc, int *justify)
2897 {
2898     int i;
2899
2900     FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
2901           dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
2902
2903     for (i = 0; i < num_chars; i++) justify[i] = advance[i];
2904     return S_OK;
2905 }
2906
2907 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
2908                              int num_glyphs, int dx, int min_kashida, int *justify)
2909 {
2910     int i;
2911
2912     FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
2913
2914     for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
2915     return S_OK;
2916 }