usp10: Remove separate invalid flag from string analysis structure.
[wine.git] / dlls / usp10 / usp10.c
blob0b8c28e6148874c0eaf7beeaa8e5d4bf15a7c457
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 enum stringanalysis_flags
693 SCRIPT_STRING_ANALYSIS_FLAGS_SIZE = 0x1,
694 SCRIPT_STRING_ANALYSIS_FLAGS_INVALID = 0x2,
697 typedef struct {
698 HDC hdc;
699 DWORD ssa_flags;
700 DWORD flags;
701 int clip_len;
702 int cItems;
703 int cMaxGlyphs;
704 SCRIPT_ITEM* pItem;
705 int numItems;
706 StringGlyphs* glyphs;
707 SCRIPT_LOGATTR* logattrs;
708 SIZE sz;
709 int* logical2visual;
710 } StringAnalysis;
712 typedef struct {
713 BOOL ascending;
714 WORD target;
715 } FindGlyph_struct;
717 BOOL usp10_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
719 SIZE_T max_capacity, new_capacity;
720 void *new_elements;
722 if (count <= *capacity)
723 return TRUE;
725 max_capacity = ~(SIZE_T)0 / size;
726 if (count > max_capacity)
727 return FALSE;
729 new_capacity = max(1, *capacity);
730 while (new_capacity < count && new_capacity <= max_capacity / 2)
731 new_capacity *= 2;
732 if (new_capacity < count)
733 new_capacity = count;
735 if (!*elements)
736 new_elements = heap_alloc_zero(new_capacity * size);
737 else
738 new_elements = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *elements, new_capacity * size);
739 if (!new_elements)
740 return FALSE;
742 *elements = new_elements;
743 *capacity = new_capacity;
744 return TRUE;
747 /* TODO Fix font properties on Arabic locale */
748 static inline BOOL set_cache_font_properties(const HDC hdc, ScriptCache *sc)
750 sc->sfp.cBytes = sizeof(sc->sfp);
752 if (!sc->sfnt)
754 sc->sfp.wgBlank = sc->tm.tmBreakChar;
755 sc->sfp.wgDefault = sc->tm.tmDefaultChar;
756 sc->sfp.wgInvalid = sc->sfp.wgBlank;
757 sc->sfp.wgKashida = 0xFFFF;
758 sc->sfp.iKashidaWidth = 0;
760 else
762 static const WCHAR chars[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
763 /* U+0020: numeric space
764 U+200B: zero width space
765 U+F71B: unknown char found by black box testing
766 U+0640: kashida */
767 WORD gi[4];
769 if (GetGlyphIndicesW(hdc, chars, 4, gi, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
771 if(gi[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
772 sc->sfp.wgBlank = gi[0];
773 else
774 sc->sfp.wgBlank = 0;
776 sc->sfp.wgDefault = 0;
778 if (gi[2] != 0xFFFF)
779 sc->sfp.wgInvalid = gi[2];
780 else if (gi[1] != 0xFFFF)
781 sc->sfp.wgInvalid = gi[1];
782 else if (gi[0] != 0xFFFF)
783 sc->sfp.wgInvalid = gi[0];
784 else
785 sc->sfp.wgInvalid = 0;
787 sc->sfp.wgKashida = gi[3];
789 sc->sfp.iKashidaWidth = 0; /* TODO */
791 else
792 return FALSE;
794 return TRUE;
797 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES *sfp, ScriptCache *sc)
799 *sfp = sc->sfp;
802 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
804 return ((ScriptCache *)*psc)->tm.tmHeight;
807 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
809 return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
812 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
814 CacheGlyphPage *page = ((ScriptCache *)*psc)->page[c / 0x10000];
815 WORD *block;
817 if (!page) return 0;
818 block = page->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
819 if (!block) return 0;
820 return block[(c % 0x10000) & GLYPH_BLOCK_MASK];
823 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
825 CacheGlyphPage **page = &((ScriptCache *)*psc)->page[c / 0x10000];
826 WORD **block;
827 if (!*page && !(*page = heap_alloc_zero(sizeof(CacheGlyphPage)))) return 0;
829 block = &(*page)->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
830 if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
831 return ((*block)[(c % 0x10000) & GLYPH_BLOCK_MASK] = glyph);
834 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
836 static const ABC nil;
837 ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
839 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
840 memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
841 return TRUE;
844 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
846 ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
848 if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
849 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
850 return TRUE;
853 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
855 ScriptCache *sc;
856 int size;
858 if (!psc) return E_INVALIDARG;
859 if (*psc) return S_OK;
860 if (!hdc) return E_PENDING;
862 if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
863 if (!GetTextMetricsW(hdc, &sc->tm))
865 heap_free(sc);
866 return E_INVALIDARG;
868 size = GetOutlineTextMetricsW(hdc, 0, NULL);
869 if (size)
871 sc->otm = heap_alloc(size);
872 sc->otm->otmSize = size;
873 GetOutlineTextMetricsW(hdc, size, sc->otm);
875 if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
877 heap_free(sc);
878 return E_INVALIDARG;
880 sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
881 if (!set_cache_font_properties(hdc, sc))
883 heap_free(sc);
884 return E_INVALIDARG;
886 *psc = sc;
887 TRACE("<- %p\n", sc);
888 return S_OK;
891 static WCHAR mirror_char( WCHAR ch )
893 extern const WCHAR wine_mirror_map[] DECLSPEC_HIDDEN;
894 return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
897 static DWORD decode_surrogate_pair(const WCHAR *str, unsigned int index, unsigned int end)
899 if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
901 DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
902 TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
903 return ch;
905 return 0;
908 static int usp10_compare_script_range(const void *key, const void *value)
910 const struct usp10_script_range *range = value;
911 const DWORD *ch = key;
913 if (*ch < range->rangeFirst)
914 return -1;
915 if (*ch > range->rangeLast)
916 return 1;
917 return 0;
920 static enum usp10_script get_char_script(const WCHAR *str, unsigned int index,
921 unsigned int end, unsigned int *consumed)
923 static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
924 struct usp10_script_range *range;
925 WORD type = 0, type2 = 0;
926 DWORD ch;
928 *consumed = 1;
930 if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
931 return Script_CR;
933 /* These punctuation characters are separated out as Latin punctuation */
934 if (strchrW(latin_punc,str[index]))
935 return Script_Punctuation2;
937 /* These chars are itemized as Punctuation by Windows */
938 if (str[index] == 0x2212 || str[index] == 0x2044)
939 return Script_Punctuation;
941 /* Currency Symbols by Unicode point */
942 switch (str[index])
944 case 0x09f2:
945 case 0x09f3: return Script_Bengali_Currency;
946 case 0x0af1: return Script_Gujarati_Currency;
947 case 0x0e3f: return Script_Thai_Currency;
948 case 0x20aa: return Script_Hebrew_Currency;
949 case 0x20ab: return Script_Vietnamese_Currency;
950 case 0xfb29: return Script_Hebrew_Currency;
953 GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
954 GetStringTypeW(CT_CTYPE2, &str[index], 1, &type2);
956 if (type == 0)
957 return SCRIPT_UNDEFINED;
959 if (type & C1_CNTRL)
960 return Script_Control;
962 ch = decode_surrogate_pair(str, index, end);
963 if (ch)
964 *consumed = 2;
965 else
966 ch = str[index];
968 if (!(range = bsearch(&ch, script_ranges, ARRAY_SIZE(script_ranges),
969 sizeof(*script_ranges), usp10_compare_script_range)))
970 return (*consumed == 2) ? Script_Surrogates : Script_Undefined;
972 if (range->numericScript && (type & C1_DIGIT || type2 == C2_ARABICNUMBER))
973 return range->numericScript;
974 if (range->punctScript && type & C1_PUNCT)
975 return range->punctScript;
976 return range->script;
979 static int compare_FindGlyph(const void *a, const void* b)
981 const FindGlyph_struct *find = (FindGlyph_struct*)a;
982 const WORD *idx= (WORD*)b;
983 int rc = 0;
985 if ( find->target > *idx)
986 rc = 1;
987 else if (find->target < *idx)
988 rc = -1;
990 if (!find->ascending)
991 rc *= -1;
992 return rc;
995 int USP10_FindGlyphInLogClust(const WORD* pwLogClust, int cChars, WORD target)
997 FindGlyph_struct fgs;
998 WORD *ptr;
999 INT k;
1001 if (pwLogClust[0] < pwLogClust[cChars-1])
1002 fgs.ascending = TRUE;
1003 else
1004 fgs.ascending = FALSE;
1006 fgs.target = target;
1007 ptr = bsearch(&fgs, pwLogClust, cChars, sizeof(WORD), compare_FindGlyph);
1009 if (!ptr)
1010 return -1;
1012 for (k = (ptr - pwLogClust)-1; k >= 0 && pwLogClust[k] == target; k--)
1014 k++;
1016 return k;
1019 /***********************************************************************
1020 * ScriptFreeCache (USP10.@)
1022 * Free a script cache.
1024 * PARAMS
1025 * psc [I/O] Script cache.
1027 * RETURNS
1028 * Success: S_OK
1029 * Failure: Non-zero HRESULT value.
1031 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
1033 TRACE("%p\n", psc);
1035 if (psc && *psc)
1037 unsigned int i;
1038 INT n;
1039 for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
1041 heap_free(((ScriptCache *)*psc)->widths[i]);
1043 for (i = 0; i < NUM_PAGES; i++)
1045 unsigned int j;
1046 if (((ScriptCache *)*psc)->page[i])
1047 for (j = 0; j < GLYPH_MAX / GLYPH_BLOCK_SIZE; j++)
1048 heap_free(((ScriptCache *)*psc)->page[i]->glyphs[j]);
1049 heap_free(((ScriptCache *)*psc)->page[i]);
1051 heap_free(((ScriptCache *)*psc)->GSUB_Table);
1052 heap_free(((ScriptCache *)*psc)->GDEF_Table);
1053 heap_free(((ScriptCache *)*psc)->CMAP_Table);
1054 heap_free(((ScriptCache *)*psc)->GPOS_Table);
1055 for (n = 0; n < ((ScriptCache *)*psc)->script_count; n++)
1057 int j;
1058 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].language_count; j++)
1060 int k;
1061 for (k = 0; k < ((ScriptCache *)*psc)->scripts[n].languages[j].feature_count; k++)
1062 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features[k].lookups);
1063 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features);
1065 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].default_language.feature_count; j++)
1066 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features[j].lookups);
1067 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features);
1068 heap_free(((ScriptCache *)*psc)->scripts[n].languages);
1070 heap_free(((ScriptCache *)*psc)->scripts);
1071 heap_free(((ScriptCache *)*psc)->otm);
1072 heap_free(*psc);
1073 *psc = NULL;
1075 return S_OK;
1078 /***********************************************************************
1079 * ScriptGetProperties (USP10.@)
1081 * Retrieve a list of script properties.
1083 * PARAMS
1084 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1085 * num [I] Pointer to the number of scripts.
1087 * RETURNS
1088 * Success: S_OK
1089 * Failure: Non-zero HRESULT value.
1091 * NOTES
1092 * Behaviour matches WinXP.
1094 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
1096 TRACE("(%p,%p)\n", props, num);
1098 if (!props && !num) return E_INVALIDARG;
1100 if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
1101 if (props) *props = script_props;
1103 return S_OK;
1106 /***********************************************************************
1107 * ScriptGetFontProperties (USP10.@)
1109 * Get information on special glyphs.
1111 * PARAMS
1112 * hdc [I] Device context.
1113 * psc [I/O] Opaque pointer to a script cache.
1114 * sfp [O] Font properties structure.
1116 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
1118 HRESULT hr;
1120 TRACE("%p,%p,%p\n", hdc, psc, sfp);
1122 if (!sfp) return E_INVALIDARG;
1123 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1125 if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
1126 return E_INVALIDARG;
1128 get_cache_font_properties(sfp, *psc);
1130 return S_OK;
1133 /***********************************************************************
1134 * ScriptRecordDigitSubstitution (USP10.@)
1136 * Record digit substitution settings for a given locale.
1138 * PARAMS
1139 * locale [I] Locale identifier.
1140 * sds [I] Structure to record substitution settings.
1142 * RETURNS
1143 * Success: S_OK
1144 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1146 * SEE ALSO
1147 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1149 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
1151 DWORD plgid, sub;
1153 TRACE("0x%x, %p\n", locale, sds);
1155 /* This implementation appears to be correct for all languages, but it's
1156 * not clear if sds->DigitSubstitute is ever set to anything except
1157 * CONTEXT or NONE in reality */
1159 if (!sds) return E_POINTER;
1161 locale = ConvertDefaultLocale(locale);
1163 if (!IsValidLocale(locale, LCID_INSTALLED))
1164 return E_INVALIDARG;
1166 plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
1167 sds->TraditionalDigitLanguage = plgid;
1169 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1170 sds->NationalDigitLanguage = plgid;
1171 else
1172 sds->NationalDigitLanguage = LANG_ENGLISH;
1174 if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
1175 (WCHAR *)&sub, sizeof(sub) / sizeof(WCHAR)))
1176 return E_INVALIDARG;
1178 switch (sub)
1180 case 0:
1181 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1182 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
1183 else
1184 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1185 break;
1186 case 1:
1187 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1188 break;
1189 case 2:
1190 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
1191 break;
1192 default:
1193 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
1194 break;
1197 sds->dwReserved = 0;
1198 return S_OK;
1201 /***********************************************************************
1202 * ScriptApplyDigitSubstitution (USP10.@)
1204 * Apply digit substitution settings.
1206 * PARAMS
1207 * sds [I] Structure with recorded substitution settings.
1208 * sc [I] Script control structure.
1209 * ss [I] Script state structure.
1211 * RETURNS
1212 * Success: S_OK
1213 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1215 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds,
1216 SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
1218 SCRIPT_DIGITSUBSTITUTE psds;
1220 TRACE("%p, %p, %p\n", sds, sc, ss);
1222 if (!sc || !ss) return E_POINTER;
1223 if (!sds)
1225 sds = &psds;
1226 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
1227 return E_INVALIDARG;
1230 sc->uDefaultLanguage = LANG_ENGLISH;
1231 sc->fContextDigits = 0;
1232 ss->fDigitSubstitute = 0;
1234 switch (sds->DigitSubstitute) {
1235 case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
1236 case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
1237 case SCRIPT_DIGITSUBSTITUTE_NONE:
1238 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
1239 return S_OK;
1240 default:
1241 return E_INVALIDARG;
1245 static inline BOOL is_indic(enum usp10_script script)
1247 return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
1250 static inline enum usp10_script base_indic(enum usp10_script script)
1252 switch (script)
1254 case Script_Devanagari:
1255 case Script_Devanagari_Numeric: return Script_Devanagari;
1256 case Script_Bengali:
1257 case Script_Bengali_Numeric:
1258 case Script_Bengali_Currency: return Script_Bengali;
1259 case Script_Gurmukhi:
1260 case Script_Gurmukhi_Numeric: return Script_Gurmukhi;
1261 case Script_Gujarati:
1262 case Script_Gujarati_Numeric:
1263 case Script_Gujarati_Currency: return Script_Gujarati;
1264 case Script_Oriya:
1265 case Script_Oriya_Numeric: return Script_Oriya;
1266 case Script_Tamil:
1267 case Script_Tamil_Numeric: return Script_Tamil;
1268 case Script_Telugu:
1269 case Script_Telugu_Numeric: return Script_Telugu;
1270 case Script_Kannada:
1271 case Script_Kannada_Numeric: return Script_Kannada;
1272 case Script_Malayalam:
1273 case Script_Malayalam_Numeric: return Script_Malayalam;
1274 default:
1275 return Script_Undefined;
1279 static BOOL script_is_numeric(enum usp10_script script)
1281 return scriptInformation[script].props.fNumeric;
1284 static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
1285 int cMaxItems, const SCRIPT_CONTROL *psControl,
1286 const SCRIPT_STATE *psState, SCRIPT_ITEM *pItems,
1287 OPENTYPE_TAG *pScriptTags, int *pcItems)
1290 #define Numeric_space 0x0020
1291 #define ZWSP 0x200B
1292 #define ZWNJ 0x200C
1293 #define ZWJ 0x200D
1295 enum usp10_script last_indic = Script_Undefined;
1296 int cnt = 0, index = 0, str = 0;
1297 enum usp10_script New_Script = -1;
1298 int i;
1299 WORD *levels = NULL;
1300 WORD *layout_levels = NULL;
1301 WORD *overrides = NULL;
1302 WORD *strength = NULL;
1303 enum usp10_script *scripts;
1304 WORD baselevel = 0;
1305 WORD baselayout = 0;
1306 BOOL new_run;
1307 WORD layoutRTL = 0;
1308 BOOL forceLevels = FALSE;
1309 unsigned int consumed = 0;
1310 HRESULT res = E_OUTOFMEMORY;
1312 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
1313 psControl, psState, pItems, pcItems);
1315 if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
1316 return E_INVALIDARG;
1318 if (!(scripts = heap_alloc(cInChars * sizeof(*scripts))))
1319 return E_OUTOFMEMORY;
1321 for (i = 0; i < cInChars; i++)
1323 if (!consumed)
1325 scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
1326 consumed --;
1328 else
1330 scripts[i] = scripts[i-1];
1331 consumed --;
1333 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1334 all Indic scripts */
1335 if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic != Script_Undefined)
1336 scripts[i] = last_indic;
1337 else if (is_indic(scripts[i]))
1338 last_indic = base_indic(scripts[i]);
1340 /* Some unicode points :
1341 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1342 (Left Right Embed U+202A - Left Right Override U+202D)
1343 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1344 will force us into bidi mode */
1345 if (!forceLevels && ((pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F) ||
1346 (pwcInChars[i] >= 0x202A && pwcInChars[i] <= 0x202E) ||
1347 (pwcInChars[i] >= 0x2066 && pwcInChars[i] <= 0x2069)))
1349 forceLevels = TRUE;
1351 /* Diacritical marks merge with other scripts */
1352 if (scripts[i] == Script_Diacritical)
1354 if (i > 0)
1356 if (pScriptTags)
1357 scripts[i] = scripts[i-1];
1358 else
1360 int j;
1361 BOOL asian = FALSE;
1362 enum usp10_script first_script = scripts[i-1];
1363 for (j = i-1; j >= 0 && scripts[j] == first_script && pwcInChars[j] != Numeric_space; j--)
1365 enum usp10_script original = scripts[j];
1366 if (original == Script_Ideograph || original == Script_Kana || original == Script_Yi || original == Script_CJK_Han || original == Script_Bopomofo)
1368 asian = TRUE;
1369 break;
1371 if (original != Script_MathAlpha && scriptInformation[scripts[j]].props.fComplex)
1372 break;
1373 scripts[j] = scripts[i];
1374 if (original == Script_Punctuation2)
1375 break;
1377 if (j >= 0 && (scriptInformation[scripts[j]].props.fComplex || asian))
1378 scripts[i] = scripts[j];
1384 for (i = 0; i < cInChars; i++)
1386 /* Joiners get merged preferencially right */
1387 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1389 int j;
1390 if (i+1 == cInChars)
1391 scripts[i] = scripts[i-1];
1392 else
1394 for (j = i+1; j < cInChars; j++)
1396 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1397 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1399 scripts[i] = scripts[j];
1400 break;
1407 if (psState && psControl)
1409 levels = heap_alloc_zero(cInChars * sizeof(WORD));
1410 if (!levels)
1411 goto nomemory;
1413 overrides = heap_alloc_zero(cInChars * sizeof(WORD));
1414 if (!overrides)
1415 goto nomemory;
1417 layout_levels = heap_alloc_zero(cInChars * sizeof(WORD));
1418 if (!layout_levels)
1419 goto nomemory;
1421 if (psState->fOverrideDirection)
1423 if (!forceLevels)
1425 SCRIPT_STATE s = *psState;
1426 s.fOverrideDirection = FALSE;
1427 BIDI_DetermineLevels(pwcInChars, cInChars, &s, psControl, layout_levels, overrides);
1428 if (odd(layout_levels[0]))
1429 forceLevels = TRUE;
1430 else for (i = 0; i < cInChars; i++)
1431 if (layout_levels[i]!=layout_levels[0])
1433 forceLevels = TRUE;
1434 break;
1438 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1440 else
1442 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1443 memcpy(layout_levels, levels, cInChars * sizeof(WORD));
1445 baselevel = levels[0];
1446 baselayout = layout_levels[0];
1447 for (i = 0; i < cInChars; i++)
1448 if (levels[i]!=levels[0])
1449 break;
1450 if (i >= cInChars && !odd(baselevel) && !odd(psState->uBidiLevel) && !forceLevels)
1452 heap_free(levels);
1453 heap_free(overrides);
1454 heap_free(layout_levels);
1455 overrides = NULL;
1456 levels = NULL;
1457 layout_levels = NULL;
1459 else
1461 static const WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1462 static const WCHAR repeatable_math_punc[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1464 strength = heap_alloc_zero(cInChars * sizeof(WORD));
1465 if (!strength)
1466 goto nomemory;
1467 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
1469 /* We currently mis-level leading Diacriticals */
1470 if (scripts[0] == Script_Diacritical)
1471 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
1473 levels[i] = odd(levels[i])?levels[i]+1:levels[i];
1474 strength[i] = BIDI_STRONG;
1477 /* Math punctuation bordered on both sides by numbers can be
1478 merged into the number */
1479 for (i = 0; i < cInChars; i++)
1481 if (i > 0 && i < cInChars-1 &&
1482 script_is_numeric(scripts[i-1]) &&
1483 strchrW(math_punc, pwcInChars[i]))
1485 if (script_is_numeric(scripts[i+1]))
1487 scripts[i] = scripts[i+1];
1488 levels[i] = levels[i-1];
1489 strength[i] = strength[i-1];
1490 i++;
1492 else if (strchrW(repeatable_math_punc, pwcInChars[i]))
1494 int j;
1495 for (j = i+1; j < cInChars; j++)
1497 if (script_is_numeric(scripts[j]))
1499 for(;i<j; i++)
1501 scripts[i] = scripts[j];
1502 levels[i] = levels[i-1];
1503 strength[i] = strength[i-1];
1506 else if (pwcInChars[i] != pwcInChars[j]) break;
1512 for (i = 0; i < cInChars; i++)
1514 /* Numerics at level 0 get bumped to level 2 */
1515 if (!overrides[i] && (levels[i] == 0 || (odd(psState->uBidiLevel)
1516 && levels[i] == psState->uBidiLevel + 1)) && script_is_numeric(scripts[i]))
1518 levels[i] = 2;
1521 /* Joiners get merged preferencially right */
1522 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1524 int j;
1525 if (i+1 == cInChars && levels[i-1] == levels[i])
1526 strength[i] = strength[i-1];
1527 else
1528 for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
1529 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1530 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1532 strength[i] = strength[j];
1533 break;
1537 if (psControl->fMergeNeutralItems)
1539 /* Merge the neutrals */
1540 for (i = 0; i < cInChars; i++)
1542 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1544 int j;
1545 for (j = i; j > 0; j--)
1547 if (levels[i] != levels[j])
1548 break;
1549 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1551 scripts[i] = scripts[j];
1552 strength[i] = strength[j];
1553 break;
1557 /* Try going the other way */
1558 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1560 int j;
1561 for (j = i; j < cInChars; j++)
1563 if (levels[i] != levels[j])
1564 break;
1565 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1567 scripts[i] = scripts[j];
1568 strength[i] = strength[j];
1569 break;
1578 while ((!levels || (levels && cnt+1 < cInChars && levels[cnt+1] == levels[0]))
1579 && (cnt < cInChars && pwcInChars[cnt] == Numeric_space))
1580 cnt++;
1582 if (cnt == cInChars) /* All Spaces */
1584 cnt = 0;
1585 New_Script = scripts[cnt];
1588 pItems[index].iCharPos = 0;
1589 pItems[index].a = scriptInformation[scripts[cnt]].a;
1590 if (pScriptTags)
1591 pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
1593 if (strength && strength[cnt] == BIDI_STRONG)
1594 str = strength[cnt];
1595 else if (strength)
1596 str = strength[0];
1598 cnt = 0;
1600 if (levels)
1602 if (strength[cnt] == BIDI_STRONG)
1603 layoutRTL = odd(layout_levels[cnt]);
1604 else
1605 layoutRTL = (psState->uBidiLevel || odd(layout_levels[cnt]));
1606 if (overrides)
1607 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1608 pItems[index].a.fRTL = odd(levels[cnt]);
1609 if (script_is_numeric(pItems[index].a.eScript))
1610 pItems[index].a.fLayoutRTL = layoutRTL;
1611 else
1612 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1613 pItems[index].a.s.uBidiLevel = levels[cnt];
1615 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1617 if (pItems[index].a.s.uBidiLevel != baselevel)
1618 pItems[index].a.s.fOverrideDirection = TRUE;
1619 layoutRTL = odd(baselayout);
1620 pItems[index].a.s.uBidiLevel = baselevel;
1621 pItems[index].a.fRTL = odd(baselevel);
1622 if (script_is_numeric(pItems[index].a.eScript))
1623 pItems[index].a.fLayoutRTL = odd(baselayout);
1624 else
1625 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1628 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1629 levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
1630 pItems[index].iCharPos);
1632 for (cnt=1; cnt < cInChars; cnt++)
1634 if(pwcInChars[cnt] != Numeric_space)
1635 New_Script = scripts[cnt];
1636 else if (levels)
1638 int j = 1;
1639 while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
1640 j++;
1641 if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
1642 New_Script = scripts[cnt+j];
1643 else
1644 New_Script = scripts[cnt];
1647 new_run = FALSE;
1648 /* merge space strengths*/
1649 if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
1650 str = BIDI_STRONG;
1652 if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
1653 str = BIDI_NEUTRAL;
1655 /* changes in level */
1656 if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
1658 TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
1659 new_run = TRUE;
1661 /* changes in strength */
1662 else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
1664 TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
1665 new_run = TRUE;
1667 /* changes in script */
1668 else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
1670 TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
1671 new_run = TRUE;
1674 if (!new_run && strength && str == BIDI_STRONG)
1676 layoutRTL = odd(layout_levels[cnt]);
1677 if (script_is_numeric(pItems[index].a.eScript))
1678 pItems[index].a.fLayoutRTL = layoutRTL;
1681 if (new_run)
1683 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);
1685 index++;
1686 if (index+1 > cMaxItems)
1687 goto nomemory;
1689 if (strength)
1690 str = strength[cnt];
1692 pItems[index].iCharPos = cnt;
1693 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1695 pItems[index].a = scriptInformation[New_Script].a;
1696 if (pScriptTags)
1697 pScriptTags[index] = scriptInformation[New_Script].scriptTag;
1698 if (levels)
1700 if (overrides)
1701 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1702 if (layout_levels[cnt] == 0)
1703 layoutRTL = 0;
1704 else
1705 layoutRTL = (layoutRTL || odd(layout_levels[cnt]));
1706 pItems[index].a.fRTL = odd(levels[cnt]);
1707 if (script_is_numeric(pItems[index].a.eScript))
1708 pItems[index].a.fLayoutRTL = layoutRTL;
1709 else
1710 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1711 pItems[index].a.s.uBidiLevel = levels[cnt];
1713 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1715 if (pItems[index].a.s.uBidiLevel != baselevel)
1716 pItems[index].a.s.fOverrideDirection = TRUE;
1717 pItems[index].a.s.uBidiLevel = baselevel;
1718 pItems[index].a.fRTL = odd(baselevel);
1719 if (script_is_numeric(pItems[index].a.eScript))
1720 pItems[index].a.fLayoutRTL = layoutRTL;
1721 else
1722 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1725 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1729 /* While not strictly necessary according to the spec, make sure the n+1
1730 * item is set up to prevent random behaviour if the caller erroneously
1731 * checks the n+1 structure */
1732 index++;
1733 if (index + 1 > cMaxItems) goto nomemory;
1734 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1736 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1738 /* Set one SCRIPT_STATE item being returned */
1739 if (pcItems) *pcItems = index;
1741 /* Set SCRIPT_ITEM */
1742 pItems[index].iCharPos = cnt; /* the last item contains the ptr to the lastchar */
1743 res = S_OK;
1744 nomemory:
1745 heap_free(levels);
1746 heap_free(overrides);
1747 heap_free(layout_levels);
1748 heap_free(strength);
1749 heap_free(scripts);
1750 return res;
1753 /***********************************************************************
1754 * ScriptItemizeOpenType (USP10.@)
1756 * Split a Unicode string into shapeable parts.
1758 * PARAMS
1759 * pwcInChars [I] String to split.
1760 * cInChars [I] Number of characters in pwcInChars.
1761 * cMaxItems [I] Maximum number of items to return.
1762 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1763 * psState [I] Pointer to a SCRIPT_STATE structure.
1764 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1765 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1766 * pcItems [O] Number of script items returned.
1768 * RETURNS
1769 * Success: S_OK
1770 * Failure: Non-zero HRESULT value.
1772 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1773 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1774 SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
1776 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pScriptTags, pcItems);
1779 /***********************************************************************
1780 * ScriptItemize (USP10.@)
1782 * Split a Unicode string into shapeable parts.
1784 * PARAMS
1785 * pwcInChars [I] String to split.
1786 * cInChars [I] Number of characters in pwcInChars.
1787 * cMaxItems [I] Maximum number of items to return.
1788 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1789 * psState [I] Pointer to a SCRIPT_STATE structure.
1790 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1791 * pcItems [O] Number of script items returned.
1793 * RETURNS
1794 * Success: S_OK
1795 * Failure: Non-zero HRESULT value.
1797 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1798 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1799 SCRIPT_ITEM *pItems, int *pcItems)
1801 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, NULL, pcItems);
1804 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1806 int defWidth;
1807 int cTabStops=0;
1808 INT *lpTabPos = NULL;
1809 INT nTabOrg = 0;
1810 INT x = 0;
1812 if (pTabdef)
1813 lpTabPos = pTabdef->pTabStops;
1815 if (pTabdef && pTabdef->iTabOrigin)
1817 if (pTabdef->iScale)
1818 nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1819 else
1820 nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1823 if (pTabdef)
1824 cTabStops = pTabdef->cTabStops;
1826 if (cTabStops == 1)
1828 if (pTabdef->iScale)
1829 defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1830 else
1831 defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1832 cTabStops = 0;
1834 else
1836 if (pTabdef->iScale)
1837 defWidth = (32 * pTabdef->iScale) / 4;
1838 else
1839 defWidth = 8 * psc->tm.tmAveCharWidth;
1842 for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1844 int position = *lpTabPos;
1845 if (position < 0)
1846 position = -1 * position;
1847 if (pTabdef->iScale)
1848 position = (position * pTabdef->iScale) / 4;
1849 else
1850 position = position * psc->tm.tmAveCharWidth;
1852 if( nTabOrg + position > current_x)
1854 if( position >= 0)
1856 /* a left aligned tab */
1857 x = (nTabOrg + position) - current_x;
1858 break;
1860 else
1862 FIXME("Negative tabstop\n");
1863 break;
1867 if ((!cTabStops) && (defWidth > 0))
1868 x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1869 else if ((!cTabStops) && (defWidth < 0))
1870 FIXME("TODO: Negative defWidth\n");
1872 return x;
1875 /***********************************************************************
1876 * Helper function for ScriptStringAnalyse
1878 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1879 const WCHAR *pwcInChars, int cChars )
1881 /* FIXME: When to properly fallback is still a bit of a mystery */
1882 WORD *glyphs;
1884 if (psa->fNoGlyphIndex)
1885 return FALSE;
1887 if (init_script_cache(hdc, psc) != S_OK)
1888 return FALSE;
1890 if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1891 return TRUE;
1893 glyphs = heap_alloc(sizeof(WORD) * cChars);
1894 if (!glyphs)
1895 return FALSE;
1896 if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1898 heap_free(glyphs);
1899 return TRUE;
1901 heap_free(glyphs);
1903 return FALSE;
1906 static void find_fallback_font(enum usp10_script scriptid, WCHAR *FaceName)
1908 HKEY hkey;
1910 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1912 static const WCHAR szFmt[] = {'%','x',0};
1913 WCHAR value[10];
1914 DWORD count = LF_FACESIZE * sizeof(WCHAR);
1915 DWORD type;
1917 sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1918 if (RegQueryValueExW(hkey, value, 0, &type, (BYTE *)FaceName, &count))
1919 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1920 RegCloseKey(hkey);
1922 else
1923 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1926 /***********************************************************************
1927 * ScriptStringAnalyse (USP10.@)
1930 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1931 int cGlyphs, int iCharset, DWORD dwFlags,
1932 int iReqWidth, SCRIPT_CONTROL *psControl,
1933 SCRIPT_STATE *psState, const int *piDx,
1934 SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1935 SCRIPT_STRING_ANALYSIS *pssa)
1937 HRESULT hr = E_OUTOFMEMORY;
1938 StringAnalysis *analysis = NULL;
1939 SCRIPT_CONTROL sControl;
1940 SCRIPT_STATE sState;
1941 int i, num_items = 255;
1942 BYTE *BidiLevel;
1943 WCHAR *iString = NULL;
1945 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1946 hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1947 psControl, psState, piDx, pTabdef, pbInClass, pssa);
1949 if (iCharset != -1)
1951 FIXME("Only Unicode strings are supported\n");
1952 return E_INVALIDARG;
1954 if (cString < 1 || !pString) return E_INVALIDARG;
1955 if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1957 if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1958 if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1960 /* FIXME: handle clipping */
1961 analysis->clip_len = cString;
1962 analysis->hdc = hdc;
1963 analysis->ssa_flags = dwFlags;
1965 if (psState)
1966 sState = *psState;
1967 else
1968 memset(&sState, 0, sizeof(SCRIPT_STATE));
1970 if (psControl)
1971 sControl = *psControl;
1972 else
1973 memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1975 if (dwFlags & SSA_PASSWORD)
1977 iString = heap_alloc(sizeof(WCHAR)*cString);
1978 if (!iString)
1980 hr = E_OUTOFMEMORY;
1981 goto error;
1983 for (i = 0; i < cString; i++)
1984 iString[i] = *((const WCHAR *)pString);
1985 pString = iString;
1988 hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1989 &analysis->numItems);
1991 if (FAILED(hr))
1993 if (hr == E_OUTOFMEMORY)
1994 hr = E_INVALIDARG;
1995 goto error;
1998 /* set back to out of memory for default goto error behaviour */
1999 hr = E_OUTOFMEMORY;
2001 if (dwFlags & SSA_BREAK)
2003 if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
2005 for (i = 0; i < analysis->numItems; i++)
2006 ScriptBreak(&((WCHAR *)pString)[analysis->pItem[i].iCharPos],
2007 analysis->pItem[i + 1].iCharPos - analysis->pItem[i].iCharPos,
2008 &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
2010 else
2011 goto error;
2014 if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
2015 goto error;
2016 if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
2017 goto error;
2019 if (dwFlags & SSA_GLYPHS)
2021 int tab_x = 0;
2022 if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
2024 heap_free(BidiLevel);
2025 goto error;
2028 for (i = 0; i < analysis->numItems; i++)
2030 SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
2031 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2032 int numGlyphs = 1.5 * cChar + 16;
2033 WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
2034 WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
2035 int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
2036 SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
2037 GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
2038 int numGlyphsReturned;
2039 HFONT originalFont = 0x0;
2041 /* FIXME: non unicode strings */
2042 const WCHAR* pStr = (const WCHAR*)pString;
2043 analysis->glyphs[i].fallbackFont = NULL;
2045 if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset)
2047 heap_free (BidiLevel);
2048 heap_free (glyphs);
2049 heap_free (pwLogClust);
2050 heap_free (piAdvance);
2051 heap_free (psva);
2052 heap_free (pGoffset);
2053 hr = E_OUTOFMEMORY;
2054 goto error;
2057 if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
2059 LOGFONTW lf;
2060 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
2061 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
2062 lf.lfFaceName[0] = 0;
2063 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
2064 if (lf.lfFaceName[0])
2066 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
2067 if (analysis->glyphs[i].fallbackFont)
2069 ScriptFreeCache(sc);
2070 originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
2075 /* FIXME: When we properly shape Hangul remove this check */
2076 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && analysis->pItem[i].a.eScript == Script_Hangul)
2077 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2079 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && !scriptInformation[analysis->pItem[i].a.eScript].props.fComplex && !analysis->pItem[i].a.fRTL)
2080 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2082 ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos], cChar, numGlyphs,
2083 &analysis->pItem[i].a, glyphs, pwLogClust, psva, &numGlyphsReturned);
2084 hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
2085 piAdvance, pGoffset, &analysis->glyphs[i].abc);
2086 if (originalFont)
2087 SelectObject(hdc,originalFont);
2089 if (dwFlags & SSA_TAB)
2091 int tabi = 0;
2092 for (tabi = 0; tabi < cChar; tabi++)
2094 if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
2095 piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
2096 tab_x+=piAdvance[tabi];
2100 analysis->glyphs[i].numGlyphs = numGlyphsReturned;
2101 analysis->glyphs[i].glyphs = glyphs;
2102 analysis->glyphs[i].pwLogClust = pwLogClust;
2103 analysis->glyphs[i].piAdvance = piAdvance;
2104 analysis->glyphs[i].psva = psva;
2105 analysis->glyphs[i].pGoffset = pGoffset;
2106 analysis->glyphs[i].iMaxPosX= -1;
2108 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2111 else
2113 for (i = 0; i < analysis->numItems; i++)
2114 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2117 ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
2118 heap_free(BidiLevel);
2120 *pssa = analysis;
2121 heap_free(iString);
2122 return S_OK;
2124 error:
2125 heap_free(iString);
2126 heap_free(analysis->glyphs);
2127 heap_free(analysis->logattrs);
2128 heap_free(analysis->pItem);
2129 heap_free(analysis->logical2visual);
2130 heap_free(analysis);
2131 return hr;
2134 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
2136 if (pva[glyph].fClusterStart)
2137 return TRUE;
2138 if (USP10_FindGlyphInLogClust(pwLogClust, cChars, glyph) >= 0)
2139 return TRUE;
2141 return FALSE;
2145 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
2146 int iX,
2147 int iY,
2148 int iItem,
2149 int cStart,
2150 int cEnd,
2151 UINT uOptions,
2152 const RECT *prc,
2153 BOOL fSelected,
2154 BOOL fDisabled)
2156 StringAnalysis *analysis;
2157 int off_x = 0;
2158 HRESULT hr;
2159 COLORREF BkColor = 0x0;
2160 COLORREF TextColor = 0x0;
2161 INT BkMode = 0;
2162 INT runStart, runEnd;
2163 INT iGlyph, cGlyphs;
2164 HFONT oldFont = 0x0;
2165 RECT crc;
2166 int i;
2168 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2169 ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
2171 if (!(analysis = ssa)) return E_INVALIDARG;
2173 if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
2174 (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
2175 return S_OK;
2177 CopyRect(&crc,prc);
2178 if (fSelected)
2180 BkMode = GetBkMode(analysis->hdc);
2181 SetBkMode( analysis->hdc, OPAQUE);
2182 BkColor = GetBkColor(analysis->hdc);
2183 SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
2184 if (!fDisabled)
2186 TextColor = GetTextColor(analysis->hdc);
2187 SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2190 if (analysis->glyphs[iItem].fallbackFont)
2191 oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
2193 if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
2194 runStart = cStart - analysis->pItem[iItem].iCharPos;
2195 else
2196 runStart = 0;
2197 if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
2198 runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
2199 else
2200 runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
2202 if (analysis->pItem[iItem].a.fRTL)
2204 if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
2205 ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
2206 else
2207 ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
2208 crc.left = iX + off_x;
2210 else
2212 if (cStart >=0 && runStart)
2213 ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
2214 else
2215 ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
2216 crc.left = iX + off_x;
2219 if (analysis->pItem[iItem].a.fRTL)
2220 iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
2221 else
2222 iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
2224 if (analysis->pItem[iItem].a.fRTL)
2225 cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
2226 else
2227 cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
2229 cGlyphs++;
2231 /* adjust for cluster glyphs when starting */
2232 if (analysis->pItem[iItem].a.fRTL)
2233 i = analysis->pItem[iItem+1].iCharPos - 1;
2234 else
2235 i = analysis->pItem[iItem].iCharPos;
2237 for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
2239 if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
2241 if (analysis->pItem[iItem].a.fRTL)
2242 ScriptStringCPtoX(ssa, i, TRUE, &off_x);
2243 else
2244 ScriptStringCPtoX(ssa, i, FALSE, &off_x);
2245 break;
2249 if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
2251 INT direction;
2252 INT clust_glyph;
2254 clust_glyph = iGlyph + cGlyphs;
2255 if (analysis->pItem[iItem].a.fRTL)
2256 direction = -1;
2257 else
2258 direction = 1;
2260 while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
2261 !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
2263 cGlyphs++;
2264 clust_glyph++;
2268 hr = ScriptTextOut(analysis->hdc,
2269 (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
2270 iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
2271 &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
2272 &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
2273 &analysis->glyphs[iItem].pGoffset[iGlyph]);
2275 TRACE("ScriptTextOut hr=%08x\n", hr);
2277 if (fSelected)
2279 SetBkColor(analysis->hdc, BkColor);
2280 SetBkMode( analysis->hdc, BkMode);
2281 if (!fDisabled)
2282 SetTextColor(analysis->hdc, TextColor);
2284 if (analysis->glyphs[iItem].fallbackFont)
2285 SelectObject(analysis->hdc, oldFont);
2287 return hr;
2290 /***********************************************************************
2291 * ScriptStringOut (USP10.@)
2293 * This function takes the output of ScriptStringAnalyse and joins the segments
2294 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2295 * only processes glyphs.
2297 * Parameters:
2298 * ssa [I] buffer to hold the analysed string components
2299 * iX [I] X axis displacement for output
2300 * iY [I] Y axis displacement for output
2301 * uOptions [I] flags controlling output processing
2302 * prc [I] rectangle coordinates
2303 * iMinSel [I] starting pos for substringing output string
2304 * iMaxSel [I] ending pos for substringing output string
2305 * fDisabled [I] controls text highlighting
2307 * RETURNS
2308 * Success: S_OK
2309 * Failure: is the value returned by ScriptTextOut
2311 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
2312 int iX,
2313 int iY,
2314 UINT uOptions,
2315 const RECT *prc,
2316 int iMinSel,
2317 int iMaxSel,
2318 BOOL fDisabled)
2320 StringAnalysis *analysis;
2321 int item;
2322 HRESULT hr;
2324 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2325 ssa, iX, iY, uOptions, wine_dbgstr_rect(prc), iMinSel, iMaxSel, fDisabled);
2327 if (!(analysis = ssa)) return E_INVALIDARG;
2328 if (!(analysis->ssa_flags & SSA_GLYPHS)) return E_INVALIDARG;
2330 for (item = 0; item < analysis->numItems; item++)
2332 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
2333 if (FAILED(hr))
2334 return hr;
2337 if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
2339 if (iMaxSel > 0 && iMinSel < 0)
2340 iMinSel = 0;
2341 for (item = 0; item < analysis->numItems; item++)
2343 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
2344 if (FAILED(hr))
2345 return hr;
2349 return S_OK;
2352 /***********************************************************************
2353 * ScriptStringCPtoX (USP10.@)
2356 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
2358 int item;
2359 int runningX = 0;
2360 StringAnalysis* analysis = ssa;
2362 TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
2364 if (!ssa || !pX) return S_FALSE;
2365 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
2367 /* icp out of range */
2368 if(icp < 0)
2370 analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2371 return E_INVALIDARG;
2374 for(item=0; item<analysis->numItems; item++)
2376 int CP, i;
2377 int offset;
2379 i = analysis->logical2visual[item];
2380 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2381 /* initialize max extents for uninitialized runs */
2382 if (analysis->glyphs[i].iMaxPosX == -1)
2384 if (analysis->pItem[i].a.fRTL)
2385 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2386 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2387 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2388 else
2389 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2390 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2391 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2394 if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
2396 runningX += analysis->glyphs[i].iMaxPosX;
2397 continue;
2400 icp -= analysis->pItem[i].iCharPos;
2401 ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2402 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2403 &analysis->pItem[i].a, &offset);
2404 runningX += offset;
2406 *pX = runningX;
2407 return S_OK;
2410 /* icp out of range */
2411 analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2412 return E_INVALIDARG;
2415 /***********************************************************************
2416 * ScriptStringXtoCP (USP10.@)
2419 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
2421 StringAnalysis* analysis = ssa;
2422 int item;
2424 TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
2426 if (!ssa || !piCh || !piTrailing) return S_FALSE;
2427 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
2429 /* out of range */
2430 if(iX < 0)
2432 if (analysis->pItem[0].a.fRTL)
2434 *piCh = 1;
2435 *piTrailing = FALSE;
2437 else
2439 *piCh = -1;
2440 *piTrailing = TRUE;
2442 return S_OK;
2445 for(item=0; item<analysis->numItems; item++)
2447 int i;
2448 int CP;
2450 for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
2451 /* nothing */;
2453 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2454 /* initialize max extents for uninitialized runs */
2455 if (analysis->glyphs[i].iMaxPosX == -1)
2457 if (analysis->pItem[i].a.fRTL)
2458 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2459 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2460 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2461 else
2462 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2463 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2464 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2467 if (iX > analysis->glyphs[i].iMaxPosX)
2469 iX -= analysis->glyphs[i].iMaxPosX;
2470 continue;
2473 ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2474 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2475 &analysis->pItem[i].a, piCh, piTrailing);
2476 *piCh += analysis->pItem[i].iCharPos;
2478 return S_OK;
2481 /* out of range */
2482 *piCh = analysis->pItem[analysis->numItems].iCharPos;
2483 *piTrailing = FALSE;
2485 return S_OK;
2489 /***********************************************************************
2490 * ScriptStringFree (USP10.@)
2492 * Free a string analysis.
2494 * PARAMS
2495 * pssa [I] string analysis.
2497 * RETURNS
2498 * Success: S_OK
2499 * Failure: Non-zero HRESULT value.
2501 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
2503 StringAnalysis* analysis;
2504 BOOL invalid;
2505 int i;
2507 TRACE("(%p)\n", pssa);
2509 if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
2511 invalid = analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2513 if (analysis->glyphs)
2515 for (i = 0; i < analysis->numItems; i++)
2517 heap_free(analysis->glyphs[i].glyphs);
2518 heap_free(analysis->glyphs[i].pwLogClust);
2519 heap_free(analysis->glyphs[i].piAdvance);
2520 heap_free(analysis->glyphs[i].psva);
2521 heap_free(analysis->glyphs[i].pGoffset);
2522 if (analysis->glyphs[i].fallbackFont)
2523 DeleteObject(analysis->glyphs[i].fallbackFont);
2524 ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
2525 heap_free(analysis->glyphs[i].sc);
2527 heap_free(analysis->glyphs);
2530 heap_free(analysis->pItem);
2531 heap_free(analysis->logattrs);
2532 heap_free(analysis->logical2visual);
2533 heap_free(analysis);
2535 if (invalid) return E_INVALIDARG;
2536 return S_OK;
2539 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
2540 int direction, int* iCluster, int *check_out)
2542 int clust_size = 1;
2543 int check;
2544 WORD clust = pwLogClust[item];
2546 for (check = item+direction; check < cChars && check >= 0; check+=direction)
2548 if (pwLogClust[check] == clust)
2550 clust_size ++;
2551 if (iCluster && *iCluster == -1)
2552 *iCluster = item;
2554 else break;
2557 if (check_out)
2558 *check_out = check;
2560 return clust_size;
2563 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)
2565 int advance;
2566 int log_clust_max;
2568 advance = piAdvance[glyph];
2570 if (pwLogClust[0] > pwLogClust[cChars-1])
2571 log_clust_max = pwLogClust[0];
2572 else
2573 log_clust_max = pwLogClust[cChars-1];
2575 if (glyph > log_clust_max)
2576 return advance;
2578 for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
2581 if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
2582 break;
2583 if (glyph > log_clust_max)
2584 break;
2585 advance += piAdvance[glyph];
2588 return advance;
2591 /***********************************************************************
2592 * ScriptCPtoX (USP10.@)
2595 HRESULT WINAPI ScriptCPtoX(int iCP,
2596 BOOL fTrailing,
2597 int cChars,
2598 int cGlyphs,
2599 const WORD *pwLogClust,
2600 const SCRIPT_VISATTR *psva,
2601 const int *piAdvance,
2602 const SCRIPT_ANALYSIS *psa,
2603 int *piX)
2605 int item;
2606 float iPosX;
2607 int iSpecial = -1;
2608 int iCluster = -1;
2609 int clust_size = 1;
2610 float special_size = 0.0;
2611 int iMaxPos = 0;
2612 int advance = 0;
2613 BOOL rtl = FALSE;
2615 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2616 iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2617 psa, piX);
2619 if (psa->fRTL && ! psa->fLogicalOrder)
2620 rtl = TRUE;
2622 if (fTrailing)
2623 iCP++;
2625 if (rtl)
2627 int max_clust = pwLogClust[0];
2629 for (item=0; item < cGlyphs; item++)
2630 if (pwLogClust[item] > max_clust)
2632 ERR("We do not handle non reversed clusters properly\n");
2633 break;
2636 iMaxPos = 0;
2637 for (item = max_clust; item >=0; item --)
2638 iMaxPos += piAdvance[item];
2641 iPosX = 0.0;
2642 for (item=0; item < iCP && item < cChars; item++)
2644 if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
2646 int check;
2647 int clust = pwLogClust[item];
2649 iCluster = -1;
2650 clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2651 &check);
2653 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2655 if (check >= cChars && !iMaxPos)
2657 int glyph;
2658 for (glyph = clust; glyph < cGlyphs; glyph++)
2659 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, glyph, 1);
2660 iSpecial = item;
2661 special_size /= (cChars - item);
2662 iPosX += special_size;
2664 else
2666 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2668 clust_size --;
2669 if (clust_size == 0)
2670 iPosX += advance;
2672 else
2673 iPosX += advance / (float)clust_size;
2676 else if (iSpecial != -1)
2677 iPosX += special_size;
2678 else /* (iCluster != -1) */
2680 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2681 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2683 clust_size --;
2684 if (clust_size == 0)
2685 iPosX += adv;
2687 else
2688 iPosX += adv / (float)clust_size;
2692 if (iMaxPos > 0)
2694 iPosX = iMaxPos - iPosX;
2695 if (iPosX < 0)
2696 iPosX = 0;
2699 *piX = iPosX;
2700 TRACE("*piX=%d\n", *piX);
2701 return S_OK;
2704 /* Count the number of characters in a cluster and its starting index*/
2705 static inline BOOL get_cluster_data(const WORD *pwLogClust, int cChars, int cluster_index, int *cluster_size, int *start_index)
2707 int size = 0;
2708 int i;
2710 for (i = 0; i < cChars; i++)
2712 if (pwLogClust[i] == cluster_index)
2714 if (!size && start_index)
2716 *start_index = i;
2717 if (!cluster_size)
2718 return TRUE;
2720 size++;
2722 else if (size) break;
2724 if (cluster_size)
2725 *cluster_size = size;
2727 return (size > 0);
2731 To handle multi-glyph clusters we need to find all the glyphs that are
2732 represented in the cluster. This involves finding the glyph whose
2733 index is the cluster index as well as whose glyph indices are greater than
2734 our cluster index but not part of a new cluster.
2736 Then we sum all those glyphs' advances.
2738 static inline int get_cluster_advance(const int* piAdvance,
2739 const SCRIPT_VISATTR *psva,
2740 const WORD *pwLogClust, int cGlyphs,
2741 int cChars, int cluster, int direction)
2743 int glyph_start;
2744 int glyph_end;
2745 int i, advance;
2747 if (direction > 0)
2748 i = 0;
2749 else
2750 i = (cChars - 1);
2752 for (glyph_start = -1, glyph_end = -1; i < cChars && i >= 0 && (glyph_start < 0 || glyph_end < 0); i+=direction)
2754 if (glyph_start < 0 && pwLogClust[i] != cluster) continue;
2755 if (pwLogClust[i] == cluster && glyph_start < 0) glyph_start = pwLogClust[i];
2756 if (glyph_start >= 0 && glyph_end < 0 && pwLogClust[i] != cluster) glyph_end = pwLogClust[i];
2758 if (glyph_end < 0)
2760 if (direction > 0)
2761 glyph_end = cGlyphs;
2762 else
2764 /* Don't fully understand multi-glyph reversed clusters yet,
2765 * do they occur for real or just in our test? */
2766 FIXME("multi-glyph reversed clusters found\n");
2767 glyph_end = glyph_start + 1;
2771 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2772 for (i = glyph_start+1; i< glyph_end; i++)
2774 if (psva[i].fClusterStart)
2776 glyph_end = i;
2777 break;
2781 for (advance = 0, i = glyph_start; i < glyph_end; i++)
2782 advance += piAdvance[i];
2784 return advance;
2788 /***********************************************************************
2789 * ScriptXtoCP (USP10.@)
2791 * Basic algorithm :
2792 * Use piAdvance to find the cluster we are looking at.
2793 * Find the character that is the first character of the cluster.
2794 * That is our base piCP.
2795 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2796 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2797 * determine how far through the cluster to advance the cursor.
2799 HRESULT WINAPI ScriptXtoCP(int iX,
2800 int cChars,
2801 int cGlyphs,
2802 const WORD *pwLogClust,
2803 const SCRIPT_VISATTR *psva,
2804 const int *piAdvance,
2805 const SCRIPT_ANALYSIS *psa,
2806 int *piCP,
2807 int *piTrailing)
2809 int direction = 1;
2810 int iPosX;
2811 int i;
2812 int glyph_index, cluster_index;
2813 int cluster_size;
2815 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2816 iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2817 psa, piCP, piTrailing);
2819 if (psa->fRTL && ! psa->fLogicalOrder)
2820 direction = -1;
2822 /* Handle an iX < 0 */
2823 if (iX < 0)
2825 if (direction < 0)
2827 *piCP = cChars;
2828 *piTrailing = 0;
2830 else
2832 *piCP = -1;
2833 *piTrailing = 1;
2835 return S_OK;
2838 /* Looking for non-reversed clusters in a reversed string */
2839 if (direction < 0)
2841 int max_clust = pwLogClust[0];
2842 for (i=0; i< cChars; i++)
2843 if (pwLogClust[i] > max_clust)
2845 FIXME("We do not handle non reversed clusters properly\n");
2846 break;
2850 /* find the glyph_index based in iX */
2851 if (direction > 0)
2853 for (glyph_index = -1, iPosX = iX; iPosX >=0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2856 else
2858 for (glyph_index = -1, iPosX = iX; iPosX > 0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2862 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX, glyph_index, cGlyphs);
2864 *piTrailing = 0;
2865 if (glyph_index >= 0 && glyph_index < cGlyphs)
2867 /* find the cluster */
2868 if (direction > 0 )
2869 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] <= glyph_index; cluster_index=pwLogClust[i++])
2871 else
2872 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] >= glyph_index; cluster_index=pwLogClust[i++])
2875 TRACE("cluster_index %i\n", cluster_index);
2877 if (direction < 0 && iPosX >= 0 && glyph_index != cluster_index)
2879 /* We are off the end of the string */
2880 *piCP = -1;
2881 *piTrailing = 1;
2882 return S_OK;
2885 get_cluster_data(pwLogClust, cChars, cluster_index, &cluster_size, &i);
2887 TRACE("first char index %i\n",i);
2888 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2890 /* Check trailing */
2891 if (glyph_index != cluster_index ||
2892 (direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2893 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2894 *piTrailing = cluster_size;
2896 else
2898 if (cluster_size > 1)
2900 /* Be part way through the glyph cluster based on size and position */
2901 int cluster_advance = get_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, cluster_index, direction);
2902 double cluster_part_width = cluster_advance / (float)cluster_size;
2903 double adv;
2904 int part_index;
2906 /* back up to the beginning of the cluster */
2907 for (adv = iPosX, part_index = cluster_index; part_index <= glyph_index; part_index++)
2908 adv += piAdvance[part_index];
2909 if (adv > iX) adv = iX;
2911 TRACE("Multi-char cluster, no snap\n");
2912 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size, adv);
2913 TRACE("advance %i divides into %f per char\n", cluster_advance, cluster_part_width);
2914 if (direction > 0)
2916 for (part_index = 0; adv >= 0; adv-=cluster_part_width, part_index++)
2918 if (part_index) part_index--;
2920 else
2922 for (part_index = 0; adv > 0; adv-=cluster_part_width, part_index++)
2924 if (part_index > cluster_size)
2926 adv += cluster_part_width;
2927 part_index=cluster_size;
2931 TRACE("base_char %i part_index %i, leftover advance %f\n",i, part_index, adv);
2933 if (direction > 0)
2934 i += part_index;
2935 else
2936 i += (cluster_size - part_index);
2938 /* Check trailing */
2939 if ((direction > 0 && fabs(adv) <= (cluster_part_width / 2.0)) ||
2940 (direction < 0 && adv && fabs(adv) >= (cluster_part_width / 2.0)))
2941 *piTrailing = 1;
2943 else
2945 /* Check trailing */
2946 if ((direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2947 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2948 *piTrailing = 1;
2952 else
2954 TRACE("Point falls outside of string\n");
2955 if (glyph_index < 0)
2956 i = cChars-1;
2957 else /* (glyph_index >= cGlyphs) */
2958 i = cChars;
2960 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2961 point flow to the next character */
2962 if (direction < 0)
2964 if (!scriptInformation[psa->eScript].props.fNeedsCaretInfo && abs(iPosX) == piAdvance[glyph_index])
2965 i++;
2966 else
2967 *piTrailing = 1;
2971 *piCP = i;
2973 TRACE("*piCP=%d\n", *piCP);
2974 TRACE("*piTrailing=%d\n", *piTrailing);
2975 return S_OK;
2978 /***********************************************************************
2979 * ScriptBreak (USP10.@)
2981 * Retrieve line break information.
2983 * PARAMS
2984 * chars [I] Array of characters.
2985 * sa [I] Script analysis.
2986 * la [I] Array of logical attribute structures.
2988 * RETURNS
2989 * Success: S_OK
2990 * Failure: S_FALSE
2992 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2994 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2996 if (count < 0 || !la) return E_INVALIDARG;
2997 if (count == 0) return E_FAIL;
2999 BREAK_line(chars, count, sa, la);
3001 return S_OK;
3004 /***********************************************************************
3005 * ScriptIsComplex (USP10.@)
3007 * Determine if a string is complex.
3009 * PARAMS
3010 * chars [I] Array of characters to test.
3011 * len [I] Length in characters.
3012 * flag [I] Flag.
3014 * RETURNS
3015 * Success: S_OK
3016 * Failure: S_FALSE
3019 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
3021 enum usp10_script script;
3022 unsigned int i, consumed;
3024 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
3026 if (!chars || len < 0)
3027 return E_INVALIDARG;
3029 for (i = 0; i < len; i+=consumed)
3031 if (i >= len)
3032 break;
3034 if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
3035 return S_OK;
3037 script = get_char_script(chars,i,len, &consumed);
3038 if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
3039 (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
3040 return S_OK;
3042 return S_FALSE;
3045 /***********************************************************************
3046 * ScriptShapeOpenType (USP10.@)
3048 * Produce glyphs and visual attributes for a run.
3050 * PARAMS
3051 * hdc [I] Device context.
3052 * psc [I/O] Opaque pointer to a script cache.
3053 * psa [I/O] Script analysis.
3054 * tagScript [I] The OpenType tag for the Script
3055 * tagLangSys [I] The OpenType tag for the Language
3056 * rcRangeChars[I] Array of Character counts in each range
3057 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3058 * cRanges [I] Count of ranges
3059 * pwcChars [I] Array of characters specifying the run.
3060 * cChars [I] Number of characters in pwcChars.
3061 * cMaxGlyphs [I] Length of pwOutGlyphs.
3062 * pwLogClust [O] Array of logical cluster info.
3063 * pCharProps [O] Array of character property values
3064 * pwOutGlyphs [O] Array of glyphs.
3065 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3066 * pcGlyphs [O] Number of glyphs returned.
3068 * RETURNS
3069 * Success: S_OK
3070 * Failure: Non-zero HRESULT value.
3072 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
3073 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3074 OPENTYPE_TAG tagLangSys, int *rcRangeChars,
3075 TEXTRANGE_PROPERTIES **rpRangeProperties,
3076 int cRanges, const WCHAR *pwcChars, int cChars,
3077 int cMaxGlyphs, WORD *pwLogClust,
3078 SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
3079 SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
3081 HRESULT hr;
3082 int i;
3083 unsigned int g;
3084 BOOL rtl;
3085 int cluster;
3086 static int once = 0;
3088 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3089 hdc, psc, psa,
3090 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3091 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3092 cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
3094 if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
3095 psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
3097 if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
3098 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3100 if (cRanges)
3101 if(!once++) FIXME("Ranges not supported yet\n");
3103 rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
3105 *pcGlyphs = cChars;
3106 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3107 if (!pwLogClust) return E_FAIL;
3109 ((ScriptCache *)*psc)->userScript = tagScript;
3110 ((ScriptCache *)*psc)->userLang = tagLangSys;
3112 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3113 for (i = 0; i < cChars; i++)
3115 int idx = i;
3116 if (rtl) idx = cChars - 1 - i;
3117 /* FIXME: set to better values */
3118 pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
3119 pOutGlyphProps[i].sva.fClusterStart = 1;
3120 pOutGlyphProps[i].sva.fDiacritic = 0;
3121 pOutGlyphProps[i].sva.fZeroWidth = 0;
3122 pOutGlyphProps[i].sva.fReserved = 0;
3123 pOutGlyphProps[i].sva.fShapeReserved = 0;
3125 /* FIXME: have the shaping engine set this */
3126 pCharProps[i].fCanGlyphAlone = 0;
3128 pwLogClust[i] = idx;
3131 if (psa && !psa->fNoGlyphIndex && ((ScriptCache *)*psc)->sfnt)
3133 WCHAR *rChars;
3134 if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
3136 rChars = heap_alloc(sizeof(WCHAR) * cChars);
3137 if (!rChars) return E_OUTOFMEMORY;
3138 for (i = 0, g = 0, cluster = 0; i < cChars; i++)
3140 int idx = i;
3141 DWORD chInput;
3143 if (rtl) idx = cChars - 1 - i;
3144 if (!cluster)
3146 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
3147 if (!chInput)
3149 if (psa->fRTL)
3150 chInput = mirror_char(pwcChars[idx]);
3151 else
3152 chInput = pwcChars[idx];
3153 rChars[i] = chInput;
3155 else
3157 rChars[i] = pwcChars[idx];
3158 rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
3159 cluster = 1;
3161 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
3163 WORD glyph;
3164 if (!hdc)
3166 heap_free(rChars);
3167 return E_PENDING;
3169 if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
3171 heap_free(rChars);
3172 return S_FALSE;
3174 pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
3176 g++;
3178 else
3180 int k;
3181 cluster--;
3182 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
3183 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3184 pwLogClust[k]--;
3187 *pcGlyphs = g;
3189 SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3190 SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
3191 SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
3193 for (i = 0; i < cChars; ++i)
3195 /* Special case for tabs and joiners. As control characters, ZWNJ
3196 * and ZWJ would in principle get handled by the corresponding
3197 * shaping functions. However, since ZWNJ and ZWJ can get merged
3198 * into adjoining runs during itemisation, these don't generally
3199 * get classified as Script_Control. */
3200 if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
3202 pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
3203 pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
3206 heap_free(rChars);
3208 else
3210 TRACE("no glyph translation\n");
3211 for (i = 0; i < cChars; i++)
3213 int idx = i;
3214 /* No mirroring done here */
3215 if (rtl) idx = cChars - 1 - i;
3216 pwOutGlyphs[i] = pwcChars[idx];
3218 if (!psa)
3219 continue;
3221 /* overwrite some basic control glyphs to blank */
3222 if (psa->fNoGlyphIndex)
3224 if (pwcChars[idx] == ZWSP || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3226 pwOutGlyphs[i] = 0x20;
3227 pOutGlyphProps[i].sva.fZeroWidth = 1;
3230 else if (psa->eScript == Script_Control || pwcChars[idx] == ZWSP
3231 || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3233 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
3234 pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)
3236 pwOutGlyphs[i] = ((ScriptCache *)*psc)->sfp.wgBlank;
3237 pOutGlyphProps[i].sva.fZeroWidth = 1;
3243 return S_OK;
3247 /***********************************************************************
3248 * ScriptShape (USP10.@)
3250 * Produce glyphs and visual attributes for a run.
3252 * PARAMS
3253 * hdc [I] Device context.
3254 * psc [I/O] Opaque pointer to a script cache.
3255 * pwcChars [I] Array of characters specifying the run.
3256 * cChars [I] Number of characters in pwcChars.
3257 * cMaxGlyphs [I] Length of pwOutGlyphs.
3258 * psa [I/O] Script analysis.
3259 * pwOutGlyphs [O] Array of glyphs.
3260 * pwLogClust [O] Array of logical cluster info.
3261 * psva [O] Array of visual attributes.
3262 * pcGlyphs [O] Number of glyphs returned.
3264 * RETURNS
3265 * Success: S_OK
3266 * Failure: Non-zero HRESULT value.
3268 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
3269 int cChars, int cMaxGlyphs,
3270 SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
3271 SCRIPT_VISATTR *psva, int *pcGlyphs)
3273 HRESULT hr;
3274 int i;
3275 SCRIPT_CHARPROP *charProps;
3276 SCRIPT_GLYPHPROP *glyphProps;
3278 if (!psva || !pcGlyphs) return E_INVALIDARG;
3279 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3281 charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
3282 if (!charProps) return E_OUTOFMEMORY;
3283 glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
3284 if (!glyphProps)
3286 heap_free(charProps);
3287 return E_OUTOFMEMORY;
3290 hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
3292 if (SUCCEEDED(hr))
3294 for (i = 0; i < *pcGlyphs; i++)
3295 psva[i] = glyphProps[i].sva;
3298 heap_free(charProps);
3299 heap_free(glyphProps);
3301 return hr;
3304 /***********************************************************************
3305 * ScriptPlaceOpenType (USP10.@)
3307 * Produce advance widths for a run.
3309 * PARAMS
3310 * hdc [I] Device context.
3311 * psc [I/O] Opaque pointer to a script cache.
3312 * psa [I/O] Script analysis.
3313 * tagScript [I] The OpenType tag for the Script
3314 * tagLangSys [I] The OpenType tag for the Language
3315 * rcRangeChars[I] Array of Character counts in each range
3316 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3317 * cRanges [I] Count of ranges
3318 * pwcChars [I] Array of characters specifying the run.
3319 * pwLogClust [I] Array of logical cluster info
3320 * pCharProps [I] Array of character property values
3321 * cChars [I] Number of characters in pwcChars.
3322 * pwGlyphs [I] Array of glyphs.
3323 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3324 * cGlyphs [I] Count of Glyphs
3325 * piAdvance [O] Array of advance widths.
3326 * pGoffset [O] Glyph offsets.
3327 * pABC [O] Combined ABC width.
3329 * RETURNS
3330 * Success: S_OK
3331 * Failure: Non-zero HRESULT value.
3334 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
3335 OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
3336 int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
3337 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3338 SCRIPT_CHARPROP *pCharProps, int cChars,
3339 const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
3340 int cGlyphs, int *piAdvance,
3341 GOFFSET *pGoffset, ABC *pABC
3344 HRESULT hr;
3345 int i;
3346 static int once = 0;
3348 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3349 hdc, psc, psa,
3350 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3351 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3352 pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
3353 pGoffset, pABC);
3355 if (!pGlyphProps) return E_INVALIDARG;
3356 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3357 if (!pGoffset) return E_FAIL;
3359 if (cRanges)
3360 if (!once++) FIXME("Ranges not supported yet\n");
3362 ((ScriptCache *)*psc)->userScript = tagScript;
3363 ((ScriptCache *)*psc)->userLang = tagLangSys;
3365 if (pABC) memset(pABC, 0, sizeof(ABC));
3366 for (i = 0; i < cGlyphs; i++)
3368 ABC abc;
3369 if (pGlyphProps[i].sva.fZeroWidth)
3371 abc.abcA = abc.abcB = abc.abcC = 0;
3373 else if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
3375 BOOL ret;
3376 if (!hdc) return E_PENDING;
3377 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
3379 if (psa->fNoGlyphIndex)
3380 ret = GetCharABCWidthsW(hdc, pwGlyphs[i], pwGlyphs[i], &abc);
3381 else
3382 ret = GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc);
3383 if (!ret) return S_FALSE;
3385 else
3387 INT width;
3388 if (psa->fNoGlyphIndex)
3389 ret = GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width);
3390 else
3391 ret = GetCharWidthI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &width);
3392 if (!ret) return S_FALSE;
3393 abc.abcB = width;
3394 abc.abcA = abc.abcC = 0;
3396 set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
3398 if (pABC)
3400 pABC->abcA += abc.abcA;
3401 pABC->abcB += abc.abcB;
3402 pABC->abcC += abc.abcC;
3404 /* FIXME: set to more reasonable values */
3405 pGoffset[i].du = pGoffset[i].dv = 0;
3406 if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
3409 SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset);
3411 if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
3412 return S_OK;
3415 /***********************************************************************
3416 * ScriptPlace (USP10.@)
3418 * Produce advance widths for a run.
3420 * PARAMS
3421 * hdc [I] Device context.
3422 * psc [I/O] Opaque pointer to a script cache.
3423 * pwGlyphs [I] Array of glyphs.
3424 * cGlyphs [I] Number of glyphs in pwGlyphs.
3425 * psva [I] Array of visual attributes.
3426 * psa [I/O] String analysis.
3427 * piAdvance [O] Array of advance widths.
3428 * pGoffset [O] Glyph offsets.
3429 * pABC [O] Combined ABC width.
3431 * RETURNS
3432 * Success: S_OK
3433 * Failure: Non-zero HRESULT value.
3435 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
3436 int cGlyphs, const SCRIPT_VISATTR *psva,
3437 SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
3439 HRESULT hr;
3440 SCRIPT_GLYPHPROP *glyphProps;
3441 int i;
3443 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
3444 piAdvance, pGoffset, pABC);
3446 if (!psva) return E_INVALIDARG;
3447 if (!pGoffset) return E_FAIL;
3449 glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
3450 if (!glyphProps) return E_OUTOFMEMORY;
3452 for (i = 0; i < cGlyphs; i++)
3453 glyphProps[i].sva = psva[i];
3455 hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
3457 heap_free(glyphProps);
3459 return hr;
3462 /***********************************************************************
3463 * ScriptGetCMap (USP10.@)
3465 * Retrieve glyph indices.
3467 * PARAMS
3468 * hdc [I] Device context.
3469 * psc [I/O] Opaque pointer to a script cache.
3470 * pwcInChars [I] Array of Unicode characters.
3471 * cChars [I] Number of characters in pwcInChars.
3472 * dwFlags [I] Flags.
3473 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3475 * RETURNS
3476 * Success: S_OK
3477 * Failure: Non-zero HRESULT value.
3479 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
3480 int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
3482 HRESULT hr;
3483 int i;
3485 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
3486 cChars, dwFlags, pwOutGlyphs);
3488 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3490 hr = S_OK;
3492 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3494 for (i = 0; i < cChars; i++)
3496 WCHAR inChar;
3497 if (dwFlags == SGCM_RTL)
3498 inChar = mirror_char(pwcInChars[i]);
3499 else
3500 inChar = pwcInChars[i];
3501 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
3503 WORD glyph;
3504 if (!hdc) return E_PENDING;
3505 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
3506 if (glyph == 0xffff)
3508 hr = S_FALSE;
3509 glyph = 0x0;
3511 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
3515 else
3517 TRACE("no glyph translation\n");
3518 for (i = 0; i < cChars; i++)
3520 WCHAR inChar;
3521 if (dwFlags == SGCM_RTL)
3522 inChar = mirror_char(pwcInChars[i]);
3523 else
3524 inChar = pwcInChars[i];
3525 pwOutGlyphs[i] = inChar;
3528 return hr;
3531 /***********************************************************************
3532 * ScriptTextOut (USP10.@)
3535 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
3536 const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
3537 int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
3538 const int *piJustify, const GOFFSET *pGoffset)
3540 HRESULT hr = S_OK;
3541 INT i, dir = 1;
3542 INT *lpDx;
3543 WORD *reordered_glyphs = (WORD *)pwGlyphs;
3545 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3546 hdc, psc, x, y, fuOptions, wine_dbgstr_rect(lprc), psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
3547 piAdvance, piJustify, pGoffset);
3549 if (!hdc || !psc) return E_INVALIDARG;
3550 if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
3552 fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
3553 fuOptions |= ETO_IGNORELANGUAGE;
3554 if (!psa->fNoGlyphIndex) /* Have Glyphs? */
3555 fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */
3557 lpDx = heap_alloc(cGlyphs * sizeof(INT) * 2);
3558 if (!lpDx) return E_OUTOFMEMORY;
3559 fuOptions |= ETO_PDY;
3561 if (psa->fRTL && psa->fLogicalOrder)
3563 reordered_glyphs = heap_alloc( cGlyphs * sizeof(WORD) );
3564 if (!reordered_glyphs)
3566 heap_free( lpDx );
3567 return E_OUTOFMEMORY;
3570 for (i = 0; i < cGlyphs; i++)
3571 reordered_glyphs[i] = pwGlyphs[cGlyphs - 1 - i];
3572 dir = -1;
3575 for (i = 0; i < cGlyphs; i++)
3577 int orig_index = (dir > 0) ? i : cGlyphs - 1 - i;
3578 lpDx[i * 2] = piAdvance[orig_index];
3579 lpDx[i * 2 + 1] = 0;
3581 if (pGoffset)
3583 if (i == 0)
3585 x += pGoffset[orig_index].du * dir;
3586 y += pGoffset[orig_index].dv;
3588 else
3590 lpDx[(i - 1) * 2] += pGoffset[orig_index].du * dir;
3591 lpDx[(i - 1) * 2 + 1] += pGoffset[orig_index].dv;
3593 lpDx[i * 2] -= pGoffset[orig_index].du * dir;
3594 lpDx[i * 2 + 1] -= pGoffset[orig_index].dv;
3598 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, reordered_glyphs, cGlyphs, lpDx))
3599 hr = S_FALSE;
3601 if (reordered_glyphs != pwGlyphs) heap_free( reordered_glyphs );
3602 heap_free(lpDx);
3604 return hr;
3607 /***********************************************************************
3608 * ScriptCacheGetHeight (USP10.@)
3610 * Retrieve the height of the font in the cache.
3612 * PARAMS
3613 * hdc [I] Device context.
3614 * psc [I/O] Opaque pointer to a script cache.
3615 * height [O] Receives font height.
3617 * RETURNS
3618 * Success: S_OK
3619 * Failure: Non-zero HRESULT value.
3621 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
3623 HRESULT hr;
3625 TRACE("(%p, %p, %p)\n", hdc, psc, height);
3627 if (!height) return E_INVALIDARG;
3628 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3630 *height = get_cache_height(psc);
3631 return S_OK;
3634 /***********************************************************************
3635 * ScriptGetGlyphABCWidth (USP10.@)
3637 * Retrieve the width of a glyph.
3639 * PARAMS
3640 * hdc [I] Device context.
3641 * psc [I/O] Opaque pointer to a script cache.
3642 * glyph [I] Glyph to retrieve the width for.
3643 * abc [O] ABC widths of the glyph.
3645 * RETURNS
3646 * Success: S_OK
3647 * Failure: Non-zero HRESULT value.
3649 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
3651 HRESULT hr;
3653 TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
3655 if (!abc) return E_INVALIDARG;
3656 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3658 if (!get_cache_glyph_widths(psc, glyph, abc))
3660 if (!hdc) return E_PENDING;
3661 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3663 if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
3665 else
3667 INT width;
3668 if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
3669 abc->abcB = width;
3670 abc->abcA = abc->abcC = 0;
3672 set_cache_glyph_widths(psc, glyph, abc);
3674 return S_OK;
3677 /***********************************************************************
3678 * ScriptLayout (USP10.@)
3680 * Map embedding levels to visual and/or logical order.
3682 * PARAMS
3683 * runs [I] Size of level array.
3684 * level [I] Array of embedding levels.
3685 * vistolog [O] Map of embedding levels from visual to logical order.
3686 * logtovis [O] Map of embedding levels from logical to visual order.
3688 * RETURNS
3689 * Success: S_OK
3690 * Failure: Non-zero HRESULT value.
3693 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
3695 int* indexs;
3696 int ich;
3698 TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
3700 if (!level || (!vistolog && !logtovis))
3701 return E_INVALIDARG;
3703 indexs = heap_alloc(sizeof(int) * runs);
3704 if (!indexs)
3705 return E_OUTOFMEMORY;
3707 if (vistolog)
3709 for( ich = 0; ich < runs; ich++)
3710 indexs[ich] = ich;
3712 ich = 0;
3713 while (ich < runs)
3714 ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3715 memcpy(vistolog, indexs, runs * sizeof(*vistolog));
3718 if (logtovis)
3720 for( ich = 0; ich < runs; ich++)
3721 indexs[ich] = ich;
3723 ich = 0;
3724 while (ich < runs)
3725 ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3726 memcpy(logtovis, indexs, runs * sizeof(*logtovis));
3728 heap_free(indexs);
3730 return S_OK;
3733 /***********************************************************************
3734 * ScriptStringGetLogicalWidths (USP10.@)
3736 * Returns logical widths from a string analysis.
3738 * PARAMS
3739 * ssa [I] string analysis.
3740 * piDx [O] logical widths returned.
3742 * RETURNS
3743 * Success: S_OK
3744 * Failure: a non-zero HRESULT.
3746 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
3748 int i, j, next = 0;
3749 StringAnalysis *analysis = ssa;
3751 TRACE("%p, %p\n", ssa, piDx);
3753 if (!analysis) return S_FALSE;
3754 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3756 for (i = 0; i < analysis->numItems; i++)
3758 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
3759 int direction = 1;
3761 if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
3762 direction = -1;
3764 for (j = 0; j < cChar; j++)
3766 int k;
3767 int glyph = analysis->glyphs[i].pwLogClust[j];
3768 int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
3769 cChar, j, direction, NULL, NULL);
3770 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);
3772 for (k = 0; k < clust_size; k++)
3774 piDx[next] = advance / clust_size;
3775 next++;
3776 if (k) j++;
3780 return S_OK;
3783 /***********************************************************************
3784 * ScriptStringValidate (USP10.@)
3786 * Validate a string analysis.
3788 * PARAMS
3789 * ssa [I] string analysis.
3791 * RETURNS
3792 * Success: S_OK
3793 * Failure: S_FALSE if invalid sequences are found
3794 * or a non-zero HRESULT if it fails.
3796 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
3798 StringAnalysis *analysis = ssa;
3800 TRACE("(%p)\n", ssa);
3802 if (!analysis) return E_INVALIDARG;
3803 return analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID ? S_FALSE : S_OK;
3806 /***********************************************************************
3807 * ScriptString_pSize (USP10.@)
3809 * Retrieve width and height of an analysed string.
3811 * PARAMS
3812 * ssa [I] string analysis.
3814 * RETURNS
3815 * Success: Pointer to a SIZE structure.
3816 * Failure: NULL
3818 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
3820 int i, j;
3821 StringAnalysis *analysis = ssa;
3823 TRACE("(%p)\n", ssa);
3825 if (!analysis) return NULL;
3826 if (!(analysis->ssa_flags & SSA_GLYPHS)) return NULL;
3828 if (!(analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_SIZE))
3830 analysis->sz.cy = analysis->glyphs[0].sc->tm.tmHeight;
3832 analysis->sz.cx = 0;
3833 for (i = 0; i < analysis->numItems; i++)
3835 if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz.cy)
3836 analysis->sz.cy = analysis->glyphs[i].sc->tm.tmHeight;
3837 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3838 analysis->sz.cx += analysis->glyphs[i].piAdvance[j];
3841 return &analysis->sz;
3844 /***********************************************************************
3845 * ScriptString_pLogAttr (USP10.@)
3847 * Retrieve logical attributes of an analysed string.
3849 * PARAMS
3850 * ssa [I] string analysis.
3852 * RETURNS
3853 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3854 * Failure: NULL
3856 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
3858 StringAnalysis *analysis = ssa;
3860 TRACE("(%p)\n", ssa);
3862 if (!analysis) return NULL;
3863 if (!(analysis->ssa_flags & SSA_BREAK)) return NULL;
3864 return analysis->logattrs;
3867 /***********************************************************************
3868 * ScriptString_pcOutChars (USP10.@)
3870 * Retrieve the length of a string after clipping.
3872 * PARAMS
3873 * ssa [I] String analysis.
3875 * RETURNS
3876 * Success: Pointer to the length.
3877 * Failure: NULL
3879 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
3881 StringAnalysis *analysis = ssa;
3883 TRACE("(%p)\n", ssa);
3885 if (!analysis) return NULL;
3886 return &analysis->clip_len;
3889 /***********************************************************************
3890 * ScriptStringGetOrder (USP10.@)
3892 * Retrieve a glyph order map.
3894 * PARAMS
3895 * ssa [I] String analysis.
3896 * order [I/O] Array of glyph positions.
3898 * RETURNS
3899 * Success: S_OK
3900 * Failure: a non-zero HRESULT.
3902 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
3904 int i, j;
3905 unsigned int k;
3906 StringAnalysis *analysis = ssa;
3908 TRACE("(%p)\n", ssa);
3910 if (!analysis) return S_FALSE;
3911 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3913 /* FIXME: handle RTL scripts */
3914 for (i = 0, k = 0; i < analysis->numItems; i++)
3915 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3916 order[k] = k;
3918 return S_OK;
3921 /***********************************************************************
3922 * ScriptGetLogicalWidths (USP10.@)
3924 * Convert advance widths to logical widths.
3926 * PARAMS
3927 * sa [I] Script analysis.
3928 * nbchars [I] Number of characters.
3929 * nbglyphs [I] Number of glyphs.
3930 * glyph_width [I] Array of glyph widths.
3931 * log_clust [I] Array of logical clusters.
3932 * sva [I] Visual attributes.
3933 * widths [O] Array of logical widths.
3935 * RETURNS
3936 * Success: S_OK
3937 * Failure: a non-zero HRESULT.
3939 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3940 const int *advances, const WORD *log_clust,
3941 const SCRIPT_VISATTR *sva, int *widths)
3943 int i, next = 0, direction;
3945 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3946 sa, nbchars, nbglyphs, advances, log_clust, sva, widths);
3948 if (sa->fRTL && !sa->fLogicalOrder)
3949 direction = -1;
3950 else
3951 direction = 1;
3953 for (i = 0; i < nbchars; i++)
3955 int clust_size = get_cluster_size(log_clust, nbchars, i, direction, NULL, NULL);
3956 int advance = get_glyph_cluster_advance(advances, sva, log_clust, nbglyphs, nbchars, log_clust[i], direction);
3957 int j;
3959 for (j = 0; j < clust_size; j++)
3961 widths[next] = advance / clust_size;
3962 next++;
3963 if (j) i++;
3967 return S_OK;
3970 /***********************************************************************
3971 * ScriptApplyLogicalWidth (USP10.@)
3973 * Generate glyph advance widths.
3975 * PARAMS
3976 * dx [I] Array of logical advance widths.
3977 * num_chars [I] Number of characters.
3978 * num_glyphs [I] Number of glyphs.
3979 * log_clust [I] Array of logical clusters.
3980 * sva [I] Visual attributes.
3981 * advance [I] Array of glyph advance widths.
3982 * sa [I] Script analysis.
3983 * abc [I/O] Summed ABC widths.
3984 * justify [O] Array of glyph advance widths.
3986 * RETURNS
3987 * Success: S_OK
3988 * Failure: a non-zero HRESULT.
3990 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
3991 const WORD *log_clust, const SCRIPT_VISATTR *sva,
3992 const int *advance, const SCRIPT_ANALYSIS *sa,
3993 ABC *abc, int *justify)
3995 int i;
3997 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3998 dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
4000 for (i = 0; i < num_chars; i++) justify[i] = advance[i];
4001 return S_OK;
4004 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
4005 int num_glyphs, int dx, int min_kashida, int *justify)
4007 int i;
4009 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
4011 for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
4012 return S_OK;
4015 HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
4017 HRESULT hr;
4018 if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4019 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4021 return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
4024 HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
4026 HRESULT hr;
4027 if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4028 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4030 return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
4033 HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
4035 HRESULT hr;
4036 if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4037 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4039 return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);