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