usp10: Handle the fNeedsCaretInfo flag in XtoCP and CPtoX.
[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     GetStringTypeW(CT_CTYPE1, &ch, 1, &type);
498
499     if (type == 0)
500         return SCRIPT_UNDEFINED;
501
502     if (type & C1_CNTRL)
503         return Script_Control;
504
505     i = 0;
506     do
507     {
508         if (ch < scriptRanges[i].rangeFirst || scriptRanges[i].script == SCRIPT_UNDEFINED)
509             break;
510
511         if (ch >= scriptRanges[i].rangeFirst && ch <= scriptRanges[i].rangeLast)
512         {
513             if (scriptRanges[i].numericScript && type & C1_DIGIT)
514                 return scriptRanges[i].numericScript;
515             if (scriptRanges[i].punctScript && type & C1_PUNCT)
516                 return scriptRanges[i].punctScript;
517             return scriptRanges[i].script;
518         }
519         i++;
520     } while (1);
521
522     return SCRIPT_UNDEFINED;
523 }
524
525 /***********************************************************************
526  *      DllMain
527  *
528  */
529 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
530 {
531     switch(fdwReason)
532     {
533     case DLL_PROCESS_ATTACH:
534         DisableThreadLibraryCalls(hInstDLL);
535         break;
536     case DLL_PROCESS_DETACH:
537         break;
538     }
539     return TRUE;
540 }
541
542 /***********************************************************************
543  *      ScriptFreeCache (USP10.@)
544  *
545  * Free a script cache.
546  *
547  * PARAMS
548  *   psc [I/O] Script cache.
549  *
550  * RETURNS
551  *  Success: S_OK
552  *  Failure: Non-zero HRESULT value.
553  */
554 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
555 {
556     TRACE("%p\n", psc);
557
558     if (psc && *psc)
559     {
560         unsigned int i;
561         for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
562         {
563             heap_free(((ScriptCache *)*psc)->glyphs[i]);
564             heap_free(((ScriptCache *)*psc)->widths[i]);
565         }
566         heap_free(((ScriptCache *)*psc)->GSUB_Table);
567         heap_free(((ScriptCache *)*psc)->GDEF_Table);
568         heap_free(((ScriptCache *)*psc)->features);
569         heap_free(*psc);
570         *psc = NULL;
571     }
572     return S_OK;
573 }
574
575 /***********************************************************************
576  *      ScriptGetProperties (USP10.@)
577  *
578  * Retrieve a list of script properties.
579  *
580  * PARAMS
581  *  props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
582  *  num   [I] Pointer to the number of scripts.
583  *
584  * RETURNS
585  *  Success: S_OK
586  *  Failure: Non-zero HRESULT value.
587  *
588  * NOTES
589  *  Behaviour matches WinXP.
590  */
591 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
592 {
593     TRACE("(%p,%p)\n", props, num);
594
595     if (!props && !num) return E_INVALIDARG;
596
597     if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
598     if (props) *props = script_props;
599
600     return S_OK;
601 }
602
603 /***********************************************************************
604  *      ScriptGetFontProperties (USP10.@)
605  *
606  * Get information on special glyphs.
607  *
608  * PARAMS
609  *  hdc [I]   Device context.
610  *  psc [I/O] Opaque pointer to a script cache.
611  *  sfp [O]   Font properties structure.
612  */
613 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
614 {
615     HRESULT hr;
616
617     TRACE("%p,%p,%p\n", hdc, psc, sfp);
618
619     if (!sfp) return E_INVALIDARG;
620     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
621
622     if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
623         return E_INVALIDARG;
624
625     /* return something sensible? */
626     sfp->wgBlank = 0;
627     sfp->wgDefault = get_cache_default_char(psc);
628     sfp->wgInvalid = 0;
629     sfp->wgKashida = 0xffff;
630     sfp->iKashidaWidth = 0;
631
632     return S_OK;
633 }
634
635 /***********************************************************************
636  *      ScriptRecordDigitSubstitution (USP10.@)
637  *
638  *  Record digit substitution settings for a given locale.
639  *
640  *  PARAMS
641  *   locale [I] Locale identifier.
642  *   sds    [I] Structure to record substitution settings.
643  *
644  *  RETURNS
645  *   Success: S_OK
646  *   Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
647  *
648  *  SEE ALSO
649  *   http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
650  */
651 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
652 {
653     DWORD plgid, sub;
654
655     TRACE("0x%x, %p\n", locale, sds);
656
657     /* This implementation appears to be correct for all languages, but it's
658      * not clear if sds->DigitSubstitute is ever set to anything except 
659      * CONTEXT or NONE in reality */
660
661     if (!sds) return E_POINTER;
662
663     locale = ConvertDefaultLocale(locale);
664
665     if (!IsValidLocale(locale, LCID_INSTALLED))
666         return E_INVALIDARG;
667
668     plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
669     sds->TraditionalDigitLanguage = plgid;
670
671     if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
672         sds->NationalDigitLanguage = plgid;
673     else
674         sds->NationalDigitLanguage = LANG_ENGLISH;
675
676     if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
677                         (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
678
679     switch (sub)
680     {
681     case 0: 
682         if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
683             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
684         else
685             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
686         break;
687     case 1:
688         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
689         break;
690     case 2:
691         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
692         break;
693     default:
694         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
695         break;
696     }
697
698     sds->dwReserved = 0;
699     return S_OK;
700 }
701
702 /***********************************************************************
703  *      ScriptApplyDigitSubstitution (USP10.@)
704  *
705  *  Apply digit substitution settings.
706  *
707  *  PARAMS
708  *   sds [I] Structure with recorded substitution settings.
709  *   sc  [I] Script control structure.
710  *   ss  [I] Script state structure.
711  *
712  *  RETURNS
713  *   Success: S_OK
714  *   Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
715  */
716 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds, 
717                                             SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
718 {
719     SCRIPT_DIGITSUBSTITUTE psds;
720
721     TRACE("%p, %p, %p\n", sds, sc, ss);
722
723     if (!sc || !ss) return E_POINTER;
724     if (!sds)
725     {
726         sds = &psds;
727         if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
728             return E_INVALIDARG;
729     }
730
731     sc->uDefaultLanguage = LANG_ENGLISH;
732     sc->fContextDigits = 0;
733     ss->fDigitSubstitute = 0;
734
735     switch (sds->DigitSubstitute) {
736         case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
737         case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
738         case SCRIPT_DIGITSUBSTITUTE_NONE:
739         case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
740             return S_OK;
741         default:
742             return E_INVALIDARG;
743     }
744 }
745
746 /***********************************************************************
747  *      ScriptItemizeOpenType (USP10.@)
748  *
749  * Split a Unicode string into shapeable parts.
750  *
751  * PARAMS
752  *  pwcInChars  [I] String to split.
753  *  cInChars    [I] Number of characters in pwcInChars.
754  *  cMaxItems   [I] Maximum number of items to return.
755  *  psControl   [I] Pointer to a SCRIPT_CONTROL structure.
756  *  psState     [I] Pointer to a SCRIPT_STATE structure.
757  *  pItems      [O] Buffer to receive SCRIPT_ITEM structures.
758  *  pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
759  *  pcItems     [O] Number of script items returned.
760  *
761  * RETURNS
762  *  Success: S_OK
763  *  Failure: Non-zero HRESULT value.
764  */
765 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
766                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
767                              SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
768 {
769
770 #define Numeric_space 0x0020
771 #define ZWNJ 0x200C
772 #define ZWJ  0x200D
773
774     int   cnt = 0, index = 0, str = 0;
775     int   New_Script = SCRIPT_UNDEFINED;
776     WORD  *levels = NULL;
777     WORD  *strength = NULL;
778     WORD  baselevel = 0;
779
780     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
781           psControl, psState, pItems, pcItems);
782
783     if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
784         return E_INVALIDARG;
785
786     if (psState && psControl)
787     {
788         int i;
789         levels = heap_alloc_zero(cInChars * sizeof(WORD));
790         if (!levels)
791             return E_OUTOFMEMORY;
792
793         BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
794         baselevel = levels[0];
795         for (i = 0; i < cInChars; i++)
796             if (levels[i]!=levels[0])
797                 break;
798         if (i >= cInChars && !odd(baselevel))
799         {
800             heap_free(levels);
801             levels = NULL;
802         }
803         else
804         {
805             if (!psControl->fMergeNeutralItems)
806             {
807                 strength = heap_alloc_zero(cInChars * sizeof(WORD));
808                 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
809             }
810         }
811     }
812
813     while ((pwcInChars[cnt] == Numeric_space || pwcInChars[cnt] == ZWJ || pwcInChars[cnt] == ZWNJ) && cnt < cInChars)
814         cnt++;
815
816     if (cnt == cInChars) /* All Spaces */
817     {
818         cnt = 0;
819         New_Script = get_char_script(pwcInChars[cnt]);
820     }
821
822     pItems[index].iCharPos = 0;
823     pItems[index].a = scriptInformation[get_char_script(pwcInChars[cnt])].a;
824     pScriptTags[index] = scriptInformation[get_char_script(pwcInChars[cnt])].scriptTag;
825
826     if (strength)
827         str = strength[cnt];
828
829     cnt = 0;
830     if (levels)
831     {
832         pItems[index].a.fRTL = odd(levels[cnt]);
833         pItems[index].a.fLayoutRTL = odd(levels[cnt]);
834         pItems[index].a.s.uBidiLevel = levels[cnt];
835     }
836     else if (!pItems[index].a.s.uBidiLevel)
837     {
838         pItems[index].a.s.uBidiLevel = baselevel;
839         pItems[index].a.fLayoutRTL = odd(baselevel);
840         pItems[index].a.fRTL = odd(baselevel);
841     }
842
843     TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
844           levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
845           pItems[index].iCharPos);
846
847     for (cnt=1; cnt < cInChars; cnt++)
848     {
849         if (levels && (levels[cnt] == pItems[index].a.s.uBidiLevel && (!strength || (strength[cnt] == 0 || strength[cnt] == str))))
850             continue;
851
852         if(pwcInChars[cnt] != Numeric_space && pwcInChars[cnt] != ZWJ && pwcInChars[cnt] != ZWNJ)
853             New_Script = get_char_script(pwcInChars[cnt]);
854         else if (levels)
855         {
856             int j = 1;
857             while (cnt + j < cInChars - 1 && (pwcInChars[cnt+j] == Numeric_space || pwcInChars[cnt+j] == ZWJ || pwcInChars[cnt+j] == ZWNJ))
858                 j++;
859             New_Script = get_char_script(pwcInChars[cnt+j]);
860         }
861
862         if ((levels && (levels[cnt] != pItems[index].a.s.uBidiLevel || (strength && (strength[cnt] != str)))) || New_Script != pItems[index].a.eScript || New_Script == Script_Control)
863         {
864             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);
865
866             if (strength && strength[cnt] != 0)
867                 str = strength[cnt];
868
869             index++;
870             if  (index+1 > cMaxItems)
871                 return E_OUTOFMEMORY;
872
873             pItems[index].iCharPos = cnt;
874             memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
875
876             pItems[index].a = scriptInformation[New_Script].a;
877             pScriptTags[index] = scriptInformation[New_Script].scriptTag;
878             if (levels)
879             {
880                 pItems[index].a.fRTL = odd(levels[cnt]);
881                 pItems[index].a.fLayoutRTL = odd(levels[cnt]);
882                 pItems[index].a.s.uBidiLevel = levels[cnt];
883             }
884             else if (!pItems[index].a.s.uBidiLevel)
885             {
886                 pItems[index].a.s.uBidiLevel = baselevel;
887                 pItems[index].a.fLayoutRTL = odd(baselevel);
888                 pItems[index].a.fRTL = odd(baselevel);
889             }
890
891             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
892         }
893     }
894
895     /* While not strictly necessary according to the spec, make sure the n+1
896      * item is set up to prevent random behaviour if the caller erroneously
897      * checks the n+1 structure                                              */
898     index++;
899     memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
900
901     TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
902
903     /*  Set one SCRIPT_STATE item being returned  */
904     if  (index + 1 > cMaxItems) return E_OUTOFMEMORY;
905     if (pcItems) *pcItems = index;
906
907     /*  Set SCRIPT_ITEM                                     */
908     pItems[index].iCharPos = cnt;         /* the last item contains the ptr to the lastchar */
909     heap_free(levels);
910     heap_free(strength);
911     return S_OK;
912 }
913
914 /***********************************************************************
915  *      ScriptItemize (USP10.@)
916  *
917  * Split a Unicode string into shapeable parts.
918  *
919  * PARAMS
920  *  pwcInChars [I] String to split.
921  *  cInChars   [I] Number of characters in pwcInChars.
922  *  cMaxItems  [I] Maximum number of items to return.
923  *  psControl  [I] Pointer to a SCRIPT_CONTROL structure.
924  *  psState    [I] Pointer to a SCRIPT_STATE structure.
925  *  pItems     [O] Buffer to receive SCRIPT_ITEM structures.
926  *  pcItems    [O] Number of script items returned.
927  *
928  * RETURNS
929  *  Success: S_OK
930  *  Failure: Non-zero HRESULT value.
931  */
932 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
933                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
934                              SCRIPT_ITEM *pItems, int *pcItems)
935 {
936     OPENTYPE_TAG *discarded_tags;
937     HRESULT res;
938
939     discarded_tags = heap_alloc(cMaxItems * sizeof(OPENTYPE_TAG));
940     if (!discarded_tags)
941         return E_OUTOFMEMORY;
942     res = ScriptItemizeOpenType(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, discarded_tags, pcItems);
943     heap_free(discarded_tags);
944     return res;
945 }
946
947 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
948 {
949     int defWidth;
950     int cTabStops=0;
951     INT *lpTabPos = NULL;
952     INT nTabOrg = 0;
953     INT x = 0;
954
955     if (pTabdef)
956         lpTabPos = pTabdef->pTabStops;
957
958     if (pTabdef && pTabdef->iTabOrigin)
959     {
960         if (pTabdef->iScale)
961             nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
962         else
963             nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
964     }
965
966     if (pTabdef)
967         cTabStops = pTabdef->cTabStops;
968
969     if (cTabStops == 1)
970     {
971         if (pTabdef->iScale)
972             defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
973         else
974             defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
975         cTabStops = 0;
976     }
977     else
978         defWidth = 8 * psc->tm.tmAveCharWidth;
979
980     for (; cTabStops>0 ; lpTabPos++, cTabStops--)
981     {
982         int position = *lpTabPos;
983         if (position < 0)
984             position = -1 * position;
985         if (pTabdef->iScale)
986             position = (position * pTabdef->iScale) / 4;
987         else
988             position = position * psc->tm.tmAveCharWidth;
989
990         if( nTabOrg + position > current_x)
991         {
992             if( *lpTabPos >= 0)
993             {
994                 /* a left aligned tab */
995                 x = (nTabOrg + *lpTabPos) - current_x;
996                 break;
997             }
998             else
999             {
1000                 FIXME("Negative tabstop\n");
1001                 break;
1002             }
1003         }
1004     }
1005     if ((!cTabStops) && (defWidth > 0))
1006         x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1007     else if ((!cTabStops) && (defWidth < 0))
1008         FIXME("TODO: Negative defWidth\n");
1009
1010     return x;
1011 }
1012
1013 /***********************************************************************
1014  * Helper function for ScriptStringAnalyse
1015  */
1016 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1017                               const WCHAR *pwcInChars, int cChars )
1018 {
1019     /* FIXME: When to properly fallback is still a bit of a mystery */
1020     WORD *glyphs;
1021
1022     if (psa->fNoGlyphIndex)
1023         return FALSE;
1024
1025     if (init_script_cache(hdc, psc) != S_OK)
1026         return FALSE;
1027
1028     if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1029         return TRUE;
1030
1031     glyphs = heap_alloc(sizeof(WORD) * cChars);
1032     if (!glyphs)
1033         return FALSE;
1034     if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1035     {
1036         heap_free(glyphs);
1037         return TRUE;
1038     }
1039     heap_free(glyphs);
1040
1041     return FALSE;
1042 }
1043
1044 static void find_fallback_font(DWORD scriptid, LPWSTR FaceName)
1045 {
1046     HKEY hkey;
1047
1048     if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1049     {
1050         static const WCHAR szFmt[] = {'%','x',0};
1051         WCHAR value[10];
1052         DWORD count = LF_FACESIZE * sizeof(WCHAR);
1053         DWORD type;
1054
1055         sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1056         if (RegQueryValueExW(hkey, value, 0, &type, (LPBYTE)FaceName, &count))
1057             lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1058         RegCloseKey(hkey);
1059     }
1060     else
1061         lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1062 }
1063
1064 /***********************************************************************
1065  *      ScriptStringAnalyse (USP10.@)
1066  *
1067  */
1068 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1069                                    int cGlyphs, int iCharset, DWORD dwFlags,
1070                                    int iReqWidth, SCRIPT_CONTROL *psControl,
1071                                    SCRIPT_STATE *psState, const int *piDx,
1072                                    SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1073                                    SCRIPT_STRING_ANALYSIS *pssa)
1074 {
1075     HRESULT hr = E_OUTOFMEMORY;
1076     StringAnalysis *analysis = NULL;
1077     SCRIPT_CONTROL sControl;
1078     SCRIPT_STATE sState;
1079     int i, num_items = 255;
1080     BYTE   *BidiLevel;
1081     WCHAR *iString = NULL;
1082
1083     TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1084           hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1085           psControl, psState, piDx, pTabdef, pbInClass, pssa);
1086
1087     if (iCharset != -1)
1088     {
1089         FIXME("Only Unicode strings are supported\n");
1090         return E_INVALIDARG;
1091     }
1092     if (cString < 1 || !pString) return E_INVALIDARG;
1093     if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1094
1095     if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1096     if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1097
1098     /* FIXME: handle clipping */
1099     analysis->clip_len = cString;
1100     analysis->hdc = hdc;
1101     analysis->dwFlags = dwFlags;
1102
1103     if (psState)
1104         sState = *psState;
1105     else
1106         memset(&sState, 0, sizeof(SCRIPT_STATE));
1107
1108     if (psControl)
1109         sControl = *psControl;
1110     else
1111         memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1112
1113     if (dwFlags & SSA_PASSWORD)
1114     {
1115         iString = heap_alloc(sizeof(WCHAR)*cString);
1116         if (!iString)
1117         {
1118             hr = E_OUTOFMEMORY;
1119             goto error;
1120         }
1121         for (i = 0; i < cString; i++)
1122             iString[i] = *((const WCHAR *)pString);
1123         pString = iString;
1124     }
1125
1126     hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1127                        &analysis->numItems);
1128
1129     while (hr == E_OUTOFMEMORY)
1130     {
1131         SCRIPT_ITEM *tmp;
1132
1133         num_items *= 2;
1134         if (!(tmp = heap_realloc_zero(analysis->pItem, num_items * sizeof(SCRIPT_ITEM) + 1)))
1135             goto error;
1136
1137         analysis->pItem = tmp;
1138         hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
1139                            &analysis->numItems);
1140     }
1141     if (hr != S_OK) goto error;
1142
1143     /* set back to out of memory for default goto error behaviour */
1144     hr = E_OUTOFMEMORY;
1145
1146     if (dwFlags & SSA_BREAK)
1147     {
1148         if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
1149         {
1150             for (i = 0; i < analysis->numItems; i++)
1151                 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]);
1152         }
1153         else
1154             goto error;
1155     }
1156
1157     if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
1158         goto error;
1159     if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
1160         goto error;
1161
1162     if (dwFlags & SSA_GLYPHS)
1163     {
1164         int tab_x = 0;
1165         if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
1166             goto error;
1167
1168         for (i = 0; i < analysis->numItems; i++)
1169         {
1170             SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
1171             int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1172             int numGlyphs = 1.5 * cChar + 16;
1173             WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
1174             WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
1175             int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
1176             SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
1177             GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
1178             ABC *abc = heap_alloc_zero(sizeof(ABC));
1179             int numGlyphsReturned;
1180             HFONT originalFont = 0x0;
1181
1182             /* FIXME: non unicode strings */
1183             const WCHAR* pStr = (const WCHAR*)pString;
1184             analysis->glyphs[i].fallbackFont = NULL;
1185
1186             if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
1187             {
1188                 heap_free (glyphs);
1189                 heap_free (pwLogClust);
1190                 heap_free (piAdvance);
1191                 heap_free (psva);
1192                 heap_free (pGoffset);
1193                 heap_free (abc);
1194                 hr = E_OUTOFMEMORY;
1195                 goto error;
1196             }
1197
1198             if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
1199             {
1200                 LOGFONTW lf;
1201                 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
1202                 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
1203                 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
1204                 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
1205                 if (analysis->glyphs[i].fallbackFont)
1206                 {
1207                     ScriptFreeCache(sc);
1208                     originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
1209                 }
1210             }
1211
1212             hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
1213                              cChar, numGlyphs, &analysis->pItem[i].a,
1214                              glyphs, pwLogClust, psva, &numGlyphsReturned);
1215             hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
1216                              piAdvance, pGoffset, abc);
1217             if (originalFont)
1218                 SelectObject(hdc,originalFont);
1219
1220             if (dwFlags & SSA_TAB)
1221             {
1222                 int tabi = 0;
1223                 for (tabi = 0; tabi < cChar; tabi++)
1224                 {
1225                     if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
1226                         piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
1227                     tab_x+=piAdvance[tabi];
1228                 }
1229             }
1230
1231             analysis->glyphs[i].numGlyphs = numGlyphsReturned;
1232             analysis->glyphs[i].glyphs = glyphs;
1233             analysis->glyphs[i].pwLogClust = pwLogClust;
1234             analysis->glyphs[i].piAdvance = piAdvance;
1235             analysis->glyphs[i].psva = psva;
1236             analysis->glyphs[i].pGoffset = pGoffset;
1237             analysis->glyphs[i].abc = abc;
1238             analysis->glyphs[i].iMaxPosX= -1;
1239
1240             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1241         }
1242     }
1243     else
1244     {
1245         for (i = 0; i < analysis->numItems; i++)
1246             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1247     }
1248
1249     ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
1250     heap_free(BidiLevel);
1251
1252     *pssa = analysis;
1253     heap_free(iString);
1254     return S_OK;
1255
1256 error:
1257     heap_free(iString);
1258     heap_free(analysis->glyphs);
1259     heap_free(analysis->logattrs);
1260     heap_free(analysis->pItem);
1261     heap_free(analysis->logical2visual);
1262     heap_free(analysis);
1263     return hr;
1264 }
1265
1266 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
1267                            int iX,
1268                            int iY,
1269                            int iItem,
1270                            int cStart,
1271                            int cEnd,
1272                            UINT uOptions,
1273                            const RECT *prc,
1274                            BOOL fSelected,
1275                            BOOL fDisabled)
1276 {
1277     StringAnalysis *analysis;
1278     int off_x = 0;
1279     HRESULT hr;
1280     COLORREF BkColor = 0x0;
1281     COLORREF TextColor = 0x0;
1282     INT BkMode = 0;
1283     INT runStart, runEnd;
1284     INT iGlyph, cGlyphs;
1285     HFONT oldFont = 0x0;
1286
1287     TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
1288          ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
1289
1290     if (!(analysis = ssa)) return E_INVALIDARG;
1291
1292     if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
1293          (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
1294             return S_OK;
1295
1296     if (fSelected)
1297     {
1298         BkMode = GetBkMode(analysis->hdc);
1299         SetBkMode( analysis->hdc, OPAQUE);
1300         BkColor = GetBkColor(analysis->hdc);
1301         SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
1302         if (!fDisabled)
1303         {
1304             TextColor = GetTextColor(analysis->hdc);
1305             SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1306         }
1307     }
1308     if (analysis->glyphs[iItem].fallbackFont)
1309         oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
1310
1311     if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
1312         runStart = cStart - analysis->pItem[iItem].iCharPos;
1313     else
1314         runStart =  0;
1315     if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
1316         runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
1317     else
1318         runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
1319
1320     if (analysis->pItem[iItem].a.fRTL)
1321     {
1322         if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
1323             ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
1324         else
1325             ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
1326     }
1327     else
1328     {
1329         if (cStart >=0 && runStart)
1330             ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
1331         else
1332             ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
1333     }
1334
1335     if (analysis->pItem[iItem].a.fRTL)
1336         iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
1337     else
1338         iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
1339
1340     if (analysis->pItem[iItem].a.fRTL)
1341         cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
1342     else
1343         cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
1344
1345     cGlyphs++;
1346
1347     hr = ScriptTextOut(analysis->hdc,
1348                        (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
1349                        iY, uOptions, prc, &analysis->pItem[iItem].a, NULL, 0,
1350                        &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
1351                        &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
1352                        &analysis->glyphs[iItem].pGoffset[iGlyph]);
1353
1354     TRACE("ScriptTextOut hr=%08x\n", hr);
1355
1356     if (fSelected)
1357     {
1358         SetBkColor(analysis->hdc, BkColor);
1359         SetBkMode( analysis->hdc, BkMode);
1360         if (!fDisabled)
1361             SetTextColor(analysis->hdc, TextColor);
1362     }
1363     if (analysis->glyphs[iItem].fallbackFont)
1364         SelectObject(analysis->hdc, oldFont);
1365
1366     return hr;
1367 }
1368
1369 /***********************************************************************
1370  *      ScriptStringOut (USP10.@)
1371  *
1372  * This function takes the output of ScriptStringAnalyse and joins the segments
1373  * of glyphs and passes the resulting string to ScriptTextOut.  ScriptStringOut
1374  * only processes glyphs.
1375  *
1376  * Parameters:
1377  *  ssa       [I] buffer to hold the analysed string components
1378  *  iX        [I] X axis displacement for output
1379  *  iY        [I] Y axis displacement for output
1380  *  uOptions  [I] flags controling output processing
1381  *  prc       [I] rectangle coordinates
1382  *  iMinSel   [I] starting pos for substringing output string
1383  *  iMaxSel   [I] ending pos for substringing output string
1384  *  fDisabled [I] controls text highlighting
1385  *
1386  *  RETURNS
1387  *   Success: S_OK
1388  *   Failure: is the value returned by ScriptTextOut
1389  */
1390 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
1391                                int iX,
1392                                int iY, 
1393                                UINT uOptions, 
1394                                const RECT *prc, 
1395                                int iMinSel, 
1396                                int iMaxSel,
1397                                BOOL fDisabled)
1398 {
1399     StringAnalysis *analysis;
1400     int   item;
1401     HRESULT hr;
1402
1403     TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
1404          ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
1405
1406     if (!(analysis = ssa)) return E_INVALIDARG;
1407     if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
1408
1409     for (item = 0; item < analysis->numItems; item++)
1410     {
1411         hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
1412         if (FAILED(hr))
1413             return hr;
1414     }
1415
1416     if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
1417     {
1418         if (iMaxSel > 0 &&  iMinSel < 0)
1419             iMinSel = 0;
1420         for (item = 0; item < analysis->numItems; item++)
1421         {
1422             hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
1423             if (FAILED(hr))
1424                 return hr;
1425         }
1426     }
1427
1428     return S_OK;
1429 }
1430
1431 /***********************************************************************
1432  *      ScriptStringCPtoX (USP10.@)
1433  *
1434  */
1435 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
1436 {
1437     int item;
1438     int runningX = 0;
1439     StringAnalysis* analysis = ssa;
1440
1441     TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
1442
1443     if (!ssa || !pX) return S_FALSE;
1444     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1445
1446     /* icp out of range */
1447     if(icp < 0)
1448     {
1449         analysis->invalid = TRUE;
1450         return E_INVALIDARG;
1451     }
1452
1453     for(item=0; item<analysis->numItems; item++)
1454     {
1455         int CP, i;
1456         int offset;
1457
1458         i = analysis->logical2visual[item];
1459         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1460         /* initialize max extents for uninitialized runs */
1461         if (analysis->glyphs[i].iMaxPosX == -1)
1462         {
1463             if (analysis->pItem[i].a.fRTL)
1464                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1465                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1466                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1467             else
1468                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1469                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1470                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1471         }
1472
1473         if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
1474         {
1475             runningX += analysis->glyphs[i].iMaxPosX;
1476             continue;
1477         }
1478
1479         icp -= analysis->pItem[i].iCharPos;
1480         ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1481                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1482                     &analysis->pItem[i].a, &offset);
1483         runningX += offset;
1484
1485         *pX = runningX;
1486         return S_OK;
1487     }
1488
1489     /* icp out of range */
1490     analysis->invalid = TRUE;
1491     return E_INVALIDARG;
1492 }
1493
1494 /***********************************************************************
1495  *      ScriptStringXtoCP (USP10.@)
1496  *
1497  */
1498 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
1499 {
1500     StringAnalysis* analysis = ssa;
1501     int item;
1502
1503     TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
1504
1505     if (!ssa || !piCh || !piTrailing) return S_FALSE;
1506     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1507
1508     /* out of range */
1509     if(iX < 0)
1510     {
1511         if (analysis->pItem[0].a.fRTL)
1512         {
1513             *piCh = 1;
1514             *piTrailing = FALSE;
1515         }
1516         else
1517         {
1518             *piCh = -1;
1519             *piTrailing = TRUE;
1520         }
1521         return S_OK;
1522     }
1523
1524     for(item=0; item<analysis->numItems; item++)
1525     {
1526         int i;
1527         int CP;
1528
1529         for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
1530         /* nothing */;
1531
1532         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1533         /* initialize max extents for uninitialized runs */
1534         if (analysis->glyphs[i].iMaxPosX == -1)
1535         {
1536             if (analysis->pItem[i].a.fRTL)
1537                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1538                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1539                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1540             else
1541                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1542                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1543                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1544         }
1545
1546         if (iX > analysis->glyphs[i].iMaxPosX)
1547         {
1548             iX -= analysis->glyphs[i].iMaxPosX;
1549             continue;
1550         }
1551
1552         ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1553                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1554                     &analysis->pItem[i].a, piCh, piTrailing);
1555         *piCh += analysis->pItem[i].iCharPos;
1556
1557         return S_OK;
1558     }
1559
1560     /* out of range */
1561     *piCh = analysis->pItem[analysis->numItems].iCharPos;
1562     *piTrailing = FALSE;
1563
1564     return S_OK;
1565 }
1566
1567
1568 /***********************************************************************
1569  *      ScriptStringFree (USP10.@)
1570  *
1571  * Free a string analysis.
1572  *
1573  * PARAMS
1574  *  pssa [I] string analysis.
1575  *
1576  * RETURNS
1577  *  Success: S_OK
1578  *  Failure: Non-zero HRESULT value.
1579  */
1580 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
1581 {
1582     StringAnalysis* analysis;
1583     BOOL invalid;
1584     int i;
1585
1586     TRACE("(%p)\n", pssa);
1587
1588     if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
1589
1590     invalid = analysis->invalid;
1591
1592     if (analysis->glyphs)
1593     {
1594         for (i = 0; i < analysis->numItems; i++)
1595         {
1596             heap_free(analysis->glyphs[i].glyphs);
1597             heap_free(analysis->glyphs[i].pwLogClust);
1598             heap_free(analysis->glyphs[i].piAdvance);
1599             heap_free(analysis->glyphs[i].psva);
1600             heap_free(analysis->glyphs[i].pGoffset);
1601             heap_free(analysis->glyphs[i].abc);
1602             if (analysis->glyphs[i].fallbackFont)
1603                 DeleteObject(analysis->glyphs[i].fallbackFont);
1604             ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
1605             heap_free(analysis->glyphs[i].sc);
1606         }
1607         heap_free(analysis->glyphs);
1608     }
1609
1610     heap_free(analysis->pItem);
1611     heap_free(analysis->logattrs);
1612     heap_free(analysis->sz);
1613     heap_free(analysis->logical2visual);
1614     heap_free(analysis);
1615
1616     if (invalid) return E_INVALIDARG;
1617     return S_OK;
1618 }
1619
1620 /***********************************************************************
1621  *      ScriptCPtoX (USP10.@)
1622  *
1623  */
1624 HRESULT WINAPI ScriptCPtoX(int iCP,
1625                            BOOL fTrailing,
1626                            int cChars,
1627                            int cGlyphs,
1628                            const WORD *pwLogClust,
1629                            const SCRIPT_VISATTR *psva,
1630                            const int *piAdvance,
1631                            const SCRIPT_ANALYSIS *psa,
1632                            int *piX)
1633 {
1634     int item;
1635     float iPosX;
1636     int iSpecial = -1;
1637     int iCluster = -1;
1638     int clust_size = 1;
1639     float special_size = 0.0;
1640     int iMaxPos = 0;
1641     BOOL rtl = FALSE;
1642
1643     TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
1644           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1645           psa, piX);
1646
1647     if (psa->fRTL && ! psa->fLogicalOrder)
1648         rtl = TRUE;
1649
1650     if (fTrailing)
1651         iCP++;
1652
1653     if (rtl)
1654     {
1655         int max_clust = pwLogClust[0];
1656
1657         for (item=0; item < cGlyphs; item++)
1658             if (pwLogClust[item] > max_clust)
1659             {
1660                 ERR("We do not handle non reversed clusters properly\n");
1661                 break;
1662             }
1663
1664         iMaxPos = 0;
1665         for (item = max_clust; item >=0; item --)
1666             iMaxPos += piAdvance[item];
1667     }
1668
1669     iPosX = 0.0;
1670     for (item=0; item < iCP && item < cChars; item++)
1671     {
1672         if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
1673         {
1674             int check;
1675             int clust = pwLogClust[item];
1676
1677             clust_size = 1;
1678             iCluster = -1;
1679
1680             for (check = item+1; check < cChars; check++)
1681             {
1682                 if (pwLogClust[check] == clust)
1683                 {
1684                     clust_size ++;
1685                     if (iCluster == -1)
1686                         iCluster = item;
1687                 }
1688                 else break;
1689             }
1690
1691             if (check >= cChars && !iMaxPos)
1692             {
1693                 for (check = clust; check < cChars; check++)
1694                     special_size += piAdvance[check];
1695                 iSpecial = item;
1696                 special_size /= (cChars - item);
1697                 iPosX += special_size;
1698             }
1699             else
1700             {
1701                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1702                 {
1703                     clust_size --;
1704                     if (clust_size == 0)
1705                         iPosX += piAdvance[clust];
1706                 }
1707                 else
1708                     iPosX += piAdvance[clust] / (float)clust_size;
1709             }
1710         }
1711         else if (iSpecial != -1)
1712             iPosX += special_size;
1713         else /* (iCluster != -1) */
1714         {
1715             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1716             {
1717                 clust_size --;
1718                 if (clust_size == 0)
1719                     iPosX += piAdvance[pwLogClust[iCluster]];
1720             }
1721             else
1722                 iPosX += piAdvance[pwLogClust[iCluster]] / (float)clust_size;
1723         }
1724     }
1725
1726     if (iMaxPos > 0)
1727     {
1728         iPosX = iMaxPos - iPosX;
1729         if (iPosX < 0)
1730             iPosX = 0;
1731     }
1732
1733     *piX = iPosX;
1734     TRACE("*piX=%d\n", *piX);
1735     return S_OK;
1736 }
1737
1738 /***********************************************************************
1739  *      ScriptXtoCP (USP10.@)
1740  *
1741  */
1742 HRESULT WINAPI ScriptXtoCP(int iX,
1743                            int cChars,
1744                            int cGlyphs,
1745                            const WORD *pwLogClust,
1746                            const SCRIPT_VISATTR *psva,
1747                            const int *piAdvance,
1748                            const SCRIPT_ANALYSIS *psa,
1749                            int *piCP,
1750                            int *piTrailing)
1751 {
1752     int item;
1753     float iPosX;
1754     float iLastPosX;
1755     int iSpecial = -1;
1756     int iCluster = -1;
1757     int clust_size = 1;
1758     int cjump = 0;
1759     float special_size = 0.0;
1760     int direction = 1;
1761
1762     TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
1763           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1764           psa, piCP, piTrailing);
1765
1766     if (psa->fRTL && ! psa->fLogicalOrder)
1767         direction = -1;
1768
1769     if (direction<0)
1770     {
1771         int max_clust = pwLogClust[0];
1772
1773         if (iX < 0)
1774         {
1775             *piCP = cChars;
1776             *piTrailing = 0;
1777             return S_OK;
1778         }
1779
1780         for (item=0; item < cChars; item++)
1781             if (pwLogClust[item] > max_clust)
1782             {
1783                 ERR("We do not handle non reversed clusters properly\n");
1784                 break;
1785             }
1786     }
1787
1788     if (iX < 0)
1789     {
1790         *piCP = -1;
1791         *piTrailing = 1;
1792         return S_OK;
1793     }
1794
1795     iPosX = iLastPosX = 0;
1796     if (direction > 0)
1797         item = 0;
1798     else
1799         item = cChars - 1;
1800     for (; iPosX <= iX && item < cChars && item >= 0; item+=direction)
1801     {
1802         iLastPosX = iPosX;
1803         if (iSpecial == -1 &&
1804              (iCluster == -1 ||
1805               (iCluster != -1 &&
1806                  ((direction > 0 && iCluster+clust_size <= item) ||
1807                   (direction < 0 && iCluster-clust_size >= item))
1808               )
1809              )
1810             )
1811         {
1812             int check;
1813             int clust = pwLogClust[item];
1814
1815             clust_size = 1;
1816             iCluster = -1;
1817             cjump = 0;
1818
1819             for (check = item+direction; check < cChars && check >= 0; check+=direction)
1820             {
1821                 if (pwLogClust[check] == clust)
1822                 {
1823                     clust_size ++;
1824                     if (iCluster == -1)
1825                         iCluster = item;
1826                 }
1827                 else break;
1828             }
1829
1830             if (check >= cChars && direction > 0)
1831             {
1832                 for (check = clust; check < cChars; check++)
1833                     special_size += piAdvance[check];
1834                 iSpecial = item;
1835                 special_size /= (cChars - item);
1836                 iPosX += special_size;
1837             }
1838             else
1839             {
1840                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1841                 {
1842                     if (!cjump)
1843                         iPosX += piAdvance[clust];
1844                     cjump++;
1845                 }
1846                 else
1847                     iPosX += piAdvance[clust] / (float)clust_size;
1848             }
1849         }
1850         else if (iSpecial != -1)
1851             iPosX += special_size;
1852         else /* (iCluster != -1) */
1853         {
1854             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1855             {
1856                 if (!cjump)
1857                     iPosX += piAdvance[pwLogClust[iCluster]];
1858                 cjump++;
1859             }
1860             else
1861                 iPosX += piAdvance[pwLogClust[iCluster]] / (float)clust_size;
1862         }
1863     }
1864
1865     if (direction > 0)
1866     {
1867         if (iPosX > iX)
1868             item--;
1869         if (item < cChars && ((iPosX - iLastPosX) / 2.0) + iX >= iPosX)
1870         {
1871             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
1872                 item+=(clust_size-1);
1873             *piTrailing = 1;
1874         }
1875         else
1876             *piTrailing = 0;
1877     }
1878     else
1879     {
1880         if (iX == iLastPosX)
1881             item++;
1882         if (iX >= iLastPosX && iX <= iPosX)
1883             item++;
1884
1885         if (iLastPosX == iX)
1886             *piTrailing = 0;
1887         else if (item < 0 || ((iLastPosX - iPosX) / 2.0) + iX <= iLastPosX)
1888         {
1889             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
1890                 item-=(clust_size-1);
1891             *piTrailing = 1;
1892         }
1893         else
1894             *piTrailing = 0;
1895     }
1896
1897     *piCP = item;
1898
1899     TRACE("*piCP=%d\n", *piCP);
1900     TRACE("*piTrailing=%d\n", *piTrailing);
1901     return S_OK;
1902 }
1903
1904 /***********************************************************************
1905  *      ScriptBreak (USP10.@)
1906  *
1907  *  Retrieve line break information.
1908  *
1909  *  PARAMS
1910  *   chars [I] Array of characters.
1911  *   sa    [I] String analysis.
1912  *   la    [I] Array of logical attribute structures.
1913  *
1914  *  RETURNS
1915  *   Success: S_OK
1916  *   Failure: S_FALSE
1917  */
1918 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
1919 {
1920     TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
1921
1922     if (!la) return S_FALSE;
1923
1924     BREAK_line(chars, count, sa, la);
1925
1926     return S_OK;
1927 }
1928
1929 /***********************************************************************
1930  *      ScriptIsComplex (USP10.@)
1931  *
1932  *  Determine if a string is complex.
1933  *
1934  *  PARAMS
1935  *   chars [I] Array of characters to test.
1936  *   len   [I] Length in characters.
1937  *   flag  [I] Flag.
1938  *
1939  *  RETURNS
1940  *   Success: S_OK
1941  *   Failure: S_FALSE
1942  *
1943  */
1944 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
1945 {
1946     int i;
1947
1948     TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
1949
1950     for (i = 0; i < len; i++)
1951     {
1952         int script;
1953
1954         if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
1955             return S_OK;
1956
1957         script = get_char_script(chars[i]);
1958         if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
1959             (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
1960             return S_OK;
1961     }
1962     return S_FALSE;
1963 }
1964
1965 /***********************************************************************
1966  *      ScriptShapeOpenType (USP10.@)
1967  *
1968  * Produce glyphs and visual attributes for a run.
1969  *
1970  * PARAMS
1971  *  hdc         [I]   Device context.
1972  *  psc         [I/O] Opaque pointer to a script cache.
1973  *  psa         [I/O] Script analysis.
1974  *  tagScript   [I]   The OpenType tag for the Script
1975  *  tagLangSys  [I]   The OpenType tag for the Language
1976  *  rcRangeChars[I]   Array of Character counts in each range
1977  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
1978  *  cRanges     [I]   Count of ranges
1979  *  pwcChars    [I]   Array of characters specifying the run.
1980  *  cChars      [I]   Number of characters in pwcChars.
1981  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
1982  *  pwLogClust  [O]   Array of logical cluster info.
1983  *  pCharProps  [O]   Array of character property values
1984  *  pwOutGlyphs [O]   Array of glyphs.
1985  *  pOutGlyphProps [O]  Array of attributes for the retrieved glyphs
1986  *  pcGlyphs    [O]   Number of glyphs returned.
1987  *
1988  * RETURNS
1989  *  Success: S_OK
1990  *  Failure: Non-zero HRESULT value.
1991  */
1992 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
1993                                     SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
1994                                     OPENTYPE_TAG tagLangSys, int *rcRangeChars,
1995                                     TEXTRANGE_PROPERTIES **rpRangeProperties,
1996                                     int cRanges, const WCHAR *pwcChars, int cChars,
1997                                     int cMaxGlyphs, WORD *pwLogClust,
1998                                     SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
1999                                     SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
2000 {
2001     HRESULT hr;
2002     unsigned int i;
2003     BOOL rtl;
2004
2005     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
2006      hdc, psc, psa,
2007      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2008      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2009      cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
2010
2011     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
2012                    psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
2013
2014     if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
2015     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2016
2017     if (cRanges)
2018         FIXME("Ranges not supported yet\n");
2019
2020     rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
2021
2022     *pcGlyphs = cChars;
2023     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2024     if (!pwLogClust) return E_FAIL;
2025
2026     ((ScriptCache *)*psc)->userScript = tagScript;
2027     ((ScriptCache *)*psc)->userLang = tagLangSys;
2028
2029     /* set fNoGlyphIndex non truetype/opentype fonts */
2030     if (!psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
2031         psa->fNoGlyphIndex = TRUE;
2032
2033     /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
2034     for (i = 0; i < cChars; i++)
2035     {
2036         int idx = i;
2037         if (rtl) idx = cChars - 1 - i;
2038         /* FIXME: set to better values */
2039         pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
2040         pOutGlyphProps[i].sva.fClusterStart  = 1;
2041         pOutGlyphProps[i].sva.fDiacritic     = 0;
2042         pOutGlyphProps[i].sva.fZeroWidth     = 0;
2043         pOutGlyphProps[i].sva.fReserved      = 0;
2044         pOutGlyphProps[i].sva.fShapeReserved = 0;
2045
2046         /* FIXME: have the shaping engine set this */
2047         pCharProps[i].fCanGlyphAlone = 0;
2048
2049         pwLogClust[i] = idx;
2050     }
2051
2052     if (psa && !psa->fNoGlyphIndex)
2053     {
2054         WCHAR *rChars;
2055         if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
2056
2057         rChars = heap_alloc(sizeof(WCHAR) * cChars);
2058         if (!rChars) return E_OUTOFMEMORY;
2059         for (i = 0; i < cChars; i++)
2060         {
2061             int idx = i;
2062             WCHAR chInput;
2063             if (rtl) idx = cChars - 1 - i;
2064             if (psa->fRTL)
2065                 chInput = mirror_char(pwcChars[idx]);
2066             else
2067                 chInput = pwcChars[idx];
2068             /* special case for tabs */
2069             if (chInput == 0x0009)
2070                 chInput = 0x0020;
2071             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, chInput)))
2072             {
2073                 WORD glyph;
2074                 if (!hdc) return E_PENDING;
2075                 if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR) return S_FALSE;
2076                 pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph);
2077             }
2078             rChars[i] = chInput;
2079         }
2080
2081         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2082         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
2083         SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
2084         heap_free(rChars);
2085     }
2086     else
2087     {
2088         TRACE("no glyph translation\n");
2089         for (i = 0; i < cChars; i++)
2090         {
2091             int idx = i;
2092             /* No mirroring done here */
2093             if (rtl) idx = cChars - 1 - i;
2094             pwOutGlyphs[i] = pwcChars[idx];
2095         }
2096     }
2097
2098     return S_OK;
2099 }
2100
2101
2102 /***********************************************************************
2103  *      ScriptShape (USP10.@)
2104  *
2105  * Produce glyphs and visual attributes for a run.
2106  *
2107  * PARAMS
2108  *  hdc         [I]   Device context.
2109  *  psc         [I/O] Opaque pointer to a script cache.
2110  *  pwcChars    [I]   Array of characters specifying the run.
2111  *  cChars      [I]   Number of characters in pwcChars.
2112  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
2113  *  psa         [I/O] Script analysis.
2114  *  pwOutGlyphs [O]   Array of glyphs.
2115  *  pwLogClust  [O]   Array of logical cluster info.
2116  *  psva        [O]   Array of visual attributes.
2117  *  pcGlyphs    [O]   Number of glyphs returned.
2118  *
2119  * RETURNS
2120  *  Success: S_OK
2121  *  Failure: Non-zero HRESULT value.
2122  */
2123 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
2124                            int cChars, int cMaxGlyphs,
2125                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
2126                            SCRIPT_VISATTR *psva, int *pcGlyphs)
2127 {
2128     HRESULT hr;
2129     int i;
2130     SCRIPT_CHARPROP *charProps;
2131     SCRIPT_GLYPHPROP *glyphProps;
2132
2133     if (!psva || !pcGlyphs) return E_INVALIDARG;
2134     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2135
2136     charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
2137     if (!charProps) return E_OUTOFMEMORY;
2138     glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
2139     if (!glyphProps) return E_OUTOFMEMORY;
2140
2141     hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
2142
2143     if (SUCCEEDED(hr))
2144     {
2145         for (i = 0; i < *pcGlyphs; i++)
2146             psva[i] = glyphProps[i].sva;
2147     }
2148
2149     heap_free(charProps);
2150     heap_free(glyphProps);
2151
2152     return hr;
2153 }
2154
2155 /***********************************************************************
2156  *      ScriptPlaceOpenType (USP10.@)
2157  *
2158  * Produce advance widths for a run.
2159  *
2160  * PARAMS
2161  *  hdc       [I]   Device context.
2162  *  psc       [I/O] Opaque pointer to a script cache.
2163  *  psa       [I/O] String analysis.
2164  *  tagScript   [I]   The OpenType tag for the Script
2165  *  tagLangSys  [I]   The OpenType tag for the Language
2166  *  rcRangeChars[I]   Array of Character counts in each range
2167  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2168  *  cRanges     [I]   Count of ranges
2169  *  pwcChars    [I]   Array of characters specifying the run.
2170  *  pwLogClust  [I]   Array of logical cluster info
2171  *  pCharProps  [I]   Array of character property values
2172  *  cChars      [I]   Number of characters in pwcChars.
2173  *  pwGlyphs  [I]   Array of glyphs.
2174  *  pGlyphProps [I]  Array of attributes for the retrieved glyphs
2175  *  cGlyphs [I] Count of Glyphs
2176  *  piAdvance [O]   Array of advance widths.
2177  *  pGoffset  [O]   Glyph offsets.
2178  *  pABC      [O]   Combined ABC width.
2179  *
2180  * RETURNS
2181  *  Success: S_OK
2182  *  Failure: Non-zero HRESULT value.
2183  */
2184
2185 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
2186                                     OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
2187                                     int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
2188                                     int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
2189                                     SCRIPT_CHARPROP *pCharProps, int cChars,
2190                                     const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
2191                                     int cGlyphs, int *piAdvance,
2192                                     GOFFSET *pGoffset, ABC *pABC
2193 )
2194 {
2195     HRESULT hr;
2196     int i;
2197
2198     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
2199      hdc, psc, psa,
2200      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2201      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2202      pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
2203      pGoffset, pABC);
2204
2205     if (!pGlyphProps) return E_INVALIDARG;
2206     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2207     if (!pGoffset) return E_FAIL;
2208
2209     if (cRanges)
2210         FIXME("Ranges not supported yet\n");
2211
2212     ((ScriptCache *)*psc)->userScript = tagScript;
2213     ((ScriptCache *)*psc)->userLang = tagLangSys;
2214
2215     if (pABC) memset(pABC, 0, sizeof(ABC));
2216     for (i = 0; i < cGlyphs; i++)
2217     {
2218         ABC abc;
2219         if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
2220         {
2221             if (!hdc) return E_PENDING;
2222             if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
2223             {
2224                 if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
2225             }
2226             else
2227             {
2228                 INT width;
2229                 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
2230                 abc.abcB = width;
2231                 abc.abcA = abc.abcC = 0;
2232             }
2233             set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
2234         }
2235         if (pABC)
2236         {
2237             pABC->abcA += abc.abcA;
2238             pABC->abcB += abc.abcB;
2239             pABC->abcC += abc.abcC;
2240         }
2241         /* FIXME: set to more reasonable values */
2242         pGoffset[i].du = pGoffset[i].dv = 0;
2243         if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
2244     }
2245
2246     if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
2247     return S_OK;
2248 }
2249
2250 /***********************************************************************
2251  *      ScriptPlace (USP10.@)
2252  *
2253  * Produce advance widths for a run.
2254  *
2255  * PARAMS
2256  *  hdc       [I]   Device context.
2257  *  psc       [I/O] Opaque pointer to a script cache.
2258  *  pwGlyphs  [I]   Array of glyphs.
2259  *  cGlyphs   [I]   Number of glyphs in pwGlyphs.
2260  *  psva      [I]   Array of visual attributes.
2261  *  psa       [I/O] String analysis.
2262  *  piAdvance [O]   Array of advance widths.
2263  *  pGoffset  [O]   Glyph offsets.
2264  *  pABC      [O]   Combined ABC width.
2265  *
2266  * RETURNS
2267  *  Success: S_OK
2268  *  Failure: Non-zero HRESULT value.
2269  */
2270 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
2271                            int cGlyphs, const SCRIPT_VISATTR *psva,
2272                            SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
2273 {
2274     HRESULT hr;
2275     SCRIPT_GLYPHPROP *glyphProps;
2276     int i;
2277
2278     TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n",  hdc, psc, pwGlyphs, cGlyphs, psva, psa,
2279           piAdvance, pGoffset, pABC);
2280
2281     if (!psva) return E_INVALIDARG;
2282     if (!pGoffset) return E_FAIL;
2283
2284     glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
2285     if (!glyphProps) return E_OUTOFMEMORY;
2286
2287     for (i = 0; i < cGlyphs; i++)
2288         glyphProps[i].sva = psva[i];
2289
2290     hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
2291
2292     heap_free(glyphProps);
2293
2294     return hr;
2295 }
2296
2297 /***********************************************************************
2298  *      ScriptGetCMap (USP10.@)
2299  *
2300  * Retrieve glyph indices.
2301  *
2302  * PARAMS
2303  *  hdc         [I]   Device context.
2304  *  psc         [I/O] Opaque pointer to a script cache.
2305  *  pwcInChars  [I]   Array of Unicode characters.
2306  *  cChars      [I]   Number of characters in pwcInChars.
2307  *  dwFlags     [I]   Flags.
2308  *  pwOutGlyphs [O]   Buffer to receive the array of glyph indices.
2309  *
2310  * RETURNS
2311  *  Success: S_OK
2312  *  Failure: Non-zero HRESULT value.
2313  */
2314 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
2315                              int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
2316 {
2317     HRESULT hr;
2318     int i;
2319
2320     TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
2321           cChars, dwFlags, pwOutGlyphs);
2322
2323     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2324
2325     hr = S_OK;
2326
2327     if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2328     {
2329         for (i = 0; i < cChars; i++)
2330         {
2331             WCHAR inChar;
2332             if (dwFlags == SGCM_RTL)
2333                 inChar = mirror_char(pwcInChars[i]);
2334             else
2335                 inChar = pwcInChars[i];
2336             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
2337             {
2338                 WORD glyph;
2339                 if (!hdc) return E_PENDING;
2340                 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
2341                 if (glyph == 0xffff)
2342                 {
2343                     hr = S_FALSE;
2344                     glyph = 0x0;
2345                 }
2346                 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
2347             }
2348         }
2349     }
2350     else
2351     {
2352         TRACE("no glyph translation\n");
2353         for (i = 0; i < cChars; i++)
2354         {
2355             WCHAR inChar;
2356             if (dwFlags == SGCM_RTL)
2357                 inChar = mirror_char(pwcInChars[i]);
2358             else
2359                 inChar = pwcInChars[i];
2360             pwOutGlyphs[i] = inChar;
2361         }
2362     }
2363     return hr;
2364 }
2365
2366 /***********************************************************************
2367  *      ScriptTextOut (USP10.@)
2368  *
2369  */
2370 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
2371                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
2372                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
2373                              const int *piJustify, const GOFFSET *pGoffset)
2374 {
2375     HRESULT hr = S_OK;
2376
2377     TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
2378          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
2379          piAdvance, piJustify, pGoffset);
2380
2381     if (!hdc || !psc) return E_INVALIDARG;
2382     if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
2383
2384     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
2385     fuOptions |= ETO_IGNORELANGUAGE;
2386     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
2387         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do translation to glyph */
2388
2389     if (psa->fRTL && psa->fLogicalOrder)
2390     {
2391         int i;
2392         WORD *rtlGlyphs;
2393
2394         rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD));
2395         if (!rtlGlyphs)
2396             return E_OUTOFMEMORY;
2397
2398         for (i = 0; i < cGlyphs; i++)
2399             rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i];
2400
2401         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL))
2402             hr = S_FALSE;
2403         heap_free(rtlGlyphs);
2404     }
2405     else
2406         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
2407             hr = S_FALSE;
2408
2409     return hr;
2410 }
2411
2412 /***********************************************************************
2413  *      ScriptCacheGetHeight (USP10.@)
2414  *
2415  * Retrieve the height of the font in the cache.
2416  *
2417  * PARAMS
2418  *  hdc    [I]    Device context.
2419  *  psc    [I/O]  Opaque pointer to a script cache.
2420  *  height [O]    Receives font height.
2421  *
2422  * RETURNS
2423  *  Success: S_OK
2424  *  Failure: Non-zero HRESULT value.
2425  */
2426 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
2427 {
2428     HRESULT hr;
2429
2430     TRACE("(%p, %p, %p)\n", hdc, psc, height);
2431
2432     if (!height) return E_INVALIDARG;
2433     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2434
2435     *height = get_cache_height(psc);
2436     return S_OK;
2437 }
2438
2439 /***********************************************************************
2440  *      ScriptGetGlyphABCWidth (USP10.@)
2441  *
2442  * Retrieve the width of a glyph.
2443  *
2444  * PARAMS
2445  *  hdc    [I]    Device context.
2446  *  psc    [I/O]  Opaque pointer to a script cache.
2447  *  glyph  [I]    Glyph to retrieve the width for.
2448  *  abc    [O]    ABC widths of the glyph.
2449  *
2450  * RETURNS
2451  *  Success: S_OK
2452  *  Failure: Non-zero HRESULT value.
2453  */
2454 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
2455 {
2456     HRESULT hr;
2457
2458     TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
2459
2460     if (!abc) return E_INVALIDARG;
2461     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2462
2463     if (!get_cache_glyph_widths(psc, glyph, abc))
2464     {
2465         if (!hdc) return E_PENDING;
2466         if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2467         {
2468             if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
2469         }
2470         else
2471         {
2472             INT width;
2473             if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
2474             abc->abcB = width;
2475             abc->abcA = abc->abcC = 0;
2476         }
2477         set_cache_glyph_widths(psc, glyph, abc);
2478     }
2479     return S_OK;
2480 }
2481
2482 /***********************************************************************
2483  *      ScriptLayout (USP10.@)
2484  *
2485  * Map embedding levels to visual and/or logical order.
2486  *
2487  * PARAMS
2488  *  runs     [I] Size of level array.
2489  *  level    [I] Array of embedding levels.
2490  *  vistolog [O] Map of embedding levels from visual to logical order.
2491  *  logtovis [O] Map of embedding levels from logical to visual order.
2492  *
2493  * RETURNS
2494  *  Success: S_OK
2495  *  Failure: Non-zero HRESULT value.
2496  *
2497  * BUGS
2498  *  This stub works correctly for any sequence of a single
2499  *  embedding level but not for sequences of different
2500  *  embedding levels, i.e. mixtures of RTL and LTR scripts.
2501  */
2502 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
2503 {
2504     int* indexs;
2505     int ich;
2506
2507     TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
2508
2509     if (!level || (!vistolog && !logtovis))
2510         return E_INVALIDARG;
2511
2512     indexs = heap_alloc(sizeof(int) * runs);
2513     if (!indexs)
2514         return E_OUTOFMEMORY;
2515
2516
2517     if (vistolog)
2518     {
2519         for( ich = 0; ich < runs; ich++)
2520             indexs[ich] = ich;
2521
2522         ich = 0;
2523         while (ich < runs)
2524             ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2525         for (ich = 0; ich < runs; ich++)
2526             vistolog[ich] = indexs[ich];
2527     }
2528
2529
2530     if (logtovis)
2531     {
2532         for( ich = 0; ich < runs; ich++)
2533             indexs[ich] = ich;
2534
2535         ich = 0;
2536         while (ich < runs)
2537             ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2538         for (ich = 0; ich < runs; ich++)
2539             logtovis[ich] = indexs[ich];
2540     }
2541     heap_free(indexs);
2542
2543     return S_OK;
2544 }
2545
2546 /***********************************************************************
2547  *      ScriptStringGetLogicalWidths (USP10.@)
2548  *
2549  * Returns logical widths from a string analysis.
2550  *
2551  * PARAMS
2552  *  ssa  [I] string analysis.
2553  *  piDx [O] logical widths returned.
2554  *
2555  * RETURNS
2556  *  Success: S_OK
2557  *  Failure: a non-zero HRESULT.
2558  */
2559 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
2560 {
2561     int i, j, next = 0;
2562     StringAnalysis *analysis = ssa;
2563
2564     TRACE("%p, %p\n", ssa, piDx);
2565
2566     if (!analysis) return S_FALSE;
2567     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2568
2569     for (i = 0; i < analysis->numItems; i++)
2570     {
2571         int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2572         for (j = 0; j < cChar; j++)
2573         {
2574
2575             int glyph = analysis->glyphs[i].pwLogClust[j];
2576             piDx[next] = analysis->glyphs[i].piAdvance[glyph];
2577             next++;
2578         }
2579     }
2580     return S_OK;
2581 }
2582
2583 /***********************************************************************
2584  *      ScriptStringValidate (USP10.@)
2585  *
2586  * Validate a string analysis.
2587  *
2588  * PARAMS
2589  *  ssa [I] string analysis.
2590  *
2591  * RETURNS
2592  *  Success: S_OK
2593  *  Failure: S_FALSE if invalid sequences are found
2594  *           or a non-zero HRESULT if it fails.
2595  */
2596 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
2597 {
2598     StringAnalysis *analysis = ssa;
2599
2600     TRACE("(%p)\n", ssa);
2601
2602     if (!analysis) return E_INVALIDARG;
2603     return (analysis->invalid) ? S_FALSE : S_OK;
2604 }
2605
2606 /***********************************************************************
2607  *      ScriptString_pSize (USP10.@)
2608  *
2609  * Retrieve width and height of an analysed string.
2610  *
2611  * PARAMS
2612  *  ssa [I] string analysis.
2613  *
2614  * RETURNS
2615  *  Success: Pointer to a SIZE structure.
2616  *  Failure: NULL
2617  */
2618 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
2619 {
2620     int i, j;
2621     StringAnalysis *analysis = ssa;
2622
2623     TRACE("(%p)\n", ssa);
2624
2625     if (!analysis) return NULL;
2626     if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
2627
2628     if (!analysis->sz)
2629     {
2630         if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
2631         analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
2632
2633         analysis->sz->cx = 0;
2634         for (i = 0; i < analysis->numItems; i++)
2635         {
2636             if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
2637                 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
2638             for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
2639                 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
2640         }
2641     }
2642     return analysis->sz;
2643 }
2644
2645 /***********************************************************************
2646  *      ScriptString_pLogAttr (USP10.@)
2647  *
2648  * Retrieve logical attributes of an analysed string.
2649  *
2650  * PARAMS
2651  *  ssa [I] string analysis.
2652  *
2653  * RETURNS
2654  *  Success: Pointer to an array of SCRIPT_LOGATTR structures.
2655  *  Failure: NULL
2656  */
2657 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
2658 {
2659     StringAnalysis *analysis = ssa;
2660
2661     TRACE("(%p)\n", ssa);
2662
2663     if (!analysis) return NULL;
2664     if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
2665     return analysis->logattrs;
2666 }
2667
2668 /***********************************************************************
2669  *      ScriptString_pcOutChars (USP10.@)
2670  *
2671  * Retrieve the length of a string after clipping.
2672  *
2673  * PARAMS
2674  *  ssa [I] String analysis.
2675  *
2676  * RETURNS
2677  *  Success: Pointer to the length.
2678  *  Failure: NULL
2679  */
2680 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
2681 {
2682     StringAnalysis *analysis = ssa;
2683
2684     TRACE("(%p)\n", ssa);
2685
2686     if (!analysis) return NULL;
2687     return &analysis->clip_len;
2688 }
2689
2690 /***********************************************************************
2691  *      ScriptStringGetOrder (USP10.@)
2692  *
2693  * Retrieve a glyph order map.
2694  *
2695  * PARAMS
2696  *  ssa   [I]   String analysis.
2697  *  order [I/O] Array of glyph positions.
2698  *
2699  * RETURNS
2700  *  Success: S_OK
2701  *  Failure: a non-zero HRESULT.
2702  */
2703 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
2704 {
2705     int i, j;
2706     unsigned int k;
2707     StringAnalysis *analysis = ssa;
2708
2709     TRACE("(%p)\n", ssa);
2710
2711     if (!analysis) return S_FALSE;
2712     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2713
2714     /* FIXME: handle RTL scripts */
2715     for (i = 0, k = 0; i < analysis->numItems; i++)
2716         for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
2717             order[k] = k;
2718
2719     return S_OK;
2720 }
2721
2722 /***********************************************************************
2723  *      ScriptGetLogicalWidths (USP10.@)
2724  *
2725  * Convert advance widths to logical widths.
2726  *
2727  * PARAMS
2728  *  sa          [I] Script analysis.
2729  *  nbchars     [I] Number of characters.
2730  *  nbglyphs    [I] Number of glyphs.
2731  *  glyph_width [I] Array of glyph widths.
2732  *  log_clust   [I] Array of logical clusters.
2733  *  sva         [I] Visual attributes.
2734  *  widths      [O] Array of logical widths.
2735  *
2736  * RETURNS
2737  *  Success: S_OK
2738  *  Failure: a non-zero HRESULT.
2739  */
2740 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
2741                                       const int *glyph_width, const WORD *log_clust,
2742                                       const SCRIPT_VISATTR *sva, int *widths)
2743 {
2744     int i;
2745
2746     TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
2747           sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);
2748
2749     /* FIXME */
2750     for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
2751     return S_OK;
2752 }
2753
2754 /***********************************************************************
2755  *      ScriptApplyLogicalWidth (USP10.@)
2756  *
2757  * Generate glyph advance widths.
2758  *
2759  * PARAMS
2760  *  dx          [I]   Array of logical advance widths.
2761  *  num_chars   [I]   Number of characters.
2762  *  num_glyphs  [I]   Number of glyphs.
2763  *  log_clust   [I]   Array of logical clusters.
2764  *  sva         [I]   Visual attributes.
2765  *  advance     [I]   Array of glyph advance widths.
2766  *  sa          [I]   Script analysis.
2767  *  abc         [I/O] Summed ABC widths.
2768  *  justify     [O]   Array of glyph advance widths.
2769  *
2770  * RETURNS
2771  *  Success: S_OK
2772  *  Failure: a non-zero HRESULT.
2773  */
2774 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
2775                                        const WORD *log_clust, const SCRIPT_VISATTR *sva,
2776                                        const int *advance, const SCRIPT_ANALYSIS *sa,
2777                                        ABC *abc, int *justify)
2778 {
2779     int i;
2780
2781     FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
2782           dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
2783
2784     for (i = 0; i < num_chars; i++) justify[i] = advance[i];
2785     return S_OK;
2786 }
2787
2788 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
2789                              int num_glyphs, int dx, int min_kashida, int *justify)
2790 {
2791     int i;
2792
2793     FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
2794
2795     for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
2796     return S_OK;
2797 }