gdiplus: Support GdipSetClipRegion in metafiles.
[wine.git] / dlls / usp10 / usp10.c
bloba6309ed3537f868b64ce40ce8b6d350d38f7207a
1 /*
2 * Implementation of Uniscribe Script Processor (usp10.dll)
4 * Copyright 2005 Steven Edwards for CodeWeavers
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Notes:
23 * Uniscribe allows for processing of complex scripts such as joining
24 * and filtering characters and bi-directional text with custom line breaks.
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <math.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winnls.h"
36 #include "winreg.h"
37 #include "usp10.h"
39 #include "usp10_internal.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
46 static const struct usp10_script_range
48 enum usp10_script script;
49 DWORD rangeFirst;
50 DWORD rangeLast;
51 enum usp10_script numericScript;
52 enum usp10_script punctScript;
54 script_ranges[] =
56 /* Basic Latin: U+0000–U+007A */
57 { Script_Latin, 0x00, 0x07a , Script_Numeric, Script_Punctuation},
58 /* Latin-1 Supplement: U+0080–U+00FF */
59 /* Latin Extended-A: U+0100–U+017F */
60 /* Latin Extended-B: U+0180–U+024F */
61 /* IPA Extensions: U+0250–U+02AF */
62 /* Spacing Modifier Letters:U+02B0–U+02FF */
63 { Script_Latin, 0x80, 0x2ff , Script_Numeric2, Script_Punctuation},
64 /* Combining Diacritical Marks : U+0300–U+036F */
65 { Script_Diacritical,0x300, 0x36f, 0, 0},
66 /* Greek: U+0370–U+03FF */
67 { Script_Greek, 0x370, 0x3ff, 0, 0},
68 /* Cyrillic: U+0400–U+04FF */
69 /* Cyrillic Supplement: U+0500–U+052F */
70 { Script_Cyrillic, 0x400, 0x52f, 0, 0},
71 /* Armenian: U+0530–U+058F */
72 { Script_Armenian, 0x530, 0x58f, 0, 0},
73 /* Hebrew: U+0590–U+05FF */
74 { Script_Hebrew, 0x590, 0x5ff, 0, 0},
75 /* Arabic: U+0600–U+06FF */
76 { Script_Arabic, 0x600, 0x6ef, Script_Arabic_Numeric, 0},
77 /* Defined by Windows */
78 { Script_Persian, 0x6f0, 0x6f9, 0, 0},
79 /* Continue Arabic: U+0600–U+06FF */
80 { Script_Arabic, 0x6fa, 0x6ff, 0, 0},
81 /* Syriac: U+0700–U+074F*/
82 { Script_Syriac, 0x700, 0x74f, 0, 0},
83 /* Arabic Supplement: U+0750–U+077F */
84 { Script_Arabic, 0x750, 0x77f, 0, 0},
85 /* Thaana: U+0780–U+07BF */
86 { Script_Thaana, 0x780, 0x7bf, 0, 0},
87 /* N’Ko: U+07C0–U+07FF */
88 { Script_NKo, 0x7c0, 0x7ff, 0, 0},
89 /* Devanagari: U+0900–U+097F */
90 { Script_Devanagari, 0x900, 0x97f, Script_Devanagari_Numeric, 0},
91 /* Bengali: U+0980–U+09FF */
92 { Script_Bengali, 0x980, 0x9ff, Script_Bengali_Numeric, 0},
93 /* Gurmukhi: U+0A00–U+0A7F*/
94 { Script_Gurmukhi, 0xa00, 0xa7f, Script_Gurmukhi_Numeric, 0},
95 /* Gujarati: U+0A80–U+0AFF*/
96 { Script_Gujarati, 0xa80, 0xaff, Script_Gujarati_Numeric, 0},
97 /* Oriya: U+0B00–U+0B7F */
98 { Script_Oriya, 0xb00, 0xb7f, Script_Oriya_Numeric, 0},
99 /* Tamil: U+0B80–U+0BFF */
100 { Script_Tamil, 0xb80, 0xbff, Script_Tamil_Numeric, 0},
101 /* Telugu: U+0C00–U+0C7F */
102 { Script_Telugu, 0xc00, 0xc7f, Script_Telugu_Numeric, 0},
103 /* Kannada: U+0C80–U+0CFF */
104 { Script_Kannada, 0xc80, 0xcff, Script_Kannada_Numeric, 0},
105 /* Malayalam: U+0D00–U+0D7F */
106 { Script_Malayalam, 0xd00, 0xd7f, Script_Malayalam_Numeric, 0},
107 /* Sinhala: U+0D80–U+0DFF */
108 { Script_Sinhala, 0xd80, 0xdff, 0, 0},
109 /* Thai: U+0E00–U+0E7F */
110 { Script_Thai, 0xe00, 0xe7f, Script_Thai_Numeric, 0},
111 /* Lao: U+0E80–U+0EFF */
112 { Script_Lao, 0xe80, 0xeff, Script_Lao_Numeric, 0},
113 /* Tibetan: U+0F00–U+0FFF */
114 { Script_Tibetan, 0xf00, 0xfff, 0, 0},
115 /* Myanmar: U+1000–U+109F */
116 { Script_Myanmar, 0x1000, 0x109f, Script_Myanmar_Numeric, 0},
117 /* Georgian: U+10A0–U+10FF */
118 { Script_Georgian, 0x10a0, 0x10ff, 0, 0},
119 /* Hangul Jamo: U+1100–U+11FF */
120 { Script_Hangul, 0x1100, 0x11ff, 0, 0},
121 /* Ethiopic: U+1200–U+137F */
122 /* Ethiopic Extensions: U+1380–U+139F */
123 { Script_Ethiopic, 0x1200, 0x139f, 0, 0},
124 /* Cherokee: U+13A0–U+13FF */
125 { Script_Cherokee, 0x13a0, 0x13ff, 0, 0},
126 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
127 { Script_Canadian, 0x1400, 0x167f, 0, 0},
128 /* Ogham: U+1680–U+169F */
129 { Script_Ogham, 0x1680, 0x169f, 0, 0},
130 /* Runic: U+16A0–U+16F0 */
131 { Script_Runic, 0x16a0, 0x16f0, 0, 0},
132 /* Khmer: U+1780–U+17FF */
133 { Script_Khmer, 0x1780, 0x17ff, Script_Khmer_Numeric, 0},
134 /* Mongolian: U+1800–U+18AF */
135 { Script_Mongolian, 0x1800, 0x18af, Script_Mongolian_Numeric, 0},
136 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
137 { Script_Canadian, 0x18b0, 0x18ff, 0, 0},
138 /* Tai Le: U+1950–U+197F */
139 { Script_Tai_Le, 0x1950, 0x197f, 0, 0},
140 /* New Tai Lue: U+1980–U+19DF */
141 { Script_New_Tai_Lue,0x1980, 0x19df, Script_New_Tai_Lue_Numeric, 0},
142 /* Khmer Symbols: U+19E0–U+19FF */
143 { Script_Khmer, 0x19e0, 0x19ff, Script_Khmer_Numeric, 0},
144 /* Vedic Extensions: U+1CD0-U+1CFF */
145 { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
146 /* Phonetic Extensions: U+1D00–U+1DBF */
147 { Script_Latin, 0x1d00, 0x1dbf, 0, 0},
148 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
149 { Script_Diacritical,0x1dc0, 0x1dff, 0, 0},
150 /* Latin Extended Additional: U+1E00–U+1EFF */
151 { Script_Latin, 0x1e00, 0x1eff, 0, 0},
152 /* Greek Extended: U+1F00–U+1FFF */
153 { Script_Greek, 0x1f00, 0x1fff, 0, 0},
154 /* General Punctuation: U+2000 –U+206f */
155 { Script_Latin, 0x2000, 0x206f, 0, 0},
156 /* Superscripts and Subscripts : U+2070 –U+209f */
157 /* Currency Symbols : U+20a0 –U+20cf */
158 { Script_Numeric2, 0x2070, 0x2070, 0, 0},
159 { Script_Latin, 0x2071, 0x2073, 0, 0},
160 { Script_Numeric2, 0x2074, 0x2079, 0, 0},
161 { Script_Latin, 0x207a, 0x207f, 0, 0},
162 { Script_Numeric2, 0x2080, 0x2089, 0, 0},
163 { Script_Latin, 0x208a, 0x20cf, 0, 0},
164 /* Letterlike Symbols : U+2100 –U+214f */
165 /* Number Forms : U+2150 –U+218f */
166 /* Arrows : U+2190 –U+21ff */
167 /* Mathematical Operators : U+2200 –U+22ff */
168 /* Miscellaneous Technical : U+2300 –U+23ff */
169 /* Control Pictures : U+2400 –U+243f */
170 /* Optical Character Recognition : U+2440 –U+245f */
171 /* Enclosed Alphanumerics : U+2460 –U+24ff */
172 /* Box Drawing : U+2500 –U+25ff */
173 /* Block Elements : U+2580 –U+259f */
174 /* Geometric Shapes : U+25a0 –U+25ff */
175 /* Miscellaneous Symbols : U+2600 –U+26ff */
176 /* Dingbats : U+2700 –U+27bf */
177 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
178 /* Supplemental Arrows-A : U+27f0 –U+27ff */
179 { Script_Latin, 0x2100, 0x27ff, 0, 0},
180 /* Braille Patterns: U+2800–U+28FF */
181 { Script_Braille, 0x2800, 0x28ff, 0, 0},
182 /* Supplemental Arrows-B : U+2900 –U+297f */
183 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
184 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
185 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
186 { Script_Latin, 0x2900, 0x2bff, 0, 0},
187 /* Latin Extended-C: U+2C60–U+2C7F */
188 { Script_Latin, 0x2c60, 0x2c7f, 0, 0},
189 /* Georgian: U+2D00–U+2D2F */
190 { Script_Georgian, 0x2d00, 0x2d2f, 0, 0},
191 /* Tifinagh: U+2D30–U+2D7F */
192 { Script_Tifinagh, 0x2d30, 0x2d7f, 0, 0},
193 /* Ethiopic Extensions: U+2D80–U+2DDF */
194 { Script_Ethiopic, 0x2d80, 0x2ddf, 0, 0},
195 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
196 { Script_Cyrillic, 0x2de0, 0x2dff, 0, 0},
197 /* CJK Radicals Supplement: U+2E80–U+2EFF */
198 /* Kangxi Radicals: U+2F00–U+2FDF */
199 { Script_CJK_Han, 0x2e80, 0x2fdf, 0, 0},
200 /* Ideographic Description Characters: U+2FF0–U+2FFF */
201 { Script_Ideograph ,0x2ff0, 0x2fff, 0, 0},
202 /* CJK Symbols and Punctuation: U+3000–U+303F */
203 { Script_Ideograph ,0x3000, 0x3004, 0, 0},
204 { Script_CJK_Han ,0x3005, 0x3005, 0, 0},
205 { Script_Ideograph ,0x3006, 0x3006, 0, 0},
206 { Script_CJK_Han ,0x3007, 0x3007, 0, 0},
207 { Script_Ideograph ,0x3008, 0x3020, 0, 0},
208 { Script_CJK_Han ,0x3021, 0x3029, 0, 0},
209 { Script_Ideograph ,0x302a, 0x3030, 0, 0},
210 /* Kana Marks: */
211 { Script_Kana ,0x3031, 0x3035, 0, 0},
212 { Script_Ideograph ,0x3036, 0x3037, 0, 0},
213 { Script_CJK_Han ,0x3038, 0x303b, 0, 0},
214 { Script_Ideograph ,0x303c, 0x303f, 0, 0},
215 /* Hiragana: U+3040–U+309F */
216 /* Katakana: U+30A0–U+30FF */
217 { Script_Kana ,0x3040, 0x30ff, 0, 0},
218 /* Bopomofo: U+3100–U+312F */
219 { Script_Bopomofo ,0x3100, 0x312f, 0, 0},
220 /* Hangul Compatibility Jamo: U+3130–U+318F */
221 { Script_Hangul ,0x3130, 0x318f, 0, 0},
222 /* Kanbun: U+3190–U+319F */
223 { Script_Ideograph ,0x3190, 0x319f, 0, 0},
224 /* Bopomofo Extended: U+31A0–U+31BF */
225 { Script_Bopomofo ,0x31a0, 0x31bf, 0, 0},
226 /* CJK Strokes: U+31C0–U+31EF */
227 { Script_Ideograph ,0x31c0, 0x31ef, 0, 0},
228 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
229 { Script_Kana ,0x31f0, 0x31ff, 0, 0},
230 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
231 { Script_Hangul ,0x3200, 0x321f, 0, 0},
232 { Script_Ideograph ,0x3220, 0x325f, 0, 0},
233 { Script_Hangul ,0x3260, 0x327f, 0, 0},
234 { Script_Ideograph ,0x3280, 0x32ef, 0, 0},
235 { Script_Kana ,0x32d0, 0x31ff, 0, 0},
236 /* CJK Compatibility: U+3300–U+33FF*/
237 { Script_Kana ,0x3300, 0x3357, 0, 0},
238 { Script_Ideograph ,0x3358, 0x33ff, 0, 0},
239 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
240 { Script_CJK_Han ,0x3400, 0x4dbf, 0, 0},
241 /* CJK Unified Ideographs: U+4E00–U+9FFF */
242 { Script_CJK_Han ,0x4e00, 0x9fff, 0, 0},
243 /* Yi: U+A000–U+A4CF */
244 { Script_Yi ,0xa000, 0xa4cf, 0, 0},
245 /* Vai: U+A500–U+A63F */
246 { Script_Vai ,0xa500, 0xa63f, Script_Vai_Numeric, 0},
247 /* Cyrillic Extended-B: U+A640–U+A69F */
248 { Script_Cyrillic, 0xa640, 0xa69f, 0, 0},
249 /* Modifier Tone Letters: U+A700–U+A71F */
250 /* Latin Extended-D: U+A720–U+A7FF */
251 { Script_Latin, 0xa700, 0xa7ff, 0, 0},
252 /* Phags-pa: U+A840–U+A87F */
253 { Script_Phags_pa, 0xa840, 0xa87f, 0, 0},
254 /* Devanagari Extended: U+A8E0-U+A8FF */
255 { Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
256 /* Myanmar Extended-A: U+AA60–U+AA7F */
257 { Script_Myanmar, 0xaa60, 0xaa7f, Script_Myanmar_Numeric, 0},
258 /* Hangul Jamo Extended-A: U+A960–U+A97F */
259 { Script_Hangul, 0xa960, 0xa97f, 0, 0},
260 /* Hangul Syllables: U+AC00–U+D7A3 */
261 { Script_Hangul, 0xac00, 0xd7a3, 0, 0},
262 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
263 { Script_Hangul, 0xd7b0, 0xd7ff, 0, 0},
264 /* Surrogates Area: U+D800–U+DFFF */
265 { Script_Surrogates, 0xd800, 0xdbfe, 0, 0},
266 { Script_Private, 0xdbff, 0xdc00, 0, 0},
267 { Script_Surrogates, 0xdc01, 0xdfff, 0, 0},
268 /* Private Use Area: U+E000–U+F8FF */
269 { Script_Private, 0xe000, 0xf8ff, 0, 0},
270 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
271 { Script_CJK_Han ,0xf900, 0xfaff, 0, 0},
272 /* Latin Ligatures: U+FB00–U+FB06 */
273 { Script_Latin, 0xfb00, 0xfb06, 0, 0},
274 /* Armenian ligatures U+FB13..U+FB17 */
275 { Script_Armenian, 0xfb13, 0xfb17, 0, 0},
276 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
277 { Script_Hebrew, 0xfb1d, 0xfb4f, 0, 0},
278 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
279 { Script_Arabic, 0xfb50, 0xfdff, 0, 0},
280 /* Vertical Forms: U+FE10–U+FE1F */
281 /* Combining Half Marks: U+FE20–U+FE2F */
282 /* CJK Compatibility Forms: U+FE30–U+FE4F */
283 /* Small Form Variants: U+FE50–U+FE6F */
284 { Script_Ideograph ,0xfe10, 0xfe6f, 0, 0},
285 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
286 { Script_Arabic, 0xfe70, 0xfeff, 0, 0},
287 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
288 { Script_Ideograph ,0xff00, 0xff64, Script_Numeric2, 0},
289 { Script_Kana ,0xff65, 0xff9f, 0, 0},
290 { Script_Hangul ,0xffa0, 0xffdf, 0, 0},
291 { Script_Ideograph ,0xffe0, 0xffef, 0, 0},
292 /* Plane - 1 */
293 /* Deseret: U+10400–U+1044F */
294 { Script_Deseret, 0x10400, 0x1044F, 0, 0},
295 /* Osmanya: U+10480–U+104AF */
296 { Script_Osmanya, 0x10480, 0x104AF, Script_Osmanya_Numeric, 0},
297 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
298 { Script_MathAlpha, 0x1D400, 0x1D7FF, 0, 0},
301 /* this must be in order so that the index matches the Script value */
302 const scriptData scriptInformation[] = {
303 {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
304 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
305 0x00000000,
306 {0}},
307 {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
308 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
309 MS_MAKE_TAG('l','a','t','n'),
310 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
311 {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
312 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
313 0x00000000,
314 {0}},
315 {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
316 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
317 0x00000000,
318 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
319 {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
320 {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
321 0x00000000,
322 {0}},
323 {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
324 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
325 0x00000000,
326 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
327 {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
328 {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
329 MS_MAKE_TAG('a','r','a','b'),
330 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
331 {{Script_Arabic_Numeric, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
332 {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
333 MS_MAKE_TAG('a','r','a','b'),
334 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
335 {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
336 {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
337 MS_MAKE_TAG('h','e','b','r'),
338 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
339 {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
340 {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
341 MS_MAKE_TAG('s','y','r','c'),
342 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
343 {{Script_Persian, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
344 {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
345 MS_MAKE_TAG('a','r','a','b'),
346 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
347 {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
348 {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
349 MS_MAKE_TAG('t','h','a','a'),
350 {'M','V',' ','B','o','l','i',0}},
351 {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
352 {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
353 MS_MAKE_TAG('g','r','e','k'),
354 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
355 {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
356 {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
357 MS_MAKE_TAG('c','y','r','l'),
358 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
359 {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
360 {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
361 MS_MAKE_TAG('a','r','m','n'),
362 {'S','y','l','f','a','e','n',0}},
363 {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
364 {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
365 MS_MAKE_TAG('g','e','o','r'),
366 {'S','y','l','f','a','e','n',0}},
367 {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
368 {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
369 MS_MAKE_TAG('s','i','n','h'),
370 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
371 {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
372 {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
373 MS_MAKE_TAG('t','i','b','t'),
374 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
375 {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
376 {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
377 MS_MAKE_TAG('t','i','b','t'),
378 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
379 {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
380 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
381 MS_MAKE_TAG('p','h','a','g'),
382 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
383 {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
384 {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
385 MS_MAKE_TAG('t','h','a','i'),
386 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
387 {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
388 {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
389 MS_MAKE_TAG('t','h','a','i'),
390 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
391 {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
392 {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
393 MS_MAKE_TAG('l','a','o',' '),
394 {'D','o','k','C','h','a','m','p','a',0}},
395 {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
396 {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
397 MS_MAKE_TAG('l','a','o',' '),
398 {'D','o','k','C','h','a','m','p','a',0}},
399 {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
400 {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
401 MS_MAKE_TAG('d','e','v','a'),
402 {'M','a','n','g','a','l',0}},
403 {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
404 {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
405 MS_MAKE_TAG('d','e','v','a'),
406 {'M','a','n','g','a','l',0}},
407 {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
408 {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
409 MS_MAKE_TAG('b','e','n','g'),
410 {'V','r','i','n','d','a',0}},
411 {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
412 {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
413 MS_MAKE_TAG('b','e','n','g'),
414 {'V','r','i','n','d','a',0}},
415 {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
416 {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
417 MS_MAKE_TAG('b','e','n','g'),
418 {'V','r','i','n','d','a',0}},
419 {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
420 {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
421 MS_MAKE_TAG('g','u','r','u'),
422 {'R','a','a','v','i',0}},
423 {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
424 {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
425 MS_MAKE_TAG('g','u','r','u'),
426 {'R','a','a','v','i',0}},
427 {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
428 {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
429 MS_MAKE_TAG('g','u','j','r'),
430 {'S','h','r','u','t','i',0}},
431 {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
432 {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
433 MS_MAKE_TAG('g','u','j','r'),
434 {'S','h','r','u','t','i',0}},
435 {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
436 {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
437 MS_MAKE_TAG('g','u','j','r'),
438 {'S','h','r','u','t','i',0}},
439 {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
440 {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
441 MS_MAKE_TAG('o','r','y','a'),
442 {'K','a','l','i','n','g','a',0}},
443 {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
444 {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
445 MS_MAKE_TAG('o','r','y','a'),
446 {'K','a','l','i','n','g','a',0}},
447 {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
448 {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
449 MS_MAKE_TAG('t','a','m','l'),
450 {'L','a','t','h','a',0}},
451 {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
452 {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
453 MS_MAKE_TAG('t','a','m','l'),
454 {'L','a','t','h','a',0}},
455 {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
456 {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
457 MS_MAKE_TAG('t','e','l','u'),
458 {'G','a','u','t','a','m','i',0}},
459 {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
460 {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
461 MS_MAKE_TAG('t','e','l','u'),
462 {'G','a','u','t','a','m','i',0}},
463 {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
464 {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
465 MS_MAKE_TAG('k','n','d','a'),
466 {'T','u','n','g','a',0}},
467 {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
468 {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
469 MS_MAKE_TAG('k','n','d','a'),
470 {'T','u','n','g','a',0}},
471 {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
472 {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
473 MS_MAKE_TAG('m','l','y','m'),
474 {'K','a','r','t','i','k','a',0}},
475 {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
476 {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
477 MS_MAKE_TAG('m','l','y','m'),
478 {'K','a','r','t','i','k','a',0}},
479 {{Script_Diacritical, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
480 {LANG_ENGLISH, 0, 1, 0, 1, ANSI_CHARSET, 0, 0, 0, 0, 0, 1, 1, 0, 0},
481 0x00000000,
482 {0}},
483 {{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
484 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
485 MS_MAKE_TAG('l','a','t','n'),
486 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
487 {{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
488 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
489 0x00000000,
490 {0}},
491 {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
492 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
493 MS_MAKE_TAG('m','y','m','r'),
494 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
495 {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
496 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
497 MS_MAKE_TAG('m','y','m','r'),
498 {0}},
499 {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
500 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
501 MS_MAKE_TAG('t','a','l','e'),
502 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
503 {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
504 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
505 MS_MAKE_TAG('t','a','l','u'),
506 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
507 {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
508 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
509 MS_MAKE_TAG('t','a','l','u'),
510 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
511 {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
512 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
513 MS_MAKE_TAG('k','h','m','r'),
514 {'D','a','u','n','P','e','n','h',0}},
515 {{Script_Khmer_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
516 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
517 MS_MAKE_TAG('k','h','m','r'),
518 {'D','a','u','n','P','e','n','h',0}},
519 {{Script_CJK_Han, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
520 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
521 MS_MAKE_TAG('h','a','n','i'),
522 {0}},
523 {{Script_Ideograph, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
524 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
525 MS_MAKE_TAG('h','a','n','i'),
526 {0}},
527 {{Script_Bopomofo, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
528 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
529 MS_MAKE_TAG('b','o','p','o'),
530 {0}},
531 {{Script_Kana, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
532 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
533 MS_MAKE_TAG('k','a','n','a'),
534 {0}},
535 {{Script_Hangul, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
536 {LANG_KOREAN, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
537 MS_MAKE_TAG('h','a','n','g'),
538 {0}},
539 {{Script_Yi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
540 {LANG_ENGLISH, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
541 MS_MAKE_TAG('y','i',' ',' '),
542 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
543 {{Script_Ethiopic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
544 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
545 MS_MAKE_TAG('e','t','h','i'),
546 {'N','y','a','l','a',0}},
547 {{Script_Ethiopic_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
548 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
549 MS_MAKE_TAG('e','t','h','i'),
550 {'N','y','a','l','a',0}},
551 {{Script_Mongolian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
552 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
553 MS_MAKE_TAG('m','o','n','g'),
554 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
555 {{Script_Mongolian_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
556 {LANG_MONGOLIAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
557 MS_MAKE_TAG('m','o','n','g'),
558 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
559 {{Script_Tifinagh, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
560 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
561 MS_MAKE_TAG('t','f','n','g'),
562 {'E','b','r','i','m','a',0}},
563 {{Script_NKo, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
564 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
565 MS_MAKE_TAG('n','k','o',' '),
566 {'E','b','r','i','m','a',0}},
567 {{Script_Vai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
568 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
569 MS_MAKE_TAG('v','a','i',' '),
570 {'E','b','r','i','m','a',0}},
571 {{Script_Vai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
572 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
573 MS_MAKE_TAG('v','a','i',' '),
574 {'E','b','r','i','m','a',0}},
575 {{Script_Cherokee, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
576 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
577 MS_MAKE_TAG('c','h','e','r'),
578 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
579 {{Script_Canadian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
580 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
581 MS_MAKE_TAG('c','a','n','s'),
582 {'E','u','p','h','e','m','i','a',0}},
583 {{Script_Ogham, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
584 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
585 MS_MAKE_TAG('o','g','a','m'),
586 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
587 {{Script_Runic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
588 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
589 MS_MAKE_TAG('r','u','n','r'),
590 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
591 {{Script_Braille, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
592 {LANG_ENGLISH, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
593 MS_MAKE_TAG('b','r','a','i'),
594 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
595 {{Script_Surrogates, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
596 {LANG_ENGLISH, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
597 0x00000000,
598 {0}},
599 {{Script_Private, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
600 {0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 1, 0, 0, 0, 0, 1, 0, 0},
601 0x00000000,
602 {0}},
603 {{Script_Deseret, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
604 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
605 MS_MAKE_TAG('d','s','r','t'),
606 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
607 {{Script_Osmanya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
608 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
609 MS_MAKE_TAG('o','s','m','a'),
610 {'E','b','r','i','m','a',0}},
611 {{Script_Osmanya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
612 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
613 MS_MAKE_TAG('o','s','m','a'),
614 {'E','b','r','i','m','a',0}},
615 {{Script_MathAlpha, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
616 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
617 MS_MAKE_TAG('m','a','t','h'),
618 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
619 {{Script_Hebrew_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
620 {LANG_HEBREW, 0, 1, 0, 0, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
621 MS_MAKE_TAG('h','e','b','r'),
622 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
623 {{Script_Vietnamese_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
624 {LANG_VIETNAMESE, 0, 0, 0, 0, VIETNAMESE_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
625 MS_MAKE_TAG('l','a','t','n'),
626 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
627 {{Script_Thai_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
628 {LANG_THAI, 0, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
629 MS_MAKE_TAG('t','h','a','i'),
630 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
633 static const SCRIPT_PROPERTIES *script_props[] =
635 &scriptInformation[0].props, &scriptInformation[1].props,
636 &scriptInformation[2].props, &scriptInformation[3].props,
637 &scriptInformation[4].props, &scriptInformation[5].props,
638 &scriptInformation[6].props, &scriptInformation[7].props,
639 &scriptInformation[8].props, &scriptInformation[9].props,
640 &scriptInformation[10].props, &scriptInformation[11].props,
641 &scriptInformation[12].props, &scriptInformation[13].props,
642 &scriptInformation[14].props, &scriptInformation[15].props,
643 &scriptInformation[16].props, &scriptInformation[17].props,
644 &scriptInformation[18].props, &scriptInformation[19].props,
645 &scriptInformation[20].props, &scriptInformation[21].props,
646 &scriptInformation[22].props, &scriptInformation[23].props,
647 &scriptInformation[24].props, &scriptInformation[25].props,
648 &scriptInformation[26].props, &scriptInformation[27].props,
649 &scriptInformation[28].props, &scriptInformation[29].props,
650 &scriptInformation[30].props, &scriptInformation[31].props,
651 &scriptInformation[32].props, &scriptInformation[33].props,
652 &scriptInformation[34].props, &scriptInformation[35].props,
653 &scriptInformation[36].props, &scriptInformation[37].props,
654 &scriptInformation[38].props, &scriptInformation[39].props,
655 &scriptInformation[40].props, &scriptInformation[41].props,
656 &scriptInformation[42].props, &scriptInformation[43].props,
657 &scriptInformation[44].props, &scriptInformation[45].props,
658 &scriptInformation[46].props, &scriptInformation[47].props,
659 &scriptInformation[48].props, &scriptInformation[49].props,
660 &scriptInformation[50].props, &scriptInformation[51].props,
661 &scriptInformation[52].props, &scriptInformation[53].props,
662 &scriptInformation[54].props, &scriptInformation[55].props,
663 &scriptInformation[56].props, &scriptInformation[57].props,
664 &scriptInformation[58].props, &scriptInformation[59].props,
665 &scriptInformation[60].props, &scriptInformation[61].props,
666 &scriptInformation[62].props, &scriptInformation[63].props,
667 &scriptInformation[64].props, &scriptInformation[65].props,
668 &scriptInformation[66].props, &scriptInformation[67].props,
669 &scriptInformation[68].props, &scriptInformation[69].props,
670 &scriptInformation[70].props, &scriptInformation[71].props,
671 &scriptInformation[72].props, &scriptInformation[73].props,
672 &scriptInformation[74].props, &scriptInformation[75].props,
673 &scriptInformation[76].props, &scriptInformation[77].props,
674 &scriptInformation[78].props, &scriptInformation[79].props,
675 &scriptInformation[80].props, &scriptInformation[81].props
678 typedef struct {
679 ScriptCache *sc;
680 int numGlyphs;
681 WORD* glyphs;
682 WORD* pwLogClust;
683 int* piAdvance;
684 SCRIPT_VISATTR* psva;
685 GOFFSET* pGoffset;
686 ABC* abc;
687 int iMaxPosX;
688 HFONT fallbackFont;
689 } StringGlyphs;
691 typedef struct {
692 HDC hdc;
693 DWORD dwFlags;
694 BOOL invalid;
695 int clip_len;
696 int cItems;
697 int cMaxGlyphs;
698 SCRIPT_ITEM* pItem;
699 int numItems;
700 StringGlyphs* glyphs;
701 SCRIPT_LOGATTR* logattrs;
702 SIZE* sz;
703 int* logical2visual;
704 } StringAnalysis;
706 typedef struct {
707 BOOL ascending;
708 WORD target;
709 } FindGlyph_struct;
711 BOOL usp10_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
713 SIZE_T max_capacity, new_capacity;
714 void *new_elements;
716 if (count <= *capacity)
717 return TRUE;
719 max_capacity = ~(SIZE_T)0 / size;
720 if (count > max_capacity)
721 return FALSE;
723 new_capacity = max(1, *capacity);
724 while (new_capacity < count && new_capacity <= max_capacity / 2)
725 new_capacity *= 2;
726 if (new_capacity < count)
727 new_capacity = count;
729 if (!*elements)
730 new_elements = heap_alloc_zero(new_capacity * size);
731 else
732 new_elements = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *elements, new_capacity * size);
733 if (!new_elements)
734 return FALSE;
736 *elements = new_elements;
737 *capacity = new_capacity;
738 return TRUE;
741 /* TODO Fix font properties on Arabic locale */
742 static inline BOOL set_cache_font_properties(const HDC hdc, ScriptCache *sc)
744 if (!sc->sfnt)
746 sc->sfp.wgBlank = sc->tm.tmBreakChar;
747 sc->sfp.wgDefault = sc->tm.tmDefaultChar;
748 sc->sfp.wgInvalid = sc->sfp.wgBlank;
749 sc->sfp.wgKashida = 0xFFFF;
750 sc->sfp.iKashidaWidth = 0;
752 else
754 static const WCHAR chars[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
755 /* U+0020: numeric space
756 U+200B: zero width space
757 U+F71B: unknown char found by black box testing
758 U+0640: kashida */
759 WORD gi[4];
761 if (GetGlyphIndicesW(hdc, chars, 4, gi, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
763 if(gi[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
764 sc->sfp.wgBlank = gi[0];
765 else
766 sc->sfp.wgBlank = 0;
768 sc->sfp.wgDefault = 0;
770 if (gi[2] != 0xFFFF)
771 sc->sfp.wgInvalid = gi[2];
772 else if (gi[1] != 0xFFFF)
773 sc->sfp.wgInvalid = gi[1];
774 else if (gi[0] != 0xFFFF)
775 sc->sfp.wgInvalid = gi[0];
776 else
777 sc->sfp.wgInvalid = 0;
779 sc->sfp.wgKashida = gi[3];
781 sc->sfp.iKashidaWidth = 0; /* TODO */
783 else
784 return FALSE;
786 return TRUE;
789 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES *sfp, ScriptCache *sc)
791 sfp->wgBlank = sc->sfp.wgBlank;
792 sfp->wgDefault = sc->sfp.wgDefault;
793 sfp->wgInvalid = sc->sfp.wgInvalid;
794 sfp->wgKashida = sc->sfp.wgKashida;
795 sfp->iKashidaWidth = sc->sfp.iKashidaWidth;
798 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
800 return ((ScriptCache *)*psc)->tm.tmHeight;
803 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
805 return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
808 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
810 CacheGlyphPage *page = ((ScriptCache *)*psc)->page[c / 0x10000];
811 WORD *block;
813 if (!page) return 0;
814 block = page->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
815 if (!block) return 0;
816 return block[(c % 0x10000) & GLYPH_BLOCK_MASK];
819 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
821 CacheGlyphPage **page = &((ScriptCache *)*psc)->page[c / 0x10000];
822 WORD **block;
823 if (!*page && !(*page = heap_alloc_zero(sizeof(CacheGlyphPage)))) return 0;
825 block = &(*page)->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
826 if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
827 return ((*block)[(c % 0x10000) & GLYPH_BLOCK_MASK] = glyph);
830 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
832 static const ABC nil;
833 ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
835 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
836 memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
837 return TRUE;
840 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
842 ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
844 if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
845 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
846 return TRUE;
849 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
851 ScriptCache *sc;
852 int size;
854 if (!psc) return E_INVALIDARG;
855 if (*psc) return S_OK;
856 if (!hdc) return E_PENDING;
858 if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
859 if (!GetTextMetricsW(hdc, &sc->tm))
861 heap_free(sc);
862 return E_INVALIDARG;
864 size = GetOutlineTextMetricsW(hdc, 0, NULL);
865 if (size)
867 sc->otm = heap_alloc(size);
868 sc->otm->otmSize = size;
869 GetOutlineTextMetricsW(hdc, size, sc->otm);
871 if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
873 heap_free(sc);
874 return E_INVALIDARG;
876 sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
877 if (!set_cache_font_properties(hdc, sc))
879 heap_free(sc);
880 return E_INVALIDARG;
882 *psc = sc;
883 TRACE("<- %p\n", sc);
884 return S_OK;
887 static WCHAR mirror_char( WCHAR ch )
889 extern const WCHAR wine_mirror_map[] DECLSPEC_HIDDEN;
890 return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
893 static DWORD decode_surrogate_pair(const WCHAR *str, unsigned int index, unsigned int end)
895 if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
897 DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
898 TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
899 return ch;
901 return 0;
904 static int usp10_compare_script_range(const void *key, const void *value)
906 const struct usp10_script_range *range = value;
907 const DWORD *ch = key;
909 if (*ch < range->rangeFirst)
910 return -1;
911 if (*ch > range->rangeLast)
912 return 1;
913 return 0;
916 static enum usp10_script get_char_script(const WCHAR *str, unsigned int index,
917 unsigned int end, unsigned int *consumed)
919 static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
920 struct usp10_script_range *range;
921 WORD type = 0, type2 = 0;
922 DWORD ch;
924 *consumed = 1;
926 if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
927 return Script_CR;
929 /* These punctuation characters are separated out as Latin punctuation */
930 if (strchrW(latin_punc,str[index]))
931 return Script_Punctuation2;
933 /* These chars are itemized as Punctuation by Windows */
934 if (str[index] == 0x2212 || str[index] == 0x2044)
935 return Script_Punctuation;
937 /* Currency Symbols by Unicode point */
938 switch (str[index])
940 case 0x09f2:
941 case 0x09f3: return Script_Bengali_Currency;
942 case 0x0af1: return Script_Gujarati_Currency;
943 case 0x0e3f: return Script_Thai_Currency;
944 case 0x20aa: return Script_Hebrew_Currency;
945 case 0x20ab: return Script_Vietnamese_Currency;
946 case 0xfb29: return Script_Hebrew_Currency;
949 GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
950 GetStringTypeW(CT_CTYPE2, &str[index], 1, &type2);
952 if (type == 0)
953 return SCRIPT_UNDEFINED;
955 if (type & C1_CNTRL)
956 return Script_Control;
958 ch = decode_surrogate_pair(str, index, end);
959 if (ch)
960 *consumed = 2;
961 else
962 ch = str[index];
964 if (!(range = bsearch(&ch, script_ranges, ARRAY_SIZE(script_ranges),
965 sizeof(*script_ranges), usp10_compare_script_range)))
966 return Script_Undefined;
968 if (range->numericScript && (type & C1_DIGIT || type2 == C2_ARABICNUMBER))
969 return range->numericScript;
970 if (range->punctScript && type & C1_PUNCT)
971 return range->punctScript;
972 return range->script;
975 static int compare_FindGlyph(const void *a, const void* b)
977 const FindGlyph_struct *find = (FindGlyph_struct*)a;
978 const WORD *idx= (WORD*)b;
979 int rc = 0;
981 if ( find->target > *idx)
982 rc = 1;
983 else if (find->target < *idx)
984 rc = -1;
986 if (!find->ascending)
987 rc *= -1;
988 return rc;
991 int USP10_FindGlyphInLogClust(const WORD* pwLogClust, int cChars, WORD target)
993 FindGlyph_struct fgs;
994 WORD *ptr;
995 INT k;
997 if (pwLogClust[0] < pwLogClust[cChars-1])
998 fgs.ascending = TRUE;
999 else
1000 fgs.ascending = FALSE;
1002 fgs.target = target;
1003 ptr = bsearch(&fgs, pwLogClust, cChars, sizeof(WORD), compare_FindGlyph);
1005 if (!ptr)
1006 return -1;
1008 for (k = (ptr - pwLogClust)-1; k >= 0 && pwLogClust[k] == target; k--)
1010 k++;
1012 return k;
1015 /***********************************************************************
1016 * ScriptFreeCache (USP10.@)
1018 * Free a script cache.
1020 * PARAMS
1021 * psc [I/O] Script cache.
1023 * RETURNS
1024 * Success: S_OK
1025 * Failure: Non-zero HRESULT value.
1027 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
1029 TRACE("%p\n", psc);
1031 if (psc && *psc)
1033 unsigned int i;
1034 INT n;
1035 for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
1037 heap_free(((ScriptCache *)*psc)->widths[i]);
1039 for (i = 0; i < NUM_PAGES; i++)
1041 unsigned int j;
1042 if (((ScriptCache *)*psc)->page[i])
1043 for (j = 0; j < GLYPH_MAX / GLYPH_BLOCK_SIZE; j++)
1044 heap_free(((ScriptCache *)*psc)->page[i]->glyphs[j]);
1045 heap_free(((ScriptCache *)*psc)->page[i]);
1047 heap_free(((ScriptCache *)*psc)->GSUB_Table);
1048 heap_free(((ScriptCache *)*psc)->GDEF_Table);
1049 heap_free(((ScriptCache *)*psc)->CMAP_Table);
1050 heap_free(((ScriptCache *)*psc)->GPOS_Table);
1051 for (n = 0; n < ((ScriptCache *)*psc)->script_count; n++)
1053 int j;
1054 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].language_count; j++)
1056 int k;
1057 for (k = 0; k < ((ScriptCache *)*psc)->scripts[n].languages[j].feature_count; k++)
1058 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features[k].lookups);
1059 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features);
1061 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].default_language.feature_count; j++)
1062 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features[j].lookups);
1063 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features);
1064 heap_free(((ScriptCache *)*psc)->scripts[n].languages);
1066 heap_free(((ScriptCache *)*psc)->scripts);
1067 heap_free(((ScriptCache *)*psc)->otm);
1068 heap_free(*psc);
1069 *psc = NULL;
1071 return S_OK;
1074 /***********************************************************************
1075 * ScriptGetProperties (USP10.@)
1077 * Retrieve a list of script properties.
1079 * PARAMS
1080 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1081 * num [I] Pointer to the number of scripts.
1083 * RETURNS
1084 * Success: S_OK
1085 * Failure: Non-zero HRESULT value.
1087 * NOTES
1088 * Behaviour matches WinXP.
1090 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
1092 TRACE("(%p,%p)\n", props, num);
1094 if (!props && !num) return E_INVALIDARG;
1096 if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
1097 if (props) *props = script_props;
1099 return S_OK;
1102 /***********************************************************************
1103 * ScriptGetFontProperties (USP10.@)
1105 * Get information on special glyphs.
1107 * PARAMS
1108 * hdc [I] Device context.
1109 * psc [I/O] Opaque pointer to a script cache.
1110 * sfp [O] Font properties structure.
1112 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
1114 HRESULT hr;
1116 TRACE("%p,%p,%p\n", hdc, psc, sfp);
1118 if (!sfp) return E_INVALIDARG;
1119 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1121 if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
1122 return E_INVALIDARG;
1124 get_cache_font_properties(sfp, *psc);
1126 return S_OK;
1129 /***********************************************************************
1130 * ScriptRecordDigitSubstitution (USP10.@)
1132 * Record digit substitution settings for a given locale.
1134 * PARAMS
1135 * locale [I] Locale identifier.
1136 * sds [I] Structure to record substitution settings.
1138 * RETURNS
1139 * Success: S_OK
1140 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1142 * SEE ALSO
1143 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1145 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
1147 DWORD plgid, sub;
1149 TRACE("0x%x, %p\n", locale, sds);
1151 /* This implementation appears to be correct for all languages, but it's
1152 * not clear if sds->DigitSubstitute is ever set to anything except
1153 * CONTEXT or NONE in reality */
1155 if (!sds) return E_POINTER;
1157 locale = ConvertDefaultLocale(locale);
1159 if (!IsValidLocale(locale, LCID_INSTALLED))
1160 return E_INVALIDARG;
1162 plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
1163 sds->TraditionalDigitLanguage = plgid;
1165 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1166 sds->NationalDigitLanguage = plgid;
1167 else
1168 sds->NationalDigitLanguage = LANG_ENGLISH;
1170 if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
1171 (WCHAR *)&sub, sizeof(sub) / sizeof(WCHAR)))
1172 return E_INVALIDARG;
1174 switch (sub)
1176 case 0:
1177 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1178 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
1179 else
1180 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1181 break;
1182 case 1:
1183 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1184 break;
1185 case 2:
1186 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
1187 break;
1188 default:
1189 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
1190 break;
1193 sds->dwReserved = 0;
1194 return S_OK;
1197 /***********************************************************************
1198 * ScriptApplyDigitSubstitution (USP10.@)
1200 * Apply digit substitution settings.
1202 * PARAMS
1203 * sds [I] Structure with recorded substitution settings.
1204 * sc [I] Script control structure.
1205 * ss [I] Script state structure.
1207 * RETURNS
1208 * Success: S_OK
1209 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1211 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds,
1212 SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
1214 SCRIPT_DIGITSUBSTITUTE psds;
1216 TRACE("%p, %p, %p\n", sds, sc, ss);
1218 if (!sc || !ss) return E_POINTER;
1219 if (!sds)
1221 sds = &psds;
1222 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
1223 return E_INVALIDARG;
1226 sc->uDefaultLanguage = LANG_ENGLISH;
1227 sc->fContextDigits = 0;
1228 ss->fDigitSubstitute = 0;
1230 switch (sds->DigitSubstitute) {
1231 case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
1232 case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
1233 case SCRIPT_DIGITSUBSTITUTE_NONE:
1234 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
1235 return S_OK;
1236 default:
1237 return E_INVALIDARG;
1241 static inline BOOL is_indic(enum usp10_script script)
1243 return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
1246 static inline enum usp10_script base_indic(enum usp10_script script)
1248 switch (script)
1250 case Script_Devanagari:
1251 case Script_Devanagari_Numeric: return Script_Devanagari;
1252 case Script_Bengali:
1253 case Script_Bengali_Numeric:
1254 case Script_Bengali_Currency: return Script_Bengali;
1255 case Script_Gurmukhi:
1256 case Script_Gurmukhi_Numeric: return Script_Gurmukhi;
1257 case Script_Gujarati:
1258 case Script_Gujarati_Numeric:
1259 case Script_Gujarati_Currency: return Script_Gujarati;
1260 case Script_Oriya:
1261 case Script_Oriya_Numeric: return Script_Oriya;
1262 case Script_Tamil:
1263 case Script_Tamil_Numeric: return Script_Tamil;
1264 case Script_Telugu:
1265 case Script_Telugu_Numeric: return Script_Telugu;
1266 case Script_Kannada:
1267 case Script_Kannada_Numeric: return Script_Kannada;
1268 case Script_Malayalam:
1269 case Script_Malayalam_Numeric: return Script_Malayalam;
1270 default:
1271 return Script_Undefined;
1275 static BOOL script_is_numeric(enum usp10_script script)
1277 return scriptInformation[script].props.fNumeric;
1280 static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
1281 int cMaxItems, const SCRIPT_CONTROL *psControl,
1282 const SCRIPT_STATE *psState, SCRIPT_ITEM *pItems,
1283 OPENTYPE_TAG *pScriptTags, int *pcItems)
1286 #define Numeric_space 0x0020
1287 #define ZWSP 0x200B
1288 #define ZWNJ 0x200C
1289 #define ZWJ 0x200D
1291 enum usp10_script last_indic = Script_Undefined;
1292 int cnt = 0, index = 0, str = 0;
1293 enum usp10_script New_Script = -1;
1294 int i;
1295 WORD *levels = NULL;
1296 WORD *layout_levels = NULL;
1297 WORD *overrides = NULL;
1298 WORD *strength = NULL;
1299 enum usp10_script *scripts;
1300 WORD baselevel = 0;
1301 WORD baselayout = 0;
1302 BOOL new_run;
1303 WORD layoutRTL = 0;
1304 BOOL forceLevels = FALSE;
1305 unsigned int consumed = 0;
1306 HRESULT res = E_OUTOFMEMORY;
1308 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
1309 psControl, psState, pItems, pcItems);
1311 if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
1312 return E_INVALIDARG;
1314 if (!(scripts = heap_alloc(cInChars * sizeof(*scripts))))
1315 return E_OUTOFMEMORY;
1317 for (i = 0; i < cInChars; i++)
1319 if (!consumed)
1321 scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
1322 consumed --;
1324 else
1326 scripts[i] = scripts[i-1];
1327 consumed --;
1329 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1330 all Indic scripts */
1331 if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic != Script_Undefined)
1332 scripts[i] = last_indic;
1333 else if (is_indic(scripts[i]))
1334 last_indic = base_indic(scripts[i]);
1336 /* Some unicode points :
1337 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1338 (Left Right Embed U+202A - Left Right Override U+202D)
1339 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1340 will force us into bidi mode */
1341 if (!forceLevels && ((pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F) ||
1342 (pwcInChars[i] >= 0x202A && pwcInChars[i] <= 0x202E) ||
1343 (pwcInChars[i] >= 0x2066 && pwcInChars[i] <= 0x2069)))
1345 forceLevels = TRUE;
1347 /* Diacritical marks merge with other scripts */
1348 if (scripts[i] == Script_Diacritical)
1350 if (i > 0)
1352 if (pScriptTags)
1353 scripts[i] = scripts[i-1];
1354 else
1356 int j;
1357 BOOL asian = FALSE;
1358 enum usp10_script first_script = scripts[i-1];
1359 for (j = i-1; j >= 0 && scripts[j] == first_script && pwcInChars[j] != Numeric_space; j--)
1361 enum usp10_script original = scripts[j];
1362 if (original == Script_Ideograph || original == Script_Kana || original == Script_Yi || original == Script_CJK_Han || original == Script_Bopomofo)
1364 asian = TRUE;
1365 break;
1367 if (original != Script_MathAlpha && scriptInformation[scripts[j]].props.fComplex)
1368 break;
1369 scripts[j] = scripts[i];
1370 if (original == Script_Punctuation2)
1371 break;
1373 if (j >= 0 && (scriptInformation[scripts[j]].props.fComplex || asian))
1374 scripts[i] = scripts[j];
1380 for (i = 0; i < cInChars; i++)
1382 /* Joiners get merged preferencially right */
1383 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1385 int j;
1386 if (i+1 == cInChars)
1387 scripts[i] = scripts[i-1];
1388 else
1390 for (j = i+1; j < cInChars; j++)
1392 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1393 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1395 scripts[i] = scripts[j];
1396 break;
1403 if (psState && psControl)
1405 levels = heap_alloc_zero(cInChars * sizeof(WORD));
1406 if (!levels)
1407 goto nomemory;
1409 overrides = heap_alloc_zero(cInChars * sizeof(WORD));
1410 if (!overrides)
1411 goto nomemory;
1413 layout_levels = heap_alloc_zero(cInChars * sizeof(WORD));
1414 if (!layout_levels)
1415 goto nomemory;
1417 if (psState->fOverrideDirection)
1419 if (!forceLevels)
1421 SCRIPT_STATE s = *psState;
1422 s.fOverrideDirection = FALSE;
1423 BIDI_DetermineLevels(pwcInChars, cInChars, &s, psControl, layout_levels, overrides);
1424 if (odd(layout_levels[0]))
1425 forceLevels = TRUE;
1426 else for (i = 0; i < cInChars; i++)
1427 if (layout_levels[i]!=layout_levels[0])
1429 forceLevels = TRUE;
1430 break;
1434 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1436 else
1438 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1439 memcpy(layout_levels, levels, cInChars * sizeof(WORD));
1441 baselevel = levels[0];
1442 baselayout = layout_levels[0];
1443 for (i = 0; i < cInChars; i++)
1444 if (levels[i]!=levels[0])
1445 break;
1446 if (i >= cInChars && !odd(baselevel) && !odd(psState->uBidiLevel) && !forceLevels)
1448 heap_free(levels);
1449 heap_free(overrides);
1450 heap_free(layout_levels);
1451 overrides = NULL;
1452 levels = NULL;
1453 layout_levels = NULL;
1455 else
1457 static const WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1458 static const WCHAR repeatable_math_punc[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1460 strength = heap_alloc_zero(cInChars * sizeof(WORD));
1461 if (!strength)
1462 goto nomemory;
1463 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
1465 /* We currently mis-level leading Diacriticals */
1466 if (scripts[0] == Script_Diacritical)
1467 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
1469 levels[i] = odd(levels[i])?levels[i]+1:levels[i];
1470 strength[i] = BIDI_STRONG;
1473 /* Math punctuation bordered on both sides by numbers can be
1474 merged into the number */
1475 for (i = 0; i < cInChars; i++)
1477 if (i > 0 && i < cInChars-1 &&
1478 script_is_numeric(scripts[i-1]) &&
1479 strchrW(math_punc, pwcInChars[i]))
1481 if (script_is_numeric(scripts[i+1]))
1483 scripts[i] = scripts[i+1];
1484 levels[i] = levels[i-1];
1485 strength[i] = strength[i-1];
1486 i++;
1488 else if (strchrW(repeatable_math_punc, pwcInChars[i]))
1490 int j;
1491 for (j = i+1; j < cInChars; j++)
1493 if (script_is_numeric(scripts[j]))
1495 for(;i<j; i++)
1497 scripts[i] = scripts[j];
1498 levels[i] = levels[i-1];
1499 strength[i] = strength[i-1];
1502 else if (pwcInChars[i] != pwcInChars[j]) break;
1508 for (i = 0; i < cInChars; i++)
1510 /* Numerics at level 0 get bumped to level 2 */
1511 if (!overrides[i] && (levels[i] == 0 || (odd(psState->uBidiLevel)
1512 && levels[i] == psState->uBidiLevel + 1)) && script_is_numeric(scripts[i]))
1514 levels[i] = 2;
1517 /* Joiners get merged preferencially right */
1518 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1520 int j;
1521 if (i+1 == cInChars && levels[i-1] == levels[i])
1522 strength[i] = strength[i-1];
1523 else
1524 for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
1525 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1526 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1528 strength[i] = strength[j];
1529 break;
1533 if (psControl->fMergeNeutralItems)
1535 /* Merge the neutrals */
1536 for (i = 0; i < cInChars; i++)
1538 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1540 int j;
1541 for (j = i; j > 0; j--)
1543 if (levels[i] != levels[j])
1544 break;
1545 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1547 scripts[i] = scripts[j];
1548 strength[i] = strength[j];
1549 break;
1553 /* Try going the other way */
1554 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1556 int j;
1557 for (j = i; j < cInChars; j++)
1559 if (levels[i] != levels[j])
1560 break;
1561 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1563 scripts[i] = scripts[j];
1564 strength[i] = strength[j];
1565 break;
1574 while ((!levels || (levels && cnt+1 < cInChars && levels[cnt+1] == levels[0]))
1575 && (cnt < cInChars && pwcInChars[cnt] == Numeric_space))
1576 cnt++;
1578 if (cnt == cInChars) /* All Spaces */
1580 cnt = 0;
1581 New_Script = scripts[cnt];
1584 pItems[index].iCharPos = 0;
1585 pItems[index].a = scriptInformation[scripts[cnt]].a;
1586 if (pScriptTags)
1587 pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
1589 if (strength && strength[cnt] == BIDI_STRONG)
1590 str = strength[cnt];
1591 else if (strength)
1592 str = strength[0];
1594 cnt = 0;
1596 if (levels)
1598 if (strength[cnt] == BIDI_STRONG)
1599 layoutRTL = odd(layout_levels[cnt]);
1600 else
1601 layoutRTL = (psState->uBidiLevel || odd(layout_levels[cnt]));
1602 if (overrides)
1603 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1604 pItems[index].a.fRTL = odd(levels[cnt]);
1605 if (script_is_numeric(pItems[index].a.eScript))
1606 pItems[index].a.fLayoutRTL = layoutRTL;
1607 else
1608 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1609 pItems[index].a.s.uBidiLevel = levels[cnt];
1611 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1613 if (pItems[index].a.s.uBidiLevel != baselevel)
1614 pItems[index].a.s.fOverrideDirection = TRUE;
1615 layoutRTL = odd(baselayout);
1616 pItems[index].a.s.uBidiLevel = baselevel;
1617 pItems[index].a.fRTL = odd(baselevel);
1618 if (script_is_numeric(pItems[index].a.eScript))
1619 pItems[index].a.fLayoutRTL = odd(baselayout);
1620 else
1621 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1624 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1625 levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
1626 pItems[index].iCharPos);
1628 for (cnt=1; cnt < cInChars; cnt++)
1630 if(pwcInChars[cnt] != Numeric_space)
1631 New_Script = scripts[cnt];
1632 else if (levels)
1634 int j = 1;
1635 while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
1636 j++;
1637 if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
1638 New_Script = scripts[cnt+j];
1639 else
1640 New_Script = scripts[cnt];
1643 new_run = FALSE;
1644 /* merge space strengths*/
1645 if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
1646 str = BIDI_STRONG;
1648 if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
1649 str = BIDI_NEUTRAL;
1651 /* changes in level */
1652 if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
1654 TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
1655 new_run = TRUE;
1657 /* changes in strength */
1658 else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
1660 TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
1661 new_run = TRUE;
1663 /* changes in script */
1664 else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
1666 TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
1667 new_run = TRUE;
1670 if (!new_run && strength && str == BIDI_STRONG)
1672 layoutRTL = odd(layout_levels[cnt]);
1673 if (script_is_numeric(pItems[index].a.eScript))
1674 pItems[index].a.fLayoutRTL = layoutRTL;
1677 if (new_run)
1679 TRACE("New_Level = %i, New_Strength = %i, New_Script=%d, eScript=%d\n", levels?levels[cnt]:-1, strength?strength[cnt]:str, New_Script, pItems[index].a.eScript);
1681 index++;
1682 if (index+1 > cMaxItems)
1683 goto nomemory;
1685 if (strength)
1686 str = strength[cnt];
1688 pItems[index].iCharPos = cnt;
1689 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1691 pItems[index].a = scriptInformation[New_Script].a;
1692 if (pScriptTags)
1693 pScriptTags[index] = scriptInformation[New_Script].scriptTag;
1694 if (levels)
1696 if (overrides)
1697 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1698 if (layout_levels[cnt] == 0)
1699 layoutRTL = 0;
1700 else
1701 layoutRTL = (layoutRTL || odd(layout_levels[cnt]));
1702 pItems[index].a.fRTL = odd(levels[cnt]);
1703 if (script_is_numeric(pItems[index].a.eScript))
1704 pItems[index].a.fLayoutRTL = layoutRTL;
1705 else
1706 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1707 pItems[index].a.s.uBidiLevel = levels[cnt];
1709 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1711 if (pItems[index].a.s.uBidiLevel != baselevel)
1712 pItems[index].a.s.fOverrideDirection = TRUE;
1713 pItems[index].a.s.uBidiLevel = baselevel;
1714 pItems[index].a.fRTL = odd(baselevel);
1715 if (script_is_numeric(pItems[index].a.eScript))
1716 pItems[index].a.fLayoutRTL = layoutRTL;
1717 else
1718 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1721 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1725 /* While not strictly necessary according to the spec, make sure the n+1
1726 * item is set up to prevent random behaviour if the caller erroneously
1727 * checks the n+1 structure */
1728 index++;
1729 if (index + 1 > cMaxItems) goto nomemory;
1730 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1732 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1734 /* Set one SCRIPT_STATE item being returned */
1735 if (pcItems) *pcItems = index;
1737 /* Set SCRIPT_ITEM */
1738 pItems[index].iCharPos = cnt; /* the last item contains the ptr to the lastchar */
1739 res = S_OK;
1740 nomemory:
1741 heap_free(levels);
1742 heap_free(overrides);
1743 heap_free(layout_levels);
1744 heap_free(strength);
1745 heap_free(scripts);
1746 return res;
1749 /***********************************************************************
1750 * ScriptItemizeOpenType (USP10.@)
1752 * Split a Unicode string into shapeable parts.
1754 * PARAMS
1755 * pwcInChars [I] String to split.
1756 * cInChars [I] Number of characters in pwcInChars.
1757 * cMaxItems [I] Maximum number of items to return.
1758 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1759 * psState [I] Pointer to a SCRIPT_STATE structure.
1760 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1761 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1762 * pcItems [O] Number of script items returned.
1764 * RETURNS
1765 * Success: S_OK
1766 * Failure: Non-zero HRESULT value.
1768 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1769 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1770 SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
1772 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pScriptTags, pcItems);
1775 /***********************************************************************
1776 * ScriptItemize (USP10.@)
1778 * Split a Unicode string into shapeable parts.
1780 * PARAMS
1781 * pwcInChars [I] String to split.
1782 * cInChars [I] Number of characters in pwcInChars.
1783 * cMaxItems [I] Maximum number of items to return.
1784 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1785 * psState [I] Pointer to a SCRIPT_STATE structure.
1786 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1787 * pcItems [O] Number of script items returned.
1789 * RETURNS
1790 * Success: S_OK
1791 * Failure: Non-zero HRESULT value.
1793 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1794 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1795 SCRIPT_ITEM *pItems, int *pcItems)
1797 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, NULL, pcItems);
1800 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1802 int defWidth;
1803 int cTabStops=0;
1804 INT *lpTabPos = NULL;
1805 INT nTabOrg = 0;
1806 INT x = 0;
1808 if (pTabdef)
1809 lpTabPos = pTabdef->pTabStops;
1811 if (pTabdef && pTabdef->iTabOrigin)
1813 if (pTabdef->iScale)
1814 nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1815 else
1816 nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1819 if (pTabdef)
1820 cTabStops = pTabdef->cTabStops;
1822 if (cTabStops == 1)
1824 if (pTabdef->iScale)
1825 defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1826 else
1827 defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1828 cTabStops = 0;
1830 else
1832 if (pTabdef->iScale)
1833 defWidth = (32 * pTabdef->iScale) / 4;
1834 else
1835 defWidth = 8 * psc->tm.tmAveCharWidth;
1838 for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1840 int position = *lpTabPos;
1841 if (position < 0)
1842 position = -1 * position;
1843 if (pTabdef->iScale)
1844 position = (position * pTabdef->iScale) / 4;
1845 else
1846 position = position * psc->tm.tmAveCharWidth;
1848 if( nTabOrg + position > current_x)
1850 if( position >= 0)
1852 /* a left aligned tab */
1853 x = (nTabOrg + position) - current_x;
1854 break;
1856 else
1858 FIXME("Negative tabstop\n");
1859 break;
1863 if ((!cTabStops) && (defWidth > 0))
1864 x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1865 else if ((!cTabStops) && (defWidth < 0))
1866 FIXME("TODO: Negative defWidth\n");
1868 return x;
1871 /***********************************************************************
1872 * Helper function for ScriptStringAnalyse
1874 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1875 const WCHAR *pwcInChars, int cChars )
1877 /* FIXME: When to properly fallback is still a bit of a mystery */
1878 WORD *glyphs;
1880 if (psa->fNoGlyphIndex)
1881 return FALSE;
1883 if (init_script_cache(hdc, psc) != S_OK)
1884 return FALSE;
1886 if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1887 return TRUE;
1889 glyphs = heap_alloc(sizeof(WORD) * cChars);
1890 if (!glyphs)
1891 return FALSE;
1892 if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1894 heap_free(glyphs);
1895 return TRUE;
1897 heap_free(glyphs);
1899 return FALSE;
1902 static void find_fallback_font(enum usp10_script scriptid, WCHAR *FaceName)
1904 HKEY hkey;
1906 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1908 static const WCHAR szFmt[] = {'%','x',0};
1909 WCHAR value[10];
1910 DWORD count = LF_FACESIZE * sizeof(WCHAR);
1911 DWORD type;
1913 sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1914 if (RegQueryValueExW(hkey, value, 0, &type, (BYTE *)FaceName, &count))
1915 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1916 RegCloseKey(hkey);
1918 else
1919 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1922 /***********************************************************************
1923 * ScriptStringAnalyse (USP10.@)
1926 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1927 int cGlyphs, int iCharset, DWORD dwFlags,
1928 int iReqWidth, SCRIPT_CONTROL *psControl,
1929 SCRIPT_STATE *psState, const int *piDx,
1930 SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1931 SCRIPT_STRING_ANALYSIS *pssa)
1933 HRESULT hr = E_OUTOFMEMORY;
1934 StringAnalysis *analysis = NULL;
1935 SCRIPT_CONTROL sControl;
1936 SCRIPT_STATE sState;
1937 int i, num_items = 255;
1938 BYTE *BidiLevel;
1939 WCHAR *iString = NULL;
1941 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1942 hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1943 psControl, psState, piDx, pTabdef, pbInClass, pssa);
1945 if (iCharset != -1)
1947 FIXME("Only Unicode strings are supported\n");
1948 return E_INVALIDARG;
1950 if (cString < 1 || !pString) return E_INVALIDARG;
1951 if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1953 if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1954 if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1956 /* FIXME: handle clipping */
1957 analysis->clip_len = cString;
1958 analysis->hdc = hdc;
1959 analysis->dwFlags = dwFlags;
1961 if (psState)
1962 sState = *psState;
1963 else
1964 memset(&sState, 0, sizeof(SCRIPT_STATE));
1966 if (psControl)
1967 sControl = *psControl;
1968 else
1969 memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1971 if (dwFlags & SSA_PASSWORD)
1973 iString = heap_alloc(sizeof(WCHAR)*cString);
1974 if (!iString)
1976 hr = E_OUTOFMEMORY;
1977 goto error;
1979 for (i = 0; i < cString; i++)
1980 iString[i] = *((const WCHAR *)pString);
1981 pString = iString;
1984 hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1985 &analysis->numItems);
1987 if (FAILED(hr))
1989 if (hr == E_OUTOFMEMORY)
1990 hr = E_INVALIDARG;
1991 goto error;
1994 /* set back to out of memory for default goto error behaviour */
1995 hr = E_OUTOFMEMORY;
1997 if (dwFlags & SSA_BREAK)
1999 if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
2001 for (i = 0; i < analysis->numItems; i++)
2002 ScriptBreak(&((WCHAR *)pString)[analysis->pItem[i].iCharPos],
2003 analysis->pItem[i + 1].iCharPos - analysis->pItem[i].iCharPos,
2004 &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
2006 else
2007 goto error;
2010 if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
2011 goto error;
2012 if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
2013 goto error;
2015 if (dwFlags & SSA_GLYPHS)
2017 int tab_x = 0;
2018 if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
2020 heap_free(BidiLevel);
2021 goto error;
2024 for (i = 0; i < analysis->numItems; i++)
2026 SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
2027 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2028 int numGlyphs = 1.5 * cChar + 16;
2029 WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
2030 WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
2031 int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
2032 SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
2033 GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
2034 ABC *abc = heap_alloc_zero(sizeof(ABC));
2035 int numGlyphsReturned;
2036 HFONT originalFont = 0x0;
2038 /* FIXME: non unicode strings */
2039 const WCHAR* pStr = (const WCHAR*)pString;
2040 analysis->glyphs[i].fallbackFont = NULL;
2042 if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
2044 heap_free (BidiLevel);
2045 heap_free (glyphs);
2046 heap_free (pwLogClust);
2047 heap_free (piAdvance);
2048 heap_free (psva);
2049 heap_free (pGoffset);
2050 heap_free (abc);
2051 hr = E_OUTOFMEMORY;
2052 goto error;
2055 if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
2057 LOGFONTW lf;
2058 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
2059 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
2060 lf.lfFaceName[0] = 0;
2061 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
2062 if (lf.lfFaceName[0])
2064 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
2065 if (analysis->glyphs[i].fallbackFont)
2067 ScriptFreeCache(sc);
2068 originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
2073 /* FIXME: When we properly shape Hangul remove this check */
2074 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && analysis->pItem[i].a.eScript == Script_Hangul)
2075 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2077 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && !scriptInformation[analysis->pItem[i].a.eScript].props.fComplex && !analysis->pItem[i].a.fRTL)
2078 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2080 ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos], cChar, numGlyphs,
2081 &analysis->pItem[i].a, glyphs, pwLogClust, psva, &numGlyphsReturned);
2082 hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
2083 piAdvance, pGoffset, abc);
2084 if (originalFont)
2085 SelectObject(hdc,originalFont);
2087 if (dwFlags & SSA_TAB)
2089 int tabi = 0;
2090 for (tabi = 0; tabi < cChar; tabi++)
2092 if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
2093 piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
2094 tab_x+=piAdvance[tabi];
2098 analysis->glyphs[i].numGlyphs = numGlyphsReturned;
2099 analysis->glyphs[i].glyphs = glyphs;
2100 analysis->glyphs[i].pwLogClust = pwLogClust;
2101 analysis->glyphs[i].piAdvance = piAdvance;
2102 analysis->glyphs[i].psva = psva;
2103 analysis->glyphs[i].pGoffset = pGoffset;
2104 analysis->glyphs[i].abc = abc;
2105 analysis->glyphs[i].iMaxPosX= -1;
2107 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2110 else
2112 for (i = 0; i < analysis->numItems; i++)
2113 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2116 ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
2117 heap_free(BidiLevel);
2119 *pssa = analysis;
2120 heap_free(iString);
2121 return S_OK;
2123 error:
2124 heap_free(iString);
2125 heap_free(analysis->glyphs);
2126 heap_free(analysis->logattrs);
2127 heap_free(analysis->pItem);
2128 heap_free(analysis->logical2visual);
2129 heap_free(analysis);
2130 return hr;
2133 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
2135 if (pva[glyph].fClusterStart)
2136 return TRUE;
2137 if (USP10_FindGlyphInLogClust(pwLogClust, cChars, glyph) >= 0)
2138 return TRUE;
2140 return FALSE;
2144 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
2145 int iX,
2146 int iY,
2147 int iItem,
2148 int cStart,
2149 int cEnd,
2150 UINT uOptions,
2151 const RECT *prc,
2152 BOOL fSelected,
2153 BOOL fDisabled)
2155 StringAnalysis *analysis;
2156 int off_x = 0;
2157 HRESULT hr;
2158 COLORREF BkColor = 0x0;
2159 COLORREF TextColor = 0x0;
2160 INT BkMode = 0;
2161 INT runStart, runEnd;
2162 INT iGlyph, cGlyphs;
2163 HFONT oldFont = 0x0;
2164 RECT crc;
2165 int i;
2167 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2168 ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
2170 if (!(analysis = ssa)) return E_INVALIDARG;
2172 if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
2173 (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
2174 return S_OK;
2176 CopyRect(&crc,prc);
2177 if (fSelected)
2179 BkMode = GetBkMode(analysis->hdc);
2180 SetBkMode( analysis->hdc, OPAQUE);
2181 BkColor = GetBkColor(analysis->hdc);
2182 SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
2183 if (!fDisabled)
2185 TextColor = GetTextColor(analysis->hdc);
2186 SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2189 if (analysis->glyphs[iItem].fallbackFont)
2190 oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
2192 if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
2193 runStart = cStart - analysis->pItem[iItem].iCharPos;
2194 else
2195 runStart = 0;
2196 if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
2197 runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
2198 else
2199 runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
2201 if (analysis->pItem[iItem].a.fRTL)
2203 if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
2204 ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
2205 else
2206 ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
2207 crc.left = iX + off_x;
2209 else
2211 if (cStart >=0 && runStart)
2212 ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
2213 else
2214 ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
2215 crc.left = iX + off_x;
2218 if (analysis->pItem[iItem].a.fRTL)
2219 iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
2220 else
2221 iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
2223 if (analysis->pItem[iItem].a.fRTL)
2224 cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
2225 else
2226 cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
2228 cGlyphs++;
2230 /* adjust for cluster glyphs when starting */
2231 if (analysis->pItem[iItem].a.fRTL)
2232 i = analysis->pItem[iItem+1].iCharPos - 1;
2233 else
2234 i = analysis->pItem[iItem].iCharPos;
2236 for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
2238 if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
2240 if (analysis->pItem[iItem].a.fRTL)
2241 ScriptStringCPtoX(ssa, i, TRUE, &off_x);
2242 else
2243 ScriptStringCPtoX(ssa, i, FALSE, &off_x);
2244 break;
2248 if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
2250 INT direction;
2251 INT clust_glyph;
2253 clust_glyph = iGlyph + cGlyphs;
2254 if (analysis->pItem[iItem].a.fRTL)
2255 direction = -1;
2256 else
2257 direction = 1;
2259 while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
2260 !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
2262 cGlyphs++;
2263 clust_glyph++;
2267 hr = ScriptTextOut(analysis->hdc,
2268 (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
2269 iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
2270 &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
2271 &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
2272 &analysis->glyphs[iItem].pGoffset[iGlyph]);
2274 TRACE("ScriptTextOut hr=%08x\n", hr);
2276 if (fSelected)
2278 SetBkColor(analysis->hdc, BkColor);
2279 SetBkMode( analysis->hdc, BkMode);
2280 if (!fDisabled)
2281 SetTextColor(analysis->hdc, TextColor);
2283 if (analysis->glyphs[iItem].fallbackFont)
2284 SelectObject(analysis->hdc, oldFont);
2286 return hr;
2289 /***********************************************************************
2290 * ScriptStringOut (USP10.@)
2292 * This function takes the output of ScriptStringAnalyse and joins the segments
2293 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2294 * only processes glyphs.
2296 * Parameters:
2297 * ssa [I] buffer to hold the analysed string components
2298 * iX [I] X axis displacement for output
2299 * iY [I] Y axis displacement for output
2300 * uOptions [I] flags controlling output processing
2301 * prc [I] rectangle coordinates
2302 * iMinSel [I] starting pos for substringing output string
2303 * iMaxSel [I] ending pos for substringing output string
2304 * fDisabled [I] controls text highlighting
2306 * RETURNS
2307 * Success: S_OK
2308 * Failure: is the value returned by ScriptTextOut
2310 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
2311 int iX,
2312 int iY,
2313 UINT uOptions,
2314 const RECT *prc,
2315 int iMinSel,
2316 int iMaxSel,
2317 BOOL fDisabled)
2319 StringAnalysis *analysis;
2320 int item;
2321 HRESULT hr;
2323 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2324 ssa, iX, iY, uOptions, wine_dbgstr_rect(prc), iMinSel, iMaxSel, fDisabled);
2326 if (!(analysis = ssa)) return E_INVALIDARG;
2327 if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
2329 for (item = 0; item < analysis->numItems; item++)
2331 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
2332 if (FAILED(hr))
2333 return hr;
2336 if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
2338 if (iMaxSel > 0 && iMinSel < 0)
2339 iMinSel = 0;
2340 for (item = 0; item < analysis->numItems; item++)
2342 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
2343 if (FAILED(hr))
2344 return hr;
2348 return S_OK;
2351 /***********************************************************************
2352 * ScriptStringCPtoX (USP10.@)
2355 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
2357 int item;
2358 int runningX = 0;
2359 StringAnalysis* analysis = ssa;
2361 TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
2363 if (!ssa || !pX) return S_FALSE;
2364 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2366 /* icp out of range */
2367 if(icp < 0)
2369 analysis->invalid = TRUE;
2370 return E_INVALIDARG;
2373 for(item=0; item<analysis->numItems; item++)
2375 int CP, i;
2376 int offset;
2378 i = analysis->logical2visual[item];
2379 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2380 /* initialize max extents for uninitialized runs */
2381 if (analysis->glyphs[i].iMaxPosX == -1)
2383 if (analysis->pItem[i].a.fRTL)
2384 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2385 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2386 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2387 else
2388 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2389 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2390 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2393 if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
2395 runningX += analysis->glyphs[i].iMaxPosX;
2396 continue;
2399 icp -= analysis->pItem[i].iCharPos;
2400 ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2401 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2402 &analysis->pItem[i].a, &offset);
2403 runningX += offset;
2405 *pX = runningX;
2406 return S_OK;
2409 /* icp out of range */
2410 analysis->invalid = TRUE;
2411 return E_INVALIDARG;
2414 /***********************************************************************
2415 * ScriptStringXtoCP (USP10.@)
2418 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
2420 StringAnalysis* analysis = ssa;
2421 int item;
2423 TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
2425 if (!ssa || !piCh || !piTrailing) return S_FALSE;
2426 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2428 /* out of range */
2429 if(iX < 0)
2431 if (analysis->pItem[0].a.fRTL)
2433 *piCh = 1;
2434 *piTrailing = FALSE;
2436 else
2438 *piCh = -1;
2439 *piTrailing = TRUE;
2441 return S_OK;
2444 for(item=0; item<analysis->numItems; item++)
2446 int i;
2447 int CP;
2449 for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
2450 /* nothing */;
2452 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2453 /* initialize max extents for uninitialized runs */
2454 if (analysis->glyphs[i].iMaxPosX == -1)
2456 if (analysis->pItem[i].a.fRTL)
2457 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2458 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2459 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2460 else
2461 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2462 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2463 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2466 if (iX > analysis->glyphs[i].iMaxPosX)
2468 iX -= analysis->glyphs[i].iMaxPosX;
2469 continue;
2472 ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2473 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2474 &analysis->pItem[i].a, piCh, piTrailing);
2475 *piCh += analysis->pItem[i].iCharPos;
2477 return S_OK;
2480 /* out of range */
2481 *piCh = analysis->pItem[analysis->numItems].iCharPos;
2482 *piTrailing = FALSE;
2484 return S_OK;
2488 /***********************************************************************
2489 * ScriptStringFree (USP10.@)
2491 * Free a string analysis.
2493 * PARAMS
2494 * pssa [I] string analysis.
2496 * RETURNS
2497 * Success: S_OK
2498 * Failure: Non-zero HRESULT value.
2500 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
2502 StringAnalysis* analysis;
2503 BOOL invalid;
2504 int i;
2506 TRACE("(%p)\n", pssa);
2508 if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
2510 invalid = analysis->invalid;
2512 if (analysis->glyphs)
2514 for (i = 0; i < analysis->numItems; i++)
2516 heap_free(analysis->glyphs[i].glyphs);
2517 heap_free(analysis->glyphs[i].pwLogClust);
2518 heap_free(analysis->glyphs[i].piAdvance);
2519 heap_free(analysis->glyphs[i].psva);
2520 heap_free(analysis->glyphs[i].pGoffset);
2521 heap_free(analysis->glyphs[i].abc);
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->sz);
2533 heap_free(analysis->logical2visual);
2534 heap_free(analysis);
2536 if (invalid) return E_INVALIDARG;
2537 return S_OK;
2540 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
2541 int direction, int* iCluster, int *check_out)
2543 int clust_size = 1;
2544 int check;
2545 WORD clust = pwLogClust[item];
2547 for (check = item+direction; check < cChars && check >= 0; check+=direction)
2549 if (pwLogClust[check] == clust)
2551 clust_size ++;
2552 if (iCluster && *iCluster == -1)
2553 *iCluster = item;
2555 else break;
2558 if (check_out)
2559 *check_out = check;
2561 return clust_size;
2564 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)
2566 int advance;
2567 int log_clust_max;
2569 advance = piAdvance[glyph];
2571 if (pwLogClust[0] > pwLogClust[cChars-1])
2572 log_clust_max = pwLogClust[0];
2573 else
2574 log_clust_max = pwLogClust[cChars-1];
2576 if (glyph > log_clust_max)
2577 return advance;
2579 for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
2582 if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
2583 break;
2584 if (glyph > log_clust_max)
2585 break;
2586 advance += piAdvance[glyph];
2589 return advance;
2592 /***********************************************************************
2593 * ScriptCPtoX (USP10.@)
2596 HRESULT WINAPI ScriptCPtoX(int iCP,
2597 BOOL fTrailing,
2598 int cChars,
2599 int cGlyphs,
2600 const WORD *pwLogClust,
2601 const SCRIPT_VISATTR *psva,
2602 const int *piAdvance,
2603 const SCRIPT_ANALYSIS *psa,
2604 int *piX)
2606 int item;
2607 float iPosX;
2608 int iSpecial = -1;
2609 int iCluster = -1;
2610 int clust_size = 1;
2611 float special_size = 0.0;
2612 int iMaxPos = 0;
2613 int advance = 0;
2614 BOOL rtl = FALSE;
2616 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2617 iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2618 psa, piX);
2620 if (psa->fRTL && ! psa->fLogicalOrder)
2621 rtl = TRUE;
2623 if (fTrailing)
2624 iCP++;
2626 if (rtl)
2628 int max_clust = pwLogClust[0];
2630 for (item=0; item < cGlyphs; item++)
2631 if (pwLogClust[item] > max_clust)
2633 ERR("We do not handle non reversed clusters properly\n");
2634 break;
2637 iMaxPos = 0;
2638 for (item = max_clust; item >=0; item --)
2639 iMaxPos += piAdvance[item];
2642 iPosX = 0.0;
2643 for (item=0; item < iCP && item < cChars; item++)
2645 if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
2647 int check;
2648 int clust = pwLogClust[item];
2650 iCluster = -1;
2651 clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2652 &check);
2654 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2656 if (check >= cChars && !iMaxPos)
2658 int glyph;
2659 for (glyph = clust; glyph < cGlyphs; glyph++)
2660 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, glyph, 1);
2661 iSpecial = item;
2662 special_size /= (cChars - item);
2663 iPosX += special_size;
2665 else
2667 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2669 clust_size --;
2670 if (clust_size == 0)
2671 iPosX += advance;
2673 else
2674 iPosX += advance / (float)clust_size;
2677 else if (iSpecial != -1)
2678 iPosX += special_size;
2679 else /* (iCluster != -1) */
2681 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2682 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2684 clust_size --;
2685 if (clust_size == 0)
2686 iPosX += adv;
2688 else
2689 iPosX += adv / (float)clust_size;
2693 if (iMaxPos > 0)
2695 iPosX = iMaxPos - iPosX;
2696 if (iPosX < 0)
2697 iPosX = 0;
2700 *piX = iPosX;
2701 TRACE("*piX=%d\n", *piX);
2702 return S_OK;
2705 /* Count the number of characters in a cluster and its starting index*/
2706 static inline BOOL get_cluster_data(const WORD *pwLogClust, int cChars, int cluster_index, int *cluster_size, int *start_index)
2708 int size = 0;
2709 int i;
2711 for (i = 0; i < cChars; i++)
2713 if (pwLogClust[i] == cluster_index)
2715 if (!size && start_index)
2717 *start_index = i;
2718 if (!cluster_size)
2719 return TRUE;
2721 size++;
2723 else if (size) break;
2725 if (cluster_size)
2726 *cluster_size = size;
2728 return (size > 0);
2732 To handle multi-glyph clusters we need to find all the glyphs that are
2733 represented in the cluster. This involves finding the glyph whose
2734 index is the cluster index as well as whose glyph indices are greater than
2735 our cluster index but not part of a new cluster.
2737 Then we sum all those glyphs' advances.
2739 static inline int get_cluster_advance(const int* piAdvance,
2740 const SCRIPT_VISATTR *psva,
2741 const WORD *pwLogClust, int cGlyphs,
2742 int cChars, int cluster, int direction)
2744 int glyph_start;
2745 int glyph_end;
2746 int i, advance;
2748 if (direction > 0)
2749 i = 0;
2750 else
2751 i = (cChars - 1);
2753 for (glyph_start = -1, glyph_end = -1; i < cChars && i >= 0 && (glyph_start < 0 || glyph_end < 0); i+=direction)
2755 if (glyph_start < 0 && pwLogClust[i] != cluster) continue;
2756 if (pwLogClust[i] == cluster && glyph_start < 0) glyph_start = pwLogClust[i];
2757 if (glyph_start >= 0 && glyph_end < 0 && pwLogClust[i] != cluster) glyph_end = pwLogClust[i];
2759 if (glyph_end < 0)
2761 if (direction > 0)
2762 glyph_end = cGlyphs;
2763 else
2765 /* Don't fully understand multi-glyph reversed clusters yet,
2766 * do they occur for real or just in our test? */
2767 FIXME("multi-glyph reversed clusters found\n");
2768 glyph_end = glyph_start + 1;
2772 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2773 for (i = glyph_start+1; i< glyph_end; i++)
2775 if (psva[i].fClusterStart)
2777 glyph_end = i;
2778 break;
2782 for (advance = 0, i = glyph_start; i < glyph_end; i++)
2783 advance += piAdvance[i];
2785 return advance;
2789 /***********************************************************************
2790 * ScriptXtoCP (USP10.@)
2792 * Basic algorithm :
2793 * Use piAdvance to find the cluster we are looking at.
2794 * Find the character that is the first character of the cluster.
2795 * That is our base piCP.
2796 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2797 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2798 * determine how far through the cluster to advance the cursor.
2800 HRESULT WINAPI ScriptXtoCP(int iX,
2801 int cChars,
2802 int cGlyphs,
2803 const WORD *pwLogClust,
2804 const SCRIPT_VISATTR *psva,
2805 const int *piAdvance,
2806 const SCRIPT_ANALYSIS *psa,
2807 int *piCP,
2808 int *piTrailing)
2810 int direction = 1;
2811 int iPosX;
2812 int i;
2813 int glyph_index, cluster_index;
2814 int cluster_size;
2816 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2817 iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2818 psa, piCP, piTrailing);
2820 if (psa->fRTL && ! psa->fLogicalOrder)
2821 direction = -1;
2823 /* Handle an iX < 0 */
2824 if (iX < 0)
2826 if (direction < 0)
2828 *piCP = cChars;
2829 *piTrailing = 0;
2831 else
2833 *piCP = -1;
2834 *piTrailing = 1;
2836 return S_OK;
2839 /* Looking for non-reversed clusters in a reversed string */
2840 if (direction < 0)
2842 int max_clust = pwLogClust[0];
2843 for (i=0; i< cChars; i++)
2844 if (pwLogClust[i] > max_clust)
2846 FIXME("We do not handle non reversed clusters properly\n");
2847 break;
2851 /* find the glyph_index based in iX */
2852 if (direction > 0)
2854 for (glyph_index = -1, iPosX = iX; iPosX >=0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2857 else
2859 for (glyph_index = -1, iPosX = iX; iPosX > 0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2863 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX, glyph_index, cGlyphs);
2865 *piTrailing = 0;
2866 if (glyph_index >= 0 && glyph_index < cGlyphs)
2868 /* find the cluster */
2869 if (direction > 0 )
2870 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] <= glyph_index; cluster_index=pwLogClust[i++])
2872 else
2873 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] >= glyph_index; cluster_index=pwLogClust[i++])
2876 TRACE("cluster_index %i\n", cluster_index);
2878 if (direction < 0 && iPosX >= 0 && glyph_index != cluster_index)
2880 /* We are off the end of the string */
2881 *piCP = -1;
2882 *piTrailing = 1;
2883 return S_OK;
2886 get_cluster_data(pwLogClust, cChars, cluster_index, &cluster_size, &i);
2888 TRACE("first char index %i\n",i);
2889 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2891 /* Check trailing */
2892 if (glyph_index != cluster_index ||
2893 (direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2894 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2895 *piTrailing = cluster_size;
2897 else
2899 if (cluster_size > 1)
2901 /* Be part way through the glyph cluster based on size and position */
2902 int cluster_advance = get_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, cluster_index, direction);
2903 double cluster_part_width = cluster_advance / (float)cluster_size;
2904 double adv;
2905 int part_index;
2907 /* back up to the beginning of the cluster */
2908 for (adv = iPosX, part_index = cluster_index; part_index <= glyph_index; part_index++)
2909 adv += piAdvance[part_index];
2910 if (adv > iX) adv = iX;
2912 TRACE("Multi-char cluster, no snap\n");
2913 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size, adv);
2914 TRACE("advance %i divides into %f per char\n", cluster_advance, cluster_part_width);
2915 if (direction > 0)
2917 for (part_index = 0; adv >= 0; adv-=cluster_part_width, part_index++)
2919 if (part_index) part_index--;
2921 else
2923 for (part_index = 0; adv > 0; adv-=cluster_part_width, part_index++)
2925 if (part_index > cluster_size)
2927 adv += cluster_part_width;
2928 part_index=cluster_size;
2932 TRACE("base_char %i part_index %i, leftover advance %f\n",i, part_index, adv);
2934 if (direction > 0)
2935 i += part_index;
2936 else
2937 i += (cluster_size - part_index);
2939 /* Check trailing */
2940 if ((direction > 0 && fabs(adv) <= (cluster_part_width / 2.0)) ||
2941 (direction < 0 && adv && fabs(adv) >= (cluster_part_width / 2.0)))
2942 *piTrailing = 1;
2944 else
2946 /* Check trailing */
2947 if ((direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2948 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2949 *piTrailing = 1;
2953 else
2955 TRACE("Point falls outside of string\n");
2956 if (glyph_index < 0)
2957 i = cChars-1;
2958 else /* (glyph_index >= cGlyphs) */
2959 i = cChars;
2961 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2962 point flow to the next character */
2963 if (direction < 0)
2965 if (!scriptInformation[psa->eScript].props.fNeedsCaretInfo && abs(iPosX) == piAdvance[glyph_index])
2966 i++;
2967 else
2968 *piTrailing = 1;
2972 *piCP = i;
2974 TRACE("*piCP=%d\n", *piCP);
2975 TRACE("*piTrailing=%d\n", *piTrailing);
2976 return S_OK;
2979 /***********************************************************************
2980 * ScriptBreak (USP10.@)
2982 * Retrieve line break information.
2984 * PARAMS
2985 * chars [I] Array of characters.
2986 * sa [I] Script analysis.
2987 * la [I] Array of logical attribute structures.
2989 * RETURNS
2990 * Success: S_OK
2991 * Failure: S_FALSE
2993 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2995 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2997 if (count < 0 || !la) return E_INVALIDARG;
2998 if (count == 0) return E_FAIL;
3000 BREAK_line(chars, count, sa, la);
3002 return S_OK;
3005 /***********************************************************************
3006 * ScriptIsComplex (USP10.@)
3008 * Determine if a string is complex.
3010 * PARAMS
3011 * chars [I] Array of characters to test.
3012 * len [I] Length in characters.
3013 * flag [I] Flag.
3015 * RETURNS
3016 * Success: S_OK
3017 * Failure: S_FALSE
3020 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
3022 enum usp10_script script;
3023 unsigned int i, consumed;
3025 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
3027 if (!chars || len < 0)
3028 return E_INVALIDARG;
3030 for (i = 0; i < len; i+=consumed)
3032 if (i >= len)
3033 break;
3035 if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
3036 return S_OK;
3038 script = get_char_script(chars,i,len, &consumed);
3039 if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
3040 (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
3041 return S_OK;
3043 return S_FALSE;
3046 /***********************************************************************
3047 * ScriptShapeOpenType (USP10.@)
3049 * Produce glyphs and visual attributes for a run.
3051 * PARAMS
3052 * hdc [I] Device context.
3053 * psc [I/O] Opaque pointer to a script cache.
3054 * psa [I/O] Script analysis.
3055 * tagScript [I] The OpenType tag for the Script
3056 * tagLangSys [I] The OpenType tag for the Language
3057 * rcRangeChars[I] Array of Character counts in each range
3058 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3059 * cRanges [I] Count of ranges
3060 * pwcChars [I] Array of characters specifying the run.
3061 * cChars [I] Number of characters in pwcChars.
3062 * cMaxGlyphs [I] Length of pwOutGlyphs.
3063 * pwLogClust [O] Array of logical cluster info.
3064 * pCharProps [O] Array of character property values
3065 * pwOutGlyphs [O] Array of glyphs.
3066 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3067 * pcGlyphs [O] Number of glyphs returned.
3069 * RETURNS
3070 * Success: S_OK
3071 * Failure: Non-zero HRESULT value.
3073 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
3074 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3075 OPENTYPE_TAG tagLangSys, int *rcRangeChars,
3076 TEXTRANGE_PROPERTIES **rpRangeProperties,
3077 int cRanges, const WCHAR *pwcChars, int cChars,
3078 int cMaxGlyphs, WORD *pwLogClust,
3079 SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
3080 SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
3082 HRESULT hr;
3083 int i;
3084 unsigned int g;
3085 BOOL rtl;
3086 int cluster;
3087 static int once = 0;
3089 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3090 hdc, psc, psa,
3091 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3092 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3093 cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
3095 if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
3096 psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
3098 if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
3099 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3101 if (cRanges)
3102 if(!once++) FIXME("Ranges not supported yet\n");
3104 rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
3106 *pcGlyphs = cChars;
3107 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3108 if (!pwLogClust) return E_FAIL;
3110 ((ScriptCache *)*psc)->userScript = tagScript;
3111 ((ScriptCache *)*psc)->userLang = tagLangSys;
3113 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3114 for (i = 0; i < cChars; i++)
3116 int idx = i;
3117 if (rtl) idx = cChars - 1 - i;
3118 /* FIXME: set to better values */
3119 pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
3120 pOutGlyphProps[i].sva.fClusterStart = 1;
3121 pOutGlyphProps[i].sva.fDiacritic = 0;
3122 pOutGlyphProps[i].sva.fZeroWidth = 0;
3123 pOutGlyphProps[i].sva.fReserved = 0;
3124 pOutGlyphProps[i].sva.fShapeReserved = 0;
3126 /* FIXME: have the shaping engine set this */
3127 pCharProps[i].fCanGlyphAlone = 0;
3129 pwLogClust[i] = idx;
3132 if (psa && !psa->fNoGlyphIndex && ((ScriptCache *)*psc)->sfnt)
3134 WCHAR *rChars;
3135 if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
3137 rChars = heap_alloc(sizeof(WCHAR) * cChars);
3138 if (!rChars) return E_OUTOFMEMORY;
3139 for (i = 0, g = 0, cluster = 0; i < cChars; i++)
3141 int idx = i;
3142 DWORD chInput;
3144 if (rtl) idx = cChars - 1 - i;
3145 if (!cluster)
3147 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
3148 if (!chInput)
3150 if (psa->fRTL)
3151 chInput = mirror_char(pwcChars[idx]);
3152 else
3153 chInput = pwcChars[idx];
3154 rChars[i] = chInput;
3156 else
3158 rChars[i] = pwcChars[idx];
3159 rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
3160 cluster = 1;
3162 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
3164 WORD glyph;
3165 if (!hdc)
3167 heap_free(rChars);
3168 return E_PENDING;
3170 if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
3172 heap_free(rChars);
3173 return S_FALSE;
3175 pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
3177 g++;
3179 else
3181 int k;
3182 cluster--;
3183 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
3184 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3185 pwLogClust[k]--;
3188 *pcGlyphs = g;
3190 SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3191 SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
3192 SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
3194 for (i = 0; i < cChars; ++i)
3196 /* Special case for tabs and joiners. As control characters, ZWNJ
3197 * and ZWJ would in principle get handled by the corresponding
3198 * shaping functions. However, since ZWNJ and ZWJ can get merged
3199 * into adjoining runs during itemisation, these don't generally
3200 * get classified as Script_Control. */
3201 if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
3203 pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
3204 pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
3207 heap_free(rChars);
3209 else
3211 TRACE("no glyph translation\n");
3212 for (i = 0; i < cChars; i++)
3214 int idx = i;
3215 /* No mirroring done here */
3216 if (rtl) idx = cChars - 1 - i;
3217 pwOutGlyphs[i] = pwcChars[idx];
3219 if (!psa)
3220 continue;
3222 /* overwrite some basic control glyphs to blank */
3223 if (psa->fNoGlyphIndex)
3225 if (pwcChars[idx] == ZWSP || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3227 pwOutGlyphs[i] = 0x20;
3228 pOutGlyphProps[i].sva.fZeroWidth = 1;
3231 else if (psa->eScript == Script_Control || pwcChars[idx] == ZWSP
3232 || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3234 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
3235 pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)
3237 pwOutGlyphs[i] = ((ScriptCache *)*psc)->sfp.wgBlank;
3238 pOutGlyphProps[i].sva.fZeroWidth = 1;
3244 return S_OK;
3248 /***********************************************************************
3249 * ScriptShape (USP10.@)
3251 * Produce glyphs and visual attributes for a run.
3253 * PARAMS
3254 * hdc [I] Device context.
3255 * psc [I/O] Opaque pointer to a script cache.
3256 * pwcChars [I] Array of characters specifying the run.
3257 * cChars [I] Number of characters in pwcChars.
3258 * cMaxGlyphs [I] Length of pwOutGlyphs.
3259 * psa [I/O] Script analysis.
3260 * pwOutGlyphs [O] Array of glyphs.
3261 * pwLogClust [O] Array of logical cluster info.
3262 * psva [O] Array of visual attributes.
3263 * pcGlyphs [O] Number of glyphs returned.
3265 * RETURNS
3266 * Success: S_OK
3267 * Failure: Non-zero HRESULT value.
3269 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
3270 int cChars, int cMaxGlyphs,
3271 SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
3272 SCRIPT_VISATTR *psva, int *pcGlyphs)
3274 HRESULT hr;
3275 int i;
3276 SCRIPT_CHARPROP *charProps;
3277 SCRIPT_GLYPHPROP *glyphProps;
3279 if (!psva || !pcGlyphs) return E_INVALIDARG;
3280 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3282 charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
3283 if (!charProps) return E_OUTOFMEMORY;
3284 glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
3285 if (!glyphProps)
3287 heap_free(charProps);
3288 return E_OUTOFMEMORY;
3291 hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
3293 if (SUCCEEDED(hr))
3295 for (i = 0; i < *pcGlyphs; i++)
3296 psva[i] = glyphProps[i].sva;
3299 heap_free(charProps);
3300 heap_free(glyphProps);
3302 return hr;
3305 /***********************************************************************
3306 * ScriptPlaceOpenType (USP10.@)
3308 * Produce advance widths for a run.
3310 * PARAMS
3311 * hdc [I] Device context.
3312 * psc [I/O] Opaque pointer to a script cache.
3313 * psa [I/O] Script analysis.
3314 * tagScript [I] The OpenType tag for the Script
3315 * tagLangSys [I] The OpenType tag for the Language
3316 * rcRangeChars[I] Array of Character counts in each range
3317 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3318 * cRanges [I] Count of ranges
3319 * pwcChars [I] Array of characters specifying the run.
3320 * pwLogClust [I] Array of logical cluster info
3321 * pCharProps [I] Array of character property values
3322 * cChars [I] Number of characters in pwcChars.
3323 * pwGlyphs [I] Array of glyphs.
3324 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3325 * cGlyphs [I] Count of Glyphs
3326 * piAdvance [O] Array of advance widths.
3327 * pGoffset [O] Glyph offsets.
3328 * pABC [O] Combined ABC width.
3330 * RETURNS
3331 * Success: S_OK
3332 * Failure: Non-zero HRESULT value.
3335 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
3336 OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
3337 int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
3338 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3339 SCRIPT_CHARPROP *pCharProps, int cChars,
3340 const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
3341 int cGlyphs, int *piAdvance,
3342 GOFFSET *pGoffset, ABC *pABC
3345 HRESULT hr;
3346 int i;
3347 static int once = 0;
3349 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3350 hdc, psc, psa,
3351 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3352 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3353 pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
3354 pGoffset, pABC);
3356 if (!pGlyphProps) return E_INVALIDARG;
3357 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3358 if (!pGoffset) return E_FAIL;
3360 if (cRanges)
3361 if (!once++) FIXME("Ranges not supported yet\n");
3363 ((ScriptCache *)*psc)->userScript = tagScript;
3364 ((ScriptCache *)*psc)->userLang = tagLangSys;
3366 if (pABC) memset(pABC, 0, sizeof(ABC));
3367 for (i = 0; i < cGlyphs; i++)
3369 ABC abc;
3370 if (pGlyphProps[i].sva.fZeroWidth)
3372 abc.abcA = abc.abcB = abc.abcC = 0;
3374 else if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
3376 BOOL ret;
3377 if (!hdc) return E_PENDING;
3378 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
3380 if (psa->fNoGlyphIndex)
3381 ret = GetCharABCWidthsW(hdc, pwGlyphs[i], pwGlyphs[i], &abc);
3382 else
3383 ret = GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc);
3384 if (!ret) return S_FALSE;
3386 else
3388 INT width;
3389 if (psa->fNoGlyphIndex)
3390 ret = GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width);
3391 else
3392 ret = GetCharWidthI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &width);
3393 if (!ret) return S_FALSE;
3394 abc.abcB = width;
3395 abc.abcA = abc.abcC = 0;
3397 set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
3399 if (pABC)
3401 pABC->abcA += abc.abcA;
3402 pABC->abcB += abc.abcB;
3403 pABC->abcC += abc.abcC;
3405 /* FIXME: set to more reasonable values */
3406 pGoffset[i].du = pGoffset[i].dv = 0;
3407 if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
3410 SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset);
3412 if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
3413 return S_OK;
3416 /***********************************************************************
3417 * ScriptPlace (USP10.@)
3419 * Produce advance widths for a run.
3421 * PARAMS
3422 * hdc [I] Device context.
3423 * psc [I/O] Opaque pointer to a script cache.
3424 * pwGlyphs [I] Array of glyphs.
3425 * cGlyphs [I] Number of glyphs in pwGlyphs.
3426 * psva [I] Array of visual attributes.
3427 * psa [I/O] String analysis.
3428 * piAdvance [O] Array of advance widths.
3429 * pGoffset [O] Glyph offsets.
3430 * pABC [O] Combined ABC width.
3432 * RETURNS
3433 * Success: S_OK
3434 * Failure: Non-zero HRESULT value.
3436 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
3437 int cGlyphs, const SCRIPT_VISATTR *psva,
3438 SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
3440 HRESULT hr;
3441 SCRIPT_GLYPHPROP *glyphProps;
3442 int i;
3444 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
3445 piAdvance, pGoffset, pABC);
3447 if (!psva) return E_INVALIDARG;
3448 if (!pGoffset) return E_FAIL;
3450 glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
3451 if (!glyphProps) return E_OUTOFMEMORY;
3453 for (i = 0; i < cGlyphs; i++)
3454 glyphProps[i].sva = psva[i];
3456 hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
3458 heap_free(glyphProps);
3460 return hr;
3463 /***********************************************************************
3464 * ScriptGetCMap (USP10.@)
3466 * Retrieve glyph indices.
3468 * PARAMS
3469 * hdc [I] Device context.
3470 * psc [I/O] Opaque pointer to a script cache.
3471 * pwcInChars [I] Array of Unicode characters.
3472 * cChars [I] Number of characters in pwcInChars.
3473 * dwFlags [I] Flags.
3474 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3476 * RETURNS
3477 * Success: S_OK
3478 * Failure: Non-zero HRESULT value.
3480 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
3481 int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
3483 HRESULT hr;
3484 int i;
3486 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
3487 cChars, dwFlags, pwOutGlyphs);
3489 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3491 hr = S_OK;
3493 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3495 for (i = 0; i < cChars; i++)
3497 WCHAR inChar;
3498 if (dwFlags == SGCM_RTL)
3499 inChar = mirror_char(pwcInChars[i]);
3500 else
3501 inChar = pwcInChars[i];
3502 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
3504 WORD glyph;
3505 if (!hdc) return E_PENDING;
3506 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
3507 if (glyph == 0xffff)
3509 hr = S_FALSE;
3510 glyph = 0x0;
3512 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
3516 else
3518 TRACE("no glyph translation\n");
3519 for (i = 0; i < cChars; i++)
3521 WCHAR inChar;
3522 if (dwFlags == SGCM_RTL)
3523 inChar = mirror_char(pwcInChars[i]);
3524 else
3525 inChar = pwcInChars[i];
3526 pwOutGlyphs[i] = inChar;
3529 return hr;
3532 /***********************************************************************
3533 * ScriptTextOut (USP10.@)
3536 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
3537 const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
3538 int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
3539 const int *piJustify, const GOFFSET *pGoffset)
3541 HRESULT hr = S_OK;
3542 INT i, dir = 1;
3543 INT *lpDx;
3544 WORD *reordered_glyphs = (WORD *)pwGlyphs;
3546 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3547 hdc, psc, x, y, fuOptions, wine_dbgstr_rect(lprc), psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
3548 piAdvance, piJustify, pGoffset);
3550 if (!hdc || !psc) return E_INVALIDARG;
3551 if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
3553 fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
3554 fuOptions |= ETO_IGNORELANGUAGE;
3555 if (!psa->fNoGlyphIndex) /* Have Glyphs? */
3556 fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */
3558 lpDx = heap_alloc(cGlyphs * sizeof(INT) * 2);
3559 if (!lpDx) return E_OUTOFMEMORY;
3560 fuOptions |= ETO_PDY;
3562 if (psa->fRTL && psa->fLogicalOrder)
3564 reordered_glyphs = heap_alloc( cGlyphs * sizeof(WORD) );
3565 if (!reordered_glyphs)
3567 heap_free( lpDx );
3568 return E_OUTOFMEMORY;
3571 for (i = 0; i < cGlyphs; i++)
3572 reordered_glyphs[i] = pwGlyphs[cGlyphs - 1 - i];
3573 dir = -1;
3576 for (i = 0; i < cGlyphs; i++)
3578 int orig_index = (dir > 0) ? i : cGlyphs - 1 - i;
3579 lpDx[i * 2] = piAdvance[orig_index];
3580 lpDx[i * 2 + 1] = 0;
3582 if (pGoffset)
3584 if (i == 0)
3586 x += pGoffset[orig_index].du * dir;
3587 y += pGoffset[orig_index].dv;
3589 else
3591 lpDx[(i - 1) * 2] += pGoffset[orig_index].du * dir;
3592 lpDx[(i - 1) * 2 + 1] += pGoffset[orig_index].dv;
3594 lpDx[i * 2] -= pGoffset[orig_index].du * dir;
3595 lpDx[i * 2 + 1] -= pGoffset[orig_index].dv;
3599 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, reordered_glyphs, cGlyphs, lpDx))
3600 hr = S_FALSE;
3602 if (reordered_glyphs != pwGlyphs) heap_free( reordered_glyphs );
3603 heap_free(lpDx);
3605 return hr;
3608 /***********************************************************************
3609 * ScriptCacheGetHeight (USP10.@)
3611 * Retrieve the height of the font in the cache.
3613 * PARAMS
3614 * hdc [I] Device context.
3615 * psc [I/O] Opaque pointer to a script cache.
3616 * height [O] Receives font height.
3618 * RETURNS
3619 * Success: S_OK
3620 * Failure: Non-zero HRESULT value.
3622 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
3624 HRESULT hr;
3626 TRACE("(%p, %p, %p)\n", hdc, psc, height);
3628 if (!height) return E_INVALIDARG;
3629 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3631 *height = get_cache_height(psc);
3632 return S_OK;
3635 /***********************************************************************
3636 * ScriptGetGlyphABCWidth (USP10.@)
3638 * Retrieve the width of a glyph.
3640 * PARAMS
3641 * hdc [I] Device context.
3642 * psc [I/O] Opaque pointer to a script cache.
3643 * glyph [I] Glyph to retrieve the width for.
3644 * abc [O] ABC widths of the glyph.
3646 * RETURNS
3647 * Success: S_OK
3648 * Failure: Non-zero HRESULT value.
3650 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
3652 HRESULT hr;
3654 TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
3656 if (!abc) return E_INVALIDARG;
3657 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3659 if (!get_cache_glyph_widths(psc, glyph, abc))
3661 if (!hdc) return E_PENDING;
3662 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3664 if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
3666 else
3668 INT width;
3669 if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
3670 abc->abcB = width;
3671 abc->abcA = abc->abcC = 0;
3673 set_cache_glyph_widths(psc, glyph, abc);
3675 return S_OK;
3678 /***********************************************************************
3679 * ScriptLayout (USP10.@)
3681 * Map embedding levels to visual and/or logical order.
3683 * PARAMS
3684 * runs [I] Size of level array.
3685 * level [I] Array of embedding levels.
3686 * vistolog [O] Map of embedding levels from visual to logical order.
3687 * logtovis [O] Map of embedding levels from logical to visual order.
3689 * RETURNS
3690 * Success: S_OK
3691 * Failure: Non-zero HRESULT value.
3694 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
3696 int* indexs;
3697 int ich;
3699 TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
3701 if (!level || (!vistolog && !logtovis))
3702 return E_INVALIDARG;
3704 indexs = heap_alloc(sizeof(int) * runs);
3705 if (!indexs)
3706 return E_OUTOFMEMORY;
3708 if (vistolog)
3710 for( ich = 0; ich < runs; ich++)
3711 indexs[ich] = ich;
3713 ich = 0;
3714 while (ich < runs)
3715 ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3716 memcpy(vistolog, indexs, runs * sizeof(*vistolog));
3719 if (logtovis)
3721 for( ich = 0; ich < runs; ich++)
3722 indexs[ich] = ich;
3724 ich = 0;
3725 while (ich < runs)
3726 ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3727 memcpy(logtovis, indexs, runs * sizeof(*logtovis));
3729 heap_free(indexs);
3731 return S_OK;
3734 /***********************************************************************
3735 * ScriptStringGetLogicalWidths (USP10.@)
3737 * Returns logical widths from a string analysis.
3739 * PARAMS
3740 * ssa [I] string analysis.
3741 * piDx [O] logical widths returned.
3743 * RETURNS
3744 * Success: S_OK
3745 * Failure: a non-zero HRESULT.
3747 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
3749 int i, j, next = 0;
3750 StringAnalysis *analysis = ssa;
3752 TRACE("%p, %p\n", ssa, piDx);
3754 if (!analysis) return S_FALSE;
3755 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
3757 for (i = 0; i < analysis->numItems; i++)
3759 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
3760 int direction = 1;
3762 if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
3763 direction = -1;
3765 for (j = 0; j < cChar; j++)
3767 int k;
3768 int glyph = analysis->glyphs[i].pwLogClust[j];
3769 int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
3770 cChar, j, direction, NULL, NULL);
3771 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);
3773 for (k = 0; k < clust_size; k++)
3775 piDx[next] = advance / clust_size;
3776 next++;
3777 if (k) j++;
3781 return S_OK;
3784 /***********************************************************************
3785 * ScriptStringValidate (USP10.@)
3787 * Validate a string analysis.
3789 * PARAMS
3790 * ssa [I] string analysis.
3792 * RETURNS
3793 * Success: S_OK
3794 * Failure: S_FALSE if invalid sequences are found
3795 * or a non-zero HRESULT if it fails.
3797 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
3799 StringAnalysis *analysis = ssa;
3801 TRACE("(%p)\n", ssa);
3803 if (!analysis) return E_INVALIDARG;
3804 return (analysis->invalid) ? S_FALSE : S_OK;
3807 /***********************************************************************
3808 * ScriptString_pSize (USP10.@)
3810 * Retrieve width and height of an analysed string.
3812 * PARAMS
3813 * ssa [I] string analysis.
3815 * RETURNS
3816 * Success: Pointer to a SIZE structure.
3817 * Failure: NULL
3819 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
3821 int i, j;
3822 StringAnalysis *analysis = ssa;
3824 TRACE("(%p)\n", ssa);
3826 if (!analysis) return NULL;
3827 if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
3829 if (!analysis->sz)
3831 if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
3832 analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
3834 analysis->sz->cx = 0;
3835 for (i = 0; i < analysis->numItems; i++)
3837 if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
3838 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
3839 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3840 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
3843 return analysis->sz;
3846 /***********************************************************************
3847 * ScriptString_pLogAttr (USP10.@)
3849 * Retrieve logical attributes of an analysed string.
3851 * PARAMS
3852 * ssa [I] string analysis.
3854 * RETURNS
3855 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3856 * Failure: NULL
3858 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
3860 StringAnalysis *analysis = ssa;
3862 TRACE("(%p)\n", ssa);
3864 if (!analysis) return NULL;
3865 if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
3866 return analysis->logattrs;
3869 /***********************************************************************
3870 * ScriptString_pcOutChars (USP10.@)
3872 * Retrieve the length of a string after clipping.
3874 * PARAMS
3875 * ssa [I] String analysis.
3877 * RETURNS
3878 * Success: Pointer to the length.
3879 * Failure: NULL
3881 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
3883 StringAnalysis *analysis = ssa;
3885 TRACE("(%p)\n", ssa);
3887 if (!analysis) return NULL;
3888 return &analysis->clip_len;
3891 /***********************************************************************
3892 * ScriptStringGetOrder (USP10.@)
3894 * Retrieve a glyph order map.
3896 * PARAMS
3897 * ssa [I] String analysis.
3898 * order [I/O] Array of glyph positions.
3900 * RETURNS
3901 * Success: S_OK
3902 * Failure: a non-zero HRESULT.
3904 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
3906 int i, j;
3907 unsigned int k;
3908 StringAnalysis *analysis = ssa;
3910 TRACE("(%p)\n", ssa);
3912 if (!analysis) return S_FALSE;
3913 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
3915 /* FIXME: handle RTL scripts */
3916 for (i = 0, k = 0; i < analysis->numItems; i++)
3917 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3918 order[k] = k;
3920 return S_OK;
3923 /***********************************************************************
3924 * ScriptGetLogicalWidths (USP10.@)
3926 * Convert advance widths to logical widths.
3928 * PARAMS
3929 * sa [I] Script analysis.
3930 * nbchars [I] Number of characters.
3931 * nbglyphs [I] Number of glyphs.
3932 * glyph_width [I] Array of glyph widths.
3933 * log_clust [I] Array of logical clusters.
3934 * sva [I] Visual attributes.
3935 * widths [O] Array of logical widths.
3937 * RETURNS
3938 * Success: S_OK
3939 * Failure: a non-zero HRESULT.
3941 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3942 const int *advances, const WORD *log_clust,
3943 const SCRIPT_VISATTR *sva, int *widths)
3945 int i, next = 0, direction;
3947 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3948 sa, nbchars, nbglyphs, advances, log_clust, sva, widths);
3950 if (sa->fRTL && !sa->fLogicalOrder)
3951 direction = -1;
3952 else
3953 direction = 1;
3955 for (i = 0; i < nbchars; i++)
3957 int clust_size = get_cluster_size(log_clust, nbchars, i, direction, NULL, NULL);
3958 int advance = get_glyph_cluster_advance(advances, sva, log_clust, nbglyphs, nbchars, log_clust[i], direction);
3959 int j;
3961 for (j = 0; j < clust_size; j++)
3963 widths[next] = advance / clust_size;
3964 next++;
3965 if (j) i++;
3969 return S_OK;
3972 /***********************************************************************
3973 * ScriptApplyLogicalWidth (USP10.@)
3975 * Generate glyph advance widths.
3977 * PARAMS
3978 * dx [I] Array of logical advance widths.
3979 * num_chars [I] Number of characters.
3980 * num_glyphs [I] Number of glyphs.
3981 * log_clust [I] Array of logical clusters.
3982 * sva [I] Visual attributes.
3983 * advance [I] Array of glyph advance widths.
3984 * sa [I] Script analysis.
3985 * abc [I/O] Summed ABC widths.
3986 * justify [O] Array of glyph advance widths.
3988 * RETURNS
3989 * Success: S_OK
3990 * Failure: a non-zero HRESULT.
3992 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
3993 const WORD *log_clust, const SCRIPT_VISATTR *sva,
3994 const int *advance, const SCRIPT_ANALYSIS *sa,
3995 ABC *abc, int *justify)
3997 int i;
3999 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
4000 dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
4002 for (i = 0; i < num_chars; i++) justify[i] = advance[i];
4003 return S_OK;
4006 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
4007 int num_glyphs, int dx, int min_kashida, int *justify)
4009 int i;
4011 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
4013 for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
4014 return S_OK;
4017 HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
4019 HRESULT hr;
4020 if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4021 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4023 return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
4026 HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
4028 HRESULT hr;
4029 if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4030 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4032 return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
4035 HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
4037 HRESULT hr;
4038 if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4039 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4041 return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);