usp10: Add Osmanya script.
[wine/multimedia.git] / dlls / usp10 / usp10.c
blob2a5cb1c8984178db78be0c1a49b0d9fbcaaae64c
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>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "usp10.h"
37 #include "usp10_internal.h"
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
44 typedef struct _scriptRange
46 WORD script;
47 DWORD rangeFirst;
48 DWORD rangeLast;
49 WORD numericScript;
50 WORD punctScript;
51 } scriptRange;
53 static const scriptRange scriptRanges[] = {
54 /* Basic Latin: U+0000–U+007A */
55 { Script_Latin, 0x00, 0x07a , Script_Numeric, Script_Punctuation},
56 /* Latin-1 Supplement: U+0080–U+00FF */
57 /* Latin Extended-A: U+0100–U+017F */
58 /* Latin Extended-B: U+0180–U+024F */
59 /* IPA Extensions: U+0250–U+02AF */
60 /* Spacing Modifier Letters:U+02B0–U+02FF */
61 { Script_Latin, 0x80, 0x2ff , Script_Numeric2, Script_Punctuation},
62 /* Combining Diacritical Marks : U+0300–U+036F */
63 { Script_Diacritical,0x300, 0x36f, 0, 0},
64 /* Greek: U+0370–U+03FF */
65 { Script_Greek, 0x370, 0x3ff, 0, 0},
66 /* Cyrillic: U+0400–U+04FF */
67 /* Cyrillic Supplement: U+0500–U+052F */
68 { Script_Cyrillic, 0x400, 0x52f, 0, 0},
69 /* Armenian: U+0530–U+058F */
70 { Script_Armenian, 0x530, 0x58f, 0, 0},
71 /* Hebrew: U+0590–U+05FF */
72 { Script_Hebrew, 0x590, 0x5ff, 0, 0},
73 /* Arabic: U+0600–U+06FF */
74 { Script_Arabic, 0x600, 0x6ef, Script_Arabic_Numeric, 0},
75 /* Defined by Windows */
76 { Script_Persian, 0x6f0, 0x6f9, 0, 0},
77 /* Continue Arabic: U+0600–U+06FF */
78 { Script_Arabic, 0x6fa, 0x6ff, 0, 0},
79 /* Syriac: U+0700–U+074F*/
80 { Script_Syriac, 0x700, 0x74f, 0, 0},
81 /* Arabic Supplement: U+0750–U+077F */
82 { Script_Arabic, 0x750, 0x77f, 0, 0},
83 /* Thaana: U+0780–U+07BF */
84 { Script_Thaana, 0x780, 0x7bf, 0, 0},
85 /* N’Ko: U+07C0–U+07FF */
86 { Script_NKo, 0x7c0, 0x7ff, 0, 0},
87 /* Devanagari: U+0900–U+097F */
88 { Script_Devanagari, 0x900, 0x97f, Script_Devanagari_Numeric, 0},
89 /* Bengali: U+0980–U+09FF */
90 { Script_Bengali, 0x980, 0x9ff, Script_Bengali_Numeric, 0},
91 /* Gurmukhi: U+0A00–U+0A7F*/
92 { Script_Gurmukhi, 0xa00, 0xa7f, Script_Gurmukhi_Numeric, 0},
93 /* Gujarati: U+0A80–U+0AFF*/
94 { Script_Gujarati, 0xa80, 0xaff, Script_Gujarati_Numeric, 0},
95 /* Oriya: U+0B00–U+0B7F */
96 { Script_Oriya, 0xb00, 0xb7f, Script_Oriya_Numeric, 0},
97 /* Tamil: U+0B80–U+0BFF */
98 { Script_Tamil, 0xb80, 0xbff, Script_Tamil_Numeric, 0},
99 /* Telugu: U+0C00–U+0C7F */
100 { Script_Telugu, 0xc00, 0xc7f, Script_Telugu_Numeric, 0},
101 /* Kannada: U+0C80–U+0CFF */
102 { Script_Kannada, 0xc80, 0xcff, Script_Kannada_Numeric, 0},
103 /* Malayalam: U+0D00–U+0D7F */
104 { Script_Malayalam, 0xd00, 0xd7f, Script_Malayalam_Numeric, 0},
105 /* Sinhala: U+0D80–U+0DFF */
106 { Script_Sinhala, 0xd80, 0xdff, 0, 0},
107 /* Thai: U+0E00–U+0E7F */
108 { Script_Thai, 0xe00, 0xe7f, Script_Thai_Numeric, 0},
109 /* Lao: U+0E80–U+0EFF */
110 { Script_Lao, 0xe80, 0xeff, Script_Lao_Numeric, 0},
111 /* Tibetan: U+0F00–U+0FFF */
112 { Script_Tibetan, 0xf00, 0xfff, 0, 0},
113 /* Myanmar: U+1000–U+109F */
114 { Script_Myanmar, 0x1000, 0x109f, Script_Myanmar_Numeric, 0},
115 /* Georgian: U+10A0–U+10FF */
116 { Script_Georgian, 0x10a0, 0x10ff, 0, 0},
117 /* Hangul Jamo: U+1100–U+11FF */
118 { Script_Hangul, 0x1100, 0x11ff, 0, 0},
119 /* Ethiopic: U+1200–U+137F */
120 /* Ethiopic Extensions: U+1380–U+139F */
121 { Script_Ethiopic, 0x1200, 0x139f, 0, 0},
122 /* Cherokee: U+13A0–U+13FF */
123 { Script_Cherokee, 0x13a0, 0x13ff, 0, 0},
124 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
125 { Script_Canadian, 0x1400, 0x167f, 0, 0},
126 /* Ogham: U+1680–U+169F */
127 { Script_Ogham, 0x1680, 0x169f, 0, 0},
128 /* Runic: U+16A0–U+16F0 */
129 { Script_Runic, 0x16a0, 0x16f0, 0, 0},
130 /* Khmer: U+1780–U+17FF */
131 { Script_Khmer, 0x1780, 0x17ff, Script_Khmer_Numeric, 0},
132 /* Mongolian: U+1800–U+18AF */
133 { Script_Mongolian, 0x1800, 0x18af, Script_Mongolian_Numeric, 0},
134 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
135 { Script_Canadian, 0x18b0, 0x18ff, 0, 0},
136 /* Tai Le: U+1950–U+197F */
137 { Script_Tai_Le, 0x1950, 0x197f, 0, 0},
138 /* New Tai Lue: U+1980–U+19DF */
139 { Script_New_Tai_Lue,0x1980, 0x19df, Script_New_Tai_Lue_Numeric, 0},
140 /* Khmer Symbols: U+19E0–U+19FF */
141 { Script_Khmer, 0x19e0, 0x19ff, Script_Khmer_Numeric, 0},
142 /* Vedic Extensions: U+1CD0-U+1CFF */
143 { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
144 /* Phonetic Extensions: U+1D00–U+1DBF */
145 { Script_Latin, 0x1d00, 0x1dbf, 0, 0},
146 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
147 { Script_Diacritical,0x1dc0, 0x1dff, 0, 0},
148 /* Latin Extended Additional: U+1E00–U+1EFF */
149 { Script_Latin, 0x1e00, 0x1eff, 0, 0},
150 /* Greek Extended: U+1F00–U+1FFF */
151 { Script_Greek, 0x1f00, 0x1fff, 0, 0},
152 /* General Punctuation: U+2000 –U+206f */
153 { Script_Latin, 0x2000, 0x206f, 0, 0},
154 /* Superscripts and Subscripts : U+2070 –U+209f */
155 /* Currency Symbols : U+20a0 –U+20cf */
156 { Script_Numeric2, 0x2070, 0x2070, 0, 0},
157 { Script_Latin, 0x2071, 0x2073, 0, 0},
158 { Script_Numeric2, 0x2074, 0x2079, 0, 0},
159 { Script_Latin, 0x207a, 0x207f, 0, 0},
160 { Script_Numeric2, 0x2080, 0x2089, 0, 0},
161 { Script_Latin, 0x208a, 0x20cf, 0, 0},
162 /* Letterlike Symbols : U+2100 –U+214f */
163 /* Number Forms : U+2150 –U+218f */
164 /* Arrows : U+2190 –U+21ff */
165 /* Mathematical Operators : U+2200 –U+22ff */
166 /* Miscellaneous Technical : U+2300 –U+23ff */
167 /* Control Pictures : U+2400 –U+243f */
168 /* Optical Character Recognition : U+2440 –U+245f */
169 /* Enclosed Alphanumerics : U+2460 –U+24ff */
170 /* Box Drawing : U+2500 –U+25ff */
171 /* Block Elements : U+2580 –U+259f */
172 /* Geometric Shapes : U+25a0 –U+25ff */
173 /* Miscellaneous Symbols : U+2600 –U+26ff */
174 /* Dingbats : U+2700 –U+27bf */
175 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
176 /* Supplemental Arrows-A : U+27f0 –U+27ff */
177 { Script_Latin, 0x2100, 0x27ff, 0, 0},
178 /* Braille Patterns: U+2800–U+28FF */
179 { Script_Braille, 0x2800, 0x28ff, 0, 0},
180 /* Supplemental Arrows-B : U+2900 –U+297f */
181 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
182 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
183 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
184 { Script_Latin, 0x2900, 0x2bff, 0, 0},
185 /* Latin Extended-C: U+2C60–U+2C7F */
186 { Script_Latin, 0x2c60, 0x2c7f, 0, 0},
187 /* Georgian: U+2D00–U+2D2F */
188 { Script_Georgian, 0x2d00, 0x2d2f, 0, 0},
189 /* Tifinagh: U+2D30–U+2D7F */
190 { Script_Tifinagh, 0x2d30, 0x2d7f, 0, 0},
191 /* Ethiopic Extensions: U+2D80–U+2DDF */
192 { Script_Ethiopic, 0x2d80, 0x2ddf, 0, 0},
193 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
194 { Script_Cyrillic, 0x2de0, 0x2dff, 0, 0},
195 /* CJK Radicals Supplement: U+2E80–U+2EFF */
196 /* Kangxi Radicals: U+2F00–U+2FDF */
197 { Script_CJK_Han, 0x2e80, 0x2fdf, 0, 0},
198 /* Ideographic Description Characters: U+2FF0–U+2FFF */
199 { Script_Ideograph ,0x2ff0, 0x2fff, 0, 0},
200 /* CJK Symbols and Punctuation: U+3000–U+303F */
201 { Script_Ideograph ,0x3000, 0x3004, 0, 0},
202 { Script_CJK_Han ,0x3005, 0x3005, 0, 0},
203 { Script_Ideograph ,0x3006, 0x3006, 0, 0},
204 { Script_CJK_Han ,0x3007, 0x3007, 0, 0},
205 { Script_Ideograph ,0x3008, 0x3020, 0, 0},
206 { Script_CJK_Han ,0x3021, 0x3029, 0, 0},
207 { Script_Ideograph ,0x302a, 0x3030, 0, 0},
208 /* Kana Marks: */
209 { Script_Kana ,0x3031, 0x3035, 0, 0},
210 { Script_Ideograph ,0x3036, 0x3037, 0, 0},
211 { Script_CJK_Han ,0x3038, 0x303b, 0, 0},
212 { Script_Ideograph ,0x303c, 0x303f, 0, 0},
213 /* Hiragana: U+3040–U+309F */
214 /* Katakana: U+30A0–U+30FF */
215 { Script_Kana ,0x3040, 0x30ff, 0, 0},
216 /* Bopomofo: U+3100–U+312F */
217 { Script_Bopomofo ,0x3100, 0x312f, 0, 0},
218 /* Hangul Compatibility Jamo: U+3130–U+318F */
219 { Script_Hangul ,0x3130, 0x318f, 0, 0},
220 /* Kanbun: U+3190–U+319F */
221 { Script_Ideograph ,0x3190, 0x319f, 0, 0},
222 /* Bopomofo Extended: U+31A0–U+31BF */
223 { Script_Bopomofo ,0x31a0, 0x31bf, 0, 0},
224 /* CJK Strokes: U+31C0–U+31EF */
225 { Script_Ideograph ,0x31c0, 0x31ef, 0, 0},
226 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
227 { Script_Kana ,0x31f0, 0x31ff, 0, 0},
228 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
229 { Script_Hangul ,0x3200, 0x321f, 0, 0},
230 { Script_Ideograph ,0x3220, 0x325f, 0, 0},
231 { Script_Hangul ,0x3260, 0x327f, 0, 0},
232 { Script_Ideograph ,0x3280, 0x32ef, 0, 0},
233 { Script_Kana ,0x32d0, 0x31ff, 0, 0},
234 /* CJK Compatibility: U+3300–U+33FF*/
235 { Script_Kana ,0x3300, 0x3357, 0, 0},
236 { Script_Ideograph ,0x3358, 0x33ff, 0, 0},
237 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
238 { Script_CJK_Han ,0x3400, 0x4dbf, 0, 0},
239 /* CJK Unified Ideographs: U+4E00–U+9FFF */
240 { Script_CJK_Han ,0x4e00, 0x9fff, 0, 0},
241 /* Yi: U+A000–U+A4CF */
242 { Script_Yi ,0xa000, 0xa4cf, 0, 0},
243 /* Vai: U+A500–U+A63F */
244 { Script_Vai ,0xa500, 0xa63f, Script_Vai_Numeric, 0},
245 /* Cyrillic Extended-B: U+A640–U+A69F */
246 { Script_Cyrillic, 0xa640, 0xa69f, 0, 0},
247 /* Modifier Tone Letters: U+A700–U+A71F */
248 /* Latin Extended-D: U+A720–U+A7FF */
249 { Script_Latin, 0xa700, 0xa7ff, 0, 0},
250 /* Phags-pa: U+A840–U+A87F */
251 { Script_Phags_pa, 0xa840, 0xa87f, 0, 0},
252 /* Devanagari Extended: U+A8E0-U+A8FF */
253 { Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
254 /* Myanmar Extended-A: U+AA60–U+AA7F */
255 { Script_Myanmar, 0xaa60, 0xaa7f, Script_Myanmar_Numeric, 0},
256 /* Hangul Jamo Extended-A: U+A960–U+A97F */
257 { Script_Hangul, 0xa960, 0xa97f, 0, 0},
258 /* Hangul Syllables: U+AC00–U+D7A3 */
259 { Script_Hangul, 0xac00, 0xd7a3, 0, 0},
260 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
261 { Script_Hangul, 0xd7b0, 0xd7ff, 0, 0},
262 /* Surrogates Area: U+D800–U+DFFF */
263 { Script_Surrogates, 0xd800, 0xdbfe, 0, 0},
264 { Script_Private, 0xdbff, 0xdc00, 0, 0},
265 { Script_Surrogates, 0xdc01, 0xdfff, 0, 0},
266 /* Private Use Area: U+E000–U+F8FF */
267 { Script_Private, 0xe000, 0xf8ff, 0, 0},
268 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
269 { Script_CJK_Han ,0xf900, 0xfaff, 0, 0},
270 /* Latin Ligatures: U+FB00–U+FB06 */
271 { Script_Latin, 0xfb00, 0xfb06, 0, 0},
272 /* Armenian ligatures U+FB13..U+FB17 */
273 { Script_Armenian, 0xfb13, 0xfb17, 0, 0},
274 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
275 { Script_Hebrew, 0xfb1d, 0xfb4f, 0, 0},
276 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
277 { Script_Arabic, 0xfb50, 0xfdff, 0, 0},
278 /* Vertical Forms: U+FE10–U+FE1F */
279 /* Combining Half Marks: U+FE20–U+FE2F */
280 /* CJK Compatibility Forms: U+FE30–U+FE4F */
281 /* Small Form Variants: U+FE50–U+FE6F */
282 { Script_Ideograph ,0xfe10, 0xfe6f, 0, 0},
283 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
284 { Script_Arabic, 0xfe70, 0xfeff, 0, 0},
285 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
286 { Script_Ideograph ,0xff00, 0xff64, Script_Numeric2, 0},
287 { Script_Kana ,0xff65, 0xff9f, 0, 0},
288 { Script_Hangul ,0xffa0, 0xffdf, 0, 0},
289 { Script_Ideograph ,0xffe0, 0xffef, 0, 0},
290 /* Plane - 1 */
291 /* Deseret: U+10400–U+1044F */
292 { Script_Deseret, 0x10400, 0x1044F, 0, 0},
293 /* Osmanya: U+10480–U+104AF */
294 { Script_Osmanya, 0x10480, 0x104AF, Script_Osmanya_Numeric, 0},
295 /* END */
296 { SCRIPT_UNDEFINED, 0, 0, 0}
299 typedef struct _scriptData
301 SCRIPT_ANALYSIS a;
302 SCRIPT_PROPERTIES props;
303 OPENTYPE_TAG scriptTag;
304 WCHAR fallbackFont[LF_FACESIZE];
305 } scriptData;
307 /* the must be in order so that the index matches the Script value */
308 static const scriptData scriptInformation[] = {
309 {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
310 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
311 0x00000000,
312 {0}},
313 {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
314 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
315 MS_MAKE_TAG('l','a','t','n'),
316 {0}},
317 {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
318 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
319 0x00000000,
320 {0}},
321 {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
322 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
323 0x00000000,
324 {0}},
325 {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
326 {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
327 0x00000000,
328 {0}},
329 {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
330 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
331 0x00000000,
332 {0}},
333 {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
334 {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
335 MS_MAKE_TAG('a','r','a','b'),
336 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
337 {{Script_Arabic_Numeric, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
338 {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
339 MS_MAKE_TAG('a','r','a','b'),
340 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
341 {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
342 {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
343 MS_MAKE_TAG('h','e','b','r'),
344 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
345 {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
346 {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
347 MS_MAKE_TAG('s','y','r','c'),
348 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
349 {{Script_Persian, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
350 {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
351 MS_MAKE_TAG('s','y','r','c'),
352 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
353 {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
354 {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
355 MS_MAKE_TAG('t','h','a','a'),
356 {'M','V',' ','B','o','l','i',0}},
357 {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
358 {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
359 MS_MAKE_TAG('g','r','e','k'),
360 {0}},
361 {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
362 {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
363 MS_MAKE_TAG('c','y','r','l'),
364 {0}},
365 {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
366 {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
367 MS_MAKE_TAG('a','r','m','n'),
368 {'S','y','l','f','a','e','n',0}},
369 {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
370 {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
371 MS_MAKE_TAG('g','e','o','r'),
372 {'S','y','l','f','a','e','n',0}},
373 {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
374 {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
375 MS_MAKE_TAG('s','i','n','h'),
376 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
377 {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
378 {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
379 MS_MAKE_TAG('t','i','b','t'),
380 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
381 {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
382 {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
383 MS_MAKE_TAG('t','i','b','t'),
384 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
385 {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
386 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
387 MS_MAKE_TAG('p','h','a','g'),
388 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
389 {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
390 {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
391 MS_MAKE_TAG('t','h','a','i'),
392 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
393 {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
394 {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
395 MS_MAKE_TAG('t','h','a','i'),
396 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
397 {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
398 {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
399 MS_MAKE_TAG('l','a','o',' '),
400 {'D','o','k','C','h','a','m','p','a',0}},
401 {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
402 {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
403 MS_MAKE_TAG('l','a','o',' '),
404 {'D','o','k','C','h','a','m','p','a',0}},
405 {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
406 {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
407 MS_MAKE_TAG('d','e','v','a'),
408 {'M','a','n','g','a','l',0}},
409 {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
410 {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
411 MS_MAKE_TAG('d','e','v','a'),
412 {'M','a','n','g','a','l',0}},
413 {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
414 {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
415 MS_MAKE_TAG('b','e','n','g'),
416 {'V','r','i','n','d','a',0}},
417 {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
418 {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
419 MS_MAKE_TAG('b','e','n','g'),
420 {'V','r','i','n','d','a',0}},
421 {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
422 {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
423 MS_MAKE_TAG('b','e','n','g'),
424 {'V','r','i','n','d','a',0}},
425 {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
426 {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
427 MS_MAKE_TAG('g','u','r','u'),
428 {'R','a','a','v','i',0}},
429 {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
430 {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
431 MS_MAKE_TAG('g','u','r','u'),
432 {'R','a','a','v','i',0}},
433 {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
434 {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
435 MS_MAKE_TAG('g','u','j','r'),
436 {'S','h','r','u','t','i',0}},
437 {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
438 {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
439 MS_MAKE_TAG('g','u','j','r'),
440 {'S','h','r','u','t','i',0}},
441 {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
442 {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
443 MS_MAKE_TAG('g','u','j','r'),
444 {'S','h','r','u','t','i',0}},
445 {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
446 {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
447 MS_MAKE_TAG('o','r','y','a'),
448 {'K','a','l','i','n','g','a',0}},
449 {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
450 {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
451 MS_MAKE_TAG('o','r','y','a'),
452 {'K','a','l','i','n','g','a',0}},
453 {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
454 {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
455 MS_MAKE_TAG('t','a','m','l'),
456 {'L','a','t','h','a',0}},
457 {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
458 {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
459 MS_MAKE_TAG('t','a','m','l'),
460 {'L','a','t','h','a',0}},
461 {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
462 {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
463 MS_MAKE_TAG('t','e','l','u'),
464 {'G','a','u','t','a','m','i',0}},
465 {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
466 {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
467 MS_MAKE_TAG('t','e','l','u'),
468 {'G','a','u','t','a','m','i',0}},
469 {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
470 {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
471 MS_MAKE_TAG('k','n','d','a'),
472 {'T','u','n','g','a',0}},
473 {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
474 {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
475 MS_MAKE_TAG('k','n','d','a'),
476 {'T','u','n','g','a',0}},
477 {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
478 {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
479 MS_MAKE_TAG('m','l','y','m'),
480 {'K','a','r','t','i','k','a',0}},
481 {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
482 {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
483 MS_MAKE_TAG('m','l','y','m'),
484 {'K','a','r','t','i','k','a',0}},
485 {{Script_Diacritical, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
486 {LANG_ENGLISH, 0, 1, 0, 1, ANSI_CHARSET, 0, 0, 0, 0, 0, 1, 1, 0, 0},
487 0x00000000,
488 {0}},
489 {{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
490 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
491 MS_MAKE_TAG('l','a','t','n'),
492 {0}},
493 {{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
494 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
495 0x00000000,
496 {0}},
497 {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
498 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
499 MS_MAKE_TAG('m','y','m','r'),
500 {0}},
501 {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
502 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
503 MS_MAKE_TAG('m','y','m','r'),
504 {0}},
505 {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
506 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
507 MS_MAKE_TAG('t','a','l','e'),
508 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e'}},
509 {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
510 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
511 MS_MAKE_TAG('t','a','l','u'),
512 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
513 {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
514 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
515 MS_MAKE_TAG('t','a','l','u'),
516 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
517 {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
518 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
519 MS_MAKE_TAG('k','h','m','r'),
520 {'D','a','u','n','P','e','n','h'}},
521 {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
522 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
523 MS_MAKE_TAG('k','h','m','r'),
524 {'D','a','u','n','P','e','n','h'}},
525 {{Script_CJK_Han, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
526 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
527 MS_MAKE_TAG('h','a','n','i'),
528 {0}},
529 {{Script_Ideograph, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
530 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
531 MS_MAKE_TAG('h','a','n','i'),
532 {0}},
533 {{Script_Bopomofo, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
534 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
535 MS_MAKE_TAG('b','o','p','o'),
536 {0}},
537 {{Script_Kana, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
538 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
539 MS_MAKE_TAG('k','a','n','a'),
540 {0}},
541 {{Script_Hangul, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
542 {LANG_KOREAN, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
543 MS_MAKE_TAG('h','a','n','g'),
544 {0}},
545 {{Script_Yi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
546 {LANG_ENGLISH, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
547 MS_MAKE_TAG('y','i',' ',' '),
548 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i'}},
549 {{Script_Ethiopic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
550 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
551 MS_MAKE_TAG('e','t','h','i'),
552 {'N','y','a','l','a'}},
553 {{Script_Ethiopic_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
554 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
555 MS_MAKE_TAG('e','t','h','i'),
556 {'N','y','a','l','a'}},
557 {{Script_Mongolian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
558 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
559 MS_MAKE_TAG('m','o','n','g'),
560 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i'}},
561 {{Script_Mongolian_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
562 {LANG_MONGOLIAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
563 MS_MAKE_TAG('m','o','n','g'),
564 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i'}},
565 {{Script_Tifinagh, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
566 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
567 MS_MAKE_TAG('t','f','n','g'),
568 {'E','b','r','i','m','a'}},
569 {{Script_NKo, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
570 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
571 MS_MAKE_TAG('n','k','o',' '),
572 {'E','b','r','i','m','a'}},
573 {{Script_Vai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
574 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
575 MS_MAKE_TAG('v','a','i',' '),
576 {'E','b','r','i','m','a'}},
577 {{Script_Vai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
578 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
579 MS_MAKE_TAG('v','a','i',' '),
580 {'E','b','r','i','m','a'}},
581 {{Script_Cherokee, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
582 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
583 MS_MAKE_TAG('c','h','e','r'),
584 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e'}},
585 {{Script_Canadian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
586 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
587 MS_MAKE_TAG('c','a','n','s'),
588 {'E','u','p','h','e','m','i','a'}},
589 {{Script_Ogham, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
590 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
591 MS_MAKE_TAG('o','g','a','m'),
592 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
593 {{Script_Runic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
594 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
595 MS_MAKE_TAG('r','u','n','r'),
596 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
597 {{Script_Braille, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
598 {LANG_ENGLISH, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
599 MS_MAKE_TAG('b','r','a','i'),
600 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
601 {{Script_Surrogates, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
602 {LANG_ENGLISH, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
603 0x00000000,
604 {0}},
605 {{Script_Private, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
606 {0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 1, 0, 0, 0, 0, 1, 0, 0},
607 0x00000000,
608 {0}},
609 {{Script_Deseret, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
610 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
611 MS_MAKE_TAG('d','s','r','t'),
612 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l'}},
613 {{Script_Osmanya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
614 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
615 MS_MAKE_TAG('o','s','m','a'),
616 {'E','b','r','i','m','a'}},
617 {{Script_Osmanya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
618 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
619 MS_MAKE_TAG('o','s','m','a'),
620 {'E','b','r','i','m','a'}},
623 static const SCRIPT_PROPERTIES *script_props[] =
625 &scriptInformation[0].props, &scriptInformation[1].props,
626 &scriptInformation[2].props, &scriptInformation[3].props,
627 &scriptInformation[4].props, &scriptInformation[5].props,
628 &scriptInformation[6].props, &scriptInformation[7].props,
629 &scriptInformation[8].props, &scriptInformation[9].props,
630 &scriptInformation[10].props, &scriptInformation[11].props,
631 &scriptInformation[12].props, &scriptInformation[13].props,
632 &scriptInformation[14].props, &scriptInformation[15].props,
633 &scriptInformation[16].props, &scriptInformation[17].props,
634 &scriptInformation[18].props, &scriptInformation[19].props,
635 &scriptInformation[20].props, &scriptInformation[21].props,
636 &scriptInformation[22].props, &scriptInformation[23].props,
637 &scriptInformation[24].props, &scriptInformation[25].props,
638 &scriptInformation[26].props, &scriptInformation[27].props,
639 &scriptInformation[28].props, &scriptInformation[29].props,
640 &scriptInformation[30].props, &scriptInformation[31].props,
641 &scriptInformation[32].props, &scriptInformation[33].props,
642 &scriptInformation[34].props, &scriptInformation[35].props,
643 &scriptInformation[36].props, &scriptInformation[37].props,
644 &scriptInformation[38].props, &scriptInformation[39].props,
645 &scriptInformation[40].props, &scriptInformation[41].props,
646 &scriptInformation[42].props, &scriptInformation[43].props,
647 &scriptInformation[44].props, &scriptInformation[45].props,
648 &scriptInformation[46].props, &scriptInformation[47].props,
649 &scriptInformation[48].props, &scriptInformation[49].props,
650 &scriptInformation[50].props, &scriptInformation[51].props,
651 &scriptInformation[52].props, &scriptInformation[53].props,
652 &scriptInformation[54].props, &scriptInformation[55].props,
653 &scriptInformation[56].props, &scriptInformation[57].props,
654 &scriptInformation[58].props, &scriptInformation[59].props,
655 &scriptInformation[60].props, &scriptInformation[61].props,
656 &scriptInformation[62].props, &scriptInformation[63].props,
657 &scriptInformation[64].props, &scriptInformation[65].props,
658 &scriptInformation[66].props, &scriptInformation[67].props,
659 &scriptInformation[68].props, &scriptInformation[69].props,
660 &scriptInformation[70].props, &scriptInformation[71].props,
661 &scriptInformation[72].props, &scriptInformation[73].props,
662 &scriptInformation[74].props, &scriptInformation[75].props,
663 &scriptInformation[76].props, &scriptInformation[77].props
666 typedef struct {
667 ScriptCache *sc;
668 int numGlyphs;
669 WORD* glyphs;
670 WORD* pwLogClust;
671 int* piAdvance;
672 SCRIPT_VISATTR* psva;
673 GOFFSET* pGoffset;
674 ABC* abc;
675 int iMaxPosX;
676 HFONT fallbackFont;
677 } StringGlyphs;
679 typedef struct {
680 HDC hdc;
681 DWORD dwFlags;
682 BOOL invalid;
683 int clip_len;
684 int cItems;
685 int cMaxGlyphs;
686 SCRIPT_ITEM* pItem;
687 int numItems;
688 StringGlyphs* glyphs;
689 SCRIPT_LOGATTR* logattrs;
690 SIZE* sz;
691 int* logical2visual;
692 } StringAnalysis;
694 static inline void *heap_alloc(SIZE_T size)
696 return HeapAlloc(GetProcessHeap(), 0, size);
699 static inline void *heap_alloc_zero(SIZE_T size)
701 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
704 static inline void *heap_realloc_zero(LPVOID mem, SIZE_T size)
706 return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
709 static inline BOOL heap_free(LPVOID mem)
711 return HeapFree(GetProcessHeap(), 0, mem);
714 static inline WCHAR get_cache_default_char(SCRIPT_CACHE *psc)
716 return ((ScriptCache *)*psc)->tm.tmDefaultChar;
719 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
721 return ((ScriptCache *)*psc)->tm.tmHeight;
724 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
726 return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
729 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
731 WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
733 if (!block) return 0;
734 return block[c & GLYPH_BLOCK_MASK];
737 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
739 WORD **block = &((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
741 if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
742 return ((*block)[c & GLYPH_BLOCK_MASK] = glyph);
745 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
747 static const ABC nil;
748 ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
750 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
751 memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
752 return TRUE;
755 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
757 ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
759 if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
760 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
761 return TRUE;
764 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
766 ScriptCache *sc;
768 if (!psc) return E_INVALIDARG;
769 if (*psc) return S_OK;
770 if (!hdc) return E_PENDING;
772 if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
773 if (!GetTextMetricsW(hdc, &sc->tm))
775 heap_free(sc);
776 return E_INVALIDARG;
778 if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
780 heap_free(sc);
781 return E_INVALIDARG;
783 sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
784 *psc = sc;
785 TRACE("<- %p\n", sc);
786 return S_OK;
789 static WCHAR mirror_char( WCHAR ch )
791 extern const WCHAR wine_mirror_map[];
792 return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
795 static inline DWORD decode_surrogate_pair(LPCWSTR str, INT index, INT end)
797 if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
799 DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
800 TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
801 return ch;
803 return 0;
806 static WORD get_char_script( LPCWSTR str, INT index, INT end, INT *consumed)
808 static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
809 WORD type = 0;
810 DWORD ch;
811 int i;
813 *consumed = 1;
815 if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
816 return Script_CR;
818 /* These punctuation are separated out as Latin punctuation */
819 if (strchrW(latin_punc,str[index]))
820 return Script_Punctuation2;
822 /* These chars are itemized as Punctuation by Windows */
823 if (str[index] == 0x2212 || str[index] == 0x2044)
824 return Script_Punctuation;
826 GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
828 if (type == 0)
829 return SCRIPT_UNDEFINED;
831 if (type & C1_CNTRL)
832 return Script_Control;
834 ch = decode_surrogate_pair(str, index, end);
835 if (ch)
836 *consumed = 2;
837 else
838 ch = str[index];
840 i = 0;
843 if (ch < scriptRanges[i].rangeFirst || scriptRanges[i].script == SCRIPT_UNDEFINED)
844 break;
846 if (ch >= scriptRanges[i].rangeFirst && ch <= scriptRanges[i].rangeLast)
848 if (scriptRanges[i].numericScript && type & C1_DIGIT)
849 return scriptRanges[i].numericScript;
850 if (scriptRanges[i].punctScript && type & C1_PUNCT)
851 return scriptRanges[i].punctScript;
852 return scriptRanges[i].script;
854 i++;
855 } while (1);
857 return SCRIPT_UNDEFINED;
860 /***********************************************************************
861 * DllMain
864 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
866 switch(fdwReason)
868 case DLL_PROCESS_ATTACH:
869 DisableThreadLibraryCalls(hInstDLL);
870 break;
871 case DLL_PROCESS_DETACH:
872 break;
874 return TRUE;
877 /***********************************************************************
878 * ScriptFreeCache (USP10.@)
880 * Free a script cache.
882 * PARAMS
883 * psc [I/O] Script cache.
885 * RETURNS
886 * Success: S_OK
887 * Failure: Non-zero HRESULT value.
889 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
891 TRACE("%p\n", psc);
893 if (psc && *psc)
895 unsigned int i;
896 for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
898 heap_free(((ScriptCache *)*psc)->glyphs[i]);
899 heap_free(((ScriptCache *)*psc)->widths[i]);
901 heap_free(((ScriptCache *)*psc)->GSUB_Table);
902 heap_free(((ScriptCache *)*psc)->GDEF_Table);
903 heap_free(((ScriptCache *)*psc)->CMAP_Table);
904 heap_free(((ScriptCache *)*psc)->features);
905 heap_free(*psc);
906 *psc = NULL;
908 return S_OK;
911 /***********************************************************************
912 * ScriptGetProperties (USP10.@)
914 * Retrieve a list of script properties.
916 * PARAMS
917 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
918 * num [I] Pointer to the number of scripts.
920 * RETURNS
921 * Success: S_OK
922 * Failure: Non-zero HRESULT value.
924 * NOTES
925 * Behaviour matches WinXP.
927 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
929 TRACE("(%p,%p)\n", props, num);
931 if (!props && !num) return E_INVALIDARG;
933 if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
934 if (props) *props = script_props;
936 return S_OK;
939 /***********************************************************************
940 * ScriptGetFontProperties (USP10.@)
942 * Get information on special glyphs.
944 * PARAMS
945 * hdc [I] Device context.
946 * psc [I/O] Opaque pointer to a script cache.
947 * sfp [O] Font properties structure.
949 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
951 HRESULT hr;
953 TRACE("%p,%p,%p\n", hdc, psc, sfp);
955 if (!sfp) return E_INVALIDARG;
956 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
958 if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
959 return E_INVALIDARG;
961 /* return something sensible? */
962 sfp->wgBlank = 0;
963 sfp->wgDefault = get_cache_default_char(psc);
964 sfp->wgInvalid = 0;
965 sfp->wgKashida = 0xffff;
966 sfp->iKashidaWidth = 0;
968 return S_OK;
971 /***********************************************************************
972 * ScriptRecordDigitSubstitution (USP10.@)
974 * Record digit substitution settings for a given locale.
976 * PARAMS
977 * locale [I] Locale identifier.
978 * sds [I] Structure to record substitution settings.
980 * RETURNS
981 * Success: S_OK
982 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
984 * SEE ALSO
985 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
987 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
989 DWORD plgid, sub;
991 TRACE("0x%x, %p\n", locale, sds);
993 /* This implementation appears to be correct for all languages, but it's
994 * not clear if sds->DigitSubstitute is ever set to anything except
995 * CONTEXT or NONE in reality */
997 if (!sds) return E_POINTER;
999 locale = ConvertDefaultLocale(locale);
1001 if (!IsValidLocale(locale, LCID_INSTALLED))
1002 return E_INVALIDARG;
1004 plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
1005 sds->TraditionalDigitLanguage = plgid;
1007 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1008 sds->NationalDigitLanguage = plgid;
1009 else
1010 sds->NationalDigitLanguage = LANG_ENGLISH;
1012 if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
1013 (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
1015 switch (sub)
1017 case 0:
1018 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1019 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
1020 else
1021 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1022 break;
1023 case 1:
1024 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1025 break;
1026 case 2:
1027 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
1028 break;
1029 default:
1030 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
1031 break;
1034 sds->dwReserved = 0;
1035 return S_OK;
1038 /***********************************************************************
1039 * ScriptApplyDigitSubstitution (USP10.@)
1041 * Apply digit substitution settings.
1043 * PARAMS
1044 * sds [I] Structure with recorded substitution settings.
1045 * sc [I] Script control structure.
1046 * ss [I] Script state structure.
1048 * RETURNS
1049 * Success: S_OK
1050 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1052 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds,
1053 SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
1055 SCRIPT_DIGITSUBSTITUTE psds;
1057 TRACE("%p, %p, %p\n", sds, sc, ss);
1059 if (!sc || !ss) return E_POINTER;
1060 if (!sds)
1062 sds = &psds;
1063 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
1064 return E_INVALIDARG;
1067 sc->uDefaultLanguage = LANG_ENGLISH;
1068 sc->fContextDigits = 0;
1069 ss->fDigitSubstitute = 0;
1071 switch (sds->DigitSubstitute) {
1072 case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
1073 case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
1074 case SCRIPT_DIGITSUBSTITUTE_NONE:
1075 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
1076 return S_OK;
1077 default:
1078 return E_INVALIDARG;
1082 static inline BOOL is_indic(WORD script)
1084 return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
1087 static inline WORD base_indic(WORD script)
1089 switch (script)
1091 case Script_Devanagari:
1092 case Script_Devanagari_Numeric: return Script_Devanagari;
1093 case Script_Bengali:
1094 case Script_Bengali_Numeric:
1095 case Script_Bengali_Currency: return Script_Bengali;
1096 case Script_Gurmukhi:
1097 case Script_Gurmukhi_Numeric: return Script_Gurmukhi;
1098 case Script_Gujarati:
1099 case Script_Gujarati_Numeric:
1100 case Script_Gujarati_Currency: return Script_Gujarati;
1101 case Script_Oriya:
1102 case Script_Oriya_Numeric: return Script_Oriya;
1103 case Script_Tamil:
1104 case Script_Tamil_Numeric: return Script_Tamil;
1105 case Script_Telugu:
1106 case Script_Telugu_Numeric: return Script_Telugu;
1107 case Script_Kannada:
1108 case Script_Kannada_Numeric: return Script_Kannada;
1109 case Script_Malayalam:
1110 case Script_Malayalam_Numeric: return Script_Malayalam;
1111 default:
1112 return -1;
1116 /***********************************************************************
1117 * ScriptItemizeOpenType (USP10.@)
1119 * Split a Unicode string into shapeable parts.
1121 * PARAMS
1122 * pwcInChars [I] String to split.
1123 * cInChars [I] Number of characters in pwcInChars.
1124 * cMaxItems [I] Maximum number of items to return.
1125 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1126 * psState [I] Pointer to a SCRIPT_STATE structure.
1127 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1128 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1129 * pcItems [O] Number of script items returned.
1131 * RETURNS
1132 * Success: S_OK
1133 * Failure: Non-zero HRESULT value.
1135 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1136 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1137 SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
1140 #define Numeric_space 0x0020
1141 #define ZWNJ 0x200C
1142 #define ZWJ 0x200D
1144 int cnt = 0, index = 0, str = 0;
1145 int New_Script = -1;
1146 int i;
1147 WORD *levels = NULL;
1148 WORD *strength = NULL;
1149 WORD *scripts = NULL;
1150 WORD baselevel = 0;
1151 BOOL new_run;
1152 WORD last_indic = -1;
1153 WORD layoutRTL = 0;
1154 BOOL forceLevels = FALSE;
1155 INT consumed = 0;
1157 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
1158 psControl, psState, pItems, pcItems);
1160 if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
1161 return E_INVALIDARG;
1163 scripts = heap_alloc(cInChars * sizeof(WORD));
1164 if (!scripts)
1165 return E_OUTOFMEMORY;
1167 for (i = 0; i < cInChars; i++)
1169 if (consumed <= 0)
1171 scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
1172 consumed --;
1174 else
1176 scripts[i] = scripts[i-1];
1177 consumed --;
1179 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1180 all Indic scripts */
1181 if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic > 0)
1182 scripts[i] = last_indic;
1183 else if (is_indic(scripts[i]))
1184 last_indic = base_indic(scripts[i]);
1186 /* Some unicode points (Zero Width Space U+200B -
1187 Right-to-Left Mark U+200F) will force us into bidi mode */
1188 if (!forceLevels && pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F)
1189 forceLevels = TRUE;
1191 /* Diacritical marks merge with other scripts */
1192 if (scripts[i] == Script_Diacritical && i > 0)
1193 scripts[i] = scripts[i-1];
1196 for (i = 0; i < cInChars; i++)
1198 /* Joiners get merged preferencially right */
1199 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
1201 int j;
1202 if (i+1 == cInChars)
1203 scripts[i] = scripts[i-1];
1204 else
1206 for (j = i+1; j < cInChars; j++)
1208 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
1210 scripts[i] = scripts[j];
1211 break;
1218 if (psState && psControl)
1220 levels = heap_alloc_zero(cInChars * sizeof(WORD));
1221 if (!levels)
1223 heap_free(scripts);
1224 return E_OUTOFMEMORY;
1227 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
1228 baselevel = levels[0];
1229 for (i = 0; i < cInChars; i++)
1230 if (levels[i]!=levels[0])
1231 break;
1232 if (i >= cInChars && !odd(baselevel) && !odd(psState->uBidiLevel) && !forceLevels)
1234 heap_free(levels);
1235 levels = NULL;
1237 else
1239 BOOL inNumber = FALSE;
1240 static WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1242 strength = heap_alloc_zero(cInChars * sizeof(WORD));
1243 if (!strength)
1245 heap_free(scripts);
1246 heap_free(levels);
1247 return E_OUTOFMEMORY;
1249 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
1251 /* We currently mis-level leading Diacriticals */
1252 if (scripts[0] == Script_Diacritical)
1253 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
1255 levels[i] = odd(levels[i])?levels[i]+1:levels[i];
1256 strength[i] = BIDI_STRONG;
1259 for (i = 0; i < cInChars; i++)
1261 /* Script_Numeric and select puncuation at level 0 get bumped to level 2 */
1262 if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && inNumber && strchrW(math_punc,pwcInChars[i]))
1264 scripts[i] = Script_Numeric;
1265 levels[i] = 2;
1267 else if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && scripts[i] == Script_Numeric)
1269 levels[i] = 2;
1270 inNumber = TRUE;
1272 else
1273 inNumber = FALSE;
1275 /* Joiners get merged preferencially right */
1276 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
1278 int j;
1279 if (i+1 == cInChars && levels[i-1] == levels[i])
1280 strength[i] = strength[i-1];
1281 else
1282 for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
1283 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
1285 strength[i] = strength[j];
1286 break;
1290 if (psControl->fMergeNeutralItems)
1292 /* Merge the neutrals */
1293 for (i = 0; i < cInChars; i++)
1295 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1297 int j;
1298 for (j = i; j > 0; j--)
1300 if (levels[i] != levels[j])
1301 break;
1302 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1304 scripts[i] = scripts[j];
1305 strength[i] = strength[j];
1306 break;
1310 /* Try going the other way */
1311 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1313 int j;
1314 for (j = i; j < cInChars; j++)
1316 if (levels[i] != levels[j])
1317 break;
1318 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1320 scripts[i] = scripts[j];
1321 strength[i] = strength[j];
1322 break;
1331 while ((!levels || (levels && levels[cnt+1] == levels[0])) && (pwcInChars[cnt] == Numeric_space) && cnt < cInChars)
1332 cnt++;
1334 if (cnt == cInChars) /* All Spaces */
1336 cnt = 0;
1337 New_Script = scripts[cnt];
1340 pItems[index].iCharPos = 0;
1341 pItems[index].a = scriptInformation[scripts[cnt]].a;
1342 pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
1344 if (strength && strength[cnt] == BIDI_STRONG)
1345 str = strength[cnt];
1346 else if (strength)
1347 str = strength[0];
1349 cnt = 0;
1351 if (levels)
1353 if (strength[cnt] == BIDI_STRONG)
1354 layoutRTL = (odd(levels[cnt]))?1:0;
1355 else
1356 layoutRTL = (psState->uBidiLevel || odd(levels[cnt]))?1:0;
1357 pItems[index].a.fRTL = odd(levels[cnt]);
1358 pItems[index].a.fLayoutRTL = layoutRTL;
1359 pItems[index].a.s.uBidiLevel = levels[cnt];
1361 else if (!pItems[index].a.s.uBidiLevel)
1363 layoutRTL = (odd(baselevel))?1:0;
1364 pItems[index].a.s.uBidiLevel = baselevel;
1365 pItems[index].a.fLayoutRTL = odd(baselevel);
1366 pItems[index].a.fRTL = odd(baselevel);
1369 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1370 levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
1371 pItems[index].iCharPos);
1373 for (cnt=1; cnt < cInChars; cnt++)
1375 if(pwcInChars[cnt] != Numeric_space)
1376 New_Script = scripts[cnt];
1377 else if (levels)
1379 int j = 1;
1380 while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
1381 j++;
1382 if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
1383 New_Script = scripts[cnt+j];
1384 else
1385 New_Script = scripts[cnt];
1388 new_run = FALSE;
1389 /* merge space strengths*/
1390 if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
1391 str = BIDI_STRONG;
1393 if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
1394 str = BIDI_NEUTRAL;
1396 /* changes in level */
1397 if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
1399 TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
1400 new_run = TRUE;
1402 /* changes in strength */
1403 else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
1405 TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
1406 new_run = TRUE;
1408 /* changes in script */
1409 else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
1411 TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
1412 new_run = TRUE;
1415 if (!new_run && strength && str == BIDI_STRONG)
1417 layoutRTL = odd(levels[cnt])?1:0;
1418 pItems[index].a.fLayoutRTL = layoutRTL;
1421 if (new_run)
1423 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);
1425 index++;
1426 if (index+1 > cMaxItems)
1427 return E_OUTOFMEMORY;
1429 if (strength)
1430 str = strength[cnt];
1432 pItems[index].iCharPos = cnt;
1433 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1435 pItems[index].a = scriptInformation[New_Script].a;
1436 pScriptTags[index] = scriptInformation[New_Script].scriptTag;
1437 if (levels)
1439 if (levels[cnt] == 0)
1440 layoutRTL = 0;
1441 else
1442 layoutRTL = (layoutRTL || odd(levels[cnt]))?1:0;
1443 pItems[index].a.fRTL = odd(levels[cnt]);
1444 pItems[index].a.fLayoutRTL = layoutRTL;
1445 pItems[index].a.s.uBidiLevel = levels[cnt];
1447 else if (!pItems[index].a.s.uBidiLevel)
1449 pItems[index].a.s.uBidiLevel = baselevel;
1450 pItems[index].a.fLayoutRTL = layoutRTL;
1451 pItems[index].a.fRTL = odd(baselevel);
1454 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1458 /* While not strictly necessary according to the spec, make sure the n+1
1459 * item is set up to prevent random behaviour if the caller erroneously
1460 * checks the n+1 structure */
1461 index++;
1462 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1464 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1466 /* Set one SCRIPT_STATE item being returned */
1467 if (index + 1 > cMaxItems) return E_OUTOFMEMORY;
1468 if (pcItems) *pcItems = index;
1470 /* Set SCRIPT_ITEM */
1471 pItems[index].iCharPos = cnt; /* the last item contains the ptr to the lastchar */
1472 heap_free(levels);
1473 heap_free(strength);
1474 heap_free(scripts);
1475 return S_OK;
1478 /***********************************************************************
1479 * ScriptItemize (USP10.@)
1481 * Split a Unicode string into shapeable parts.
1483 * PARAMS
1484 * pwcInChars [I] String to split.
1485 * cInChars [I] Number of characters in pwcInChars.
1486 * cMaxItems [I] Maximum number of items to return.
1487 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1488 * psState [I] Pointer to a SCRIPT_STATE structure.
1489 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1490 * pcItems [O] Number of script items returned.
1492 * RETURNS
1493 * Success: S_OK
1494 * Failure: Non-zero HRESULT value.
1496 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1497 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1498 SCRIPT_ITEM *pItems, int *pcItems)
1500 OPENTYPE_TAG *discarded_tags;
1501 HRESULT res;
1503 discarded_tags = heap_alloc(cMaxItems * sizeof(OPENTYPE_TAG));
1504 if (!discarded_tags)
1505 return E_OUTOFMEMORY;
1506 res = ScriptItemizeOpenType(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, discarded_tags, pcItems);
1507 heap_free(discarded_tags);
1508 return res;
1511 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1513 int defWidth;
1514 int cTabStops=0;
1515 INT *lpTabPos = NULL;
1516 INT nTabOrg = 0;
1517 INT x = 0;
1519 if (pTabdef)
1520 lpTabPos = pTabdef->pTabStops;
1522 if (pTabdef && pTabdef->iTabOrigin)
1524 if (pTabdef->iScale)
1525 nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1526 else
1527 nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1530 if (pTabdef)
1531 cTabStops = pTabdef->cTabStops;
1533 if (cTabStops == 1)
1535 if (pTabdef->iScale)
1536 defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1537 else
1538 defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1539 cTabStops = 0;
1541 else
1542 defWidth = 8 * psc->tm.tmAveCharWidth;
1544 for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1546 int position = *lpTabPos;
1547 if (position < 0)
1548 position = -1 * position;
1549 if (pTabdef->iScale)
1550 position = (position * pTabdef->iScale) / 4;
1551 else
1552 position = position * psc->tm.tmAveCharWidth;
1554 if( nTabOrg + position > current_x)
1556 if( *lpTabPos >= 0)
1558 /* a left aligned tab */
1559 x = (nTabOrg + *lpTabPos) - current_x;
1560 break;
1562 else
1564 FIXME("Negative tabstop\n");
1565 break;
1569 if ((!cTabStops) && (defWidth > 0))
1570 x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1571 else if ((!cTabStops) && (defWidth < 0))
1572 FIXME("TODO: Negative defWidth\n");
1574 return x;
1577 /***********************************************************************
1578 * Helper function for ScriptStringAnalyse
1580 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1581 const WCHAR *pwcInChars, int cChars )
1583 /* FIXME: When to properly fallback is still a bit of a mystery */
1584 WORD *glyphs;
1586 if (psa->fNoGlyphIndex)
1587 return FALSE;
1589 if (init_script_cache(hdc, psc) != S_OK)
1590 return FALSE;
1592 if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1593 return TRUE;
1595 glyphs = heap_alloc(sizeof(WORD) * cChars);
1596 if (!glyphs)
1597 return FALSE;
1598 if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1600 heap_free(glyphs);
1601 return TRUE;
1603 heap_free(glyphs);
1605 return FALSE;
1608 static void find_fallback_font(DWORD scriptid, LPWSTR FaceName)
1610 HKEY hkey;
1612 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1614 static const WCHAR szFmt[] = {'%','x',0};
1615 WCHAR value[10];
1616 DWORD count = LF_FACESIZE * sizeof(WCHAR);
1617 DWORD type;
1619 sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1620 if (RegQueryValueExW(hkey, value, 0, &type, (LPBYTE)FaceName, &count))
1621 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1622 RegCloseKey(hkey);
1624 else
1625 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1628 /***********************************************************************
1629 * ScriptStringAnalyse (USP10.@)
1632 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1633 int cGlyphs, int iCharset, DWORD dwFlags,
1634 int iReqWidth, SCRIPT_CONTROL *psControl,
1635 SCRIPT_STATE *psState, const int *piDx,
1636 SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1637 SCRIPT_STRING_ANALYSIS *pssa)
1639 HRESULT hr = E_OUTOFMEMORY;
1640 StringAnalysis *analysis = NULL;
1641 SCRIPT_CONTROL sControl;
1642 SCRIPT_STATE sState;
1643 int i, num_items = 255;
1644 BYTE *BidiLevel;
1645 WCHAR *iString = NULL;
1647 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1648 hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1649 psControl, psState, piDx, pTabdef, pbInClass, pssa);
1651 if (iCharset != -1)
1653 FIXME("Only Unicode strings are supported\n");
1654 return E_INVALIDARG;
1656 if (cString < 1 || !pString) return E_INVALIDARG;
1657 if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1659 if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1660 if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1662 /* FIXME: handle clipping */
1663 analysis->clip_len = cString;
1664 analysis->hdc = hdc;
1665 analysis->dwFlags = dwFlags;
1667 if (psState)
1668 sState = *psState;
1669 else
1670 memset(&sState, 0, sizeof(SCRIPT_STATE));
1672 if (psControl)
1673 sControl = *psControl;
1674 else
1675 memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1677 if (dwFlags & SSA_PASSWORD)
1679 iString = heap_alloc(sizeof(WCHAR)*cString);
1680 if (!iString)
1682 hr = E_OUTOFMEMORY;
1683 goto error;
1685 for (i = 0; i < cString; i++)
1686 iString[i] = *((const WCHAR *)pString);
1687 pString = iString;
1690 hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1691 &analysis->numItems);
1693 while (hr == E_OUTOFMEMORY)
1695 SCRIPT_ITEM *tmp;
1697 num_items *= 2;
1698 if (!(tmp = heap_realloc_zero(analysis->pItem, num_items * sizeof(SCRIPT_ITEM) + 1)))
1699 goto error;
1701 analysis->pItem = tmp;
1702 hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
1703 &analysis->numItems);
1705 if (hr != S_OK) goto error;
1707 /* set back to out of memory for default goto error behaviour */
1708 hr = E_OUTOFMEMORY;
1710 if (dwFlags & SSA_BREAK)
1712 if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
1714 for (i = 0; i < analysis->numItems; i++)
1715 ScriptBreak(&((LPWSTR)pString)[analysis->pItem[i].iCharPos], analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos, &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
1717 else
1718 goto error;
1721 if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
1722 goto error;
1723 if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
1724 goto error;
1726 if (dwFlags & SSA_GLYPHS)
1728 int tab_x = 0;
1729 if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
1731 heap_free(BidiLevel);
1732 goto error;
1735 for (i = 0; i < analysis->numItems; i++)
1737 SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
1738 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1739 int numGlyphs = 1.5 * cChar + 16;
1740 WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
1741 WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
1742 int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
1743 SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
1744 GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
1745 ABC *abc = heap_alloc_zero(sizeof(ABC));
1746 int numGlyphsReturned;
1747 HFONT originalFont = 0x0;
1749 /* FIXME: non unicode strings */
1750 const WCHAR* pStr = (const WCHAR*)pString;
1751 analysis->glyphs[i].fallbackFont = NULL;
1753 if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
1755 heap_free (BidiLevel);
1756 heap_free (glyphs);
1757 heap_free (pwLogClust);
1758 heap_free (piAdvance);
1759 heap_free (psva);
1760 heap_free (pGoffset);
1761 heap_free (abc);
1762 hr = E_OUTOFMEMORY;
1763 goto error;
1766 if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
1768 LOGFONTW lf;
1769 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
1770 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
1771 lf.lfFaceName[0] = 0;
1772 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
1773 if (lf.lfFaceName[0])
1775 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
1776 if (analysis->glyphs[i].fallbackFont)
1778 ScriptFreeCache(sc);
1779 originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
1784 hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
1785 cChar, numGlyphs, &analysis->pItem[i].a,
1786 glyphs, pwLogClust, psva, &numGlyphsReturned);
1787 hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
1788 piAdvance, pGoffset, abc);
1789 if (originalFont)
1790 SelectObject(hdc,originalFont);
1792 if (dwFlags & SSA_TAB)
1794 int tabi = 0;
1795 for (tabi = 0; tabi < cChar; tabi++)
1797 if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
1798 piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
1799 tab_x+=piAdvance[tabi];
1803 analysis->glyphs[i].numGlyphs = numGlyphsReturned;
1804 analysis->glyphs[i].glyphs = glyphs;
1805 analysis->glyphs[i].pwLogClust = pwLogClust;
1806 analysis->glyphs[i].piAdvance = piAdvance;
1807 analysis->glyphs[i].psva = psva;
1808 analysis->glyphs[i].pGoffset = pGoffset;
1809 analysis->glyphs[i].abc = abc;
1810 analysis->glyphs[i].iMaxPosX= -1;
1812 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1815 else
1817 for (i = 0; i < analysis->numItems; i++)
1818 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1821 ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
1822 heap_free(BidiLevel);
1824 *pssa = analysis;
1825 heap_free(iString);
1826 return S_OK;
1828 error:
1829 heap_free(iString);
1830 heap_free(analysis->glyphs);
1831 heap_free(analysis->logattrs);
1832 heap_free(analysis->pItem);
1833 heap_free(analysis->logical2visual);
1834 heap_free(analysis);
1835 return hr;
1838 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
1840 int i;
1842 if (pva[glyph].fClusterStart)
1843 return TRUE;
1844 for (i = 0; i < cChars; i++)
1845 if (pwLogClust[i] == glyph) break;
1846 if (i != cChars)
1847 return TRUE;
1849 return FALSE;
1853 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
1854 int iX,
1855 int iY,
1856 int iItem,
1857 int cStart,
1858 int cEnd,
1859 UINT uOptions,
1860 const RECT *prc,
1861 BOOL fSelected,
1862 BOOL fDisabled)
1864 StringAnalysis *analysis;
1865 int off_x = 0;
1866 HRESULT hr;
1867 COLORREF BkColor = 0x0;
1868 COLORREF TextColor = 0x0;
1869 INT BkMode = 0;
1870 INT runStart, runEnd;
1871 INT iGlyph, cGlyphs;
1872 HFONT oldFont = 0x0;
1874 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
1875 ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
1877 if (!(analysis = ssa)) return E_INVALIDARG;
1879 if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
1880 (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
1881 return S_OK;
1883 if (fSelected)
1885 BkMode = GetBkMode(analysis->hdc);
1886 SetBkMode( analysis->hdc, OPAQUE);
1887 BkColor = GetBkColor(analysis->hdc);
1888 SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
1889 if (!fDisabled)
1891 TextColor = GetTextColor(analysis->hdc);
1892 SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1895 if (analysis->glyphs[iItem].fallbackFont)
1896 oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
1898 if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
1899 runStart = cStart - analysis->pItem[iItem].iCharPos;
1900 else
1901 runStart = 0;
1902 if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
1903 runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
1904 else
1905 runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
1907 if (analysis->pItem[iItem].a.fRTL)
1909 if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
1910 ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
1911 else
1912 ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
1914 else
1916 if (cStart >=0 && runStart)
1917 ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
1918 else
1919 ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
1922 if (analysis->pItem[iItem].a.fRTL)
1923 iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
1924 else
1925 iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
1927 if (analysis->pItem[iItem].a.fRTL)
1928 cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
1929 else
1930 cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
1932 cGlyphs++;
1934 if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
1936 INT direction;
1937 INT clust_glyph;
1939 clust_glyph = iGlyph + cGlyphs;
1940 if (analysis->pItem[iItem].a.fRTL)
1941 direction = -1;
1942 else
1943 direction = 1;
1945 while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
1946 !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
1948 cGlyphs++;
1949 clust_glyph++;
1953 hr = ScriptTextOut(analysis->hdc,
1954 (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
1955 iY, uOptions, prc, &analysis->pItem[iItem].a, NULL, 0,
1956 &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
1957 &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
1958 &analysis->glyphs[iItem].pGoffset[iGlyph]);
1960 TRACE("ScriptTextOut hr=%08x\n", hr);
1962 if (fSelected)
1964 SetBkColor(analysis->hdc, BkColor);
1965 SetBkMode( analysis->hdc, BkMode);
1966 if (!fDisabled)
1967 SetTextColor(analysis->hdc, TextColor);
1969 if (analysis->glyphs[iItem].fallbackFont)
1970 SelectObject(analysis->hdc, oldFont);
1972 return hr;
1975 /***********************************************************************
1976 * ScriptStringOut (USP10.@)
1978 * This function takes the output of ScriptStringAnalyse and joins the segments
1979 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
1980 * only processes glyphs.
1982 * Parameters:
1983 * ssa [I] buffer to hold the analysed string components
1984 * iX [I] X axis displacement for output
1985 * iY [I] Y axis displacement for output
1986 * uOptions [I] flags controling output processing
1987 * prc [I] rectangle coordinates
1988 * iMinSel [I] starting pos for substringing output string
1989 * iMaxSel [I] ending pos for substringing output string
1990 * fDisabled [I] controls text highlighting
1992 * RETURNS
1993 * Success: S_OK
1994 * Failure: is the value returned by ScriptTextOut
1996 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
1997 int iX,
1998 int iY,
1999 UINT uOptions,
2000 const RECT *prc,
2001 int iMinSel,
2002 int iMaxSel,
2003 BOOL fDisabled)
2005 StringAnalysis *analysis;
2006 int item;
2007 HRESULT hr;
2009 TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
2010 ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
2012 if (!(analysis = ssa)) return E_INVALIDARG;
2013 if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
2015 for (item = 0; item < analysis->numItems; item++)
2017 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
2018 if (FAILED(hr))
2019 return hr;
2022 if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
2024 if (iMaxSel > 0 && iMinSel < 0)
2025 iMinSel = 0;
2026 for (item = 0; item < analysis->numItems; item++)
2028 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
2029 if (FAILED(hr))
2030 return hr;
2034 return S_OK;
2037 /***********************************************************************
2038 * ScriptStringCPtoX (USP10.@)
2041 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
2043 int item;
2044 int runningX = 0;
2045 StringAnalysis* analysis = ssa;
2047 TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
2049 if (!ssa || !pX) return S_FALSE;
2050 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2052 /* icp out of range */
2053 if(icp < 0)
2055 analysis->invalid = TRUE;
2056 return E_INVALIDARG;
2059 for(item=0; item<analysis->numItems; item++)
2061 int CP, i;
2062 int offset;
2064 i = analysis->logical2visual[item];
2065 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2066 /* initialize max extents for uninitialized runs */
2067 if (analysis->glyphs[i].iMaxPosX == -1)
2069 if (analysis->pItem[i].a.fRTL)
2070 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2071 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2072 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2073 else
2074 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2075 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2076 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2079 if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
2081 runningX += analysis->glyphs[i].iMaxPosX;
2082 continue;
2085 icp -= analysis->pItem[i].iCharPos;
2086 ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2087 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2088 &analysis->pItem[i].a, &offset);
2089 runningX += offset;
2091 *pX = runningX;
2092 return S_OK;
2095 /* icp out of range */
2096 analysis->invalid = TRUE;
2097 return E_INVALIDARG;
2100 /***********************************************************************
2101 * ScriptStringXtoCP (USP10.@)
2104 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
2106 StringAnalysis* analysis = ssa;
2107 int item;
2109 TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
2111 if (!ssa || !piCh || !piTrailing) return S_FALSE;
2112 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2114 /* out of range */
2115 if(iX < 0)
2117 if (analysis->pItem[0].a.fRTL)
2119 *piCh = 1;
2120 *piTrailing = FALSE;
2122 else
2124 *piCh = -1;
2125 *piTrailing = TRUE;
2127 return S_OK;
2130 for(item=0; item<analysis->numItems; item++)
2132 int i;
2133 int CP;
2135 for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
2136 /* nothing */;
2138 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2139 /* initialize max extents for uninitialized runs */
2140 if (analysis->glyphs[i].iMaxPosX == -1)
2142 if (analysis->pItem[i].a.fRTL)
2143 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2144 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2145 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2146 else
2147 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2148 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2149 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2152 if (iX > analysis->glyphs[i].iMaxPosX)
2154 iX -= analysis->glyphs[i].iMaxPosX;
2155 continue;
2158 ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2159 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2160 &analysis->pItem[i].a, piCh, piTrailing);
2161 *piCh += analysis->pItem[i].iCharPos;
2163 return S_OK;
2166 /* out of range */
2167 *piCh = analysis->pItem[analysis->numItems].iCharPos;
2168 *piTrailing = FALSE;
2170 return S_OK;
2174 /***********************************************************************
2175 * ScriptStringFree (USP10.@)
2177 * Free a string analysis.
2179 * PARAMS
2180 * pssa [I] string analysis.
2182 * RETURNS
2183 * Success: S_OK
2184 * Failure: Non-zero HRESULT value.
2186 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
2188 StringAnalysis* analysis;
2189 BOOL invalid;
2190 int i;
2192 TRACE("(%p)\n", pssa);
2194 if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
2196 invalid = analysis->invalid;
2198 if (analysis->glyphs)
2200 for (i = 0; i < analysis->numItems; i++)
2202 heap_free(analysis->glyphs[i].glyphs);
2203 heap_free(analysis->glyphs[i].pwLogClust);
2204 heap_free(analysis->glyphs[i].piAdvance);
2205 heap_free(analysis->glyphs[i].psva);
2206 heap_free(analysis->glyphs[i].pGoffset);
2207 heap_free(analysis->glyphs[i].abc);
2208 if (analysis->glyphs[i].fallbackFont)
2209 DeleteObject(analysis->glyphs[i].fallbackFont);
2210 ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
2211 heap_free(analysis->glyphs[i].sc);
2213 heap_free(analysis->glyphs);
2216 heap_free(analysis->pItem);
2217 heap_free(analysis->logattrs);
2218 heap_free(analysis->sz);
2219 heap_free(analysis->logical2visual);
2220 heap_free(analysis);
2222 if (invalid) return E_INVALIDARG;
2223 return S_OK;
2226 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
2227 int direction, int* iCluster, int *check_out)
2229 int clust_size = 1;
2230 int check;
2231 WORD clust = pwLogClust[item];
2233 for (check = item+direction; check < cChars && check >= 0; check+=direction)
2235 if (pwLogClust[check] == clust)
2237 clust_size ++;
2238 if (iCluster && *iCluster == -1)
2239 *iCluster = item;
2241 else break;
2244 if (check_out)
2245 *check_out = check;
2247 return clust_size;
2250 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)
2252 int advance;
2253 int log_clust_max = 0;
2254 int i;
2256 advance = piAdvance[glyph];
2258 for (i = 0; i < cChars; i++)
2260 if (pwLogClust[i] > log_clust_max)
2261 log_clust_max = pwLogClust[i];
2264 if (glyph > log_clust_max)
2265 return advance;
2267 for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
2270 if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
2271 break;
2272 if (glyph > log_clust_max)
2273 break;
2274 advance += piAdvance[glyph];
2277 return advance;
2280 /***********************************************************************
2281 * ScriptCPtoX (USP10.@)
2284 HRESULT WINAPI ScriptCPtoX(int iCP,
2285 BOOL fTrailing,
2286 int cChars,
2287 int cGlyphs,
2288 const WORD *pwLogClust,
2289 const SCRIPT_VISATTR *psva,
2290 const int *piAdvance,
2291 const SCRIPT_ANALYSIS *psa,
2292 int *piX)
2294 int item;
2295 float iPosX;
2296 int iSpecial = -1;
2297 int iCluster = -1;
2298 int clust_size = 1;
2299 float special_size = 0.0;
2300 int iMaxPos = 0;
2301 int advance = 0;
2302 BOOL rtl = FALSE;
2304 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2305 iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2306 psa, piX);
2308 if (psa->fRTL && ! psa->fLogicalOrder)
2309 rtl = TRUE;
2311 if (fTrailing)
2312 iCP++;
2314 if (rtl)
2316 int max_clust = pwLogClust[0];
2318 for (item=0; item < cGlyphs; item++)
2319 if (pwLogClust[item] > max_clust)
2321 ERR("We do not handle non reversed clusters properly\n");
2322 break;
2325 iMaxPos = 0;
2326 for (item = max_clust; item >=0; item --)
2327 iMaxPos += piAdvance[item];
2330 iPosX = 0.0;
2331 for (item=0; item < iCP && item < cChars; item++)
2333 if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
2335 int check;
2336 int clust = pwLogClust[item];
2338 iCluster = -1;
2339 clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2340 &check);
2342 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2344 if (check >= cChars && !iMaxPos)
2346 for (check = clust; check < cChars; check++)
2347 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, 1);
2348 iSpecial = item;
2349 special_size /= (cChars - item);
2350 iPosX += special_size;
2352 else
2354 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2356 clust_size --;
2357 if (clust_size == 0)
2358 iPosX += advance;
2360 else
2361 iPosX += advance / (float)clust_size;
2364 else if (iSpecial != -1)
2365 iPosX += special_size;
2366 else /* (iCluster != -1) */
2368 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2369 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2371 clust_size --;
2372 if (clust_size == 0)
2373 iPosX += adv;
2375 else
2376 iPosX += adv / (float)clust_size;
2380 if (iMaxPos > 0)
2382 iPosX = iMaxPos - iPosX;
2383 if (iPosX < 0)
2384 iPosX = 0;
2387 *piX = iPosX;
2388 TRACE("*piX=%d\n", *piX);
2389 return S_OK;
2392 /***********************************************************************
2393 * ScriptXtoCP (USP10.@)
2396 HRESULT WINAPI ScriptXtoCP(int iX,
2397 int cChars,
2398 int cGlyphs,
2399 const WORD *pwLogClust,
2400 const SCRIPT_VISATTR *psva,
2401 const int *piAdvance,
2402 const SCRIPT_ANALYSIS *psa,
2403 int *piCP,
2404 int *piTrailing)
2406 int item;
2407 float iPosX;
2408 float iLastPosX;
2409 int iSpecial = -1;
2410 int iCluster = -1;
2411 int clust_size = 1;
2412 int cjump = 0;
2413 int advance;
2414 float special_size = 0.0;
2415 int direction = 1;
2417 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2418 iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2419 psa, piCP, piTrailing);
2421 if (psa->fRTL && ! psa->fLogicalOrder)
2422 direction = -1;
2424 if (direction<0)
2426 int max_clust = pwLogClust[0];
2428 if (iX < 0)
2430 *piCP = cChars;
2431 *piTrailing = 0;
2432 return S_OK;
2435 for (item=0; item < cChars; item++)
2436 if (pwLogClust[item] > max_clust)
2438 ERR("We do not handle non reversed clusters properly\n");
2439 break;
2443 if (iX < 0)
2445 *piCP = -1;
2446 *piTrailing = 1;
2447 return S_OK;
2450 iPosX = iLastPosX = 0;
2451 if (direction > 0)
2452 item = 0;
2453 else
2454 item = cChars - 1;
2455 for (; iPosX <= iX && item < cChars && item >= 0; item+=direction)
2457 iLastPosX = iPosX;
2458 if (iSpecial == -1 &&
2459 (iCluster == -1 ||
2460 (iCluster != -1 &&
2461 ((direction > 0 && iCluster+clust_size <= item) ||
2462 (direction < 0 && iCluster-clust_size >= item))
2467 int check;
2468 int clust = pwLogClust[item];
2470 iCluster = -1;
2471 cjump = 0;
2472 clust_size = get_cluster_size(pwLogClust, cChars, item, direction,
2473 &iCluster, &check);
2474 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, direction);
2476 if (check >= cChars && direction > 0)
2478 for (check = clust; check < cChars; check++)
2479 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, direction);
2480 iSpecial = item;
2481 special_size /= (cChars - item);
2482 iPosX += special_size;
2484 else
2486 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2488 if (!cjump)
2489 iPosX += advance;
2490 cjump++;
2492 else
2493 iPosX += advance / (float)clust_size;
2496 else if (iSpecial != -1)
2497 iPosX += special_size;
2498 else /* (iCluster != -1) */
2500 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], direction);
2501 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2503 if (!cjump)
2504 iPosX += adv;
2505 cjump++;
2507 else
2508 iPosX += adv / (float)clust_size;
2512 if (direction > 0)
2514 if (iPosX > iX)
2515 item--;
2516 if (item < cChars && ((iPosX - iLastPosX) / 2.0) + iX >= iPosX)
2518 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
2519 item+=(clust_size-1);
2520 *piTrailing = 1;
2522 else
2523 *piTrailing = 0;
2525 else
2527 if (iX == iLastPosX)
2528 item++;
2529 if (iX >= iLastPosX && iX <= iPosX)
2530 item++;
2532 if (iLastPosX == iX)
2533 *piTrailing = 0;
2534 else if (item < 0 || ((iLastPosX - iPosX) / 2.0) + iX <= iLastPosX)
2536 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
2537 item-=(clust_size-1);
2538 *piTrailing = 1;
2540 else
2541 *piTrailing = 0;
2544 *piCP = item;
2546 TRACE("*piCP=%d\n", *piCP);
2547 TRACE("*piTrailing=%d\n", *piTrailing);
2548 return S_OK;
2551 /***********************************************************************
2552 * ScriptBreak (USP10.@)
2554 * Retrieve line break information.
2556 * PARAMS
2557 * chars [I] Array of characters.
2558 * sa [I] String analysis.
2559 * la [I] Array of logical attribute structures.
2561 * RETURNS
2562 * Success: S_OK
2563 * Failure: S_FALSE
2565 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2567 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2569 if (!la) return S_FALSE;
2571 BREAK_line(chars, count, sa, la);
2573 return S_OK;
2576 /***********************************************************************
2577 * ScriptIsComplex (USP10.@)
2579 * Determine if a string is complex.
2581 * PARAMS
2582 * chars [I] Array of characters to test.
2583 * len [I] Length in characters.
2584 * flag [I] Flag.
2586 * RETURNS
2587 * Success: S_OK
2588 * Failure: S_FALSE
2591 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
2593 int i;
2594 INT consumed = 0;
2596 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
2598 for (i = 0; i < len; i+=consumed)
2600 int script;
2601 if (i >= len)
2602 break;
2604 if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
2605 return S_OK;
2607 script = get_char_script(chars,i,len, &consumed);
2608 if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
2609 (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
2610 return S_OK;
2612 return S_FALSE;
2615 /***********************************************************************
2616 * ScriptShapeOpenType (USP10.@)
2618 * Produce glyphs and visual attributes for a run.
2620 * PARAMS
2621 * hdc [I] Device context.
2622 * psc [I/O] Opaque pointer to a script cache.
2623 * psa [I/O] Script analysis.
2624 * tagScript [I] The OpenType tag for the Script
2625 * tagLangSys [I] The OpenType tag for the Language
2626 * rcRangeChars[I] Array of Character counts in each range
2627 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2628 * cRanges [I] Count of ranges
2629 * pwcChars [I] Array of characters specifying the run.
2630 * cChars [I] Number of characters in pwcChars.
2631 * cMaxGlyphs [I] Length of pwOutGlyphs.
2632 * pwLogClust [O] Array of logical cluster info.
2633 * pCharProps [O] Array of character property values
2634 * pwOutGlyphs [O] Array of glyphs.
2635 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
2636 * pcGlyphs [O] Number of glyphs returned.
2638 * RETURNS
2639 * Success: S_OK
2640 * Failure: Non-zero HRESULT value.
2642 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
2643 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2644 OPENTYPE_TAG tagLangSys, int *rcRangeChars,
2645 TEXTRANGE_PROPERTIES **rpRangeProperties,
2646 int cRanges, const WCHAR *pwcChars, int cChars,
2647 int cMaxGlyphs, WORD *pwLogClust,
2648 SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
2649 SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
2651 HRESULT hr;
2652 unsigned int i,g;
2653 BOOL rtl;
2654 int cluster;
2656 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
2657 hdc, psc, psa,
2658 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2659 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2660 cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
2662 if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
2663 psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
2665 if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
2666 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2668 if (cRanges)
2669 FIXME("Ranges not supported yet\n");
2671 rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
2673 *pcGlyphs = cChars;
2674 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2675 if (!pwLogClust) return E_FAIL;
2677 ((ScriptCache *)*psc)->userScript = tagScript;
2678 ((ScriptCache *)*psc)->userLang = tagLangSys;
2680 /* set fNoGlyphIndex non truetype/opentype fonts */
2681 if (!psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
2682 psa->fNoGlyphIndex = TRUE;
2684 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
2685 for (i = 0; i < cChars; i++)
2687 int idx = i;
2688 if (rtl) idx = cChars - 1 - i;
2689 /* FIXME: set to better values */
2690 pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
2691 pOutGlyphProps[i].sva.fClusterStart = 1;
2692 pOutGlyphProps[i].sva.fDiacritic = 0;
2693 pOutGlyphProps[i].sva.fZeroWidth = 0;
2694 pOutGlyphProps[i].sva.fReserved = 0;
2695 pOutGlyphProps[i].sva.fShapeReserved = 0;
2697 /* FIXME: have the shaping engine set this */
2698 pCharProps[i].fCanGlyphAlone = 0;
2700 pwLogClust[i] = idx;
2703 if (psa && !psa->fNoGlyphIndex)
2705 WCHAR *rChars;
2706 if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
2708 rChars = heap_alloc(sizeof(WCHAR) * cChars);
2709 if (!rChars) return E_OUTOFMEMORY;
2710 for (i = 0, g = 0, cluster = 0; i < cChars; i++)
2712 int idx = i;
2713 DWORD chInput;
2715 if (rtl) idx = cChars - 1 - i;
2716 if (!cluster)
2718 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
2719 if (!chInput)
2721 if (psa->fRTL)
2722 chInput = mirror_char(pwcChars[idx]);
2723 else
2724 chInput = pwcChars[idx];
2725 /* special case for tabs */
2726 if (chInput == 0x0009)
2727 chInput = 0x0020;
2728 rChars[i] = chInput;
2730 else
2732 rChars[i] = pwcChars[idx];
2733 rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
2734 cluster = 1;
2736 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
2738 WORD glyph;
2739 if (!hdc)
2741 heap_free(rChars);
2742 return E_PENDING;
2744 if (CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
2746 heap_free(rChars);
2747 return S_FALSE;
2749 pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
2751 g++;
2753 else
2755 int k;
2756 cluster--;
2757 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
2758 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
2759 pwLogClust[k]--;
2762 *pcGlyphs = g;
2764 SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2765 SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
2766 SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
2767 heap_free(rChars);
2769 else
2771 TRACE("no glyph translation\n");
2772 for (i = 0; i < cChars; i++)
2774 int idx = i;
2775 /* No mirroring done here */
2776 if (rtl) idx = cChars - 1 - i;
2777 pwOutGlyphs[i] = pwcChars[idx];
2781 return S_OK;
2785 /***********************************************************************
2786 * ScriptShape (USP10.@)
2788 * Produce glyphs and visual attributes for a run.
2790 * PARAMS
2791 * hdc [I] Device context.
2792 * psc [I/O] Opaque pointer to a script cache.
2793 * pwcChars [I] Array of characters specifying the run.
2794 * cChars [I] Number of characters in pwcChars.
2795 * cMaxGlyphs [I] Length of pwOutGlyphs.
2796 * psa [I/O] Script analysis.
2797 * pwOutGlyphs [O] Array of glyphs.
2798 * pwLogClust [O] Array of logical cluster info.
2799 * psva [O] Array of visual attributes.
2800 * pcGlyphs [O] Number of glyphs returned.
2802 * RETURNS
2803 * Success: S_OK
2804 * Failure: Non-zero HRESULT value.
2806 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
2807 int cChars, int cMaxGlyphs,
2808 SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
2809 SCRIPT_VISATTR *psva, int *pcGlyphs)
2811 HRESULT hr;
2812 int i;
2813 SCRIPT_CHARPROP *charProps;
2814 SCRIPT_GLYPHPROP *glyphProps;
2816 if (!psva || !pcGlyphs) return E_INVALIDARG;
2817 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2819 charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
2820 if (!charProps) return E_OUTOFMEMORY;
2821 glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
2822 if (!glyphProps)
2824 heap_free(charProps);
2825 return E_OUTOFMEMORY;
2828 hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
2830 if (SUCCEEDED(hr))
2832 for (i = 0; i < *pcGlyphs; i++)
2833 psva[i] = glyphProps[i].sva;
2836 heap_free(charProps);
2837 heap_free(glyphProps);
2839 return hr;
2842 /***********************************************************************
2843 * ScriptPlaceOpenType (USP10.@)
2845 * Produce advance widths for a run.
2847 * PARAMS
2848 * hdc [I] Device context.
2849 * psc [I/O] Opaque pointer to a script cache.
2850 * psa [I/O] String analysis.
2851 * tagScript [I] The OpenType tag for the Script
2852 * tagLangSys [I] The OpenType tag for the Language
2853 * rcRangeChars[I] Array of Character counts in each range
2854 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2855 * cRanges [I] Count of ranges
2856 * pwcChars [I] Array of characters specifying the run.
2857 * pwLogClust [I] Array of logical cluster info
2858 * pCharProps [I] Array of character property values
2859 * cChars [I] Number of characters in pwcChars.
2860 * pwGlyphs [I] Array of glyphs.
2861 * pGlyphProps [I] Array of attributes for the retrieved glyphs
2862 * cGlyphs [I] Count of Glyphs
2863 * piAdvance [O] Array of advance widths.
2864 * pGoffset [O] Glyph offsets.
2865 * pABC [O] Combined ABC width.
2867 * RETURNS
2868 * Success: S_OK
2869 * Failure: Non-zero HRESULT value.
2872 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
2873 OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
2874 int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
2875 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
2876 SCRIPT_CHARPROP *pCharProps, int cChars,
2877 const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
2878 int cGlyphs, int *piAdvance,
2879 GOFFSET *pGoffset, ABC *pABC
2882 HRESULT hr;
2883 int i;
2885 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
2886 hdc, psc, psa,
2887 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2888 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2889 pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
2890 pGoffset, pABC);
2892 if (!pGlyphProps) return E_INVALIDARG;
2893 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2894 if (!pGoffset) return E_FAIL;
2896 if (cRanges)
2897 FIXME("Ranges not supported yet\n");
2899 ((ScriptCache *)*psc)->userScript = tagScript;
2900 ((ScriptCache *)*psc)->userLang = tagLangSys;
2902 if (pABC) memset(pABC, 0, sizeof(ABC));
2903 for (i = 0; i < cGlyphs; i++)
2905 ABC abc;
2906 if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
2908 if (!hdc) return E_PENDING;
2909 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
2911 if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
2913 else
2915 INT width;
2916 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
2917 abc.abcB = width;
2918 abc.abcA = abc.abcC = 0;
2920 set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
2922 if (pABC)
2924 pABC->abcA += abc.abcA;
2925 pABC->abcB += abc.abcB;
2926 pABC->abcC += abc.abcC;
2928 /* FIXME: set to more reasonable values */
2929 pGoffset[i].du = pGoffset[i].dv = 0;
2930 if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
2933 if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
2934 return S_OK;
2937 /***********************************************************************
2938 * ScriptPlace (USP10.@)
2940 * Produce advance widths for a run.
2942 * PARAMS
2943 * hdc [I] Device context.
2944 * psc [I/O] Opaque pointer to a script cache.
2945 * pwGlyphs [I] Array of glyphs.
2946 * cGlyphs [I] Number of glyphs in pwGlyphs.
2947 * psva [I] Array of visual attributes.
2948 * psa [I/O] String analysis.
2949 * piAdvance [O] Array of advance widths.
2950 * pGoffset [O] Glyph offsets.
2951 * pABC [O] Combined ABC width.
2953 * RETURNS
2954 * Success: S_OK
2955 * Failure: Non-zero HRESULT value.
2957 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
2958 int cGlyphs, const SCRIPT_VISATTR *psva,
2959 SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
2961 HRESULT hr;
2962 SCRIPT_GLYPHPROP *glyphProps;
2963 int i;
2965 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
2966 piAdvance, pGoffset, pABC);
2968 if (!psva) return E_INVALIDARG;
2969 if (!pGoffset) return E_FAIL;
2971 glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
2972 if (!glyphProps) return E_OUTOFMEMORY;
2974 for (i = 0; i < cGlyphs; i++)
2975 glyphProps[i].sva = psva[i];
2977 hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
2979 heap_free(glyphProps);
2981 return hr;
2984 /***********************************************************************
2985 * ScriptGetCMap (USP10.@)
2987 * Retrieve glyph indices.
2989 * PARAMS
2990 * hdc [I] Device context.
2991 * psc [I/O] Opaque pointer to a script cache.
2992 * pwcInChars [I] Array of Unicode characters.
2993 * cChars [I] Number of characters in pwcInChars.
2994 * dwFlags [I] Flags.
2995 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
2997 * RETURNS
2998 * Success: S_OK
2999 * Failure: Non-zero HRESULT value.
3001 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
3002 int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
3004 HRESULT hr;
3005 int i;
3007 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
3008 cChars, dwFlags, pwOutGlyphs);
3010 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3012 hr = S_OK;
3014 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3016 for (i = 0; i < cChars; i++)
3018 WCHAR inChar;
3019 if (dwFlags == SGCM_RTL)
3020 inChar = mirror_char(pwcInChars[i]);
3021 else
3022 inChar = pwcInChars[i];
3023 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
3025 WORD glyph;
3026 if (!hdc) return E_PENDING;
3027 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
3028 if (glyph == 0xffff)
3030 hr = S_FALSE;
3031 glyph = 0x0;
3033 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
3037 else
3039 TRACE("no glyph translation\n");
3040 for (i = 0; i < cChars; i++)
3042 WCHAR inChar;
3043 if (dwFlags == SGCM_RTL)
3044 inChar = mirror_char(pwcInChars[i]);
3045 else
3046 inChar = pwcInChars[i];
3047 pwOutGlyphs[i] = inChar;
3050 return hr;
3053 /***********************************************************************
3054 * ScriptTextOut (USP10.@)
3057 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
3058 const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
3059 int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
3060 const int *piJustify, const GOFFSET *pGoffset)
3062 HRESULT hr = S_OK;
3064 TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3065 hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
3066 piAdvance, piJustify, pGoffset);
3068 if (!hdc || !psc) return E_INVALIDARG;
3069 if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
3071 fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
3072 fuOptions |= ETO_IGNORELANGUAGE;
3073 if (!psa->fNoGlyphIndex) /* Have Glyphs? */
3074 fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */
3076 if (psa->fRTL && psa->fLogicalOrder)
3078 int i;
3079 WORD *rtlGlyphs;
3081 rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD));
3082 if (!rtlGlyphs)
3083 return E_OUTOFMEMORY;
3085 for (i = 0; i < cGlyphs; i++)
3086 rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i];
3088 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL))
3089 hr = S_FALSE;
3090 heap_free(rtlGlyphs);
3092 else
3093 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
3094 hr = S_FALSE;
3096 return hr;
3099 /***********************************************************************
3100 * ScriptCacheGetHeight (USP10.@)
3102 * Retrieve the height of the font in the cache.
3104 * PARAMS
3105 * hdc [I] Device context.
3106 * psc [I/O] Opaque pointer to a script cache.
3107 * height [O] Receives font height.
3109 * RETURNS
3110 * Success: S_OK
3111 * Failure: Non-zero HRESULT value.
3113 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
3115 HRESULT hr;
3117 TRACE("(%p, %p, %p)\n", hdc, psc, height);
3119 if (!height) return E_INVALIDARG;
3120 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3122 *height = get_cache_height(psc);
3123 return S_OK;
3126 /***********************************************************************
3127 * ScriptGetGlyphABCWidth (USP10.@)
3129 * Retrieve the width of a glyph.
3131 * PARAMS
3132 * hdc [I] Device context.
3133 * psc [I/O] Opaque pointer to a script cache.
3134 * glyph [I] Glyph to retrieve the width for.
3135 * abc [O] ABC widths of the glyph.
3137 * RETURNS
3138 * Success: S_OK
3139 * Failure: Non-zero HRESULT value.
3141 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
3143 HRESULT hr;
3145 TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
3147 if (!abc) return E_INVALIDARG;
3148 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3150 if (!get_cache_glyph_widths(psc, glyph, abc))
3152 if (!hdc) return E_PENDING;
3153 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3155 if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
3157 else
3159 INT width;
3160 if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
3161 abc->abcB = width;
3162 abc->abcA = abc->abcC = 0;
3164 set_cache_glyph_widths(psc, glyph, abc);
3166 return S_OK;
3169 /***********************************************************************
3170 * ScriptLayout (USP10.@)
3172 * Map embedding levels to visual and/or logical order.
3174 * PARAMS
3175 * runs [I] Size of level array.
3176 * level [I] Array of embedding levels.
3177 * vistolog [O] Map of embedding levels from visual to logical order.
3178 * logtovis [O] Map of embedding levels from logical to visual order.
3180 * RETURNS
3181 * Success: S_OK
3182 * Failure: Non-zero HRESULT value.
3184 * BUGS
3185 * This stub works correctly for any sequence of a single
3186 * embedding level but not for sequences of different
3187 * embedding levels, i.e. mixtures of RTL and LTR scripts.
3189 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
3191 int* indexs;
3192 int ich;
3194 TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
3196 if (!level || (!vistolog && !logtovis))
3197 return E_INVALIDARG;
3199 indexs = heap_alloc(sizeof(int) * runs);
3200 if (!indexs)
3201 return E_OUTOFMEMORY;
3204 if (vistolog)
3206 for( ich = 0; ich < runs; ich++)
3207 indexs[ich] = ich;
3209 ich = 0;
3210 while (ich < runs)
3211 ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3212 for (ich = 0; ich < runs; ich++)
3213 vistolog[ich] = indexs[ich];
3217 if (logtovis)
3219 for( ich = 0; ich < runs; ich++)
3220 indexs[ich] = ich;
3222 ich = 0;
3223 while (ich < runs)
3224 ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3225 for (ich = 0; ich < runs; ich++)
3226 logtovis[ich] = indexs[ich];
3228 heap_free(indexs);
3230 return S_OK;
3233 /***********************************************************************
3234 * ScriptStringGetLogicalWidths (USP10.@)
3236 * Returns logical widths from a string analysis.
3238 * PARAMS
3239 * ssa [I] string analysis.
3240 * piDx [O] logical widths returned.
3242 * RETURNS
3243 * Success: S_OK
3244 * Failure: a non-zero HRESULT.
3246 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
3248 int i, j, next = 0;
3249 StringAnalysis *analysis = ssa;
3251 TRACE("%p, %p\n", ssa, piDx);
3253 if (!analysis) return S_FALSE;
3254 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
3256 for (i = 0; i < analysis->numItems; i++)
3258 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
3259 int direction = 1;
3261 if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
3262 direction = -1;
3264 for (j = 0; j < cChar; j++)
3266 int k;
3267 int glyph = analysis->glyphs[i].pwLogClust[j];
3268 int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
3269 cChar, j, direction, NULL, NULL);
3270 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);
3272 for (k = 0; k < clust_size; k++)
3274 piDx[next] = advance / clust_size;
3275 next++;
3276 if (k) j++;
3280 return S_OK;
3283 /***********************************************************************
3284 * ScriptStringValidate (USP10.@)
3286 * Validate a string analysis.
3288 * PARAMS
3289 * ssa [I] string analysis.
3291 * RETURNS
3292 * Success: S_OK
3293 * Failure: S_FALSE if invalid sequences are found
3294 * or a non-zero HRESULT if it fails.
3296 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
3298 StringAnalysis *analysis = ssa;
3300 TRACE("(%p)\n", ssa);
3302 if (!analysis) return E_INVALIDARG;
3303 return (analysis->invalid) ? S_FALSE : S_OK;
3306 /***********************************************************************
3307 * ScriptString_pSize (USP10.@)
3309 * Retrieve width and height of an analysed string.
3311 * PARAMS
3312 * ssa [I] string analysis.
3314 * RETURNS
3315 * Success: Pointer to a SIZE structure.
3316 * Failure: NULL
3318 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
3320 int i, j;
3321 StringAnalysis *analysis = ssa;
3323 TRACE("(%p)\n", ssa);
3325 if (!analysis) return NULL;
3326 if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
3328 if (!analysis->sz)
3330 if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
3331 analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
3333 analysis->sz->cx = 0;
3334 for (i = 0; i < analysis->numItems; i++)
3336 if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
3337 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
3338 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3339 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
3342 return analysis->sz;
3345 /***********************************************************************
3346 * ScriptString_pLogAttr (USP10.@)
3348 * Retrieve logical attributes of an analysed string.
3350 * PARAMS
3351 * ssa [I] string analysis.
3353 * RETURNS
3354 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3355 * Failure: NULL
3357 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
3359 StringAnalysis *analysis = ssa;
3361 TRACE("(%p)\n", ssa);
3363 if (!analysis) return NULL;
3364 if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
3365 return analysis->logattrs;
3368 /***********************************************************************
3369 * ScriptString_pcOutChars (USP10.@)
3371 * Retrieve the length of a string after clipping.
3373 * PARAMS
3374 * ssa [I] String analysis.
3376 * RETURNS
3377 * Success: Pointer to the length.
3378 * Failure: NULL
3380 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
3382 StringAnalysis *analysis = ssa;
3384 TRACE("(%p)\n", ssa);
3386 if (!analysis) return NULL;
3387 return &analysis->clip_len;
3390 /***********************************************************************
3391 * ScriptStringGetOrder (USP10.@)
3393 * Retrieve a glyph order map.
3395 * PARAMS
3396 * ssa [I] String analysis.
3397 * order [I/O] Array of glyph positions.
3399 * RETURNS
3400 * Success: S_OK
3401 * Failure: a non-zero HRESULT.
3403 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
3405 int i, j;
3406 unsigned int k;
3407 StringAnalysis *analysis = ssa;
3409 TRACE("(%p)\n", ssa);
3411 if (!analysis) return S_FALSE;
3412 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
3414 /* FIXME: handle RTL scripts */
3415 for (i = 0, k = 0; i < analysis->numItems; i++)
3416 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3417 order[k] = k;
3419 return S_OK;
3422 /***********************************************************************
3423 * ScriptGetLogicalWidths (USP10.@)
3425 * Convert advance widths to logical widths.
3427 * PARAMS
3428 * sa [I] Script analysis.
3429 * nbchars [I] Number of characters.
3430 * nbglyphs [I] Number of glyphs.
3431 * glyph_width [I] Array of glyph widths.
3432 * log_clust [I] Array of logical clusters.
3433 * sva [I] Visual attributes.
3434 * widths [O] Array of logical widths.
3436 * RETURNS
3437 * Success: S_OK
3438 * Failure: a non-zero HRESULT.
3440 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3441 const int *glyph_width, const WORD *log_clust,
3442 const SCRIPT_VISATTR *sva, int *widths)
3444 int i;
3446 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3447 sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);
3449 /* FIXME */
3450 for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
3451 return S_OK;
3454 /***********************************************************************
3455 * ScriptApplyLogicalWidth (USP10.@)
3457 * Generate glyph advance widths.
3459 * PARAMS
3460 * dx [I] Array of logical advance widths.
3461 * num_chars [I] Number of characters.
3462 * num_glyphs [I] Number of glyphs.
3463 * log_clust [I] Array of logical clusters.
3464 * sva [I] Visual attributes.
3465 * advance [I] Array of glyph advance widths.
3466 * sa [I] Script analysis.
3467 * abc [I/O] Summed ABC widths.
3468 * justify [O] Array of glyph advance widths.
3470 * RETURNS
3471 * Success: S_OK
3472 * Failure: a non-zero HRESULT.
3474 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
3475 const WORD *log_clust, const SCRIPT_VISATTR *sva,
3476 const int *advance, const SCRIPT_ANALYSIS *sa,
3477 ABC *abc, int *justify)
3479 int i;
3481 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3482 dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
3484 for (i = 0; i < num_chars; i++) justify[i] = advance[i];
3485 return S_OK;
3488 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
3489 int num_glyphs, int dx, int min_kashida, int *justify)
3491 int i;
3493 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
3495 for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
3496 return S_OK;