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