xref: /reactos/dll/win32/usp10/usp10.c (revision 5417742f)
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_calloc(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         if (!(levels = heap_calloc(cInChars, sizeof(*levels))))
1468             goto nomemory;
1469 
1470         if (!(overrides = heap_calloc(cInChars, sizeof(*overrides))))
1471             goto nomemory;
1472 
1473         if (!(layout_levels = heap_calloc(cInChars, sizeof(*layout_levels))))
1474             goto nomemory;
1475 
1476         if (psState->fOverrideDirection)
1477         {
1478             if (!forceLevels)
1479             {
1480                 SCRIPT_STATE s = *psState;
1481                 s.fOverrideDirection = FALSE;
1482                 BIDI_DetermineLevels(pwcInChars, cInChars, &s, psControl, layout_levels, overrides);
1483                 if (odd(layout_levels[0]))
1484                     forceLevels = TRUE;
1485                 else for (i = 0; i < cInChars; i++)
1486                     if (layout_levels[i]!=layout_levels[0])
1487                     {
1488                         forceLevels = TRUE;
1489                         break;
1490                     }
1491             }
1492 
1493             BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1494         }
1495         else
1496         {
1497             BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1498             memcpy(layout_levels, levels, cInChars * sizeof(WORD));
1499         }
1500         baselevel = levels[0];
1501         baselayout = layout_levels[0];
1502         for (i = 0; i < cInChars; i++)
1503             if (levels[i]!=levels[0])
1504                 break;
1505         if (i >= cInChars && !odd(baselevel) && !odd(psState->uBidiLevel) && !forceLevels)
1506         {
1507             heap_free(levels);
1508             heap_free(overrides);
1509             heap_free(layout_levels);
1510             overrides = NULL;
1511             levels = NULL;
1512             layout_levels = NULL;
1513         }
1514         else
1515         {
1516             static const WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1517             static const WCHAR repeatable_math_punc[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1518 
1519             if (!(strength = heap_calloc(cInChars, sizeof(*strength))))
1520                 goto nomemory;
1521             BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
1522 
1523             /* We currently mis-level leading Diacriticals */
1524             if (scripts[0] == Script_Diacritical)
1525                 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
1526                 {
1527                     levels[i] = odd(levels[i])?levels[i]+1:levels[i];
1528                     strength[i] = BIDI_STRONG;
1529                 }
1530 
1531             /* Math punctuation bordered on both sides by numbers can be
1532                merged into the number */
1533             for (i = 0; i < cInChars; i++)
1534             {
1535                 if (i > 0 && i < cInChars-1 &&
1536                     script_is_numeric(scripts[i-1]) &&
1537                     strchrW(math_punc, pwcInChars[i]))
1538                 {
1539                     if (script_is_numeric(scripts[i+1]))
1540                     {
1541                         scripts[i] = scripts[i+1];
1542                         levels[i] = levels[i-1];
1543                         strength[i] = strength[i-1];
1544                         i++;
1545                     }
1546                     else if (strchrW(repeatable_math_punc, pwcInChars[i]))
1547                     {
1548                         int j;
1549                         for (j = i+1; j < cInChars; j++)
1550                         {
1551                             if (script_is_numeric(scripts[j]))
1552                             {
1553                                 for(;i<j; i++)
1554                                 {
1555                                     scripts[i] = scripts[j];
1556                                     levels[i] = levels[i-1];
1557                                     strength[i] = strength[i-1];
1558                                 }
1559                             }
1560                             else if (pwcInChars[i] != pwcInChars[j]) break;
1561                         }
1562                     }
1563                 }
1564             }
1565 
1566             for (i = 0; i < cInChars; i++)
1567             {
1568                 /* Numerics at level 0 get bumped to level 2 */
1569                 if (!overrides[i] && (levels[i] == 0 || (odd(psState->uBidiLevel)
1570                         && levels[i] == psState->uBidiLevel + 1)) && script_is_numeric(scripts[i]))
1571                 {
1572                     levels[i] = 2;
1573                 }
1574 
1575                 /* Joiners get merged preferencially right */
1576                 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1577                 {
1578                     int j;
1579                     if (i+1 == cInChars && levels[i-1] == levels[i])
1580                         strength[i] = strength[i-1];
1581                     else
1582                         for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
1583                             if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1584                                     && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1585                             {
1586                                 strength[i] = strength[j];
1587                                 break;
1588                             }
1589                 }
1590             }
1591             if (psControl->fMergeNeutralItems)
1592             {
1593                 /* Merge the neutrals */
1594                 for (i = 0; i < cInChars; i++)
1595                 {
1596                     if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1597                     {
1598                         int j;
1599                         for (j = i; j > 0; j--)
1600                         {
1601                             if (levels[i] != levels[j])
1602                                 break;
1603                             if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1604                             {
1605                                 scripts[i] = scripts[j];
1606                                 strength[i] = strength[j];
1607                                 break;
1608                             }
1609                         }
1610                     }
1611                     /* Try going the other way */
1612                     if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1613                     {
1614                         int j;
1615                         for (j = i; j < cInChars; j++)
1616                         {
1617                             if (levels[i] != levels[j])
1618                                 break;
1619                             if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1620                             {
1621                                 scripts[i] = scripts[j];
1622                                 strength[i] = strength[j];
1623                                 break;
1624                             }
1625                         }
1626                     }
1627                 }
1628             }
1629         }
1630     }
1631 
1632     while ((!levels || (levels && cnt+1 < cInChars && levels[cnt+1] == levels[0]))
1633             && (cnt < cInChars && pwcInChars[cnt] == Numeric_space))
1634         cnt++;
1635 
1636     if (cnt == cInChars) /* All Spaces */
1637     {
1638         cnt = 0;
1639         New_Script = scripts[cnt];
1640     }
1641 
1642     pItems[index].iCharPos = 0;
1643     pItems[index].a = scriptInformation[scripts[cnt]].a;
1644     if (pScriptTags)
1645         pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
1646 
1647     if (strength && strength[cnt] == BIDI_STRONG)
1648         str = strength[cnt];
1649     else if (strength)
1650         str = strength[0];
1651 
1652     cnt = 0;
1653 
1654     if (levels)
1655     {
1656         if (strength[cnt] == BIDI_STRONG)
1657             layoutRTL = odd(layout_levels[cnt]);
1658         else
1659             layoutRTL = (psState->uBidiLevel || odd(layout_levels[cnt]));
1660         if (overrides)
1661             pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1662         pItems[index].a.fRTL = odd(levels[cnt]);
1663         if (script_is_numeric(pItems[index].a.eScript))
1664             pItems[index].a.fLayoutRTL = layoutRTL;
1665         else
1666             pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1667         pItems[index].a.s.uBidiLevel = levels[cnt];
1668     }
1669     else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1670     {
1671         if (pItems[index].a.s.uBidiLevel != baselevel)
1672             pItems[index].a.s.fOverrideDirection = TRUE;
1673         layoutRTL = odd(baselayout);
1674         pItems[index].a.s.uBidiLevel = baselevel;
1675         pItems[index].a.fRTL = odd(baselevel);
1676         if (script_is_numeric(pItems[index].a.eScript))
1677             pItems[index].a.fLayoutRTL = odd(baselayout);
1678         else
1679             pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1680     }
1681 
1682     TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1683           levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
1684           pItems[index].iCharPos);
1685 
1686     for (cnt=1; cnt < cInChars; cnt++)
1687     {
1688         if(pwcInChars[cnt] != Numeric_space)
1689             New_Script = scripts[cnt];
1690         else if (levels)
1691         {
1692             int j = 1;
1693             while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
1694                 j++;
1695             if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
1696                 New_Script = scripts[cnt+j];
1697             else
1698                 New_Script = scripts[cnt];
1699         }
1700 
1701         new_run = FALSE;
1702         /* merge space strengths*/
1703         if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
1704             str = BIDI_STRONG;
1705 
1706         if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
1707             str = BIDI_NEUTRAL;
1708 
1709         /* changes in level */
1710         if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
1711         {
1712             TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
1713             new_run = TRUE;
1714         }
1715         /* changes in strength */
1716         else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
1717         {
1718             TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
1719             new_run = TRUE;
1720         }
1721         /* changes in script */
1722         else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
1723         {
1724             TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
1725             new_run = TRUE;
1726         }
1727 
1728         if (!new_run && strength && str == BIDI_STRONG)
1729         {
1730             layoutRTL = odd(layout_levels[cnt]);
1731             if (script_is_numeric(pItems[index].a.eScript))
1732                 pItems[index].a.fLayoutRTL = layoutRTL;
1733         }
1734 
1735         if (new_run)
1736         {
1737             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);
1738 
1739             index++;
1740             if  (index+1 > cMaxItems)
1741                 goto nomemory;
1742 
1743             if (strength)
1744                 str = strength[cnt];
1745 
1746             pItems[index].iCharPos = cnt;
1747             memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1748 
1749             pItems[index].a = scriptInformation[New_Script].a;
1750             if (pScriptTags)
1751                 pScriptTags[index] = scriptInformation[New_Script].scriptTag;
1752             if (levels)
1753             {
1754                 if (overrides)
1755                     pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1756                 if (layout_levels[cnt] == 0)
1757                     layoutRTL = 0;
1758                 else
1759                     layoutRTL = (layoutRTL || odd(layout_levels[cnt]));
1760                 pItems[index].a.fRTL = odd(levels[cnt]);
1761                 if (script_is_numeric(pItems[index].a.eScript))
1762                     pItems[index].a.fLayoutRTL = layoutRTL;
1763                 else
1764                     pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1765                 pItems[index].a.s.uBidiLevel = levels[cnt];
1766             }
1767             else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1768             {
1769                 if (pItems[index].a.s.uBidiLevel != baselevel)
1770                     pItems[index].a.s.fOverrideDirection = TRUE;
1771                 pItems[index].a.s.uBidiLevel = baselevel;
1772                 pItems[index].a.fRTL = odd(baselevel);
1773                 if (script_is_numeric(pItems[index].a.eScript))
1774                     pItems[index].a.fLayoutRTL = layoutRTL;
1775                 else
1776                     pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1777             }
1778 
1779             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1780         }
1781     }
1782 
1783     /* While not strictly necessary according to the spec, make sure the n+1
1784      * item is set up to prevent random behaviour if the caller erroneously
1785      * checks the n+1 structure                                              */
1786     index++;
1787     if (index + 1 > cMaxItems) goto nomemory;
1788     memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1789 
1790     TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1791 
1792     /*  Set one SCRIPT_STATE item being returned  */
1793     if (pcItems) *pcItems = index;
1794 
1795     /*  Set SCRIPT_ITEM                                     */
1796     pItems[index].iCharPos = cnt;         /* the last item contains the ptr to the lastchar */
1797     res = S_OK;
1798 nomemory:
1799     heap_free(levels);
1800     heap_free(overrides);
1801     heap_free(layout_levels);
1802     heap_free(strength);
1803     heap_free(scripts);
1804     return res;
1805 }
1806 
1807 /***********************************************************************
1808  *      ScriptItemizeOpenType (USP10.@)
1809  *
1810  * Split a Unicode string into shapeable parts.
1811  *
1812  * PARAMS
1813  *  pwcInChars  [I] String to split.
1814  *  cInChars    [I] Number of characters in pwcInChars.
1815  *  cMaxItems   [I] Maximum number of items to return.
1816  *  psControl   [I] Pointer to a SCRIPT_CONTROL structure.
1817  *  psState     [I] Pointer to a SCRIPT_STATE structure.
1818  *  pItems      [O] Buffer to receive SCRIPT_ITEM structures.
1819  *  pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1820  *  pcItems     [O] Number of script items returned.
1821  *
1822  * RETURNS
1823  *  Success: S_OK
1824  *  Failure: Non-zero HRESULT value.
1825  */
1826 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1827                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1828                              SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
1829 {
1830     return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pScriptTags, pcItems);
1831 }
1832 
1833 /***********************************************************************
1834  *      ScriptItemize (USP10.@)
1835  *
1836  * Split a Unicode string into shapeable parts.
1837  *
1838  * PARAMS
1839  *  pwcInChars [I] String to split.
1840  *  cInChars   [I] Number of characters in pwcInChars.
1841  *  cMaxItems  [I] Maximum number of items to return.
1842  *  psControl  [I] Pointer to a SCRIPT_CONTROL structure.
1843  *  psState    [I] Pointer to a SCRIPT_STATE structure.
1844  *  pItems     [O] Buffer to receive SCRIPT_ITEM structures.
1845  *  pcItems    [O] Number of script items returned.
1846  *
1847  * RETURNS
1848  *  Success: S_OK
1849  *  Failure: Non-zero HRESULT value.
1850  */
1851 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1852                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1853                              SCRIPT_ITEM *pItems, int *pcItems)
1854 {
1855     return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, NULL, pcItems);
1856 }
1857 
1858 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1859 {
1860     int defWidth;
1861     int cTabStops=0;
1862     INT *lpTabPos = NULL;
1863     INT nTabOrg = 0;
1864     INT x = 0;
1865 
1866     if (pTabdef)
1867         lpTabPos = pTabdef->pTabStops;
1868 
1869     if (pTabdef && pTabdef->iTabOrigin)
1870     {
1871         if (pTabdef->iScale)
1872             nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1873         else
1874             nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1875     }
1876 
1877     if (pTabdef)
1878         cTabStops = pTabdef->cTabStops;
1879 
1880     if (cTabStops == 1)
1881     {
1882         if (pTabdef->iScale)
1883             defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1884         else
1885             defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1886         cTabStops = 0;
1887     }
1888     else
1889     {
1890         if (pTabdef->iScale)
1891             defWidth = (32 * pTabdef->iScale) / 4;
1892         else
1893             defWidth = 8 * psc->tm.tmAveCharWidth;
1894     }
1895 
1896     for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1897     {
1898         int position = *lpTabPos;
1899         if (position < 0)
1900             position = -1 * position;
1901         if (pTabdef->iScale)
1902             position = (position * pTabdef->iScale) / 4;
1903         else
1904             position = position * psc->tm.tmAveCharWidth;
1905 
1906         if( nTabOrg + position > current_x)
1907         {
1908             if( position >= 0)
1909             {
1910                 /* a left aligned tab */
1911                 x = (nTabOrg + position) - current_x;
1912                 break;
1913             }
1914             else
1915             {
1916                 FIXME("Negative tabstop\n");
1917                 break;
1918             }
1919         }
1920     }
1921     if ((!cTabStops) && (defWidth > 0))
1922         x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1923     else if ((!cTabStops) && (defWidth < 0))
1924         FIXME("TODO: Negative defWidth\n");
1925 
1926     return x;
1927 }
1928 
1929 /***********************************************************************
1930  * Helper function for ScriptStringAnalyse
1931  */
1932 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1933                               const WCHAR *pwcInChars, int cChars )
1934 {
1935     /* FIXME: When to properly fallback is still a bit of a mystery */
1936     WORD *glyphs;
1937 
1938     if (psa->fNoGlyphIndex)
1939         return FALSE;
1940 
1941     if (init_script_cache(hdc, psc) != S_OK)
1942         return FALSE;
1943 
1944     if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1945         return TRUE;
1946 
1947     if (!(glyphs = heap_calloc(cChars, sizeof(*glyphs))))
1948         return FALSE;
1949     if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1950     {
1951         heap_free(glyphs);
1952         return TRUE;
1953     }
1954     heap_free(glyphs);
1955 
1956     return FALSE;
1957 }
1958 
1959 static void find_fallback_font(enum usp10_script scriptid, WCHAR *FaceName)
1960 {
1961     HKEY hkey;
1962 
1963     if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1964     {
1965         static const WCHAR szFmt[] = {'%','x',0};
1966         WCHAR value[10];
1967         DWORD count = LF_FACESIZE * sizeof(WCHAR);
1968         DWORD type;
1969 
1970         sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1971         if (RegQueryValueExW(hkey, value, 0, &type, (BYTE *)FaceName, &count))
1972             lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1973         RegCloseKey(hkey);
1974     }
1975     else
1976         lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1977 }
1978 
1979 /***********************************************************************
1980  *      ScriptStringAnalyse (USP10.@)
1981  *
1982  */
1983 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1984                                    int cGlyphs, int iCharset, DWORD dwFlags,
1985                                    int iReqWidth, SCRIPT_CONTROL *psControl,
1986                                    SCRIPT_STATE *psState, const int *piDx,
1987                                    SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1988                                    SCRIPT_STRING_ANALYSIS *pssa)
1989 {
1990     HRESULT hr = E_OUTOFMEMORY;
1991     StringAnalysis *analysis = NULL;
1992     SCRIPT_CONTROL sControl;
1993     SCRIPT_STATE sState;
1994     int i, num_items = 255;
1995     BYTE   *BidiLevel;
1996     WCHAR *iString = NULL;
1997 
1998     TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1999           hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
2000           psControl, psState, piDx, pTabdef, pbInClass, pssa);
2001 
2002     if (iCharset != -1)
2003     {
2004         FIXME("Only Unicode strings are supported\n");
2005         return E_INVALIDARG;
2006     }
2007     if (cString < 1 || !pString) return E_INVALIDARG;
2008     if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
2009 
2010     if (!(analysis = heap_alloc_zero(sizeof(*analysis))))
2011         return E_OUTOFMEMORY;
2012     if (!(analysis->pItem = heap_calloc(num_items + 1, sizeof(*analysis->pItem))))
2013         goto error;
2014 
2015     /* FIXME: handle clipping */
2016     analysis->clip_len = cString;
2017     analysis->hdc = hdc;
2018     analysis->ssa_flags = dwFlags;
2019 
2020     if (psState)
2021         sState = *psState;
2022     else
2023         memset(&sState, 0, sizeof(SCRIPT_STATE));
2024 
2025     if (psControl)
2026         sControl = *psControl;
2027     else
2028         memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
2029 
2030     if (dwFlags & SSA_PASSWORD)
2031     {
2032         if (!(iString = heap_calloc(cString, sizeof(*iString))))
2033         {
2034             hr = E_OUTOFMEMORY;
2035             goto error;
2036         }
2037         for (i = 0; i < cString; i++)
2038             iString[i] = *((const WCHAR *)pString);
2039         pString = iString;
2040     }
2041 
2042     hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
2043                        &analysis->numItems);
2044 
2045     if (FAILED(hr))
2046     {
2047         if (hr == E_OUTOFMEMORY)
2048             hr = E_INVALIDARG;
2049         goto error;
2050     }
2051 
2052     /* set back to out of memory for default goto error behaviour */
2053     hr = E_OUTOFMEMORY;
2054 
2055     if (dwFlags & SSA_BREAK)
2056     {
2057         if (!(analysis->logattrs = heap_calloc(cString, sizeof(*analysis->logattrs))))
2058             goto error;
2059 
2060         for (i = 0; i < analysis->numItems; ++i)
2061             ScriptBreak(&((const WCHAR *)pString)[analysis->pItem[i].iCharPos],
2062                     analysis->pItem[i + 1].iCharPos - analysis->pItem[i].iCharPos,
2063                     &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
2064     }
2065 
2066     if (!(analysis->logical2visual = heap_calloc(analysis->numItems, sizeof(*analysis->logical2visual))))
2067         goto error;
2068     if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
2069         goto error;
2070 
2071     if (dwFlags & SSA_GLYPHS)
2072     {
2073         int tab_x = 0;
2074 
2075         if (!(analysis->glyphs = heap_calloc(analysis->numItems, sizeof(*analysis->glyphs))))
2076         {
2077             heap_free(BidiLevel);
2078             goto error;
2079         }
2080 
2081         for (i = 0; i < analysis->numItems; i++)
2082         {
2083             SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
2084             int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2085             int numGlyphs = 1.5 * cChar + 16;
2086             WORD *glyphs = heap_calloc(numGlyphs, sizeof(*glyphs));
2087             WORD *pwLogClust = heap_calloc(cChar, sizeof(*pwLogClust));
2088             int *piAdvance = heap_calloc(numGlyphs, sizeof(*piAdvance));
2089             SCRIPT_VISATTR *psva = heap_calloc(numGlyphs, sizeof(*psva));
2090             GOFFSET *pGoffset = heap_calloc(numGlyphs, sizeof(*pGoffset));
2091             int numGlyphsReturned;
2092             HFONT originalFont = 0x0;
2093 
2094             /* FIXME: non unicode strings */
2095             const WCHAR* pStr = (const WCHAR*)pString;
2096             analysis->glyphs[i].fallbackFont = NULL;
2097 
2098             if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset)
2099             {
2100                 heap_free (BidiLevel);
2101                 heap_free (glyphs);
2102                 heap_free (pwLogClust);
2103                 heap_free (piAdvance);
2104                 heap_free (psva);
2105                 heap_free (pGoffset);
2106                 hr = E_OUTOFMEMORY;
2107                 goto error;
2108             }
2109 
2110             if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
2111             {
2112                 LOGFONTW lf;
2113                 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
2114                 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
2115                 lf.lfFaceName[0] = 0;
2116                 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
2117                 if (lf.lfFaceName[0])
2118                 {
2119                     analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
2120                     if (analysis->glyphs[i].fallbackFont)
2121                     {
2122                         ScriptFreeCache(sc);
2123                         originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
2124                     }
2125                 }
2126             }
2127 
2128             /* FIXME: When we properly shape Hangul remove this check */
2129             if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && analysis->pItem[i].a.eScript == Script_Hangul)
2130                 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2131 
2132             if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && !scriptInformation[analysis->pItem[i].a.eScript].props.fComplex && !analysis->pItem[i].a.fRTL)
2133                 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2134 
2135             ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos], cChar, numGlyphs,
2136                         &analysis->pItem[i].a, glyphs, pwLogClust, psva, &numGlyphsReturned);
2137             hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
2138                         piAdvance, pGoffset, &analysis->glyphs[i].abc);
2139             if (originalFont)
2140                 SelectObject(hdc,originalFont);
2141 
2142             if (dwFlags & SSA_TAB)
2143             {
2144                 int tabi = 0;
2145                 for (tabi = 0; tabi < cChar; tabi++)
2146                 {
2147                     if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
2148                         piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
2149                     tab_x+=piAdvance[tabi];
2150                 }
2151             }
2152 
2153             analysis->glyphs[i].numGlyphs = numGlyphsReturned;
2154             analysis->glyphs[i].glyphs = glyphs;
2155             analysis->glyphs[i].pwLogClust = pwLogClust;
2156             analysis->glyphs[i].piAdvance = piAdvance;
2157             analysis->glyphs[i].psva = psva;
2158             analysis->glyphs[i].pGoffset = pGoffset;
2159             analysis->glyphs[i].iMaxPosX= -1;
2160 
2161             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2162         }
2163     }
2164     else
2165     {
2166         for (i = 0; i < analysis->numItems; i++)
2167             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2168     }
2169 
2170     ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
2171     heap_free(BidiLevel);
2172 
2173     *pssa = analysis;
2174     heap_free(iString);
2175     return S_OK;
2176 
2177 error:
2178     heap_free(iString);
2179     heap_free(analysis->glyphs);
2180     heap_free(analysis->logattrs);
2181     heap_free(analysis->pItem);
2182     heap_free(analysis->logical2visual);
2183     heap_free(analysis);
2184     return hr;
2185 }
2186 
2187 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
2188 {
2189     if (pva[glyph].fClusterStart)
2190         return TRUE;
2191     if (USP10_FindGlyphInLogClust(pwLogClust, cChars, glyph) >= 0)
2192         return TRUE;
2193 
2194     return FALSE;
2195 }
2196 
2197 
2198 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
2199                            int iX,
2200                            int iY,
2201                            int iItem,
2202                            int cStart,
2203                            int cEnd,
2204                            UINT uOptions,
2205                            const RECT *prc,
2206                            BOOL fSelected,
2207                            BOOL fDisabled)
2208 {
2209     StringAnalysis *analysis;
2210     int off_x = 0;
2211     HRESULT hr;
2212     COLORREF BkColor = 0x0;
2213     COLORREF TextColor = 0x0;
2214     INT BkMode = 0;
2215     INT runStart, runEnd;
2216     INT iGlyph, cGlyphs;
2217     HFONT oldFont = 0x0;
2218     RECT  crc;
2219     int i;
2220 
2221     TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2222          ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
2223 
2224     if (!(analysis = ssa)) return E_INVALIDARG;
2225 
2226     if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
2227          (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
2228             return S_OK;
2229 
2230     CopyRect(&crc,prc);
2231     if (fSelected)
2232     {
2233         BkMode = GetBkMode(analysis->hdc);
2234         SetBkMode( analysis->hdc, OPAQUE);
2235         BkColor = GetBkColor(analysis->hdc);
2236         SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
2237         if (!fDisabled)
2238         {
2239             TextColor = GetTextColor(analysis->hdc);
2240             SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2241         }
2242     }
2243     if (analysis->glyphs[iItem].fallbackFont)
2244         oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
2245 
2246     if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
2247         runStart = cStart - analysis->pItem[iItem].iCharPos;
2248     else
2249         runStart =  0;
2250     if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
2251         runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
2252     else
2253         runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
2254 
2255     if (analysis->pItem[iItem].a.fRTL)
2256     {
2257         if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
2258             ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
2259         else
2260             ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
2261         crc.left = iX + off_x;
2262     }
2263     else
2264     {
2265         if (cStart >=0 && runStart)
2266             ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
2267         else
2268             ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
2269         crc.left = iX + off_x;
2270     }
2271 
2272     if (analysis->pItem[iItem].a.fRTL)
2273         iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
2274     else
2275         iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
2276 
2277     if (analysis->pItem[iItem].a.fRTL)
2278         cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
2279     else
2280         cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
2281 
2282     cGlyphs++;
2283 
2284     /* adjust for cluster glyphs when starting */
2285     if (analysis->pItem[iItem].a.fRTL)
2286         i = analysis->pItem[iItem+1].iCharPos - 1;
2287     else
2288         i = analysis->pItem[iItem].iCharPos;
2289 
2290     for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
2291     {
2292         if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
2293         {
2294             if (analysis->pItem[iItem].a.fRTL)
2295                 ScriptStringCPtoX(ssa, i, TRUE, &off_x);
2296             else
2297                 ScriptStringCPtoX(ssa, i, FALSE, &off_x);
2298             break;
2299         }
2300     }
2301 
2302     if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
2303     {
2304         INT direction;
2305         INT clust_glyph;
2306 
2307         clust_glyph = iGlyph + cGlyphs;
2308         if (analysis->pItem[iItem].a.fRTL)
2309             direction = -1;
2310         else
2311             direction = 1;
2312 
2313         while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
2314               !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
2315         {
2316             cGlyphs++;
2317             clust_glyph++;
2318         }
2319     }
2320 
2321     hr = ScriptTextOut(analysis->hdc,
2322                        (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
2323                        iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
2324                        &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
2325                        &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
2326                        &analysis->glyphs[iItem].pGoffset[iGlyph]);
2327 
2328     TRACE("ScriptTextOut hr=%08x\n", hr);
2329 
2330     if (fSelected)
2331     {
2332         SetBkColor(analysis->hdc, BkColor);
2333         SetBkMode( analysis->hdc, BkMode);
2334         if (!fDisabled)
2335             SetTextColor(analysis->hdc, TextColor);
2336     }
2337     if (analysis->glyphs[iItem].fallbackFont)
2338         SelectObject(analysis->hdc, oldFont);
2339 
2340     return hr;
2341 }
2342 
2343 /***********************************************************************
2344  *      ScriptStringOut (USP10.@)
2345  *
2346  * This function takes the output of ScriptStringAnalyse and joins the segments
2347  * of glyphs and passes the resulting string to ScriptTextOut.  ScriptStringOut
2348  * only processes glyphs.
2349  *
2350  * Parameters:
2351  *  ssa       [I] buffer to hold the analysed string components
2352  *  iX        [I] X axis displacement for output
2353  *  iY        [I] Y axis displacement for output
2354  *  uOptions  [I] flags controlling output processing
2355  *  prc       [I] rectangle coordinates
2356  *  iMinSel   [I] starting pos for substringing output string
2357  *  iMaxSel   [I] ending pos for substringing output string
2358  *  fDisabled [I] controls text highlighting
2359  *
2360  *  RETURNS
2361  *   Success: S_OK
2362  *   Failure: is the value returned by ScriptTextOut
2363  */
2364 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
2365                                int iX,
2366                                int iY,
2367                                UINT uOptions,
2368                                const RECT *prc,
2369                                int iMinSel,
2370                                int iMaxSel,
2371                                BOOL fDisabled)
2372 {
2373     StringAnalysis *analysis;
2374     int   item;
2375     HRESULT hr;
2376 
2377     TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2378          ssa, iX, iY, uOptions, wine_dbgstr_rect(prc), iMinSel, iMaxSel, fDisabled);
2379 
2380     if (!(analysis = ssa)) return E_INVALIDARG;
2381     if (!(analysis->ssa_flags & SSA_GLYPHS)) return E_INVALIDARG;
2382 
2383     for (item = 0; item < analysis->numItems; item++)
2384     {
2385         hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
2386         if (FAILED(hr))
2387             return hr;
2388     }
2389 
2390     if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
2391     {
2392         if (iMaxSel > 0 &&  iMinSel < 0)
2393             iMinSel = 0;
2394         for (item = 0; item < analysis->numItems; item++)
2395         {
2396             hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
2397             if (FAILED(hr))
2398                 return hr;
2399         }
2400     }
2401 
2402     return S_OK;
2403 }
2404 
2405 /***********************************************************************
2406  *      ScriptStringCPtoX (USP10.@)
2407  *
2408  */
2409 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
2410 {
2411     int item;
2412     int runningX = 0;
2413     StringAnalysis* analysis = ssa;
2414 
2415     TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
2416 
2417     if (!ssa || !pX) return S_FALSE;
2418     if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
2419 
2420     /* icp out of range */
2421     if(icp < 0)
2422     {
2423         analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2424         return E_INVALIDARG;
2425     }
2426 
2427     for(item=0; item<analysis->numItems; item++)
2428     {
2429         int CP, i;
2430         int offset;
2431 
2432         i = analysis->logical2visual[item];
2433         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2434         /* initialize max extents for uninitialized runs */
2435         if (analysis->glyphs[i].iMaxPosX == -1)
2436         {
2437             if (analysis->pItem[i].a.fRTL)
2438                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2439                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2440                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2441             else
2442                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2443                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2444                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2445         }
2446 
2447         if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
2448         {
2449             runningX += analysis->glyphs[i].iMaxPosX;
2450             continue;
2451         }
2452 
2453         icp -= analysis->pItem[i].iCharPos;
2454         ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2455                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2456                     &analysis->pItem[i].a, &offset);
2457         runningX += offset;
2458 
2459         *pX = runningX;
2460         return S_OK;
2461     }
2462 
2463     /* icp out of range */
2464     analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2465     return E_INVALIDARG;
2466 }
2467 
2468 /***********************************************************************
2469  *      ScriptStringXtoCP (USP10.@)
2470  *
2471  */
2472 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
2473 {
2474     StringAnalysis* analysis = ssa;
2475     int item;
2476 
2477     TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
2478 
2479     if (!ssa || !piCh || !piTrailing) return S_FALSE;
2480     if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
2481 
2482     /* out of range */
2483     if(iX < 0)
2484     {
2485         if (analysis->pItem[0].a.fRTL)
2486         {
2487             *piCh = 1;
2488             *piTrailing = FALSE;
2489         }
2490         else
2491         {
2492             *piCh = -1;
2493             *piTrailing = TRUE;
2494         }
2495         return S_OK;
2496     }
2497 
2498     for(item=0; item<analysis->numItems; item++)
2499     {
2500         int i;
2501         int CP;
2502 
2503         for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
2504         /* nothing */;
2505 
2506         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2507         /* initialize max extents for uninitialized runs */
2508         if (analysis->glyphs[i].iMaxPosX == -1)
2509         {
2510             if (analysis->pItem[i].a.fRTL)
2511                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2512                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2513                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2514             else
2515                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2516                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2517                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2518         }
2519 
2520         if (iX > analysis->glyphs[i].iMaxPosX)
2521         {
2522             iX -= analysis->glyphs[i].iMaxPosX;
2523             continue;
2524         }
2525 
2526         ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2527                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2528                     &analysis->pItem[i].a, piCh, piTrailing);
2529         *piCh += analysis->pItem[i].iCharPos;
2530 
2531         return S_OK;
2532     }
2533 
2534     /* out of range */
2535     *piCh = analysis->pItem[analysis->numItems].iCharPos;
2536     *piTrailing = FALSE;
2537 
2538     return S_OK;
2539 }
2540 
2541 
2542 /***********************************************************************
2543  *      ScriptStringFree (USP10.@)
2544  *
2545  * Free a string analysis.
2546  *
2547  * PARAMS
2548  *  pssa [I] string analysis.
2549  *
2550  * RETURNS
2551  *  Success: S_OK
2552  *  Failure: Non-zero HRESULT value.
2553  */
2554 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
2555 {
2556     StringAnalysis* analysis;
2557     BOOL invalid;
2558     int i;
2559 
2560     TRACE("(%p)\n", pssa);
2561 
2562     if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
2563 
2564     invalid = analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2565 
2566     if (analysis->glyphs)
2567     {
2568         for (i = 0; i < analysis->numItems; i++)
2569         {
2570             heap_free(analysis->glyphs[i].glyphs);
2571             heap_free(analysis->glyphs[i].pwLogClust);
2572             heap_free(analysis->glyphs[i].piAdvance);
2573             heap_free(analysis->glyphs[i].psva);
2574             heap_free(analysis->glyphs[i].pGoffset);
2575             if (analysis->glyphs[i].fallbackFont)
2576                 DeleteObject(analysis->glyphs[i].fallbackFont);
2577             ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
2578             heap_free(analysis->glyphs[i].sc);
2579         }
2580         heap_free(analysis->glyphs);
2581     }
2582 
2583     heap_free(analysis->pItem);
2584     heap_free(analysis->logattrs);
2585     heap_free(analysis->logical2visual);
2586     heap_free(analysis);
2587 
2588     if (invalid) return E_INVALIDARG;
2589     return S_OK;
2590 }
2591 
2592 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
2593                                    int direction, int* iCluster, int *check_out)
2594 {
2595     int clust_size = 1;
2596     int check;
2597     WORD clust = pwLogClust[item];
2598 
2599     for (check = item+direction; check < cChars && check >= 0; check+=direction)
2600     {
2601         if (pwLogClust[check] == clust)
2602         {
2603             clust_size ++;
2604             if (iCluster && *iCluster == -1)
2605                 *iCluster = item;
2606         }
2607         else break;
2608     }
2609 
2610     if (check_out)
2611         *check_out = check;
2612 
2613     return clust_size;
2614 }
2615 
2616 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)
2617 {
2618     int advance;
2619     int log_clust_max;
2620 
2621     advance = piAdvance[glyph];
2622 
2623     if (pwLogClust[0] > pwLogClust[cChars-1])
2624         log_clust_max = pwLogClust[0];
2625     else
2626         log_clust_max = pwLogClust[cChars-1];
2627 
2628     if (glyph > log_clust_max)
2629         return advance;
2630 
2631     for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
2632     {
2633 
2634         if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
2635             break;
2636         if (glyph > log_clust_max)
2637             break;
2638         advance += piAdvance[glyph];
2639     }
2640 
2641     return advance;
2642 }
2643 
2644 /***********************************************************************
2645  *      ScriptCPtoX (USP10.@)
2646  *
2647  */
2648 HRESULT WINAPI ScriptCPtoX(int iCP,
2649                            BOOL fTrailing,
2650                            int cChars,
2651                            int cGlyphs,
2652                            const WORD *pwLogClust,
2653                            const SCRIPT_VISATTR *psva,
2654                            const int *piAdvance,
2655                            const SCRIPT_ANALYSIS *psa,
2656                            int *piX)
2657 {
2658     int item;
2659     float iPosX;
2660     int iSpecial = -1;
2661     int iCluster = -1;
2662     int clust_size = 1;
2663     float special_size = 0.0;
2664     int iMaxPos = 0;
2665     int advance = 0;
2666     BOOL rtl = FALSE;
2667 
2668     TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2669           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2670           psa, piX);
2671 
2672     if (psa->fRTL && ! psa->fLogicalOrder)
2673         rtl = TRUE;
2674 
2675     if (fTrailing)
2676         iCP++;
2677 
2678     if (rtl)
2679     {
2680         int max_clust = pwLogClust[0];
2681 
2682         for (item=0; item < cGlyphs; item++)
2683             if (pwLogClust[item] > max_clust)
2684             {
2685                 ERR("We do not handle non reversed clusters properly\n");
2686                 break;
2687             }
2688 
2689         iMaxPos = 0;
2690         for (item = max_clust; item >=0; item --)
2691             iMaxPos += piAdvance[item];
2692     }
2693 
2694     iPosX = 0.0;
2695     for (item=0; item < iCP && item < cChars; item++)
2696     {
2697         if (iSpecial == -1 && (iCluster == -1 || iCluster+clust_size <= item))
2698         {
2699             int check;
2700             int clust = pwLogClust[item];
2701 
2702             iCluster = -1;
2703             clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2704                                           &check);
2705 
2706             advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2707 
2708             if (check >= cChars && !iMaxPos)
2709             {
2710                 int glyph;
2711                 for (glyph = clust; glyph < cGlyphs; glyph++)
2712                     special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, glyph, 1);
2713                 iSpecial = item;
2714                 special_size /= (cChars - item);
2715                 iPosX += special_size;
2716             }
2717             else
2718             {
2719                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2720                 {
2721                     clust_size --;
2722                     if (clust_size == 0)
2723                         iPosX += advance;
2724                 }
2725                 else
2726                     iPosX += advance / (float)clust_size;
2727             }
2728         }
2729         else if (iSpecial != -1)
2730             iPosX += special_size;
2731         else /* (iCluster != -1) */
2732         {
2733             int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2734             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2735             {
2736                 clust_size --;
2737                 if (clust_size == 0)
2738                     iPosX += adv;
2739             }
2740             else
2741                 iPosX += adv / (float)clust_size;
2742         }
2743     }
2744 
2745     if (iMaxPos > 0)
2746     {
2747         iPosX = iMaxPos - iPosX;
2748         if (iPosX < 0)
2749             iPosX = 0;
2750     }
2751 
2752     *piX = iPosX;
2753     TRACE("*piX=%d\n", *piX);
2754     return S_OK;
2755 }
2756 
2757 /* Count the number of characters in a cluster and its starting index*/
2758 static inline BOOL get_cluster_data(const WORD *pwLogClust, int cChars, int cluster_index, int *cluster_size, int *start_index)
2759 {
2760     int size = 0;
2761     int i;
2762 
2763     for (i = 0; i < cChars; i++)
2764     {
2765         if (pwLogClust[i] == cluster_index)
2766         {
2767             if (!size && start_index)
2768             {
2769                 *start_index = i;
2770                 if (!cluster_size)
2771                     return TRUE;
2772             }
2773             size++;
2774         }
2775         else if (size) break;
2776     }
2777     if (cluster_size)
2778         *cluster_size = size;
2779 
2780     return (size > 0);
2781 }
2782 
2783 /*
2784     To handle multi-glyph clusters we need to find all the glyphs that are
2785     represented in the cluster. This involves finding the glyph whose
2786     index is the cluster index as well as whose glyph indices are greater than
2787     our cluster index but not part of a new cluster.
2788 
2789     Then we sum all those glyphs' advances.
2790 */
2791 static inline int get_cluster_advance(const int* piAdvance,
2792                                       const SCRIPT_VISATTR *psva,
2793                                       const WORD *pwLogClust, int cGlyphs,
2794                                       int cChars, int cluster, int direction)
2795 {
2796     int glyph_start;
2797     int glyph_end;
2798     int i, advance;
2799 
2800     if (direction > 0)
2801         i = 0;
2802     else
2803         i = (cChars - 1);
2804 
2805     for (glyph_start = -1, glyph_end = -1; i < cChars && i >= 0 && (glyph_start < 0 || glyph_end < 0); i+=direction)
2806     {
2807         if (glyph_start < 0 && pwLogClust[i] != cluster) continue;
2808         if (pwLogClust[i] == cluster && glyph_start < 0) glyph_start = pwLogClust[i];
2809         if (glyph_start >= 0 && glyph_end < 0 && pwLogClust[i] != cluster) glyph_end = pwLogClust[i];
2810     }
2811     if (glyph_end < 0)
2812     {
2813         if (direction > 0)
2814             glyph_end = cGlyphs;
2815         else
2816         {
2817             /* Don't fully understand multi-glyph reversed clusters yet,
2818              * do they occur for real or just in our test? */
2819             FIXME("multi-glyph reversed clusters found\n");
2820             glyph_end = glyph_start + 1;
2821         }
2822     }
2823 
2824     /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2825     for (i = glyph_start+1; i< glyph_end; i++)
2826     {
2827         if (psva[i].fClusterStart)
2828         {
2829             glyph_end = i;
2830             break;
2831         }
2832     }
2833 
2834     for (advance = 0, i = glyph_start; i < glyph_end; i++)
2835         advance += piAdvance[i];
2836 
2837     return advance;
2838 }
2839 
2840 
2841 /***********************************************************************
2842  *      ScriptXtoCP (USP10.@)
2843  *
2844  * Basic algorithm :
2845  *  Use piAdvance to find the cluster we are looking at.
2846  *  Find the character that is the first character of the cluster.
2847  *  That is our base piCP.
2848  *  If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2849  *  are good. Otherwise if the cluster is larger than 1 glyph we need to
2850  *  determine how far through the cluster to advance the cursor.
2851  */
2852 HRESULT WINAPI ScriptXtoCP(int iX,
2853                            int cChars,
2854                            int cGlyphs,
2855                            const WORD *pwLogClust,
2856                            const SCRIPT_VISATTR *psva,
2857                            const int *piAdvance,
2858                            const SCRIPT_ANALYSIS *psa,
2859                            int *piCP,
2860                            int *piTrailing)
2861 {
2862     int direction = 1;
2863     int iPosX;
2864     int i;
2865     int glyph_index, cluster_index;
2866     int cluster_size;
2867 
2868     TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2869           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2870           psa, piCP, piTrailing);
2871 
2872     if (psa->fRTL && ! psa->fLogicalOrder)
2873         direction = -1;
2874 
2875     /* Handle an iX < 0 */
2876     if (iX < 0)
2877     {
2878         if (direction < 0)
2879         {
2880             *piCP = cChars;
2881             *piTrailing = 0;
2882         }
2883         else
2884         {
2885             *piCP = -1;
2886             *piTrailing = 1;
2887         }
2888         return S_OK;
2889     }
2890 
2891     /* Looking for non-reversed clusters in a reversed string */
2892     if (direction < 0)
2893     {
2894         int max_clust = pwLogClust[0];
2895         for (i=0; i< cChars; i++)
2896             if (pwLogClust[i] > max_clust)
2897             {
2898                 FIXME("We do not handle non reversed clusters properly\n");
2899                 break;
2900             }
2901     }
2902 
2903     /* find the glyph_index based in iX */
2904     if (direction > 0)
2905     {
2906         for (glyph_index = -1, iPosX = iX; iPosX >=0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2907             ;
2908     }
2909     else
2910     {
2911         for (glyph_index = -1, iPosX = iX; iPosX > 0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2912             ;
2913     }
2914 
2915     TRACE("iPosX %i ->  glyph_index %i (%i)\n", iPosX, glyph_index, cGlyphs);
2916 
2917     *piTrailing = 0;
2918     if (glyph_index >= 0 && glyph_index < cGlyphs)
2919     {
2920         /* find the cluster */
2921         if (direction > 0 )
2922             for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] <= glyph_index; cluster_index=pwLogClust[i++])
2923                 ;
2924         else
2925             for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] >= glyph_index; cluster_index=pwLogClust[i++])
2926                 ;
2927 
2928         TRACE("cluster_index %i\n", cluster_index);
2929 
2930         if (direction < 0 && iPosX >= 0 && glyph_index != cluster_index)
2931         {
2932             /* We are off the end of the string */
2933             *piCP = -1;
2934             *piTrailing = 1;
2935             return S_OK;
2936         }
2937 
2938         get_cluster_data(pwLogClust, cChars, cluster_index, &cluster_size, &i);
2939 
2940         TRACE("first char index %i\n",i);
2941         if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2942         {
2943             /* Check trailing */
2944             if (glyph_index != cluster_index ||
2945                 (direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2946                 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2947                 *piTrailing = cluster_size;
2948         }
2949         else
2950         {
2951             if (cluster_size > 1)
2952             {
2953                 /* Be part way through the glyph cluster based on size and position */
2954                 int cluster_advance = get_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, cluster_index, direction);
2955                 double cluster_part_width = cluster_advance / (float)cluster_size;
2956                 double adv;
2957                 int part_index;
2958 
2959                 /* back up to the beginning of the cluster */
2960                 for (adv = iPosX, part_index = cluster_index; part_index <= glyph_index; part_index++)
2961                     adv += piAdvance[part_index];
2962                 if (adv > iX) adv = iX;
2963 
2964                 TRACE("Multi-char cluster, no snap\n");
2965                 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size, adv);
2966                 TRACE("advance %i divides into %f per char\n", cluster_advance, cluster_part_width);
2967                 if (direction > 0)
2968                 {
2969                     for (part_index = 0; adv >= 0; adv-=cluster_part_width, part_index++)
2970                         ;
2971                     if (part_index) part_index--;
2972                 }
2973                 else
2974                 {
2975                     for (part_index = 0; adv > 0; adv-=cluster_part_width, part_index++)
2976                         ;
2977                     if (part_index > cluster_size)
2978                     {
2979                         adv += cluster_part_width;
2980                         part_index=cluster_size;
2981                     }
2982                 }
2983 
2984                 TRACE("base_char %i part_index %i, leftover advance %f\n",i, part_index, adv);
2985 
2986                 if (direction > 0)
2987                     i += part_index;
2988                 else
2989                     i += (cluster_size - part_index);
2990 
2991                 /* Check trailing */
2992                 if ((direction > 0 && fabs(adv) <= (cluster_part_width / 2.0)) ||
2993                     (direction < 0 && adv && fabs(adv) >= (cluster_part_width / 2.0)))
2994                     *piTrailing = 1;
2995             }
2996             else
2997             {
2998                 /* Check trailing */
2999                 if ((direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
3000                     (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
3001                     *piTrailing = 1;
3002             }
3003         }
3004     }
3005     else
3006     {
3007         TRACE("Point falls outside of string\n");
3008         if (glyph_index < 0)
3009             i = cChars-1;
3010         else /* (glyph_index >= cGlyphs) */
3011             i = cChars;
3012 
3013         /* If not snaping in the reverse direction (such as Hebrew) Then 0
3014            point flow to the next character */
3015         if (direction < 0)
3016         {
3017             if (!scriptInformation[psa->eScript].props.fNeedsCaretInfo && abs(iPosX) == piAdvance[glyph_index])
3018                 i++;
3019             else
3020                 *piTrailing = 1;
3021         }
3022     }
3023 
3024     *piCP = i;
3025 
3026     TRACE("*piCP=%d\n", *piCP);
3027     TRACE("*piTrailing=%d\n", *piTrailing);
3028     return S_OK;
3029 }
3030 
3031 /***********************************************************************
3032  *      ScriptBreak (USP10.@)
3033  *
3034  *  Retrieve line break information.
3035  *
3036  *  PARAMS
3037  *   chars [I] Array of characters.
3038  *   sa    [I] Script analysis.
3039  *   la    [I] Array of logical attribute structures.
3040  *
3041  *  RETURNS
3042  *   Success: S_OK
3043  *   Failure: S_FALSE
3044  */
3045 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
3046 {
3047     TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
3048 
3049     if (count < 0 || !la) return E_INVALIDARG;
3050     if (count == 0) return E_FAIL;
3051 
3052     BREAK_line(chars, count, sa, la);
3053 
3054     return S_OK;
3055 }
3056 
3057 /***********************************************************************
3058  *      ScriptIsComplex (USP10.@)
3059  *
3060  *  Determine if a string is complex.
3061  *
3062  *  PARAMS
3063  *   chars [I] Array of characters to test.
3064  *   len   [I] Length in characters.
3065  *   flag  [I] Flag.
3066  *
3067  *  RETURNS
3068  *   Success: S_OK
3069  *   Failure: S_FALSE
3070  *
3071  */
3072 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
3073 {
3074     enum usp10_script script;
3075     unsigned int i, consumed;
3076 
3077     TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
3078 
3079     if (!chars || len < 0)
3080         return E_INVALIDARG;
3081 
3082     for (i = 0; i < len; i+=consumed)
3083     {
3084         if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
3085             return S_OK;
3086 
3087         script = get_char_script(chars,i,len, &consumed);
3088         if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
3089             (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
3090             return S_OK;
3091     }
3092     return S_FALSE;
3093 }
3094 
3095 /***********************************************************************
3096  *      ScriptShapeOpenType (USP10.@)
3097  *
3098  * Produce glyphs and visual attributes for a run.
3099  *
3100  * PARAMS
3101  *  hdc         [I]   Device context.
3102  *  psc         [I/O] Opaque pointer to a script cache.
3103  *  psa         [I/O] Script analysis.
3104  *  tagScript   [I]   The OpenType tag for the Script
3105  *  tagLangSys  [I]   The OpenType tag for the Language
3106  *  rcRangeChars[I]   Array of Character counts in each range
3107  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3108  *  cRanges     [I]   Count of ranges
3109  *  pwcChars    [I]   Array of characters specifying the run.
3110  *  cChars      [I]   Number of characters in pwcChars.
3111  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
3112  *  pwLogClust  [O]   Array of logical cluster info.
3113  *  pCharProps  [O]   Array of character property values
3114  *  pwOutGlyphs [O]   Array of glyphs.
3115  *  pOutGlyphProps [O]  Array of attributes for the retrieved glyphs
3116  *  pcGlyphs    [O]   Number of glyphs returned.
3117  *
3118  * RETURNS
3119  *  Success: S_OK
3120  *  Failure: Non-zero HRESULT value.
3121  */
3122 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
3123                                     SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3124                                     OPENTYPE_TAG tagLangSys, int *rcRangeChars,
3125                                     TEXTRANGE_PROPERTIES **rpRangeProperties,
3126                                     int cRanges, const WCHAR *pwcChars, int cChars,
3127                                     int cMaxGlyphs, WORD *pwLogClust,
3128                                     SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
3129                                     SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
3130 {
3131     HRESULT hr;
3132     int i;
3133     unsigned int g;
3134     BOOL rtl;
3135     int cluster;
3136     static int once = 0;
3137 
3138     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3139      hdc, psc, psa,
3140      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3141      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3142      cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
3143 
3144     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
3145                    psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
3146 
3147     if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
3148     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3149 
3150     if (cRanges)
3151         if(!once++) FIXME("Ranges not supported yet\n");
3152 
3153     rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
3154 
3155     *pcGlyphs = cChars;
3156     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3157     if (!pwLogClust) return E_FAIL;
3158 
3159     ((ScriptCache *)*psc)->userScript = tagScript;
3160     ((ScriptCache *)*psc)->userLang = tagLangSys;
3161 
3162     /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3163     for (i = 0; i < cChars; i++)
3164     {
3165         int idx = i;
3166         if (rtl) idx = cChars - 1 - i;
3167         /* FIXME: set to better values */
3168         pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
3169         pOutGlyphProps[i].sva.fClusterStart  = 1;
3170         pOutGlyphProps[i].sva.fDiacritic     = 0;
3171         pOutGlyphProps[i].sva.fZeroWidth     = 0;
3172         pOutGlyphProps[i].sva.fReserved      = 0;
3173         pOutGlyphProps[i].sva.fShapeReserved = 0;
3174 
3175         /* FIXME: have the shaping engine set this */
3176         pCharProps[i].fCanGlyphAlone = 0;
3177 
3178         pwLogClust[i] = idx;
3179     }
3180 
3181     if (psa && !psa->fNoGlyphIndex && ((ScriptCache *)*psc)->sfnt)
3182     {
3183         WCHAR *rChars;
3184         if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
3185 
3186         if (!(rChars = heap_calloc(cChars, sizeof(*rChars))))
3187             return E_OUTOFMEMORY;
3188 
3189         for (i = 0, g = 0, cluster = 0; i < cChars; i++)
3190         {
3191             int idx = i;
3192             DWORD chInput;
3193 
3194             if (rtl) idx = cChars - 1 - i;
3195             if (!cluster)
3196             {
3197                 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
3198                 if (!chInput)
3199                 {
3200                     if (psa->fRTL)
3201                         chInput = mirror_char(pwcChars[idx]);
3202                     else
3203                         chInput = pwcChars[idx];
3204                     rChars[i] = chInput;
3205                 }
3206                 else
3207                 {
3208                     rChars[i] = pwcChars[idx];
3209                     rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
3210                     cluster = 1;
3211                 }
3212                 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
3213                 {
3214                     WORD glyph;
3215                     if (!hdc)
3216                     {
3217                         heap_free(rChars);
3218                         return E_PENDING;
3219                     }
3220                     if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
3221                     {
3222                         heap_free(rChars);
3223                         return S_FALSE;
3224                     }
3225                     pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
3226                 }
3227                 g++;
3228             }
3229             else
3230             {
3231                 int k;
3232                 cluster--;
3233                 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
3234                 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3235                     pwLogClust[k]--;
3236             }
3237         }
3238         *pcGlyphs = g;
3239 
3240         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3241         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
3242         SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
3243 
3244         for (i = 0; i < cChars; ++i)
3245         {
3246             /* Special case for tabs and joiners. As control characters, ZWNJ
3247              * and ZWJ would in principle get handled by the corresponding
3248              * shaping functions. However, since ZWNJ and ZWJ can get merged
3249              * into adjoining runs during itemisation, these don't generally
3250              * get classified as Script_Control. */
3251             if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
3252             {
3253                 pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
3254                 pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
3255             }
3256         }
3257         heap_free(rChars);
3258     }
3259     else
3260     {
3261         TRACE("no glyph translation\n");
3262         for (i = 0; i < cChars; i++)
3263         {
3264             int idx = i;
3265             /* No mirroring done here */
3266             if (rtl) idx = cChars - 1 - i;
3267             pwOutGlyphs[i] = pwcChars[idx];
3268 
3269             if (!psa)
3270                 continue;
3271 
3272             /* overwrite some basic control glyphs to blank */
3273             if (psa->fNoGlyphIndex)
3274             {
3275                 if (pwcChars[idx] == ZWSP || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3276                 {
3277                     pwOutGlyphs[i] = 0x20;
3278                     pOutGlyphProps[i].sva.fZeroWidth = 1;
3279                 }
3280             }
3281             else if (psa->eScript == Script_Control || pwcChars[idx] == ZWSP
3282                     || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3283             {
3284                 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
3285                     pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)
3286                 {
3287                     pwOutGlyphs[i] = ((ScriptCache *)*psc)->sfp.wgBlank;
3288                     pOutGlyphProps[i].sva.fZeroWidth = 1;
3289                 }
3290             }
3291         }
3292     }
3293 
3294     return S_OK;
3295 }
3296 
3297 
3298 /***********************************************************************
3299  *      ScriptShape (USP10.@)
3300  *
3301  * Produce glyphs and visual attributes for a run.
3302  *
3303  * PARAMS
3304  *  hdc         [I]   Device context.
3305  *  psc         [I/O] Opaque pointer to a script cache.
3306  *  pwcChars    [I]   Array of characters specifying the run.
3307  *  cChars      [I]   Number of characters in pwcChars.
3308  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
3309  *  psa         [I/O] Script analysis.
3310  *  pwOutGlyphs [O]   Array of glyphs.
3311  *  pwLogClust  [O]   Array of logical cluster info.
3312  *  psva        [O]   Array of visual attributes.
3313  *  pcGlyphs    [O]   Number of glyphs returned.
3314  *
3315  * RETURNS
3316  *  Success: S_OK
3317  *  Failure: Non-zero HRESULT value.
3318  */
3319 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
3320                            int cChars, int cMaxGlyphs,
3321                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
3322                            SCRIPT_VISATTR *psva, int *pcGlyphs)
3323 {
3324     HRESULT hr;
3325     int i;
3326     SCRIPT_CHARPROP *charProps;
3327     SCRIPT_GLYPHPROP *glyphProps;
3328 
3329     if (!psva || !pcGlyphs) return E_INVALIDARG;
3330     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3331 
3332     if (!(charProps = heap_calloc(cChars, sizeof(*charProps))))
3333         return E_OUTOFMEMORY;
3334 
3335     if (!(glyphProps = heap_calloc(cMaxGlyphs, sizeof(*glyphProps))))
3336     {
3337         heap_free(charProps);
3338         return E_OUTOFMEMORY;
3339     }
3340 
3341     hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
3342 
3343     if (SUCCEEDED(hr))
3344     {
3345         for (i = 0; i < *pcGlyphs; i++)
3346             psva[i] = glyphProps[i].sva;
3347     }
3348 
3349     heap_free(charProps);
3350     heap_free(glyphProps);
3351 
3352     return hr;
3353 }
3354 
3355 /***********************************************************************
3356  *      ScriptPlaceOpenType (USP10.@)
3357  *
3358  * Produce advance widths for a run.
3359  *
3360  * PARAMS
3361  *  hdc       [I]   Device context.
3362  *  psc       [I/O] Opaque pointer to a script cache.
3363  *  psa       [I/O] Script analysis.
3364  *  tagScript   [I]   The OpenType tag for the Script
3365  *  tagLangSys  [I]   The OpenType tag for the Language
3366  *  rcRangeChars[I]   Array of Character counts in each range
3367  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3368  *  cRanges     [I]   Count of ranges
3369  *  pwcChars    [I]   Array of characters specifying the run.
3370  *  pwLogClust  [I]   Array of logical cluster info
3371  *  pCharProps  [I]   Array of character property values
3372  *  cChars      [I]   Number of characters in pwcChars.
3373  *  pwGlyphs  [I]   Array of glyphs.
3374  *  pGlyphProps [I]  Array of attributes for the retrieved glyphs
3375  *  cGlyphs [I] Count of Glyphs
3376  *  piAdvance [O]   Array of advance widths.
3377  *  pGoffset  [O]   Glyph offsets.
3378  *  pABC      [O]   Combined ABC width.
3379  *
3380  * RETURNS
3381  *  Success: S_OK
3382  *  Failure: Non-zero HRESULT value.
3383  */
3384 
3385 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
3386                                     OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
3387                                     int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
3388                                     int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3389                                     SCRIPT_CHARPROP *pCharProps, int cChars,
3390                                     const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
3391                                     int cGlyphs, int *piAdvance,
3392                                     GOFFSET *pGoffset, ABC *pABC
3393 )
3394 {
3395     HRESULT hr;
3396     int i;
3397     static int once = 0;
3398 
3399     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3400      hdc, psc, psa,
3401      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3402      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3403      pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
3404      pGoffset, pABC);
3405 
3406     if (!pGlyphProps) return E_INVALIDARG;
3407     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3408     if (!pGoffset) return E_FAIL;
3409 
3410     if (cRanges)
3411         if (!once++) FIXME("Ranges not supported yet\n");
3412 
3413     ((ScriptCache *)*psc)->userScript = tagScript;
3414     ((ScriptCache *)*psc)->userLang = tagLangSys;
3415 
3416     if (pABC) memset(pABC, 0, sizeof(ABC));
3417     for (i = 0; i < cGlyphs; i++)
3418     {
3419         WORD glyph;
3420         ABC abc;
3421 
3422         /* FIXME: set to more reasonable values */
3423         pGoffset[i].du = pGoffset[i].dv = 0;
3424 
3425         if (pGlyphProps[i].sva.fZeroWidth)
3426         {
3427             abc.abcA = abc.abcB = abc.abcC = 0;
3428             if (piAdvance) piAdvance[i] = 0;
3429             continue;
3430         }
3431 
3432         if (psa->fNoGlyphIndex)
3433         {
3434             if (FAILED(hr = ScriptGetCMap(hdc, psc, &pwGlyphs[i], 1, 0, &glyph))) return hr;
3435         }
3436         else
3437             glyph = pwGlyphs[i];
3438 
3439         if (!get_cache_glyph_widths(psc, glyph, &abc))
3440         {
3441             if (!hdc) return E_PENDING;
3442             if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
3443             {
3444                 if (!GetCharABCWidthsI(hdc, glyph, 1, NULL, &abc)) return S_FALSE;
3445             }
3446             else
3447             {
3448                 INT width;
3449                 if (!GetCharWidthI(hdc, glyph, 1, NULL, &width)) return S_FALSE;
3450                 abc.abcB = width;
3451                 abc.abcA = abc.abcC = 0;
3452             }
3453             set_cache_glyph_widths(psc, glyph, &abc);
3454         }
3455         if (pABC)
3456         {
3457             pABC->abcA += abc.abcA;
3458             pABC->abcB += abc.abcB;
3459             pABC->abcC += abc.abcC;
3460         }
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     if (!(glyphProps = heap_calloc(cGlyphs, sizeof(*glyphProps))))
3505         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 (!GetCharWidthI(hdc, glyph, 1, NULL, &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