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