ddraw/tests: Rewrite LimitTest().
[wine.git] / dlls / usp10 / usp10.c
blob5d257b2c1c0ae843efbce3603aa2e3a3f9d4ab58
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+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 ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
3032 return S_OK;
3034 script = get_char_script(chars,i,len, &consumed);
3035 if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
3036 (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
3037 return S_OK;
3039 return S_FALSE;
3042 /***********************************************************************
3043 * ScriptShapeOpenType (USP10.@)
3045 * Produce glyphs and visual attributes for a run.
3047 * PARAMS
3048 * hdc [I] Device context.
3049 * psc [I/O] Opaque pointer to a script cache.
3050 * psa [I/O] Script analysis.
3051 * tagScript [I] The OpenType tag for the Script
3052 * tagLangSys [I] The OpenType tag for the Language
3053 * rcRangeChars[I] Array of Character counts in each range
3054 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3055 * cRanges [I] Count of ranges
3056 * pwcChars [I] Array of characters specifying the run.
3057 * cChars [I] Number of characters in pwcChars.
3058 * cMaxGlyphs [I] Length of pwOutGlyphs.
3059 * pwLogClust [O] Array of logical cluster info.
3060 * pCharProps [O] Array of character property values
3061 * pwOutGlyphs [O] Array of glyphs.
3062 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3063 * pcGlyphs [O] Number of glyphs returned.
3065 * RETURNS
3066 * Success: S_OK
3067 * Failure: Non-zero HRESULT value.
3069 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
3070 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3071 OPENTYPE_TAG tagLangSys, int *rcRangeChars,
3072 TEXTRANGE_PROPERTIES **rpRangeProperties,
3073 int cRanges, const WCHAR *pwcChars, int cChars,
3074 int cMaxGlyphs, WORD *pwLogClust,
3075 SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
3076 SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
3078 HRESULT hr;
3079 int i;
3080 unsigned int g;
3081 BOOL rtl;
3082 int cluster;
3083 static int once = 0;
3085 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3086 hdc, psc, psa,
3087 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3088 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3089 cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
3091 if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
3092 psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
3094 if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
3095 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3097 if (cRanges)
3098 if(!once++) FIXME("Ranges not supported yet\n");
3100 rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
3102 *pcGlyphs = cChars;
3103 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3104 if (!pwLogClust) return E_FAIL;
3106 ((ScriptCache *)*psc)->userScript = tagScript;
3107 ((ScriptCache *)*psc)->userLang = tagLangSys;
3109 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3110 for (i = 0; i < cChars; i++)
3112 int idx = i;
3113 if (rtl) idx = cChars - 1 - i;
3114 /* FIXME: set to better values */
3115 pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
3116 pOutGlyphProps[i].sva.fClusterStart = 1;
3117 pOutGlyphProps[i].sva.fDiacritic = 0;
3118 pOutGlyphProps[i].sva.fZeroWidth = 0;
3119 pOutGlyphProps[i].sva.fReserved = 0;
3120 pOutGlyphProps[i].sva.fShapeReserved = 0;
3122 /* FIXME: have the shaping engine set this */
3123 pCharProps[i].fCanGlyphAlone = 0;
3125 pwLogClust[i] = idx;
3128 if (psa && !psa->fNoGlyphIndex && ((ScriptCache *)*psc)->sfnt)
3130 WCHAR *rChars;
3131 if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
3133 rChars = heap_alloc(sizeof(WCHAR) * cChars);
3134 if (!rChars) return E_OUTOFMEMORY;
3135 for (i = 0, g = 0, cluster = 0; i < cChars; i++)
3137 int idx = i;
3138 DWORD chInput;
3140 if (rtl) idx = cChars - 1 - i;
3141 if (!cluster)
3143 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
3144 if (!chInput)
3146 if (psa->fRTL)
3147 chInput = mirror_char(pwcChars[idx]);
3148 else
3149 chInput = pwcChars[idx];
3150 rChars[i] = chInput;
3152 else
3154 rChars[i] = pwcChars[idx];
3155 rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
3156 cluster = 1;
3158 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
3160 WORD glyph;
3161 if (!hdc)
3163 heap_free(rChars);
3164 return E_PENDING;
3166 if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
3168 heap_free(rChars);
3169 return S_FALSE;
3171 pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
3173 g++;
3175 else
3177 int k;
3178 cluster--;
3179 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
3180 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3181 pwLogClust[k]--;
3184 *pcGlyphs = g;
3186 SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3187 SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
3188 SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
3190 for (i = 0; i < cChars; ++i)
3192 /* Special case for tabs and joiners. As control characters, ZWNJ
3193 * and ZWJ would in principle get handled by the corresponding
3194 * shaping functions. However, since ZWNJ and ZWJ can get merged
3195 * into adjoining runs during itemisation, these don't generally
3196 * get classified as Script_Control. */
3197 if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
3199 pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
3200 pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
3203 heap_free(rChars);
3205 else
3207 TRACE("no glyph translation\n");
3208 for (i = 0; i < cChars; i++)
3210 int idx = i;
3211 /* No mirroring done here */
3212 if (rtl) idx = cChars - 1 - i;
3213 pwOutGlyphs[i] = pwcChars[idx];
3215 if (!psa)
3216 continue;
3218 /* overwrite some basic control glyphs to blank */
3219 if (psa->fNoGlyphIndex)
3221 if (pwcChars[idx] == ZWSP || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3223 pwOutGlyphs[i] = 0x20;
3224 pOutGlyphProps[i].sva.fZeroWidth = 1;
3227 else if (psa->eScript == Script_Control || pwcChars[idx] == ZWSP
3228 || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3230 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
3231 pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)
3233 pwOutGlyphs[i] = ((ScriptCache *)*psc)->sfp.wgBlank;
3234 pOutGlyphProps[i].sva.fZeroWidth = 1;
3240 return S_OK;
3244 /***********************************************************************
3245 * ScriptShape (USP10.@)
3247 * Produce glyphs and visual attributes for a run.
3249 * PARAMS
3250 * hdc [I] Device context.
3251 * psc [I/O] Opaque pointer to a script cache.
3252 * pwcChars [I] Array of characters specifying the run.
3253 * cChars [I] Number of characters in pwcChars.
3254 * cMaxGlyphs [I] Length of pwOutGlyphs.
3255 * psa [I/O] Script analysis.
3256 * pwOutGlyphs [O] Array of glyphs.
3257 * pwLogClust [O] Array of logical cluster info.
3258 * psva [O] Array of visual attributes.
3259 * pcGlyphs [O] Number of glyphs returned.
3261 * RETURNS
3262 * Success: S_OK
3263 * Failure: Non-zero HRESULT value.
3265 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
3266 int cChars, int cMaxGlyphs,
3267 SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
3268 SCRIPT_VISATTR *psva, int *pcGlyphs)
3270 HRESULT hr;
3271 int i;
3272 SCRIPT_CHARPROP *charProps;
3273 SCRIPT_GLYPHPROP *glyphProps;
3275 if (!psva || !pcGlyphs) return E_INVALIDARG;
3276 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3278 charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
3279 if (!charProps) return E_OUTOFMEMORY;
3280 glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
3281 if (!glyphProps)
3283 heap_free(charProps);
3284 return E_OUTOFMEMORY;
3287 hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
3289 if (SUCCEEDED(hr))
3291 for (i = 0; i < *pcGlyphs; i++)
3292 psva[i] = glyphProps[i].sva;
3295 heap_free(charProps);
3296 heap_free(glyphProps);
3298 return hr;
3301 /***********************************************************************
3302 * ScriptPlaceOpenType (USP10.@)
3304 * Produce advance widths for a run.
3306 * PARAMS
3307 * hdc [I] Device context.
3308 * psc [I/O] Opaque pointer to a script cache.
3309 * psa [I/O] Script analysis.
3310 * tagScript [I] The OpenType tag for the Script
3311 * tagLangSys [I] The OpenType tag for the Language
3312 * rcRangeChars[I] Array of Character counts in each range
3313 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3314 * cRanges [I] Count of ranges
3315 * pwcChars [I] Array of characters specifying the run.
3316 * pwLogClust [I] Array of logical cluster info
3317 * pCharProps [I] Array of character property values
3318 * cChars [I] Number of characters in pwcChars.
3319 * pwGlyphs [I] Array of glyphs.
3320 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3321 * cGlyphs [I] Count of Glyphs
3322 * piAdvance [O] Array of advance widths.
3323 * pGoffset [O] Glyph offsets.
3324 * pABC [O] Combined ABC width.
3326 * RETURNS
3327 * Success: S_OK
3328 * Failure: Non-zero HRESULT value.
3331 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
3332 OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
3333 int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
3334 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3335 SCRIPT_CHARPROP *pCharProps, int cChars,
3336 const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
3337 int cGlyphs, int *piAdvance,
3338 GOFFSET *pGoffset, ABC *pABC
3341 HRESULT hr;
3342 int i;
3343 static int once = 0;
3345 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3346 hdc, psc, psa,
3347 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3348 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3349 pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
3350 pGoffset, pABC);
3352 if (!pGlyphProps) return E_INVALIDARG;
3353 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3354 if (!pGoffset) return E_FAIL;
3356 if (cRanges)
3357 if (!once++) FIXME("Ranges not supported yet\n");
3359 ((ScriptCache *)*psc)->userScript = tagScript;
3360 ((ScriptCache *)*psc)->userLang = tagLangSys;
3362 if (pABC) memset(pABC, 0, sizeof(ABC));
3363 for (i = 0; i < cGlyphs; i++)
3365 ABC abc;
3366 if (pGlyphProps[i].sva.fZeroWidth)
3368 abc.abcA = abc.abcB = abc.abcC = 0;
3370 else if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
3372 BOOL ret;
3373 if (!hdc) return E_PENDING;
3374 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
3376 if (psa->fNoGlyphIndex)
3377 ret = GetCharABCWidthsW(hdc, pwGlyphs[i], pwGlyphs[i], &abc);
3378 else
3379 ret = GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc);
3380 if (!ret) return S_FALSE;
3382 else
3384 INT width;
3385 if (psa->fNoGlyphIndex)
3386 ret = GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width);
3387 else
3388 ret = GetCharWidthI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &width);
3389 if (!ret) return S_FALSE;
3390 abc.abcB = width;
3391 abc.abcA = abc.abcC = 0;
3393 set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
3395 if (pABC)
3397 pABC->abcA += abc.abcA;
3398 pABC->abcB += abc.abcB;
3399 pABC->abcC += abc.abcC;
3401 /* FIXME: set to more reasonable values */
3402 pGoffset[i].du = pGoffset[i].dv = 0;
3403 if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
3406 SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset);
3408 if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
3409 return S_OK;
3412 /***********************************************************************
3413 * ScriptPlace (USP10.@)
3415 * Produce advance widths for a run.
3417 * PARAMS
3418 * hdc [I] Device context.
3419 * psc [I/O] Opaque pointer to a script cache.
3420 * pwGlyphs [I] Array of glyphs.
3421 * cGlyphs [I] Number of glyphs in pwGlyphs.
3422 * psva [I] Array of visual attributes.
3423 * psa [I/O] String analysis.
3424 * piAdvance [O] Array of advance widths.
3425 * pGoffset [O] Glyph offsets.
3426 * pABC [O] Combined ABC width.
3428 * RETURNS
3429 * Success: S_OK
3430 * Failure: Non-zero HRESULT value.
3432 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
3433 int cGlyphs, const SCRIPT_VISATTR *psva,
3434 SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
3436 HRESULT hr;
3437 SCRIPT_GLYPHPROP *glyphProps;
3438 int i;
3440 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
3441 piAdvance, pGoffset, pABC);
3443 if (!psva) return E_INVALIDARG;
3444 if (!pGoffset) return E_FAIL;
3446 glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
3447 if (!glyphProps) return E_OUTOFMEMORY;
3449 for (i = 0; i < cGlyphs; i++)
3450 glyphProps[i].sva = psva[i];
3452 hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
3454 heap_free(glyphProps);
3456 return hr;
3459 /***********************************************************************
3460 * ScriptGetCMap (USP10.@)
3462 * Retrieve glyph indices.
3464 * PARAMS
3465 * hdc [I] Device context.
3466 * psc [I/O] Opaque pointer to a script cache.
3467 * pwcInChars [I] Array of Unicode characters.
3468 * cChars [I] Number of characters in pwcInChars.
3469 * dwFlags [I] Flags.
3470 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3472 * RETURNS
3473 * Success: S_OK
3474 * Failure: Non-zero HRESULT value.
3476 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
3477 int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
3479 HRESULT hr;
3480 int i;
3482 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
3483 cChars, dwFlags, pwOutGlyphs);
3485 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3487 hr = S_OK;
3489 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3491 for (i = 0; i < cChars; i++)
3493 WCHAR inChar;
3494 if (dwFlags == SGCM_RTL)
3495 inChar = mirror_char(pwcInChars[i]);
3496 else
3497 inChar = pwcInChars[i];
3498 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
3500 WORD glyph;
3501 if (!hdc) return E_PENDING;
3502 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
3503 if (glyph == 0xffff)
3505 hr = S_FALSE;
3506 glyph = 0x0;
3508 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
3512 else
3514 TRACE("no glyph translation\n");
3515 for (i = 0; i < cChars; i++)
3517 WCHAR inChar;
3518 if (dwFlags == SGCM_RTL)
3519 inChar = mirror_char(pwcInChars[i]);
3520 else
3521 inChar = pwcInChars[i];
3522 pwOutGlyphs[i] = inChar;
3525 return hr;
3528 /***********************************************************************
3529 * ScriptTextOut (USP10.@)
3532 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
3533 const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
3534 int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
3535 const int *piJustify, const GOFFSET *pGoffset)
3537 HRESULT hr = S_OK;
3538 INT i, dir = 1;
3539 INT *lpDx;
3540 WORD *reordered_glyphs = (WORD *)pwGlyphs;
3542 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3543 hdc, psc, x, y, fuOptions, wine_dbgstr_rect(lprc), psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
3544 piAdvance, piJustify, pGoffset);
3546 if (!hdc || !psc) return E_INVALIDARG;
3547 if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
3549 fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
3550 fuOptions |= ETO_IGNORELANGUAGE;
3551 if (!psa->fNoGlyphIndex) /* Have Glyphs? */
3552 fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */
3554 lpDx = heap_alloc(cGlyphs * sizeof(INT) * 2);
3555 if (!lpDx) return E_OUTOFMEMORY;
3556 fuOptions |= ETO_PDY;
3558 if (psa->fRTL && psa->fLogicalOrder)
3560 reordered_glyphs = heap_alloc( cGlyphs * sizeof(WORD) );
3561 if (!reordered_glyphs)
3563 heap_free( lpDx );
3564 return E_OUTOFMEMORY;
3567 for (i = 0; i < cGlyphs; i++)
3568 reordered_glyphs[i] = pwGlyphs[cGlyphs - 1 - i];
3569 dir = -1;
3572 for (i = 0; i < cGlyphs; i++)
3574 int orig_index = (dir > 0) ? i : cGlyphs - 1 - i;
3575 lpDx[i * 2] = piAdvance[orig_index];
3576 lpDx[i * 2 + 1] = 0;
3578 if (pGoffset)
3580 if (i == 0)
3582 x += pGoffset[orig_index].du * dir;
3583 y += pGoffset[orig_index].dv;
3585 else
3587 lpDx[(i - 1) * 2] += pGoffset[orig_index].du * dir;
3588 lpDx[(i - 1) * 2 + 1] += pGoffset[orig_index].dv;
3590 lpDx[i * 2] -= pGoffset[orig_index].du * dir;
3591 lpDx[i * 2 + 1] -= pGoffset[orig_index].dv;
3595 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, reordered_glyphs, cGlyphs, lpDx))
3596 hr = S_FALSE;
3598 if (reordered_glyphs != pwGlyphs) heap_free( reordered_glyphs );
3599 heap_free(lpDx);
3601 return hr;
3604 /***********************************************************************
3605 * ScriptCacheGetHeight (USP10.@)
3607 * Retrieve the height of the font in the cache.
3609 * PARAMS
3610 * hdc [I] Device context.
3611 * psc [I/O] Opaque pointer to a script cache.
3612 * height [O] Receives font height.
3614 * RETURNS
3615 * Success: S_OK
3616 * Failure: Non-zero HRESULT value.
3618 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
3620 HRESULT hr;
3622 TRACE("(%p, %p, %p)\n", hdc, psc, height);
3624 if (!height) return E_INVALIDARG;
3625 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3627 *height = get_cache_height(psc);
3628 return S_OK;
3631 /***********************************************************************
3632 * ScriptGetGlyphABCWidth (USP10.@)
3634 * Retrieve the width of a glyph.
3636 * PARAMS
3637 * hdc [I] Device context.
3638 * psc [I/O] Opaque pointer to a script cache.
3639 * glyph [I] Glyph to retrieve the width for.
3640 * abc [O] ABC widths of the glyph.
3642 * RETURNS
3643 * Success: S_OK
3644 * Failure: Non-zero HRESULT value.
3646 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
3648 HRESULT hr;
3650 TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
3652 if (!abc) return E_INVALIDARG;
3653 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3655 if (!get_cache_glyph_widths(psc, glyph, abc))
3657 if (!hdc) return E_PENDING;
3658 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3660 if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
3662 else
3664 INT width;
3665 if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
3666 abc->abcB = width;
3667 abc->abcA = abc->abcC = 0;
3669 set_cache_glyph_widths(psc, glyph, abc);
3671 return S_OK;
3674 /***********************************************************************
3675 * ScriptLayout (USP10.@)
3677 * Map embedding levels to visual and/or logical order.
3679 * PARAMS
3680 * runs [I] Size of level array.
3681 * level [I] Array of embedding levels.
3682 * vistolog [O] Map of embedding levels from visual to logical order.
3683 * logtovis [O] Map of embedding levels from logical to visual order.
3685 * RETURNS
3686 * Success: S_OK
3687 * Failure: Non-zero HRESULT value.
3690 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
3692 int* indexs;
3693 int ich;
3695 TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
3697 if (!level || (!vistolog && !logtovis))
3698 return E_INVALIDARG;
3700 indexs = heap_alloc(sizeof(int) * runs);
3701 if (!indexs)
3702 return E_OUTOFMEMORY;
3704 if (vistolog)
3706 for( ich = 0; ich < runs; ich++)
3707 indexs[ich] = ich;
3709 ich = 0;
3710 while (ich < runs)
3711 ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3712 memcpy(vistolog, indexs, runs * sizeof(*vistolog));
3715 if (logtovis)
3717 for( ich = 0; ich < runs; ich++)
3718 indexs[ich] = ich;
3720 ich = 0;
3721 while (ich < runs)
3722 ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3723 memcpy(logtovis, indexs, runs * sizeof(*logtovis));
3725 heap_free(indexs);
3727 return S_OK;
3730 /***********************************************************************
3731 * ScriptStringGetLogicalWidths (USP10.@)
3733 * Returns logical widths from a string analysis.
3735 * PARAMS
3736 * ssa [I] string analysis.
3737 * piDx [O] logical widths returned.
3739 * RETURNS
3740 * Success: S_OK
3741 * Failure: a non-zero HRESULT.
3743 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
3745 int i, j, next = 0;
3746 StringAnalysis *analysis = ssa;
3748 TRACE("%p, %p\n", ssa, piDx);
3750 if (!analysis) return S_FALSE;
3751 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3753 for (i = 0; i < analysis->numItems; i++)
3755 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
3756 int direction = 1;
3758 if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
3759 direction = -1;
3761 for (j = 0; j < cChar; j++)
3763 int k;
3764 int glyph = analysis->glyphs[i].pwLogClust[j];
3765 int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
3766 cChar, j, direction, NULL, NULL);
3767 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);
3769 for (k = 0; k < clust_size; k++)
3771 piDx[next] = advance / clust_size;
3772 next++;
3773 if (k) j++;
3777 return S_OK;
3780 /***********************************************************************
3781 * ScriptStringValidate (USP10.@)
3783 * Validate a string analysis.
3785 * PARAMS
3786 * ssa [I] string analysis.
3788 * RETURNS
3789 * Success: S_OK
3790 * Failure: S_FALSE if invalid sequences are found
3791 * or a non-zero HRESULT if it fails.
3793 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
3795 StringAnalysis *analysis = ssa;
3797 TRACE("(%p)\n", ssa);
3799 if (!analysis) return E_INVALIDARG;
3800 return analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID ? S_FALSE : S_OK;
3803 /***********************************************************************
3804 * ScriptString_pSize (USP10.@)
3806 * Retrieve width and height of an analysed string.
3808 * PARAMS
3809 * ssa [I] string analysis.
3811 * RETURNS
3812 * Success: Pointer to a SIZE structure.
3813 * Failure: NULL
3815 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
3817 int i, j;
3818 StringAnalysis *analysis = ssa;
3820 TRACE("(%p)\n", ssa);
3822 if (!analysis) return NULL;
3823 if (!(analysis->ssa_flags & SSA_GLYPHS)) return NULL;
3825 if (!(analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_SIZE))
3827 analysis->sz.cy = analysis->glyphs[0].sc->tm.tmHeight;
3829 analysis->sz.cx = 0;
3830 for (i = 0; i < analysis->numItems; i++)
3832 if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz.cy)
3833 analysis->sz.cy = analysis->glyphs[i].sc->tm.tmHeight;
3834 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3835 analysis->sz.cx += analysis->glyphs[i].piAdvance[j];
3838 return &analysis->sz;
3841 /***********************************************************************
3842 * ScriptString_pLogAttr (USP10.@)
3844 * Retrieve logical attributes of an analysed string.
3846 * PARAMS
3847 * ssa [I] string analysis.
3849 * RETURNS
3850 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3851 * Failure: NULL
3853 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
3855 StringAnalysis *analysis = ssa;
3857 TRACE("(%p)\n", ssa);
3859 if (!analysis) return NULL;
3860 if (!(analysis->ssa_flags & SSA_BREAK)) return NULL;
3861 return analysis->logattrs;
3864 /***********************************************************************
3865 * ScriptString_pcOutChars (USP10.@)
3867 * Retrieve the length of a string after clipping.
3869 * PARAMS
3870 * ssa [I] String analysis.
3872 * RETURNS
3873 * Success: Pointer to the length.
3874 * Failure: NULL
3876 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
3878 StringAnalysis *analysis = ssa;
3880 TRACE("(%p)\n", ssa);
3882 if (!analysis) return NULL;
3883 return &analysis->clip_len;
3886 /***********************************************************************
3887 * ScriptStringGetOrder (USP10.@)
3889 * Retrieve a glyph order map.
3891 * PARAMS
3892 * ssa [I] String analysis.
3893 * order [I/O] Array of glyph positions.
3895 * RETURNS
3896 * Success: S_OK
3897 * Failure: a non-zero HRESULT.
3899 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
3901 int i, j;
3902 unsigned int k;
3903 StringAnalysis *analysis = ssa;
3905 TRACE("(%p)\n", ssa);
3907 if (!analysis) return S_FALSE;
3908 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3910 /* FIXME: handle RTL scripts */
3911 for (i = 0, k = 0; i < analysis->numItems; i++)
3912 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3913 order[k] = k;
3915 return S_OK;
3918 /***********************************************************************
3919 * ScriptGetLogicalWidths (USP10.@)
3921 * Convert advance widths to logical widths.
3923 * PARAMS
3924 * sa [I] Script analysis.
3925 * nbchars [I] Number of characters.
3926 * nbglyphs [I] Number of glyphs.
3927 * glyph_width [I] Array of glyph widths.
3928 * log_clust [I] Array of logical clusters.
3929 * sva [I] Visual attributes.
3930 * widths [O] Array of logical widths.
3932 * RETURNS
3933 * Success: S_OK
3934 * Failure: a non-zero HRESULT.
3936 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3937 const int *advances, const WORD *log_clust,
3938 const SCRIPT_VISATTR *sva, int *widths)
3940 int i, next = 0, direction;
3942 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3943 sa, nbchars, nbglyphs, advances, log_clust, sva, widths);
3945 if (sa->fRTL && !sa->fLogicalOrder)
3946 direction = -1;
3947 else
3948 direction = 1;
3950 for (i = 0; i < nbchars; i++)
3952 int clust_size = get_cluster_size(log_clust, nbchars, i, direction, NULL, NULL);
3953 int advance = get_glyph_cluster_advance(advances, sva, log_clust, nbglyphs, nbchars, log_clust[i], direction);
3954 int j;
3956 for (j = 0; j < clust_size; j++)
3958 widths[next] = advance / clust_size;
3959 next++;
3960 if (j) i++;
3964 return S_OK;
3967 /***********************************************************************
3968 * ScriptApplyLogicalWidth (USP10.@)
3970 * Generate glyph advance widths.
3972 * PARAMS
3973 * dx [I] Array of logical advance widths.
3974 * num_chars [I] Number of characters.
3975 * num_glyphs [I] Number of glyphs.
3976 * log_clust [I] Array of logical clusters.
3977 * sva [I] Visual attributes.
3978 * advance [I] Array of glyph advance widths.
3979 * sa [I] Script analysis.
3980 * abc [I/O] Summed ABC widths.
3981 * justify [O] Array of glyph advance widths.
3983 * RETURNS
3984 * Success: S_OK
3985 * Failure: a non-zero HRESULT.
3987 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
3988 const WORD *log_clust, const SCRIPT_VISATTR *sva,
3989 const int *advance, const SCRIPT_ANALYSIS *sa,
3990 ABC *abc, int *justify)
3992 int i;
3994 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3995 dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
3997 for (i = 0; i < num_chars; i++) justify[i] = advance[i];
3998 return S_OK;
4001 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
4002 int num_glyphs, int dx, int min_kashida, int *justify)
4004 int i;
4006 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
4008 for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
4009 return S_OK;
4012 HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
4014 HRESULT hr;
4015 if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4016 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4018 return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
4021 HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
4023 HRESULT hr;
4024 if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4025 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4027 return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
4030 HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
4032 HRESULT hr;
4033 if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4034 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4036 return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);