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