ntdll/tests: A spelling fix in a comment.
[wine.git] / dlls / usp10 / usp10.c
blobc1d9c1c43e6b26c49736bd858ad15b0022fb4bcd
1 /*
2 * Implementation of Uniscribe Script Processor (usp10.dll)
4 * Copyright 2005 Steven Edwards for CodeWeavers
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
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.
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.
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
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.
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <math.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winnls.h"
36 #include "winreg.h"
37 #include "usp10.h"
39 #include "usp10_internal.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
46 static const struct usp10_script_range
48 enum usp10_script script;
49 DWORD rangeFirst;
50 DWORD rangeLast;
51 enum usp10_script numericScript;
52 enum usp10_script punctScript;
54 script_ranges[] =
56 /* Basic Latin: U+0000–U+007A */
57 { Script_Latin, 0x00, 0x07a , Script_Numeric, Script_Punctuation},
58 /* Latin-1 Supplement: U+0080–U+00FF */
59 /* Latin Extended-A: U+0100–U+017F */
60 /* Latin Extended-B: U+0180–U+024F */
61 /* IPA Extensions: U+0250–U+02AF */
62 /* Spacing Modifier Letters:U+02B0–U+02FF */
63 { Script_Latin, 0x80, 0x2ff , Script_Numeric2, Script_Punctuation},
64 /* Combining Diacritical Marks : U+0300–U+036F */
65 { Script_Diacritical,0x300, 0x36f, 0, 0},
66 /* Greek: U+0370–U+03FF */
67 { Script_Greek, 0x370, 0x3ff, 0, 0},
68 /* Cyrillic: U+0400–U+04FF */
69 /* Cyrillic Supplement: U+0500–U+052F */
70 { Script_Cyrillic, 0x400, 0x52f, 0, 0},
71 /* Armenian: U+0530–U+058F */
72 { Script_Armenian, 0x530, 0x58f, 0, 0},
73 /* Hebrew: U+0590–U+05FF */
74 { Script_Hebrew, 0x590, 0x5ff, 0, 0},
75 /* Arabic: U+0600–U+06FF */
76 { Script_Arabic, 0x600, 0x6ef, Script_Arabic_Numeric, 0},
77 /* Defined by Windows */
78 { Script_Persian, 0x6f0, 0x6f9, 0, 0},
79 /* Continue Arabic: U+0600–U+06FF */
80 { Script_Arabic, 0x6fa, 0x6ff, 0, 0},
81 /* Syriac: U+0700–U+074F*/
82 { Script_Syriac, 0x700, 0x74f, 0, 0},
83 /* Arabic Supplement: U+0750–U+077F */
84 { Script_Arabic, 0x750, 0x77f, 0, 0},
85 /* Thaana: U+0780–U+07BF */
86 { Script_Thaana, 0x780, 0x7bf, 0, 0},
87 /* N’Ko: U+07C0–U+07FF */
88 { Script_NKo, 0x7c0, 0x7ff, 0, 0},
89 /* Devanagari: U+0900–U+097F */
90 { Script_Devanagari, 0x900, 0x97f, Script_Devanagari_Numeric, 0},
91 /* Bengali: U+0980–U+09FF */
92 { Script_Bengali, 0x980, 0x9ff, Script_Bengali_Numeric, 0},
93 /* Gurmukhi: U+0A00–U+0A7F*/
94 { Script_Gurmukhi, 0xa00, 0xa7f, Script_Gurmukhi_Numeric, 0},
95 /* Gujarati: U+0A80–U+0AFF*/
96 { Script_Gujarati, 0xa80, 0xaff, Script_Gujarati_Numeric, 0},
97 /* Oriya: U+0B00–U+0B7F */
98 { Script_Oriya, 0xb00, 0xb7f, Script_Oriya_Numeric, 0},
99 /* Tamil: U+0B80–U+0BFF */
100 { Script_Tamil, 0xb80, 0xbff, Script_Tamil_Numeric, 0},
101 /* Telugu: U+0C00–U+0C7F */
102 { Script_Telugu, 0xc00, 0xc7f, Script_Telugu_Numeric, 0},
103 /* Kannada: U+0C80–U+0CFF */
104 { Script_Kannada, 0xc80, 0xcff, Script_Kannada_Numeric, 0},
105 /* Malayalam: U+0D00–U+0D7F */
106 { Script_Malayalam, 0xd00, 0xd7f, Script_Malayalam_Numeric, 0},
107 /* Sinhala: U+0D80–U+0DFF */
108 { Script_Sinhala, 0xd80, 0xdff, 0, 0},
109 /* Thai: U+0E00–U+0E7F */
110 { Script_Thai, 0xe00, 0xe7f, Script_Thai_Numeric, 0},
111 /* Lao: U+0E80–U+0EFF */
112 { Script_Lao, 0xe80, 0xeff, Script_Lao_Numeric, 0},
113 /* Tibetan: U+0F00–U+0FFF */
114 { Script_Tibetan, 0xf00, 0xfff, 0, 0},
115 /* Myanmar: U+1000–U+109F */
116 { Script_Myanmar, 0x1000, 0x109f, Script_Myanmar_Numeric, 0},
117 /* Georgian: U+10A0–U+10FF */
118 { Script_Georgian, 0x10a0, 0x10ff, 0, 0},
119 /* Hangul Jamo: U+1100–U+11FF */
120 { Script_Hangul, 0x1100, 0x11ff, 0, 0},
121 /* Ethiopic: U+1200–U+137F */
122 /* Ethiopic Extensions: U+1380–U+139F */
123 { Script_Ethiopic, 0x1200, 0x139f, 0, 0},
124 /* Cherokee: U+13A0–U+13FF */
125 { Script_Cherokee, 0x13a0, 0x13ff, 0, 0},
126 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
127 { Script_Canadian, 0x1400, 0x167f, 0, 0},
128 /* Ogham: U+1680–U+169F */
129 { Script_Ogham, 0x1680, 0x169f, 0, 0},
130 /* Runic: U+16A0–U+16F0 */
131 { Script_Runic, 0x16a0, 0x16f0, 0, 0},
132 /* Khmer: U+1780–U+17FF */
133 { Script_Khmer, 0x1780, 0x17ff, Script_Khmer_Numeric, 0},
134 /* Mongolian: U+1800–U+18AF */
135 { Script_Mongolian, 0x1800, 0x18af, Script_Mongolian_Numeric, 0},
136 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
137 { Script_Canadian, 0x18b0, 0x18ff, 0, 0},
138 /* Tai Le: U+1950–U+197F */
139 { Script_Tai_Le, 0x1950, 0x197f, 0, 0},
140 /* New Tai Lue: U+1980–U+19DF */
141 { Script_New_Tai_Lue,0x1980, 0x19df, Script_New_Tai_Lue_Numeric, 0},
142 /* Khmer Symbols: U+19E0–U+19FF */
143 { Script_Khmer, 0x19e0, 0x19ff, Script_Khmer_Numeric, 0},
144 /* Vedic Extensions: U+1CD0-U+1CFF */
145 { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
146 /* Phonetic Extensions: U+1D00–U+1DBF */
147 { Script_Latin, 0x1d00, 0x1dbf, 0, 0},
148 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
149 { Script_Diacritical,0x1dc0, 0x1dff, 0, 0},
150 /* Latin Extended Additional: U+1E00–U+1EFF */
151 { Script_Latin, 0x1e00, 0x1eff, 0, 0},
152 /* Greek Extended: U+1F00–U+1FFF */
153 { Script_Greek, 0x1f00, 0x1fff, 0, 0},
154 /* General Punctuation: U+2000 –U+206f */
155 { Script_Latin, 0x2000, 0x206f, 0, 0},
156 /* Superscripts and Subscripts : U+2070 –U+209f */
157 /* Currency Symbols : U+20a0 –U+20cf */
158 { Script_Numeric2, 0x2070, 0x2070, 0, 0},
159 { Script_Latin, 0x2071, 0x2073, 0, 0},
160 { Script_Numeric2, 0x2074, 0x2079, 0, 0},
161 { Script_Latin, 0x207a, 0x207f, 0, 0},
162 { Script_Numeric2, 0x2080, 0x2089, 0, 0},
163 { Script_Latin, 0x208a, 0x20cf, 0, 0},
164 /* Letterlike Symbols : U+2100 –U+214f */
165 /* Number Forms : U+2150 –U+218f */
166 /* Arrows : U+2190 –U+21ff */
167 /* Mathematical Operators : U+2200 –U+22ff */
168 /* Miscellaneous Technical : U+2300 –U+23ff */
169 /* Control Pictures : U+2400 –U+243f */
170 /* Optical Character Recognition : U+2440 –U+245f */
171 /* Enclosed Alphanumerics : U+2460 –U+24ff */
172 /* Box Drawing : U+2500 –U+25ff */
173 /* Block Elements : U+2580 –U+259f */
174 /* Geometric Shapes : U+25a0 –U+25ff */
175 /* Miscellaneous Symbols : U+2600 –U+26ff */
176 /* Dingbats : U+2700 –U+27bf */
177 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
178 /* Supplemental Arrows-A : U+27f0 –U+27ff */
179 { Script_Latin, 0x2100, 0x27ff, 0, 0},
180 /* Braille Patterns: U+2800–U+28FF */
181 { Script_Braille, 0x2800, 0x28ff, 0, 0},
182 /* Supplemental Arrows-B : U+2900 –U+297f */
183 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
184 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
185 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
186 { Script_Latin, 0x2900, 0x2bff, 0, 0},
187 /* Latin Extended-C: U+2C60–U+2C7F */
188 { Script_Latin, 0x2c60, 0x2c7f, 0, 0},
189 /* Georgian: U+2D00–U+2D2F */
190 { Script_Georgian, 0x2d00, 0x2d2f, 0, 0},
191 /* Tifinagh: U+2D30–U+2D7F */
192 { Script_Tifinagh, 0x2d30, 0x2d7f, 0, 0},
193 /* Ethiopic Extensions: U+2D80–U+2DDF */
194 { Script_Ethiopic, 0x2d80, 0x2ddf, 0, 0},
195 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
196 { Script_Cyrillic, 0x2de0, 0x2dff, 0, 0},
197 /* CJK Radicals Supplement: U+2E80–U+2EFF */
198 /* Kangxi Radicals: U+2F00–U+2FDF */
199 { Script_CJK_Han, 0x2e80, 0x2fdf, 0, 0},
200 /* Ideographic Description Characters: U+2FF0–U+2FFF */
201 { Script_Ideograph ,0x2ff0, 0x2fff, 0, 0},
202 /* CJK Symbols and Punctuation: U+3000–U+303F */
203 { Script_Ideograph ,0x3000, 0x3004, 0, 0},
204 { Script_CJK_Han ,0x3005, 0x3005, 0, 0},
205 { Script_Ideograph ,0x3006, 0x3006, 0, 0},
206 { Script_CJK_Han ,0x3007, 0x3007, 0, 0},
207 { Script_Ideograph ,0x3008, 0x3020, 0, 0},
208 { Script_CJK_Han ,0x3021, 0x3029, 0, 0},
209 { Script_Ideograph ,0x302a, 0x3030, 0, 0},
210 /* Kana Marks: */
211 { Script_Kana ,0x3031, 0x3035, 0, 0},
212 { Script_Ideograph ,0x3036, 0x3037, 0, 0},
213 { Script_CJK_Han ,0x3038, 0x303b, 0, 0},
214 { Script_Ideograph ,0x303c, 0x303f, 0, 0},
215 /* Hiragana: U+3040–U+309F */
216 /* Katakana: U+30A0–U+30FF */
217 { Script_Kana ,0x3040, 0x30ff, 0, 0},
218 /* Bopomofo: U+3100–U+312F */
219 { Script_Bopomofo ,0x3100, 0x312f, 0, 0},
220 /* Hangul Compatibility Jamo: U+3130–U+318F */
221 { Script_Hangul ,0x3130, 0x318f, 0, 0},
222 /* Kanbun: U+3190–U+319F */
223 { Script_Ideograph ,0x3190, 0x319f, 0, 0},
224 /* Bopomofo Extended: U+31A0–U+31BF */
225 { Script_Bopomofo ,0x31a0, 0x31bf, 0, 0},
226 /* CJK Strokes: U+31C0–U+31EF */
227 { Script_Ideograph ,0x31c0, 0x31ef, 0, 0},
228 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
229 { Script_Kana ,0x31f0, 0x31ff, 0, 0},
230 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
231 { Script_Hangul ,0x3200, 0x321f, 0, 0},
232 { Script_Ideograph ,0x3220, 0x325f, 0, 0},
233 { Script_Hangul ,0x3260, 0x327f, 0, 0},
234 { Script_Ideograph ,0x3280, 0x32ef, 0, 0},
235 { Script_Kana ,0x32d0, 0x31ff, 0, 0},
236 /* CJK Compatibility: U+3300–U+33FF*/
237 { Script_Kana ,0x3300, 0x3357, 0, 0},
238 { Script_Ideograph ,0x3358, 0x33ff, 0, 0},
239 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
240 { Script_CJK_Han ,0x3400, 0x4dbf, 0, 0},
241 /* CJK Unified Ideographs: U+4E00–U+9FFF */
242 { Script_CJK_Han ,0x4e00, 0x9fff, 0, 0},
243 /* Yi: U+A000–U+A4CF */
244 { Script_Yi ,0xa000, 0xa4cf, 0, 0},
245 /* Vai: U+A500–U+A63F */
246 { Script_Vai ,0xa500, 0xa63f, Script_Vai_Numeric, 0},
247 /* Cyrillic Extended-B: U+A640–U+A69F */
248 { Script_Cyrillic, 0xa640, 0xa69f, 0, 0},
249 /* Modifier Tone Letters: U+A700–U+A71F */
250 /* Latin Extended-D: U+A720–U+A7FF */
251 { Script_Latin, 0xa700, 0xa7ff, 0, 0},
252 /* Phags-pa: U+A840–U+A87F */
253 { Script_Phags_pa, 0xa840, 0xa87f, 0, 0},
254 /* Devanagari Extended: U+A8E0-U+A8FF */
255 { Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
256 /* Myanmar Extended-A: U+AA60–U+AA7F */
257 { Script_Myanmar, 0xaa60, 0xaa7f, Script_Myanmar_Numeric, 0},
258 /* Hangul Jamo Extended-A: U+A960–U+A97F */
259 { Script_Hangul, 0xa960, 0xa97f, 0, 0},
260 /* Hangul Syllables: U+AC00–U+D7A3 */
261 { Script_Hangul, 0xac00, 0xd7a3, 0, 0},
262 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
263 { Script_Hangul, 0xd7b0, 0xd7ff, 0, 0},
264 /* Surrogates Area: U+D800–U+DFFF */
265 { Script_Surrogates, 0xd800, 0xdbfe, 0, 0},
266 { Script_Private, 0xdbff, 0xdc00, 0, 0},
267 { Script_Surrogates, 0xdc01, 0xdfff, 0, 0},
268 /* Private Use Area: U+E000–U+F8FF */
269 { Script_Private, 0xe000, 0xf8ff, 0, 0},
270 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
271 { Script_CJK_Han ,0xf900, 0xfaff, 0, 0},
272 /* Latin Ligatures: U+FB00–U+FB06 */
273 { Script_Latin, 0xfb00, 0xfb06, 0, 0},
274 /* Armenian ligatures U+FB13..U+FB17 */
275 { Script_Armenian, 0xfb13, 0xfb17, 0, 0},
276 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
277 { Script_Hebrew, 0xfb1d, 0xfb4f, 0, 0},
278 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
279 { Script_Arabic, 0xfb50, 0xfdff, 0, 0},
280 /* Vertical Forms: U+FE10–U+FE1F */
281 /* Combining Half Marks: U+FE20–U+FE2F */
282 /* CJK Compatibility Forms: U+FE30–U+FE4F */
283 /* Small Form Variants: U+FE50–U+FE6F */
284 { Script_Ideograph ,0xfe10, 0xfe6f, 0, 0},
285 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
286 { Script_Arabic, 0xfe70, 0xfeff, 0, 0},
287 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
288 { Script_Ideograph ,0xff00, 0xff64, Script_Numeric2, 0},
289 { Script_Kana ,0xff65, 0xff9f, 0, 0},
290 { Script_Hangul ,0xffa0, 0xffdf, 0, 0},
291 { Script_Ideograph ,0xffe0, 0xffef, 0, 0},
292 /* Plane - 1 */
293 /* Deseret: U+10400–U+1044F */
294 { Script_Deseret, 0x10400, 0x1044F, 0, 0},
295 /* Osmanya: U+10480–U+104AF */
296 { Script_Osmanya, 0x10480, 0x104AF, Script_Osmanya_Numeric, 0},
297 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
298 { Script_MathAlpha, 0x1D400, 0x1D7FF, 0, 0},
301 /* this 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, 0, 1, 0, 0, 0, 0, { 2,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, 0, 1, 0, 0, 0, 0, { 2,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('a','r','a','b'),
346 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',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 {'M','y','a','n','m','a','r',' ','T','e','x','t',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',0}},
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',0}},
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',0}},
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',0}},
515 {{Script_Khmer_Numeric, 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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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',0}},
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}},
633 static const SCRIPT_PROPERTIES *script_props[] =
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
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;
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;
706 typedef struct {
707 BOOL ascending;
708 WORD target;
709 } FindGlyph_struct;
711 BOOL usp10_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
713 SIZE_T max_capacity, new_capacity;
714 void *new_elements;
716 if (count <= *capacity)
717 return TRUE;
719 max_capacity = ~(SIZE_T)0 / size;
720 if (count > max_capacity)
721 return FALSE;
723 new_capacity = max(1, *capacity);
724 while (new_capacity < count && new_capacity <= max_capacity / 2)
725 new_capacity *= 2;
726 if (new_capacity < count)
727 new_capacity = count;
729 if (!*elements)
730 new_elements = heap_alloc_zero(new_capacity * size);
731 else
732 new_elements = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *elements, new_capacity * size);
733 if (!new_elements)
734 return FALSE;
736 *elements = new_elements;
737 *capacity = new_capacity;
738 return TRUE;
741 /* TODO Fix font properties on Arabic locale */
742 static inline BOOL set_cache_font_properties(const HDC hdc, ScriptCache *sc)
744 if (!sc->sfnt)
746 sc->sfp.wgBlank = sc->tm.tmBreakChar;
747 sc->sfp.wgDefault = sc->tm.tmDefaultChar;
748 sc->sfp.wgInvalid = sc->sfp.wgBlank;
749 sc->sfp.wgKashida = 0xFFFF;
750 sc->sfp.iKashidaWidth = 0;
752 else
754 static const WCHAR chars[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
755 /* U+0020: numeric space
756 U+200B: zero width space
757 U+F71B: unknown char found by black box testing
758 U+0640: kashida */
759 WORD gi[4];
761 if (GetGlyphIndicesW(hdc, chars, 4, gi, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
763 if(gi[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
764 sc->sfp.wgBlank = gi[0];
765 else
766 sc->sfp.wgBlank = 0;
768 sc->sfp.wgDefault = 0;
770 if (gi[2] != 0xFFFF)
771 sc->sfp.wgInvalid = gi[2];
772 else if (gi[1] != 0xFFFF)
773 sc->sfp.wgInvalid = gi[1];
774 else if (gi[0] != 0xFFFF)
775 sc->sfp.wgInvalid = gi[0];
776 else
777 sc->sfp.wgInvalid = 0;
779 sc->sfp.wgKashida = gi[3];
781 sc->sfp.iKashidaWidth = 0; /* TODO */
783 else
784 return FALSE;
786 return TRUE;
789 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES *sfp, ScriptCache *sc)
791 sfp->wgBlank = sc->sfp.wgBlank;
792 sfp->wgDefault = sc->sfp.wgDefault;
793 sfp->wgInvalid = sc->sfp.wgInvalid;
794 sfp->wgKashida = sc->sfp.wgKashida;
795 sfp->iKashidaWidth = sc->sfp.iKashidaWidth;
798 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
800 return ((ScriptCache *)*psc)->tm.tmHeight;
803 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
805 return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
808 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
810 CacheGlyphPage *page = ((ScriptCache *)*psc)->page[c / 0x10000];
811 WORD *block;
813 if (!page) return 0;
814 block = page->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
815 if (!block) return 0;
816 return block[(c % 0x10000) & GLYPH_BLOCK_MASK];
819 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
821 CacheGlyphPage **page = &((ScriptCache *)*psc)->page[c / 0x10000];
822 WORD **block;
823 if (!*page && !(*page = heap_alloc_zero(sizeof(CacheGlyphPage)))) return 0;
825 block = &(*page)->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
826 if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
827 return ((*block)[(c % 0x10000) & GLYPH_BLOCK_MASK] = glyph);
830 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
832 static const ABC nil;
833 ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
835 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
836 memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
837 return TRUE;
840 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
842 ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
844 if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
845 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
846 return TRUE;
849 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
851 ScriptCache *sc;
852 int size;
854 if (!psc) return E_INVALIDARG;
855 if (*psc) return S_OK;
856 if (!hdc) return E_PENDING;
858 if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
859 if (!GetTextMetricsW(hdc, &sc->tm))
861 heap_free(sc);
862 return E_INVALIDARG;
864 size = GetOutlineTextMetricsW(hdc, 0, NULL);
865 if (size)
867 sc->otm = heap_alloc(size);
868 sc->otm->otmSize = size;
869 GetOutlineTextMetricsW(hdc, size, sc->otm);
871 if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
873 heap_free(sc);
874 return E_INVALIDARG;
876 sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
877 if (!set_cache_font_properties(hdc, sc))
879 heap_free(sc);
880 return E_INVALIDARG;
882 *psc = sc;
883 TRACE("<- %p\n", sc);
884 return S_OK;
887 static WCHAR mirror_char( WCHAR ch )
889 extern const WCHAR wine_mirror_map[] DECLSPEC_HIDDEN;
890 return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
893 static DWORD decode_surrogate_pair(const WCHAR *str, unsigned int index, unsigned int end)
895 if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
897 DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
898 TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
899 return ch;
901 return 0;
904 static int usp10_compare_script_range(const void *key, const void *value)
906 const struct usp10_script_range *range = value;
907 const DWORD *ch = key;
909 if (*ch < range->rangeFirst)
910 return -1;
911 if (*ch > range->rangeLast)
912 return 1;
913 return 0;
916 static enum usp10_script get_char_script(const WCHAR *str, unsigned int index,
917 unsigned int end, unsigned int *consumed)
919 static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
920 struct usp10_script_range *range;
921 WORD type = 0, type2 = 0;
922 DWORD ch;
924 *consumed = 1;
926 if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
927 return Script_CR;
929 /* These punctuation characters are separated out as Latin punctuation */
930 if (strchrW(latin_punc,str[index]))
931 return Script_Punctuation2;
933 /* These chars are itemized as Punctuation by Windows */
934 if (str[index] == 0x2212 || str[index] == 0x2044)
935 return Script_Punctuation;
937 /* Currency Symbols by Unicode point */
938 switch (str[index])
940 case 0x09f2:
941 case 0x09f3: return Script_Bengali_Currency;
942 case 0x0af1: return Script_Gujarati_Currency;
943 case 0x0e3f: return Script_Thai_Currency;
944 case 0x20aa: return Script_Hebrew_Currency;
945 case 0x20ab: return Script_Vietnamese_Currency;
946 case 0xfb29: return Script_Hebrew_Currency;
949 GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
950 GetStringTypeW(CT_CTYPE2, &str[index], 1, &type2);
952 if (type == 0)
953 return SCRIPT_UNDEFINED;
955 if (type & C1_CNTRL)
956 return Script_Control;
958 ch = decode_surrogate_pair(str, index, end);
959 if (ch)
960 *consumed = 2;
961 else
962 ch = str[index];
964 if (!(range = bsearch(&ch, script_ranges, ARRAY_SIZE(script_ranges),
965 sizeof(*script_ranges), usp10_compare_script_range)))
966 return Script_Undefined;
968 if (range->numericScript && (type & C1_DIGIT || type2 == C2_ARABICNUMBER))
969 return range->numericScript;
970 if (range->punctScript && type & C1_PUNCT)
971 return range->punctScript;
972 return range->script;
975 static int compare_FindGlyph(const void *a, const void* b)
977 const FindGlyph_struct *find = (FindGlyph_struct*)a;
978 const WORD *idx= (WORD*)b;
979 int rc = 0;
981 if ( find->target > *idx)
982 rc = 1;
983 else if (find->target < *idx)
984 rc = -1;
986 if (!find->ascending)
987 rc *= -1;
988 return rc;
991 int USP10_FindGlyphInLogClust(const WORD* pwLogClust, int cChars, WORD target)
993 FindGlyph_struct fgs;
994 WORD *ptr;
995 INT k;
997 if (pwLogClust[0] < pwLogClust[cChars-1])
998 fgs.ascending = TRUE;
999 else
1000 fgs.ascending = FALSE;
1002 fgs.target = target;
1003 ptr = bsearch(&fgs, pwLogClust, cChars, sizeof(WORD), compare_FindGlyph);
1005 if (!ptr)
1006 return -1;
1008 for (k = (ptr - pwLogClust)-1; k >= 0 && pwLogClust[k] == target; k--)
1010 k++;
1012 return k;
1015 /***********************************************************************
1016 * ScriptFreeCache (USP10.@)
1018 * Free a script cache.
1020 * PARAMS
1021 * psc [I/O] Script cache.
1023 * RETURNS
1024 * Success: S_OK
1025 * Failure: Non-zero HRESULT value.
1027 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
1029 TRACE("%p\n", psc);
1031 if (psc && *psc)
1033 unsigned int i;
1034 INT n;
1035 for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
1037 heap_free(((ScriptCache *)*psc)->widths[i]);
1039 for (i = 0; i < NUM_PAGES; i++)
1041 unsigned int j;
1042 if (((ScriptCache *)*psc)->page[i])
1043 for (j = 0; j < GLYPH_MAX / GLYPH_BLOCK_SIZE; j++)
1044 heap_free(((ScriptCache *)*psc)->page[i]->glyphs[j]);
1045 heap_free(((ScriptCache *)*psc)->page[i]);
1047 heap_free(((ScriptCache *)*psc)->GSUB_Table);
1048 heap_free(((ScriptCache *)*psc)->GDEF_Table);
1049 heap_free(((ScriptCache *)*psc)->CMAP_Table);
1050 heap_free(((ScriptCache *)*psc)->GPOS_Table);
1051 for (n = 0; n < ((ScriptCache *)*psc)->script_count; n++)
1053 int j;
1054 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].language_count; j++)
1056 int k;
1057 for (k = 0; k < ((ScriptCache *)*psc)->scripts[n].languages[j].feature_count; k++)
1058 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features[k].lookups);
1059 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features);
1061 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].default_language.feature_count; j++)
1062 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features[j].lookups);
1063 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features);
1064 heap_free(((ScriptCache *)*psc)->scripts[n].languages);
1066 heap_free(((ScriptCache *)*psc)->scripts);
1067 heap_free(((ScriptCache *)*psc)->otm);
1068 heap_free(*psc);
1069 *psc = NULL;
1071 return S_OK;
1074 /***********************************************************************
1075 * ScriptGetProperties (USP10.@)
1077 * Retrieve a list of script properties.
1079 * PARAMS
1080 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1081 * num [I] Pointer to the number of scripts.
1083 * RETURNS
1084 * Success: S_OK
1085 * Failure: Non-zero HRESULT value.
1087 * NOTES
1088 * Behaviour matches WinXP.
1090 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
1092 TRACE("(%p,%p)\n", props, num);
1094 if (!props && !num) return E_INVALIDARG;
1096 if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
1097 if (props) *props = script_props;
1099 return S_OK;
1102 /***********************************************************************
1103 * ScriptGetFontProperties (USP10.@)
1105 * Get information on special glyphs.
1107 * PARAMS
1108 * hdc [I] Device context.
1109 * psc [I/O] Opaque pointer to a script cache.
1110 * sfp [O] Font properties structure.
1112 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
1114 HRESULT hr;
1116 TRACE("%p,%p,%p\n", hdc, psc, sfp);
1118 if (!sfp) return E_INVALIDARG;
1119 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1121 if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
1122 return E_INVALIDARG;
1124 get_cache_font_properties(sfp, *psc);
1126 return S_OK;
1129 /***********************************************************************
1130 * ScriptRecordDigitSubstitution (USP10.@)
1132 * Record digit substitution settings for a given locale.
1134 * PARAMS
1135 * locale [I] Locale identifier.
1136 * sds [I] Structure to record substitution settings.
1138 * RETURNS
1139 * Success: S_OK
1140 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1142 * SEE ALSO
1143 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1145 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
1147 DWORD plgid, sub;
1149 TRACE("0x%x, %p\n", locale, sds);
1151 /* This implementation appears to be correct for all languages, but it's
1152 * not clear if sds->DigitSubstitute is ever set to anything except
1153 * CONTEXT or NONE in reality */
1155 if (!sds) return E_POINTER;
1157 locale = ConvertDefaultLocale(locale);
1159 if (!IsValidLocale(locale, LCID_INSTALLED))
1160 return E_INVALIDARG;
1162 plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
1163 sds->TraditionalDigitLanguage = plgid;
1165 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1166 sds->NationalDigitLanguage = plgid;
1167 else
1168 sds->NationalDigitLanguage = LANG_ENGLISH;
1170 if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
1171 (WCHAR *)&sub, sizeof(sub) / sizeof(WCHAR)))
1172 return E_INVALIDARG;
1174 switch (sub)
1176 case 0:
1177 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1178 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
1179 else
1180 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1181 break;
1182 case 1:
1183 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1184 break;
1185 case 2:
1186 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
1187 break;
1188 default:
1189 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
1190 break;
1193 sds->dwReserved = 0;
1194 return S_OK;
1197 /***********************************************************************
1198 * ScriptApplyDigitSubstitution (USP10.@)
1200 * Apply digit substitution settings.
1202 * PARAMS
1203 * sds [I] Structure with recorded substitution settings.
1204 * sc [I] Script control structure.
1205 * ss [I] Script state structure.
1207 * RETURNS
1208 * Success: S_OK
1209 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1211 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds,
1212 SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
1214 SCRIPT_DIGITSUBSTITUTE psds;
1216 TRACE("%p, %p, %p\n", sds, sc, ss);
1218 if (!sc || !ss) return E_POINTER;
1219 if (!sds)
1221 sds = &psds;
1222 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
1223 return E_INVALIDARG;
1226 sc->uDefaultLanguage = LANG_ENGLISH;
1227 sc->fContextDigits = 0;
1228 ss->fDigitSubstitute = 0;
1230 switch (sds->DigitSubstitute) {
1231 case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
1232 case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
1233 case SCRIPT_DIGITSUBSTITUTE_NONE:
1234 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
1235 return S_OK;
1236 default:
1237 return E_INVALIDARG;
1241 static inline BOOL is_indic(enum usp10_script script)
1243 return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
1246 static inline enum usp10_script base_indic(enum usp10_script script)
1248 switch (script)
1250 case Script_Devanagari:
1251 case Script_Devanagari_Numeric: return Script_Devanagari;
1252 case Script_Bengali:
1253 case Script_Bengali_Numeric:
1254 case Script_Bengali_Currency: return Script_Bengali;
1255 case Script_Gurmukhi:
1256 case Script_Gurmukhi_Numeric: return Script_Gurmukhi;
1257 case Script_Gujarati:
1258 case Script_Gujarati_Numeric:
1259 case Script_Gujarati_Currency: return Script_Gujarati;
1260 case Script_Oriya:
1261 case Script_Oriya_Numeric: return Script_Oriya;
1262 case Script_Tamil:
1263 case Script_Tamil_Numeric: return Script_Tamil;
1264 case Script_Telugu:
1265 case Script_Telugu_Numeric: return Script_Telugu;
1266 case Script_Kannada:
1267 case Script_Kannada_Numeric: return Script_Kannada;
1268 case Script_Malayalam:
1269 case Script_Malayalam_Numeric: return Script_Malayalam;
1270 default:
1271 return Script_Undefined;
1275 static BOOL script_is_numeric(enum usp10_script script)
1277 return scriptInformation[script].props.fNumeric;
1280 static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
1281 int cMaxItems, const SCRIPT_CONTROL *psControl,
1282 const SCRIPT_STATE *psState, SCRIPT_ITEM *pItems,
1283 OPENTYPE_TAG *pScriptTags, int *pcItems)
1286 #define Numeric_space 0x0020
1287 #define ZWSP 0x200B
1288 #define ZWNJ 0x200C
1289 #define ZWJ 0x200D
1291 enum usp10_script last_indic = Script_Undefined;
1292 int cnt = 0, index = 0, str = 0;
1293 enum usp10_script New_Script = -1;
1294 int i;
1295 WORD *levels = NULL;
1296 WORD *layout_levels = NULL;
1297 WORD *overrides = NULL;
1298 WORD *strength = NULL;
1299 enum usp10_script *scripts;
1300 WORD baselevel = 0;
1301 WORD baselayout = 0;
1302 BOOL new_run;
1303 WORD layoutRTL = 0;
1304 BOOL forceLevels = FALSE;
1305 unsigned int consumed = 0;
1306 HRESULT res = E_OUTOFMEMORY;
1308 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
1309 psControl, psState, pItems, pcItems);
1311 if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
1312 return E_INVALIDARG;
1314 if (!(scripts = heap_alloc(cInChars * sizeof(*scripts))))
1315 return E_OUTOFMEMORY;
1317 for (i = 0; i < cInChars; i++)
1319 if (!consumed)
1321 scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
1322 consumed --;
1324 else
1326 scripts[i] = scripts[i-1];
1327 consumed --;
1329 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1330 all Indic scripts */
1331 if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic != Script_Undefined)
1332 scripts[i] = last_indic;
1333 else if (is_indic(scripts[i]))
1334 last_indic = base_indic(scripts[i]);
1336 /* Some unicode points :
1337 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1338 (Left Right Embed U+202A - Left Right Override U+202D)
1339 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1340 will force us into bidi mode */
1341 if (!forceLevels && ((pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F) ||
1342 (pwcInChars[i] >= 0x202A && pwcInChars[i] <= 0x202E) ||
1343 (pwcInChars[i] >= 0x2066 && pwcInChars[i] <= 0x2069)))
1345 forceLevels = TRUE;
1347 /* Diacritical marks merge with other scripts */
1348 if (scripts[i] == Script_Diacritical)
1350 if (i > 0)
1352 if (pScriptTags)
1353 scripts[i] = scripts[i-1];
1354 else
1356 int j;
1357 BOOL asian = FALSE;
1358 enum usp10_script first_script = scripts[i-1];
1359 for (j = i-1; j >= 0 && scripts[j] == first_script && pwcInChars[j] != Numeric_space; j--)
1361 enum usp10_script original = scripts[j];
1362 if (original == Script_Ideograph || original == Script_Kana || original == Script_Yi || original == Script_CJK_Han || original == Script_Bopomofo)
1364 asian = TRUE;
1365 break;
1367 if (original != Script_MathAlpha && scriptInformation[scripts[j]].props.fComplex)
1368 break;
1369 scripts[j] = scripts[i];
1370 if (original == Script_Punctuation2)
1371 break;
1373 if (j >= 0 && (scriptInformation[scripts[j]].props.fComplex || asian))
1374 scripts[i] = scripts[j];
1380 for (i = 0; i < cInChars; i++)
1382 /* Joiners get merged preferencially right */
1383 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1385 int j;
1386 if (i+1 == cInChars)
1387 scripts[i] = scripts[i-1];
1388 else
1390 for (j = i+1; j < cInChars; j++)
1392 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1393 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1395 scripts[i] = scripts[j];
1396 break;
1403 if (psState && psControl)
1405 levels = heap_alloc_zero(cInChars * sizeof(WORD));
1406 if (!levels)
1407 goto nomemory;
1409 overrides = heap_alloc_zero(cInChars * sizeof(WORD));
1410 if (!overrides)
1411 goto nomemory;
1413 layout_levels = heap_alloc_zero(cInChars * sizeof(WORD));
1414 if (!layout_levels)
1415 goto nomemory;
1417 if (psState->fOverrideDirection)
1419 if (!forceLevels)
1421 SCRIPT_STATE s = *psState;
1422 s.fOverrideDirection = FALSE;
1423 BIDI_DetermineLevels(pwcInChars, cInChars, &s, psControl, layout_levels, overrides);
1424 if (odd(layout_levels[0]))
1425 forceLevels = TRUE;
1426 else for (i = 0; i < cInChars; i++)
1427 if (layout_levels[i]!=layout_levels[0])
1429 forceLevels = TRUE;
1430 break;
1434 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1436 else
1438 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1439 memcpy(layout_levels, levels, cInChars * sizeof(WORD));
1441 baselevel = levels[0];
1442 baselayout = layout_levels[0];
1443 for (i = 0; i < cInChars; i++)
1444 if (levels[i]!=levels[0])
1445 break;
1446 if (i >= cInChars && !odd(baselevel) && !odd(psState->uBidiLevel) && !forceLevels)
1448 heap_free(levels);
1449 heap_free(overrides);
1450 heap_free(layout_levels);
1451 overrides = NULL;
1452 levels = NULL;
1453 layout_levels = NULL;
1455 else
1457 static const WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1458 static const WCHAR repeatable_math_punc[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1460 strength = heap_alloc_zero(cInChars * sizeof(WORD));
1461 if (!strength)
1462 goto nomemory;
1463 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
1465 /* We currently mis-level leading Diacriticals */
1466 if (scripts[0] == Script_Diacritical)
1467 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
1469 levels[i] = odd(levels[i])?levels[i]+1:levels[i];
1470 strength[i] = BIDI_STRONG;
1473 /* Math punctuation bordered on both sides by numbers can be
1474 merged into the number */
1475 for (i = 0; i < cInChars; i++)
1477 if (i > 0 && i < cInChars-1 &&
1478 script_is_numeric(scripts[i-1]) &&
1479 strchrW(math_punc, pwcInChars[i]))
1481 if (script_is_numeric(scripts[i+1]))
1483 scripts[i] = scripts[i+1];
1484 levels[i] = levels[i-1];
1485 strength[i] = strength[i-1];
1486 i++;
1488 else if (strchrW(repeatable_math_punc, pwcInChars[i]))
1490 int j;
1491 for (j = i+1; j < cInChars; j++)
1493 if (script_is_numeric(scripts[j]))
1495 for(;i<j; i++)
1497 scripts[i] = scripts[j];
1498 levels[i] = levels[i-1];
1499 strength[i] = strength[i-1];
1502 else if (pwcInChars[i] != pwcInChars[j]) break;
1508 for (i = 0; i < cInChars; i++)
1510 /* Numerics at level 0 get bumped to level 2 */
1511 if (!overrides[i] && (levels[i] == 0 || (odd(psState->uBidiLevel)
1512 && levels[i] == psState->uBidiLevel + 1)) && script_is_numeric(scripts[i]))
1514 levels[i] = 2;
1517 /* Joiners get merged preferencially right */
1518 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1520 int j;
1521 if (i+1 == cInChars && levels[i-1] == levels[i])
1522 strength[i] = strength[i-1];
1523 else
1524 for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
1525 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1526 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1528 strength[i] = strength[j];
1529 break;
1533 if (psControl->fMergeNeutralItems)
1535 /* Merge the neutrals */
1536 for (i = 0; i < cInChars; i++)
1538 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1540 int j;
1541 for (j = i; j > 0; j--)
1543 if (levels[i] != levels[j])
1544 break;
1545 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1547 scripts[i] = scripts[j];
1548 strength[i] = strength[j];
1549 break;
1553 /* Try going the other way */
1554 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1556 int j;
1557 for (j = i; j < cInChars; j++)
1559 if (levels[i] != levels[j])
1560 break;
1561 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1563 scripts[i] = scripts[j];
1564 strength[i] = strength[j];
1565 break;
1574 while ((!levels || (levels && cnt+1 < cInChars && levels[cnt+1] == levels[0]))
1575 && (cnt < cInChars && pwcInChars[cnt] == Numeric_space))
1576 cnt++;
1578 if (cnt == cInChars) /* All Spaces */
1580 cnt = 0;
1581 New_Script = scripts[cnt];
1584 pItems[index].iCharPos = 0;
1585 pItems[index].a = scriptInformation[scripts[cnt]].a;
1586 if (pScriptTags)
1587 pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
1589 if (strength && strength[cnt] == BIDI_STRONG)
1590 str = strength[cnt];
1591 else if (strength)
1592 str = strength[0];
1594 cnt = 0;
1596 if (levels)
1598 if (strength[cnt] == BIDI_STRONG)
1599 layoutRTL = odd(layout_levels[cnt]);
1600 else
1601 layoutRTL = (psState->uBidiLevel || odd(layout_levels[cnt]));
1602 if (overrides)
1603 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1604 pItems[index].a.fRTL = odd(levels[cnt]);
1605 if (script_is_numeric(pItems[index].a.eScript))
1606 pItems[index].a.fLayoutRTL = layoutRTL;
1607 else
1608 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1609 pItems[index].a.s.uBidiLevel = levels[cnt];
1611 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1613 if (pItems[index].a.s.uBidiLevel != baselevel)
1614 pItems[index].a.s.fOverrideDirection = TRUE;
1615 layoutRTL = odd(baselayout);
1616 pItems[index].a.s.uBidiLevel = baselevel;
1617 pItems[index].a.fRTL = odd(baselevel);
1618 if (script_is_numeric(pItems[index].a.eScript))
1619 pItems[index].a.fLayoutRTL = odd(baselayout);
1620 else
1621 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1624 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1625 levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
1626 pItems[index].iCharPos);
1628 for (cnt=1; cnt < cInChars; cnt++)
1630 if(pwcInChars[cnt] != Numeric_space)
1631 New_Script = scripts[cnt];
1632 else if (levels)
1634 int j = 1;
1635 while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
1636 j++;
1637 if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
1638 New_Script = scripts[cnt+j];
1639 else
1640 New_Script = scripts[cnt];
1643 new_run = FALSE;
1644 /* merge space strengths*/
1645 if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
1646 str = BIDI_STRONG;
1648 if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
1649 str = BIDI_NEUTRAL;
1651 /* changes in level */
1652 if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
1654 TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
1655 new_run = TRUE;
1657 /* changes in strength */
1658 else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
1660 TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
1661 new_run = TRUE;
1663 /* changes in script */
1664 else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
1666 TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
1667 new_run = TRUE;
1670 if (!new_run && strength && str == BIDI_STRONG)
1672 layoutRTL = odd(layout_levels[cnt]);
1673 if (script_is_numeric(pItems[index].a.eScript))
1674 pItems[index].a.fLayoutRTL = layoutRTL;
1677 if (new_run)
1679 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);
1681 index++;
1682 if (index+1 > cMaxItems)
1683 goto nomemory;
1685 if (strength)
1686 str = strength[cnt];
1688 pItems[index].iCharPos = cnt;
1689 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1691 pItems[index].a = scriptInformation[New_Script].a;
1692 if (pScriptTags)
1693 pScriptTags[index] = scriptInformation[New_Script].scriptTag;
1694 if (levels)
1696 if (overrides)
1697 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1698 if (layout_levels[cnt] == 0)
1699 layoutRTL = 0;
1700 else
1701 layoutRTL = (layoutRTL || odd(layout_levels[cnt]));
1702 pItems[index].a.fRTL = odd(levels[cnt]);
1703 if (script_is_numeric(pItems[index].a.eScript))
1704 pItems[index].a.fLayoutRTL = layoutRTL;
1705 else
1706 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1707 pItems[index].a.s.uBidiLevel = levels[cnt];
1709 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1711 if (pItems[index].a.s.uBidiLevel != baselevel)
1712 pItems[index].a.s.fOverrideDirection = TRUE;
1713 pItems[index].a.s.uBidiLevel = baselevel;
1714 pItems[index].a.fRTL = odd(baselevel);
1715 if (script_is_numeric(pItems[index].a.eScript))
1716 pItems[index].a.fLayoutRTL = layoutRTL;
1717 else
1718 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1721 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1725 /* While not strictly necessary according to the spec, make sure the n+1
1726 * item is set up to prevent random behaviour if the caller erroneously
1727 * checks the n+1 structure */
1728 index++;
1729 if (index + 1 > cMaxItems) goto nomemory;
1730 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1732 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1734 /* Set one SCRIPT_STATE item being returned */
1735 if (pcItems) *pcItems = index;
1737 /* Set SCRIPT_ITEM */
1738 pItems[index].iCharPos = cnt; /* the last item contains the ptr to the lastchar */
1739 res = S_OK;
1740 nomemory:
1741 heap_free(levels);
1742 heap_free(overrides);
1743 heap_free(layout_levels);
1744 heap_free(strength);
1745 heap_free(scripts);
1746 return res;
1749 /***********************************************************************
1750 * ScriptItemizeOpenType (USP10.@)
1752 * Split a Unicode string into shapeable parts.
1754 * PARAMS
1755 * pwcInChars [I] String to split.
1756 * cInChars [I] Number of characters in pwcInChars.
1757 * cMaxItems [I] Maximum number of items to return.
1758 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1759 * psState [I] Pointer to a SCRIPT_STATE structure.
1760 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1761 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1762 * pcItems [O] Number of script items returned.
1764 * RETURNS
1765 * Success: S_OK
1766 * Failure: Non-zero HRESULT value.
1768 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1769 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1770 SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
1772 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pScriptTags, pcItems);
1775 /***********************************************************************
1776 * ScriptItemize (USP10.@)
1778 * Split a Unicode string into shapeable parts.
1780 * PARAMS
1781 * pwcInChars [I] String to split.
1782 * cInChars [I] Number of characters in pwcInChars.
1783 * cMaxItems [I] Maximum number of items to return.
1784 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1785 * psState [I] Pointer to a SCRIPT_STATE structure.
1786 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1787 * pcItems [O] Number of script items returned.
1789 * RETURNS
1790 * Success: S_OK
1791 * Failure: Non-zero HRESULT value.
1793 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1794 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1795 SCRIPT_ITEM *pItems, int *pcItems)
1797 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, NULL, pcItems);
1800 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1802 int defWidth;
1803 int cTabStops=0;
1804 INT *lpTabPos = NULL;
1805 INT nTabOrg = 0;
1806 INT x = 0;
1808 if (pTabdef)
1809 lpTabPos = pTabdef->pTabStops;
1811 if (pTabdef && pTabdef->iTabOrigin)
1813 if (pTabdef->iScale)
1814 nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1815 else
1816 nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1819 if (pTabdef)
1820 cTabStops = pTabdef->cTabStops;
1822 if (cTabStops == 1)
1824 if (pTabdef->iScale)
1825 defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1826 else
1827 defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1828 cTabStops = 0;
1830 else
1831 defWidth = 8 * psc->tm.tmAveCharWidth;
1833 for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1835 int position = *lpTabPos;
1836 if (position < 0)
1837 position = -1 * position;
1838 if (pTabdef->iScale)
1839 position = (position * pTabdef->iScale) / 4;
1840 else
1841 position = position * psc->tm.tmAveCharWidth;
1843 if( nTabOrg + position > current_x)
1845 if( *lpTabPos >= 0)
1847 /* a left aligned tab */
1848 x = (nTabOrg + *lpTabPos) - current_x;
1849 break;
1851 else
1853 FIXME("Negative tabstop\n");
1854 break;
1858 if ((!cTabStops) && (defWidth > 0))
1859 x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1860 else if ((!cTabStops) && (defWidth < 0))
1861 FIXME("TODO: Negative defWidth\n");
1863 return x;
1866 /***********************************************************************
1867 * Helper function for ScriptStringAnalyse
1869 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1870 const WCHAR *pwcInChars, int cChars )
1872 /* FIXME: When to properly fallback is still a bit of a mystery */
1873 WORD *glyphs;
1875 if (psa->fNoGlyphIndex)
1876 return FALSE;
1878 if (init_script_cache(hdc, psc) != S_OK)
1879 return FALSE;
1881 if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1882 return TRUE;
1884 glyphs = heap_alloc(sizeof(WORD) * cChars);
1885 if (!glyphs)
1886 return FALSE;
1887 if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1889 heap_free(glyphs);
1890 return TRUE;
1892 heap_free(glyphs);
1894 return FALSE;
1897 static void find_fallback_font(enum usp10_script scriptid, WCHAR *FaceName)
1899 HKEY hkey;
1901 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1903 static const WCHAR szFmt[] = {'%','x',0};
1904 WCHAR value[10];
1905 DWORD count = LF_FACESIZE * sizeof(WCHAR);
1906 DWORD type;
1908 sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1909 if (RegQueryValueExW(hkey, value, 0, &type, (BYTE *)FaceName, &count))
1910 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1911 RegCloseKey(hkey);
1913 else
1914 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1917 /***********************************************************************
1918 * ScriptStringAnalyse (USP10.@)
1921 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1922 int cGlyphs, int iCharset, DWORD dwFlags,
1923 int iReqWidth, SCRIPT_CONTROL *psControl,
1924 SCRIPT_STATE *psState, const int *piDx,
1925 SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1926 SCRIPT_STRING_ANALYSIS *pssa)
1928 HRESULT hr = E_OUTOFMEMORY;
1929 StringAnalysis *analysis = NULL;
1930 SCRIPT_CONTROL sControl;
1931 SCRIPT_STATE sState;
1932 int i, num_items = 255;
1933 BYTE *BidiLevel;
1934 WCHAR *iString = NULL;
1936 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1937 hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1938 psControl, psState, piDx, pTabdef, pbInClass, pssa);
1940 if (iCharset != -1)
1942 FIXME("Only Unicode strings are supported\n");
1943 return E_INVALIDARG;
1945 if (cString < 1 || !pString) return E_INVALIDARG;
1946 if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1948 if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1949 if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1951 /* FIXME: handle clipping */
1952 analysis->clip_len = cString;
1953 analysis->hdc = hdc;
1954 analysis->dwFlags = dwFlags;
1956 if (psState)
1957 sState = *psState;
1958 else
1959 memset(&sState, 0, sizeof(SCRIPT_STATE));
1961 if (psControl)
1962 sControl = *psControl;
1963 else
1964 memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1966 if (dwFlags & SSA_PASSWORD)
1968 iString = heap_alloc(sizeof(WCHAR)*cString);
1969 if (!iString)
1971 hr = E_OUTOFMEMORY;
1972 goto error;
1974 for (i = 0; i < cString; i++)
1975 iString[i] = *((const WCHAR *)pString);
1976 pString = iString;
1979 hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1980 &analysis->numItems);
1982 if (FAILED(hr))
1984 if (hr == E_OUTOFMEMORY)
1985 hr = E_INVALIDARG;
1986 goto error;
1989 /* set back to out of memory for default goto error behaviour */
1990 hr = E_OUTOFMEMORY;
1992 if (dwFlags & SSA_BREAK)
1994 if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
1996 for (i = 0; i < analysis->numItems; i++)
1997 ScriptBreak(&((WCHAR *)pString)[analysis->pItem[i].iCharPos],
1998 analysis->pItem[i + 1].iCharPos - analysis->pItem[i].iCharPos,
1999 &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
2001 else
2002 goto error;
2005 if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
2006 goto error;
2007 if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
2008 goto error;
2010 if (dwFlags & SSA_GLYPHS)
2012 int tab_x = 0;
2013 if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
2015 heap_free(BidiLevel);
2016 goto error;
2019 for (i = 0; i < analysis->numItems; i++)
2021 SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
2022 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2023 int numGlyphs = 1.5 * cChar + 16;
2024 WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
2025 WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
2026 int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
2027 SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
2028 GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
2029 ABC *abc = heap_alloc_zero(sizeof(ABC));
2030 int numGlyphsReturned;
2031 HFONT originalFont = 0x0;
2033 /* FIXME: non unicode strings */
2034 const WCHAR* pStr = (const WCHAR*)pString;
2035 analysis->glyphs[i].fallbackFont = NULL;
2037 if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
2039 heap_free (BidiLevel);
2040 heap_free (glyphs);
2041 heap_free (pwLogClust);
2042 heap_free (piAdvance);
2043 heap_free (psva);
2044 heap_free (pGoffset);
2045 heap_free (abc);
2046 hr = E_OUTOFMEMORY;
2047 goto error;
2050 if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
2052 LOGFONTW lf;
2053 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
2054 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
2055 lf.lfFaceName[0] = 0;
2056 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
2057 if (lf.lfFaceName[0])
2059 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
2060 if (analysis->glyphs[i].fallbackFont)
2062 ScriptFreeCache(sc);
2063 originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
2068 /* FIXME: When we properly shape Hangul remove this check */
2069 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && analysis->pItem[i].a.eScript == Script_Hangul)
2070 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2072 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && !scriptInformation[analysis->pItem[i].a.eScript].props.fComplex && !analysis->pItem[i].a.fRTL)
2073 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2075 ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos], cChar, numGlyphs,
2076 &analysis->pItem[i].a, glyphs, pwLogClust, psva, &numGlyphsReturned);
2077 hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
2078 piAdvance, pGoffset, abc);
2079 if (originalFont)
2080 SelectObject(hdc,originalFont);
2082 if (dwFlags & SSA_TAB)
2084 int tabi = 0;
2085 for (tabi = 0; tabi < cChar; tabi++)
2087 if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
2088 piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
2089 tab_x+=piAdvance[tabi];
2093 analysis->glyphs[i].numGlyphs = numGlyphsReturned;
2094 analysis->glyphs[i].glyphs = glyphs;
2095 analysis->glyphs[i].pwLogClust = pwLogClust;
2096 analysis->glyphs[i].piAdvance = piAdvance;
2097 analysis->glyphs[i].psva = psva;
2098 analysis->glyphs[i].pGoffset = pGoffset;
2099 analysis->glyphs[i].abc = abc;
2100 analysis->glyphs[i].iMaxPosX= -1;
2102 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2105 else
2107 for (i = 0; i < analysis->numItems; i++)
2108 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2111 ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
2112 heap_free(BidiLevel);
2114 *pssa = analysis;
2115 heap_free(iString);
2116 return S_OK;
2118 error:
2119 heap_free(iString);
2120 heap_free(analysis->glyphs);
2121 heap_free(analysis->logattrs);
2122 heap_free(analysis->pItem);
2123 heap_free(analysis->logical2visual);
2124 heap_free(analysis);
2125 return hr;
2128 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
2130 if (pva[glyph].fClusterStart)
2131 return TRUE;
2132 if (USP10_FindGlyphInLogClust(pwLogClust, cChars, glyph) >= 0)
2133 return TRUE;
2135 return FALSE;
2139 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
2140 int iX,
2141 int iY,
2142 int iItem,
2143 int cStart,
2144 int cEnd,
2145 UINT uOptions,
2146 const RECT *prc,
2147 BOOL fSelected,
2148 BOOL fDisabled)
2150 StringAnalysis *analysis;
2151 int off_x = 0;
2152 HRESULT hr;
2153 COLORREF BkColor = 0x0;
2154 COLORREF TextColor = 0x0;
2155 INT BkMode = 0;
2156 INT runStart, runEnd;
2157 INT iGlyph, cGlyphs;
2158 HFONT oldFont = 0x0;
2159 RECT crc;
2160 int i;
2162 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2163 ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
2165 if (!(analysis = ssa)) return E_INVALIDARG;
2167 if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
2168 (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
2169 return S_OK;
2171 CopyRect(&crc,prc);
2172 if (fSelected)
2174 BkMode = GetBkMode(analysis->hdc);
2175 SetBkMode( analysis->hdc, OPAQUE);
2176 BkColor = GetBkColor(analysis->hdc);
2177 SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
2178 if (!fDisabled)
2180 TextColor = GetTextColor(analysis->hdc);
2181 SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2184 if (analysis->glyphs[iItem].fallbackFont)
2185 oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
2187 if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
2188 runStart = cStart - analysis->pItem[iItem].iCharPos;
2189 else
2190 runStart = 0;
2191 if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
2192 runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
2193 else
2194 runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
2196 if (analysis->pItem[iItem].a.fRTL)
2198 if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
2199 ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
2200 else
2201 ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
2202 crc.left = iX + off_x;
2204 else
2206 if (cStart >=0 && runStart)
2207 ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
2208 else
2209 ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
2210 crc.left = iX + off_x;
2213 if (analysis->pItem[iItem].a.fRTL)
2214 iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
2215 else
2216 iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
2218 if (analysis->pItem[iItem].a.fRTL)
2219 cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
2220 else
2221 cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
2223 cGlyphs++;
2225 /* adjust for cluster glyphs when starting */
2226 if (analysis->pItem[iItem].a.fRTL)
2227 i = analysis->pItem[iItem+1].iCharPos - 1;
2228 else
2229 i = analysis->pItem[iItem].iCharPos;
2231 for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
2233 if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
2235 if (analysis->pItem[iItem].a.fRTL)
2236 ScriptStringCPtoX(ssa, i, TRUE, &off_x);
2237 else
2238 ScriptStringCPtoX(ssa, i, FALSE, &off_x);
2239 break;
2243 if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
2245 INT direction;
2246 INT clust_glyph;
2248 clust_glyph = iGlyph + cGlyphs;
2249 if (analysis->pItem[iItem].a.fRTL)
2250 direction = -1;
2251 else
2252 direction = 1;
2254 while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
2255 !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
2257 cGlyphs++;
2258 clust_glyph++;
2262 hr = ScriptTextOut(analysis->hdc,
2263 (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
2264 iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
2265 &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
2266 &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
2267 &analysis->glyphs[iItem].pGoffset[iGlyph]);
2269 TRACE("ScriptTextOut hr=%08x\n", hr);
2271 if (fSelected)
2273 SetBkColor(analysis->hdc, BkColor);
2274 SetBkMode( analysis->hdc, BkMode);
2275 if (!fDisabled)
2276 SetTextColor(analysis->hdc, TextColor);
2278 if (analysis->glyphs[iItem].fallbackFont)
2279 SelectObject(analysis->hdc, oldFont);
2281 return hr;
2284 /***********************************************************************
2285 * ScriptStringOut (USP10.@)
2287 * This function takes the output of ScriptStringAnalyse and joins the segments
2288 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2289 * only processes glyphs.
2291 * Parameters:
2292 * ssa [I] buffer to hold the analysed string components
2293 * iX [I] X axis displacement for output
2294 * iY [I] Y axis displacement for output
2295 * uOptions [I] flags controlling output processing
2296 * prc [I] rectangle coordinates
2297 * iMinSel [I] starting pos for substringing output string
2298 * iMaxSel [I] ending pos for substringing output string
2299 * fDisabled [I] controls text highlighting
2301 * RETURNS
2302 * Success: S_OK
2303 * Failure: is the value returned by ScriptTextOut
2305 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
2306 int iX,
2307 int iY,
2308 UINT uOptions,
2309 const RECT *prc,
2310 int iMinSel,
2311 int iMaxSel,
2312 BOOL fDisabled)
2314 StringAnalysis *analysis;
2315 int item;
2316 HRESULT hr;
2318 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2319 ssa, iX, iY, uOptions, wine_dbgstr_rect(prc), iMinSel, iMaxSel, fDisabled);
2321 if (!(analysis = ssa)) return E_INVALIDARG;
2322 if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
2324 for (item = 0; item < analysis->numItems; item++)
2326 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
2327 if (FAILED(hr))
2328 return hr;
2331 if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
2333 if (iMaxSel > 0 && iMinSel < 0)
2334 iMinSel = 0;
2335 for (item = 0; item < analysis->numItems; item++)
2337 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
2338 if (FAILED(hr))
2339 return hr;
2343 return S_OK;
2346 /***********************************************************************
2347 * ScriptStringCPtoX (USP10.@)
2350 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
2352 int item;
2353 int runningX = 0;
2354 StringAnalysis* analysis = ssa;
2356 TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
2358 if (!ssa || !pX) return S_FALSE;
2359 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2361 /* icp out of range */
2362 if(icp < 0)
2364 analysis->invalid = TRUE;
2365 return E_INVALIDARG;
2368 for(item=0; item<analysis->numItems; item++)
2370 int CP, i;
2371 int offset;
2373 i = analysis->logical2visual[item];
2374 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2375 /* initialize max extents for uninitialized runs */
2376 if (analysis->glyphs[i].iMaxPosX == -1)
2378 if (analysis->pItem[i].a.fRTL)
2379 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2380 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2381 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2382 else
2383 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2384 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2385 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2388 if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
2390 runningX += analysis->glyphs[i].iMaxPosX;
2391 continue;
2394 icp -= analysis->pItem[i].iCharPos;
2395 ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2396 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2397 &analysis->pItem[i].a, &offset);
2398 runningX += offset;
2400 *pX = runningX;
2401 return S_OK;
2404 /* icp out of range */
2405 analysis->invalid = TRUE;
2406 return E_INVALIDARG;
2409 /***********************************************************************
2410 * ScriptStringXtoCP (USP10.@)
2413 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
2415 StringAnalysis* analysis = ssa;
2416 int item;
2418 TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
2420 if (!ssa || !piCh || !piTrailing) return S_FALSE;
2421 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2423 /* out of range */
2424 if(iX < 0)
2426 if (analysis->pItem[0].a.fRTL)
2428 *piCh = 1;
2429 *piTrailing = FALSE;
2431 else
2433 *piCh = -1;
2434 *piTrailing = TRUE;
2436 return S_OK;
2439 for(item=0; item<analysis->numItems; item++)
2441 int i;
2442 int CP;
2444 for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
2445 /* nothing */;
2447 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2448 /* initialize max extents for uninitialized runs */
2449 if (analysis->glyphs[i].iMaxPosX == -1)
2451 if (analysis->pItem[i].a.fRTL)
2452 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2453 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2454 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2455 else
2456 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2457 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2458 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2461 if (iX > analysis->glyphs[i].iMaxPosX)
2463 iX -= analysis->glyphs[i].iMaxPosX;
2464 continue;
2467 ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2468 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2469 &analysis->pItem[i].a, piCh, piTrailing);
2470 *piCh += analysis->pItem[i].iCharPos;
2472 return S_OK;
2475 /* out of range */
2476 *piCh = analysis->pItem[analysis->numItems].iCharPos;
2477 *piTrailing = FALSE;
2479 return S_OK;
2483 /***********************************************************************
2484 * ScriptStringFree (USP10.@)
2486 * Free a string analysis.
2488 * PARAMS
2489 * pssa [I] string analysis.
2491 * RETURNS
2492 * Success: S_OK
2493 * Failure: Non-zero HRESULT value.
2495 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
2497 StringAnalysis* analysis;
2498 BOOL invalid;
2499 int i;
2501 TRACE("(%p)\n", pssa);
2503 if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
2505 invalid = analysis->invalid;
2507 if (analysis->glyphs)
2509 for (i = 0; i < analysis->numItems; i++)
2511 heap_free(analysis->glyphs[i].glyphs);
2512 heap_free(analysis->glyphs[i].pwLogClust);
2513 heap_free(analysis->glyphs[i].piAdvance);
2514 heap_free(analysis->glyphs[i].psva);
2515 heap_free(analysis->glyphs[i].pGoffset);
2516 heap_free(analysis->glyphs[i].abc);
2517 if (analysis->glyphs[i].fallbackFont)
2518 DeleteObject(analysis->glyphs[i].fallbackFont);
2519 ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
2520 heap_free(analysis->glyphs[i].sc);
2522 heap_free(analysis->glyphs);
2525 heap_free(analysis->pItem);
2526 heap_free(analysis->logattrs);
2527 heap_free(analysis->sz);
2528 heap_free(analysis->logical2visual);
2529 heap_free(analysis);
2531 if (invalid) return E_INVALIDARG;
2532 return S_OK;
2535 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
2536 int direction, int* iCluster, int *check_out)
2538 int clust_size = 1;
2539 int check;
2540 WORD clust = pwLogClust[item];
2542 for (check = item+direction; check < cChars && check >= 0; check+=direction)
2544 if (pwLogClust[check] == clust)
2546 clust_size ++;
2547 if (iCluster && *iCluster == -1)
2548 *iCluster = item;
2550 else break;
2553 if (check_out)
2554 *check_out = check;
2556 return clust_size;
2559 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)
2561 int advance;
2562 int log_clust_max;
2564 advance = piAdvance[glyph];
2566 if (pwLogClust[0] > pwLogClust[cChars-1])
2567 log_clust_max = pwLogClust[0];
2568 else
2569 log_clust_max = pwLogClust[cChars-1];
2571 if (glyph > log_clust_max)
2572 return advance;
2574 for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
2577 if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
2578 break;
2579 if (glyph > log_clust_max)
2580 break;
2581 advance += piAdvance[glyph];
2584 return advance;
2587 /***********************************************************************
2588 * ScriptCPtoX (USP10.@)
2591 HRESULT WINAPI ScriptCPtoX(int iCP,
2592 BOOL fTrailing,
2593 int cChars,
2594 int cGlyphs,
2595 const WORD *pwLogClust,
2596 const SCRIPT_VISATTR *psva,
2597 const int *piAdvance,
2598 const SCRIPT_ANALYSIS *psa,
2599 int *piX)
2601 int item;
2602 float iPosX;
2603 int iSpecial = -1;
2604 int iCluster = -1;
2605 int clust_size = 1;
2606 float special_size = 0.0;
2607 int iMaxPos = 0;
2608 int advance = 0;
2609 BOOL rtl = FALSE;
2611 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2612 iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2613 psa, piX);
2615 if (psa->fRTL && ! psa->fLogicalOrder)
2616 rtl = TRUE;
2618 if (fTrailing)
2619 iCP++;
2621 if (rtl)
2623 int max_clust = pwLogClust[0];
2625 for (item=0; item < cGlyphs; item++)
2626 if (pwLogClust[item] > max_clust)
2628 ERR("We do not handle non reversed clusters properly\n");
2629 break;
2632 iMaxPos = 0;
2633 for (item = max_clust; item >=0; item --)
2634 iMaxPos += piAdvance[item];
2637 iPosX = 0.0;
2638 for (item=0; item < iCP && item < cChars; item++)
2640 if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
2642 int check;
2643 int clust = pwLogClust[item];
2645 iCluster = -1;
2646 clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2647 &check);
2649 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2651 if (check >= cChars && !iMaxPos)
2653 int glyph;
2654 for (glyph = clust; glyph < cGlyphs; glyph++)
2655 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, glyph, 1);
2656 iSpecial = item;
2657 special_size /= (cChars - item);
2658 iPosX += special_size;
2660 else
2662 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2664 clust_size --;
2665 if (clust_size == 0)
2666 iPosX += advance;
2668 else
2669 iPosX += advance / (float)clust_size;
2672 else if (iSpecial != -1)
2673 iPosX += special_size;
2674 else /* (iCluster != -1) */
2676 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2677 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2679 clust_size --;
2680 if (clust_size == 0)
2681 iPosX += adv;
2683 else
2684 iPosX += adv / (float)clust_size;
2688 if (iMaxPos > 0)
2690 iPosX = iMaxPos - iPosX;
2691 if (iPosX < 0)
2692 iPosX = 0;
2695 *piX = iPosX;
2696 TRACE("*piX=%d\n", *piX);
2697 return S_OK;
2700 /* Count the number of characters in a cluster and its starting index*/
2701 static inline BOOL get_cluster_data(const WORD *pwLogClust, int cChars, int cluster_index, int *cluster_size, int *start_index)
2703 int size = 0;
2704 int i;
2706 for (i = 0; i < cChars; i++)
2708 if (pwLogClust[i] == cluster_index)
2710 if (!size && start_index)
2712 *start_index = i;
2713 if (!cluster_size)
2714 return TRUE;
2716 size++;
2718 else if (size) break;
2720 if (cluster_size)
2721 *cluster_size = size;
2723 return (size > 0);
2727 To handle multi-glyph clusters we need to find all the glyphs that are
2728 represented in the cluster. This involves finding the glyph whose
2729 index is the cluster index as well as whose glyph indices are greater than
2730 our cluster index but not part of a new cluster.
2732 Then we sum all those glyphs' advances.
2734 static inline int get_cluster_advance(const int* piAdvance,
2735 const SCRIPT_VISATTR *psva,
2736 const WORD *pwLogClust, int cGlyphs,
2737 int cChars, int cluster, int direction)
2739 int glyph_start;
2740 int glyph_end;
2741 int i, advance;
2743 if (direction > 0)
2744 i = 0;
2745 else
2746 i = (cChars - 1);
2748 for (glyph_start = -1, glyph_end = -1; i < cChars && i >= 0 && (glyph_start < 0 || glyph_end < 0); i+=direction)
2750 if (glyph_start < 0 && pwLogClust[i] != cluster) continue;
2751 if (pwLogClust[i] == cluster && glyph_start < 0) glyph_start = pwLogClust[i];
2752 if (glyph_start >= 0 && glyph_end < 0 && pwLogClust[i] != cluster) glyph_end = pwLogClust[i];
2754 if (glyph_end < 0)
2756 if (direction > 0)
2757 glyph_end = cGlyphs;
2758 else
2760 /* Don't fully understand multi-glyph reversed clusters yet,
2761 * do they occur for real or just in our test? */
2762 FIXME("multi-glyph reversed clusters found\n");
2763 glyph_end = glyph_start + 1;
2767 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2768 for (i = glyph_start+1; i< glyph_end; i++)
2770 if (psva[i].fClusterStart)
2772 glyph_end = i;
2773 break;
2777 for (advance = 0, i = glyph_start; i < glyph_end; i++)
2778 advance += piAdvance[i];
2780 return advance;
2784 /***********************************************************************
2785 * ScriptXtoCP (USP10.@)
2787 * Basic algorithm :
2788 * Use piAdvance to find the cluster we are looking at.
2789 * Find the character that is the first character of the cluster.
2790 * That is our base piCP.
2791 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2792 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2793 * determine how far through the cluster to advance the cursor.
2795 HRESULT WINAPI ScriptXtoCP(int iX,
2796 int cChars,
2797 int cGlyphs,
2798 const WORD *pwLogClust,
2799 const SCRIPT_VISATTR *psva,
2800 const int *piAdvance,
2801 const SCRIPT_ANALYSIS *psa,
2802 int *piCP,
2803 int *piTrailing)
2805 int direction = 1;
2806 int iPosX;
2807 int i;
2808 int glyph_index, cluster_index;
2809 int cluster_size;
2811 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2812 iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2813 psa, piCP, piTrailing);
2815 if (psa->fRTL && ! psa->fLogicalOrder)
2816 direction = -1;
2818 /* Handle an iX < 0 */
2819 if (iX < 0)
2821 if (direction < 0)
2823 *piCP = cChars;
2824 *piTrailing = 0;
2826 else
2828 *piCP = -1;
2829 *piTrailing = 1;
2831 return S_OK;
2834 /* Looking for non-reversed clusters in a reversed string */
2835 if (direction < 0)
2837 int max_clust = pwLogClust[0];
2838 for (i=0; i< cChars; i++)
2839 if (pwLogClust[i] > max_clust)
2841 FIXME("We do not handle non reversed clusters properly\n");
2842 break;
2846 /* find the glyph_index based in iX */
2847 if (direction > 0)
2849 for (glyph_index = -1, iPosX = iX; iPosX >=0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2852 else
2854 for (glyph_index = -1, iPosX = iX; iPosX > 0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2858 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX, glyph_index, cGlyphs);
2860 *piTrailing = 0;
2861 if (glyph_index >= 0 && glyph_index < cGlyphs)
2863 /* find the cluster */
2864 if (direction > 0 )
2865 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] <= glyph_index; cluster_index=pwLogClust[i++])
2867 else
2868 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] >= glyph_index; cluster_index=pwLogClust[i++])
2871 TRACE("cluster_index %i\n", cluster_index);
2873 if (direction < 0 && iPosX >= 0 && glyph_index != cluster_index)
2875 /* We are off the end of the string */
2876 *piCP = -1;
2877 *piTrailing = 1;
2878 return S_OK;
2881 get_cluster_data(pwLogClust, cChars, cluster_index, &cluster_size, &i);
2883 TRACE("first char index %i\n",i);
2884 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2886 /* Check trailing */
2887 if (glyph_index != cluster_index ||
2888 (direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2889 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2890 *piTrailing = cluster_size;
2892 else
2894 if (cluster_size > 1)
2896 /* Be part way through the glyph cluster based on size and position */
2897 int cluster_advance = get_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, cluster_index, direction);
2898 double cluster_part_width = cluster_advance / (float)cluster_size;
2899 double adv;
2900 int part_index;
2902 /* back up to the beginning of the cluster */
2903 for (adv = iPosX, part_index = cluster_index; part_index <= glyph_index; part_index++)
2904 adv += piAdvance[part_index];
2905 if (adv > iX) adv = iX;
2907 TRACE("Multi-char cluster, no snap\n");
2908 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size, adv);
2909 TRACE("advance %i divides into %f per char\n", cluster_advance, cluster_part_width);
2910 if (direction > 0)
2912 for (part_index = 0; adv >= 0; adv-=cluster_part_width, part_index++)
2914 if (part_index) part_index--;
2916 else
2918 for (part_index = 0; adv > 0; adv-=cluster_part_width, part_index++)
2920 if (part_index > cluster_size)
2922 adv += cluster_part_width;
2923 part_index=cluster_size;
2927 TRACE("base_char %i part_index %i, leftover advance %f\n",i, part_index, adv);
2929 if (direction > 0)
2930 i += part_index;
2931 else
2932 i += (cluster_size - part_index);
2934 /* Check trailing */
2935 if ((direction > 0 && fabs(adv) <= (cluster_part_width / 2.0)) ||
2936 (direction < 0 && adv && fabs(adv) >= (cluster_part_width / 2.0)))
2937 *piTrailing = 1;
2939 else
2941 /* Check trailing */
2942 if ((direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2943 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2944 *piTrailing = 1;
2948 else
2950 TRACE("Point falls outside of string\n");
2951 if (glyph_index < 0)
2952 i = cChars-1;
2953 else /* (glyph_index >= cGlyphs) */
2954 i = cChars;
2956 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2957 point flow to the next character */
2958 if (direction < 0)
2960 if (!scriptInformation[psa->eScript].props.fNeedsCaretInfo && abs(iPosX) == piAdvance[glyph_index])
2961 i++;
2962 else
2963 *piTrailing = 1;
2967 *piCP = i;
2969 TRACE("*piCP=%d\n", *piCP);
2970 TRACE("*piTrailing=%d\n", *piTrailing);
2971 return S_OK;
2974 /***********************************************************************
2975 * ScriptBreak (USP10.@)
2977 * Retrieve line break information.
2979 * PARAMS
2980 * chars [I] Array of characters.
2981 * sa [I] Script analysis.
2982 * la [I] Array of logical attribute structures.
2984 * RETURNS
2985 * Success: S_OK
2986 * Failure: S_FALSE
2988 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2990 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2992 if (count < 0 || !la) return E_INVALIDARG;
2993 if (count == 0) return E_FAIL;
2995 BREAK_line(chars, count, sa, la);
2997 return S_OK;
3000 /***********************************************************************
3001 * ScriptIsComplex (USP10.@)
3003 * Determine if a string is complex.
3005 * PARAMS
3006 * chars [I] Array of characters to test.
3007 * len [I] Length in characters.
3008 * flag [I] Flag.
3010 * RETURNS
3011 * Success: S_OK
3012 * Failure: S_FALSE
3015 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
3017 enum usp10_script script;
3018 unsigned int i, consumed;
3020 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
3022 if (!chars || len < 0)
3023 return E_INVALIDARG;
3025 for (i = 0; i < len; i+=consumed)
3027 if (i >= len)
3028 break;
3030 if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
3031 return S_OK;
3033 script = get_char_script(chars,i,len, &consumed);
3034 if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
3035 (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
3036 return S_OK;
3038 return S_FALSE;
3041 /***********************************************************************
3042 * ScriptShapeOpenType (USP10.@)
3044 * Produce glyphs and visual attributes for a run.
3046 * PARAMS
3047 * hdc [I] Device context.
3048 * psc [I/O] Opaque pointer to a script cache.
3049 * psa [I/O] Script analysis.
3050 * tagScript [I] The OpenType tag for the Script
3051 * tagLangSys [I] The OpenType tag for the Language
3052 * rcRangeChars[I] Array of Character counts in each range
3053 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3054 * cRanges [I] Count of ranges
3055 * pwcChars [I] Array of characters specifying the run.
3056 * cChars [I] Number of characters in pwcChars.
3057 * cMaxGlyphs [I] Length of pwOutGlyphs.
3058 * pwLogClust [O] Array of logical cluster info.
3059 * pCharProps [O] Array of character property values
3060 * pwOutGlyphs [O] Array of glyphs.
3061 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3062 * pcGlyphs [O] Number of glyphs returned.
3064 * RETURNS
3065 * Success: S_OK
3066 * Failure: Non-zero HRESULT value.
3068 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
3069 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3070 OPENTYPE_TAG tagLangSys, int *rcRangeChars,
3071 TEXTRANGE_PROPERTIES **rpRangeProperties,
3072 int cRanges, const WCHAR *pwcChars, int cChars,
3073 int cMaxGlyphs, WORD *pwLogClust,
3074 SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
3075 SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
3077 HRESULT hr;
3078 int i;
3079 unsigned int g;
3080 BOOL rtl;
3081 int cluster;
3082 static int once = 0;
3084 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3085 hdc, psc, psa,
3086 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3087 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3088 cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
3090 if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
3091 psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
3093 if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
3094 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3096 if (cRanges)
3097 if(!once++) FIXME("Ranges not supported yet\n");
3099 rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
3101 *pcGlyphs = cChars;
3102 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3103 if (!pwLogClust) return E_FAIL;
3105 ((ScriptCache *)*psc)->userScript = tagScript;
3106 ((ScriptCache *)*psc)->userLang = tagLangSys;
3108 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3109 for (i = 0; i < cChars; i++)
3111 int idx = i;
3112 if (rtl) idx = cChars - 1 - i;
3113 /* FIXME: set to better values */
3114 pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
3115 pOutGlyphProps[i].sva.fClusterStart = 1;
3116 pOutGlyphProps[i].sva.fDiacritic = 0;
3117 pOutGlyphProps[i].sva.fZeroWidth = 0;
3118 pOutGlyphProps[i].sva.fReserved = 0;
3119 pOutGlyphProps[i].sva.fShapeReserved = 0;
3121 /* FIXME: have the shaping engine set this */
3122 pCharProps[i].fCanGlyphAlone = 0;
3124 pwLogClust[i] = idx;
3127 if (psa && !psa->fNoGlyphIndex && ((ScriptCache *)*psc)->sfnt)
3129 WCHAR *rChars;
3130 if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
3132 rChars = heap_alloc(sizeof(WCHAR) * cChars);
3133 if (!rChars) return E_OUTOFMEMORY;
3134 for (i = 0, g = 0, cluster = 0; i < cChars; i++)
3136 int idx = i;
3137 DWORD chInput;
3139 if (rtl) idx = cChars - 1 - i;
3140 if (!cluster)
3142 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
3143 if (!chInput)
3145 if (psa->fRTL)
3146 chInput = mirror_char(pwcChars[idx]);
3147 else
3148 chInput = pwcChars[idx];
3149 rChars[i] = chInput;
3151 else
3153 rChars[i] = pwcChars[idx];
3154 rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
3155 cluster = 1;
3157 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
3159 WORD glyph;
3160 if (!hdc)
3162 heap_free(rChars);
3163 return E_PENDING;
3165 if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
3167 heap_free(rChars);
3168 return S_FALSE;
3170 pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
3172 g++;
3174 else
3176 int k;
3177 cluster--;
3178 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
3179 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3180 pwLogClust[k]--;
3183 *pcGlyphs = g;
3185 SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3186 SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
3187 SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
3189 for (i = 0; i < cChars; ++i)
3191 /* Special case for tabs and joiners. As control characters, ZWNJ
3192 * and ZWJ would in principle get handled by the corresponding
3193 * shaping functions. However, since ZWNJ and ZWJ can get merged
3194 * into adjoining runs during itemisation, these don't generally
3195 * get classified as Script_Control. */
3196 if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
3198 pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
3199 pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
3202 heap_free(rChars);
3204 else
3206 TRACE("no glyph translation\n");
3207 for (i = 0; i < cChars; i++)
3209 int idx = i;
3210 /* No mirroring done here */
3211 if (rtl) idx = cChars - 1 - i;
3212 pwOutGlyphs[i] = pwcChars[idx];
3214 if (!psa)
3215 continue;
3217 /* overwrite some basic control glyphs to blank */
3218 if (psa->fNoGlyphIndex)
3220 if (pwcChars[idx] == ZWSP || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3222 pwOutGlyphs[i] = 0x20;
3223 pOutGlyphProps[i].sva.fZeroWidth = 1;
3226 else if (psa->eScript == Script_Control || pwcChars[idx] == ZWSP
3227 || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3229 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
3230 pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)
3232 pwOutGlyphs[i] = ((ScriptCache *)*psc)->sfp.wgBlank;
3233 pOutGlyphProps[i].sva.fZeroWidth = 1;
3239 return S_OK;
3243 /***********************************************************************
3244 * ScriptShape (USP10.@)
3246 * Produce glyphs and visual attributes for a run.
3248 * PARAMS
3249 * hdc [I] Device context.
3250 * psc [I/O] Opaque pointer to a script cache.
3251 * pwcChars [I] Array of characters specifying the run.
3252 * cChars [I] Number of characters in pwcChars.
3253 * cMaxGlyphs [I] Length of pwOutGlyphs.
3254 * psa [I/O] Script analysis.
3255 * pwOutGlyphs [O] Array of glyphs.
3256 * pwLogClust [O] Array of logical cluster info.
3257 * psva [O] Array of visual attributes.
3258 * pcGlyphs [O] Number of glyphs returned.
3260 * RETURNS
3261 * Success: S_OK
3262 * Failure: Non-zero HRESULT value.
3264 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
3265 int cChars, int cMaxGlyphs,
3266 SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
3267 SCRIPT_VISATTR *psva, int *pcGlyphs)
3269 HRESULT hr;
3270 int i;
3271 SCRIPT_CHARPROP *charProps;
3272 SCRIPT_GLYPHPROP *glyphProps;
3274 if (!psva || !pcGlyphs) return E_INVALIDARG;
3275 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3277 charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
3278 if (!charProps) return E_OUTOFMEMORY;
3279 glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
3280 if (!glyphProps)
3282 heap_free(charProps);
3283 return E_OUTOFMEMORY;
3286 hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
3288 if (SUCCEEDED(hr))
3290 for (i = 0; i < *pcGlyphs; i++)
3291 psva[i] = glyphProps[i].sva;
3294 heap_free(charProps);
3295 heap_free(glyphProps);
3297 return hr;
3300 /***********************************************************************
3301 * ScriptPlaceOpenType (USP10.@)
3303 * Produce advance widths for a run.
3305 * PARAMS
3306 * hdc [I] Device context.
3307 * psc [I/O] Opaque pointer to a script cache.
3308 * psa [I/O] Script analysis.
3309 * tagScript [I] The OpenType tag for the Script
3310 * tagLangSys [I] The OpenType tag for the Language
3311 * rcRangeChars[I] Array of Character counts in each range
3312 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3313 * cRanges [I] Count of ranges
3314 * pwcChars [I] Array of characters specifying the run.
3315 * pwLogClust [I] Array of logical cluster info
3316 * pCharProps [I] Array of character property values
3317 * cChars [I] Number of characters in pwcChars.
3318 * pwGlyphs [I] Array of glyphs.
3319 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3320 * cGlyphs [I] Count of Glyphs
3321 * piAdvance [O] Array of advance widths.
3322 * pGoffset [O] Glyph offsets.
3323 * pABC [O] Combined ABC width.
3325 * RETURNS
3326 * Success: S_OK
3327 * Failure: Non-zero HRESULT value.
3330 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
3331 OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
3332 int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
3333 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3334 SCRIPT_CHARPROP *pCharProps, int cChars,
3335 const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
3336 int cGlyphs, int *piAdvance,
3337 GOFFSET *pGoffset, ABC *pABC
3340 HRESULT hr;
3341 int i;
3342 static int once = 0;
3344 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3345 hdc, psc, psa,
3346 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3347 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3348 pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
3349 pGoffset, pABC);
3351 if (!pGlyphProps) return E_INVALIDARG;
3352 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3353 if (!pGoffset) return E_FAIL;
3355 if (cRanges)
3356 if (!once++) FIXME("Ranges not supported yet\n");
3358 ((ScriptCache *)*psc)->userScript = tagScript;
3359 ((ScriptCache *)*psc)->userLang = tagLangSys;
3361 if (pABC) memset(pABC, 0, sizeof(ABC));
3362 for (i = 0; i < cGlyphs; i++)
3364 ABC abc;
3365 if (pGlyphProps[i].sva.fZeroWidth)
3367 abc.abcA = abc.abcB = abc.abcC = 0;
3369 else if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
3371 BOOL ret;
3372 if (!hdc) return E_PENDING;
3373 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
3375 if (psa->fNoGlyphIndex)
3376 ret = GetCharABCWidthsW(hdc, pwGlyphs[i], pwGlyphs[i], &abc);
3377 else
3378 ret = GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc);
3379 if (!ret) return S_FALSE;
3381 else
3383 INT width;
3384 if (psa->fNoGlyphIndex)
3385 ret = GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width);
3386 else
3387 ret = GetCharWidthI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &width);
3388 if (!ret) return S_FALSE;
3389 abc.abcB = width;
3390 abc.abcA = abc.abcC = 0;
3392 set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
3394 if (pABC)
3396 pABC->abcA += abc.abcA;
3397 pABC->abcB += abc.abcB;
3398 pABC->abcC += abc.abcC;
3400 /* FIXME: set to more reasonable values */
3401 pGoffset[i].du = pGoffset[i].dv = 0;
3402 if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
3405 SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset);
3407 if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
3408 return S_OK;
3411 /***********************************************************************
3412 * ScriptPlace (USP10.@)
3414 * Produce advance widths for a run.
3416 * PARAMS
3417 * hdc [I] Device context.
3418 * psc [I/O] Opaque pointer to a script cache.
3419 * pwGlyphs [I] Array of glyphs.
3420 * cGlyphs [I] Number of glyphs in pwGlyphs.
3421 * psva [I] Array of visual attributes.
3422 * psa [I/O] String analysis.
3423 * piAdvance [O] Array of advance widths.
3424 * pGoffset [O] Glyph offsets.
3425 * pABC [O] Combined ABC width.
3427 * RETURNS
3428 * Success: S_OK
3429 * Failure: Non-zero HRESULT value.
3431 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
3432 int cGlyphs, const SCRIPT_VISATTR *psva,
3433 SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
3435 HRESULT hr;
3436 SCRIPT_GLYPHPROP *glyphProps;
3437 int i;
3439 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
3440 piAdvance, pGoffset, pABC);
3442 if (!psva) return E_INVALIDARG;
3443 if (!pGoffset) return E_FAIL;
3445 glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
3446 if (!glyphProps) return E_OUTOFMEMORY;
3448 for (i = 0; i < cGlyphs; i++)
3449 glyphProps[i].sva = psva[i];
3451 hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
3453 heap_free(glyphProps);
3455 return hr;
3458 /***********************************************************************
3459 * ScriptGetCMap (USP10.@)
3461 * Retrieve glyph indices.
3463 * PARAMS
3464 * hdc [I] Device context.
3465 * psc [I/O] Opaque pointer to a script cache.
3466 * pwcInChars [I] Array of Unicode characters.
3467 * cChars [I] Number of characters in pwcInChars.
3468 * dwFlags [I] Flags.
3469 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3471 * RETURNS
3472 * Success: S_OK
3473 * Failure: Non-zero HRESULT value.
3475 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
3476 int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
3478 HRESULT hr;
3479 int i;
3481 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
3482 cChars, dwFlags, pwOutGlyphs);
3484 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3486 hr = S_OK;
3488 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3490 for (i = 0; i < cChars; i++)
3492 WCHAR inChar;
3493 if (dwFlags == SGCM_RTL)
3494 inChar = mirror_char(pwcInChars[i]);
3495 else
3496 inChar = pwcInChars[i];
3497 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
3499 WORD glyph;
3500 if (!hdc) return E_PENDING;
3501 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
3502 if (glyph == 0xffff)
3504 hr = S_FALSE;
3505 glyph = 0x0;
3507 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
3511 else
3513 TRACE("no glyph translation\n");
3514 for (i = 0; i < cChars; i++)
3516 WCHAR inChar;
3517 if (dwFlags == SGCM_RTL)
3518 inChar = mirror_char(pwcInChars[i]);
3519 else
3520 inChar = pwcInChars[i];
3521 pwOutGlyphs[i] = inChar;
3524 return hr;
3527 /***********************************************************************
3528 * ScriptTextOut (USP10.@)
3531 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
3532 const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
3533 int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
3534 const int *piJustify, const GOFFSET *pGoffset)
3536 HRESULT hr = S_OK;
3537 INT i, dir = 1;
3538 INT *lpDx;
3539 WORD *reordered_glyphs = (WORD *)pwGlyphs;
3541 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3542 hdc, psc, x, y, fuOptions, wine_dbgstr_rect(lprc), psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
3543 piAdvance, piJustify, pGoffset);
3545 if (!hdc || !psc) return E_INVALIDARG;
3546 if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
3548 fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
3549 fuOptions |= ETO_IGNORELANGUAGE;
3550 if (!psa->fNoGlyphIndex) /* Have Glyphs? */
3551 fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */
3553 lpDx = heap_alloc(cGlyphs * sizeof(INT) * 2);
3554 if (!lpDx) return E_OUTOFMEMORY;
3555 fuOptions |= ETO_PDY;
3557 if (psa->fRTL && psa->fLogicalOrder)
3559 reordered_glyphs = heap_alloc( cGlyphs * sizeof(WORD) );
3560 if (!reordered_glyphs)
3562 heap_free( lpDx );
3563 return E_OUTOFMEMORY;
3566 for (i = 0; i < cGlyphs; i++)
3567 reordered_glyphs[i] = pwGlyphs[cGlyphs - 1 - i];
3568 dir = -1;
3571 for (i = 0; i < cGlyphs; i++)
3573 int orig_index = (dir > 0) ? i : cGlyphs - 1 - i;
3574 lpDx[i * 2] = piAdvance[orig_index];
3575 lpDx[i * 2 + 1] = 0;
3577 if (pGoffset)
3579 if (i == 0)
3581 x += pGoffset[orig_index].du * dir;
3582 y += pGoffset[orig_index].dv;
3584 else
3586 lpDx[(i - 1) * 2] += pGoffset[orig_index].du * dir;
3587 lpDx[(i - 1) * 2 + 1] += pGoffset[orig_index].dv;
3589 lpDx[i * 2] -= pGoffset[orig_index].du * dir;
3590 lpDx[i * 2 + 1] -= pGoffset[orig_index].dv;
3594 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, reordered_glyphs, cGlyphs, lpDx))
3595 hr = S_FALSE;
3597 if (reordered_glyphs != pwGlyphs) heap_free( reordered_glyphs );
3598 heap_free(lpDx);
3600 return hr;
3603 /***********************************************************************
3604 * ScriptCacheGetHeight (USP10.@)
3606 * Retrieve the height of the font in the cache.
3608 * PARAMS
3609 * hdc [I] Device context.
3610 * psc [I/O] Opaque pointer to a script cache.
3611 * height [O] Receives font height.
3613 * RETURNS
3614 * Success: S_OK
3615 * Failure: Non-zero HRESULT value.
3617 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
3619 HRESULT hr;
3621 TRACE("(%p, %p, %p)\n", hdc, psc, height);
3623 if (!height) return E_INVALIDARG;
3624 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3626 *height = get_cache_height(psc);
3627 return S_OK;
3630 /***********************************************************************
3631 * ScriptGetGlyphABCWidth (USP10.@)
3633 * Retrieve the width of a glyph.
3635 * PARAMS
3636 * hdc [I] Device context.
3637 * psc [I/O] Opaque pointer to a script cache.
3638 * glyph [I] Glyph to retrieve the width for.
3639 * abc [O] ABC widths of the glyph.
3641 * RETURNS
3642 * Success: S_OK
3643 * Failure: Non-zero HRESULT value.
3645 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
3647 HRESULT hr;
3649 TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
3651 if (!abc) return E_INVALIDARG;
3652 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3654 if (!get_cache_glyph_widths(psc, glyph, abc))
3656 if (!hdc) return E_PENDING;
3657 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3659 if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
3661 else
3663 INT width;
3664 if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
3665 abc->abcB = width;
3666 abc->abcA = abc->abcC = 0;
3668 set_cache_glyph_widths(psc, glyph, abc);
3670 return S_OK;
3673 /***********************************************************************
3674 * ScriptLayout (USP10.@)
3676 * Map embedding levels to visual and/or logical order.
3678 * PARAMS
3679 * runs [I] Size of level array.
3680 * level [I] Array of embedding levels.
3681 * vistolog [O] Map of embedding levels from visual to logical order.
3682 * logtovis [O] Map of embedding levels from logical to visual order.
3684 * RETURNS
3685 * Success: S_OK
3686 * Failure: Non-zero HRESULT value.
3689 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
3691 int* indexs;
3692 int ich;
3694 TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
3696 if (!level || (!vistolog && !logtovis))
3697 return E_INVALIDARG;
3699 indexs = heap_alloc(sizeof(int) * runs);
3700 if (!indexs)
3701 return E_OUTOFMEMORY;
3703 if (vistolog)
3705 for( ich = 0; ich < runs; ich++)
3706 indexs[ich] = ich;
3708 ich = 0;
3709 while (ich < runs)
3710 ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3711 memcpy(vistolog, indexs, runs * sizeof(*vistolog));
3714 if (logtovis)
3716 for( ich = 0; ich < runs; ich++)
3717 indexs[ich] = ich;
3719 ich = 0;
3720 while (ich < runs)
3721 ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3722 memcpy(logtovis, indexs, runs * sizeof(*logtovis));
3724 heap_free(indexs);
3726 return S_OK;
3729 /***********************************************************************
3730 * ScriptStringGetLogicalWidths (USP10.@)
3732 * Returns logical widths from a string analysis.
3734 * PARAMS
3735 * ssa [I] string analysis.
3736 * piDx [O] logical widths returned.
3738 * RETURNS
3739 * Success: S_OK
3740 * Failure: a non-zero HRESULT.
3742 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
3744 int i, j, next = 0;
3745 StringAnalysis *analysis = ssa;
3747 TRACE("%p, %p\n", ssa, piDx);
3749 if (!analysis) return S_FALSE;
3750 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
3752 for (i = 0; i < analysis->numItems; i++)
3754 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
3755 int direction = 1;
3757 if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
3758 direction = -1;
3760 for (j = 0; j < cChar; j++)
3762 int k;
3763 int glyph = analysis->glyphs[i].pwLogClust[j];
3764 int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
3765 cChar, j, direction, NULL, NULL);
3766 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);
3768 for (k = 0; k < clust_size; k++)
3770 piDx[next] = advance / clust_size;
3771 next++;
3772 if (k) j++;
3776 return S_OK;
3779 /***********************************************************************
3780 * ScriptStringValidate (USP10.@)
3782 * Validate a string analysis.
3784 * PARAMS
3785 * ssa [I] string analysis.
3787 * RETURNS
3788 * Success: S_OK
3789 * Failure: S_FALSE if invalid sequences are found
3790 * or a non-zero HRESULT if it fails.
3792 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
3794 StringAnalysis *analysis = ssa;
3796 TRACE("(%p)\n", ssa);
3798 if (!analysis) return E_INVALIDARG;
3799 return (analysis->invalid) ? S_FALSE : S_OK;
3802 /***********************************************************************
3803 * ScriptString_pSize (USP10.@)
3805 * Retrieve width and height of an analysed string.
3807 * PARAMS
3808 * ssa [I] string analysis.
3810 * RETURNS
3811 * Success: Pointer to a SIZE structure.
3812 * Failure: NULL
3814 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
3816 int i, j;
3817 StringAnalysis *analysis = ssa;
3819 TRACE("(%p)\n", ssa);
3821 if (!analysis) return NULL;
3822 if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
3824 if (!analysis->sz)
3826 if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
3827 analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
3829 analysis->sz->cx = 0;
3830 for (i = 0; i < analysis->numItems; i++)
3832 if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
3833 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
3834 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3835 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
3838 return analysis->sz;
3841 /***********************************************************************
3842 * ScriptString_pLogAttr (USP10.@)
3844 * Retrieve logical attributes of an analysed string.
3846 * PARAMS
3847 * ssa [I] string analysis.
3849 * RETURNS
3850 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3851 * Failure: NULL
3853 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
3855 StringAnalysis *analysis = ssa;
3857 TRACE("(%p)\n", ssa);
3859 if (!analysis) return NULL;
3860 if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
3861 return analysis->logattrs;
3864 /***********************************************************************
3865 * ScriptString_pcOutChars (USP10.@)
3867 * Retrieve the length of a string after clipping.
3869 * PARAMS
3870 * ssa [I] String analysis.
3872 * RETURNS
3873 * Success: Pointer to the length.
3874 * Failure: NULL
3876 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
3878 StringAnalysis *analysis = ssa;
3880 TRACE("(%p)\n", ssa);
3882 if (!analysis) return NULL;
3883 return &analysis->clip_len;
3886 /***********************************************************************
3887 * ScriptStringGetOrder (USP10.@)
3889 * Retrieve a glyph order map.
3891 * PARAMS
3892 * ssa [I] String analysis.
3893 * order [I/O] Array of glyph positions.
3895 * RETURNS
3896 * Success: S_OK
3897 * Failure: a non-zero HRESULT.
3899 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
3901 int i, j;
3902 unsigned int k;
3903 StringAnalysis *analysis = ssa;
3905 TRACE("(%p)\n", ssa);
3907 if (!analysis) return S_FALSE;
3908 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
3910 /* FIXME: handle RTL scripts */
3911 for (i = 0, k = 0; i < analysis->numItems; i++)
3912 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3913 order[k] = k;
3915 return S_OK;
3918 /***********************************************************************
3919 * ScriptGetLogicalWidths (USP10.@)
3921 * Convert advance widths to logical widths.
3923 * PARAMS
3924 * sa [I] Script analysis.
3925 * nbchars [I] Number of characters.
3926 * nbglyphs [I] Number of glyphs.
3927 * glyph_width [I] Array of glyph widths.
3928 * log_clust [I] Array of logical clusters.
3929 * sva [I] Visual attributes.
3930 * widths [O] Array of logical widths.
3932 * RETURNS
3933 * Success: S_OK
3934 * Failure: a non-zero HRESULT.
3936 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3937 const int *advances, const WORD *log_clust,
3938 const SCRIPT_VISATTR *sva, int *widths)
3940 int i, next = 0, direction;
3942 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3943 sa, nbchars, nbglyphs, advances, log_clust, sva, widths);
3945 if (sa->fRTL && !sa->fLogicalOrder)
3946 direction = -1;
3947 else
3948 direction = 1;
3950 for (i = 0; i < nbchars; i++)
3952 int clust_size = get_cluster_size(log_clust, nbchars, i, direction, NULL, NULL);
3953 int advance = get_glyph_cluster_advance(advances, sva, log_clust, nbglyphs, nbchars, log_clust[i], direction);
3954 int j;
3956 for (j = 0; j < clust_size; j++)
3958 widths[next] = advance / clust_size;
3959 next++;
3960 if (j) i++;
3964 return S_OK;
3967 /***********************************************************************
3968 * ScriptApplyLogicalWidth (USP10.@)
3970 * Generate glyph advance widths.
3972 * PARAMS
3973 * dx [I] Array of logical advance widths.
3974 * num_chars [I] Number of characters.
3975 * num_glyphs [I] Number of glyphs.
3976 * log_clust [I] Array of logical clusters.
3977 * sva [I] Visual attributes.
3978 * advance [I] Array of glyph advance widths.
3979 * sa [I] Script analysis.
3980 * abc [I/O] Summed ABC widths.
3981 * justify [O] Array of glyph advance widths.
3983 * RETURNS
3984 * Success: S_OK
3985 * Failure: a non-zero HRESULT.
3987 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
3988 const WORD *log_clust, const SCRIPT_VISATTR *sva,
3989 const int *advance, const SCRIPT_ANALYSIS *sa,
3990 ABC *abc, int *justify)
3992 int i;
3994 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3995 dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
3997 for (i = 0; i < num_chars; i++) justify[i] = advance[i];
3998 return S_OK;
4001 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
4002 int num_glyphs, int dx, int min_kashida, int *justify)
4004 int i;
4006 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
4008 for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
4009 return S_OK;
4012 HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
4014 HRESULT hr;
4015 if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4016 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4018 return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
4021 HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
4023 HRESULT hr;
4024 if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4025 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4027 return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
4030 HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
4032 HRESULT hr;
4033 if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4034 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4036 return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);