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