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
23 * Uniscribe allows for processing of complex scripts such as joining
24 * and filtering characters and bi-directional text with custom line breaks.
39 #include "usp10_internal.h"
41 #include "wine/debug.h"
42 #include "wine/heap.h"
43 #include "wine/unicode.h"
45 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe
);
47 static const struct usp10_script_range
49 enum usp10_script script
;
52 enum usp10_script numericScript
;
53 enum usp10_script punctScript
;
57 /* Basic Latin: U+0000–U+007A */
58 { Script_Latin
, 0x00, 0x07a , Script_Numeric
, Script_Punctuation
},
59 /* Latin-1 Supplement: U+0080–U+00FF */
60 /* Latin Extended-A: U+0100–U+017F */
61 /* Latin Extended-B: U+0180–U+024F */
62 /* IPA Extensions: U+0250–U+02AF */
63 /* Spacing Modifier Letters:U+02B0–U+02FF */
64 { Script_Latin
, 0x80, 0x2ff , Script_Numeric2
, Script_Punctuation
},
65 /* Combining Diacritical Marks : U+0300–U+036F */
66 { Script_Diacritical
,0x300, 0x36f, 0, 0},
67 /* Greek: U+0370–U+03FF */
68 { Script_Greek
, 0x370, 0x3ff, 0, 0},
69 /* Cyrillic: U+0400–U+04FF */
70 /* Cyrillic Supplement: U+0500–U+052F */
71 { Script_Cyrillic
, 0x400, 0x52f, 0, 0},
72 /* Armenian: U+0530–U+058F */
73 { Script_Armenian
, 0x530, 0x58f, 0, 0},
74 /* Hebrew: U+0590–U+05FF */
75 { Script_Hebrew
, 0x590, 0x5ff, 0, 0},
76 /* Arabic: U+0600–U+06FF */
77 { Script_Arabic
, 0x600, 0x6ef, Script_Arabic_Numeric
, 0},
78 /* Defined by Windows */
79 { Script_Persian
, 0x6f0, 0x6f9, 0, 0},
80 /* Continue Arabic: U+0600–U+06FF */
81 { Script_Arabic
, 0x6fa, 0x6ff, 0, 0},
82 /* Syriac: U+0700–U+074F*/
83 { Script_Syriac
, 0x700, 0x74f, 0, 0},
84 /* Arabic Supplement: U+0750–U+077F */
85 { Script_Arabic
, 0x750, 0x77f, 0, 0},
86 /* Thaana: U+0780–U+07BF */
87 { Script_Thaana
, 0x780, 0x7bf, 0, 0},
88 /* N’Ko: U+07C0–U+07FF */
89 { Script_NKo
, 0x7c0, 0x7ff, 0, 0},
90 /* Devanagari: U+0900–U+097F */
91 { Script_Devanagari
, 0x900, 0x97f, Script_Devanagari_Numeric
, 0},
92 /* Bengali: U+0980–U+09FF */
93 { Script_Bengali
, 0x980, 0x9ff, Script_Bengali_Numeric
, 0},
94 /* Gurmukhi: U+0A00–U+0A7F*/
95 { Script_Gurmukhi
, 0xa00, 0xa7f, Script_Gurmukhi_Numeric
, 0},
96 /* Gujarati: U+0A80–U+0AFF*/
97 { Script_Gujarati
, 0xa80, 0xaff, Script_Gujarati_Numeric
, 0},
98 /* Oriya: U+0B00–U+0B7F */
99 { Script_Oriya
, 0xb00, 0xb7f, Script_Oriya_Numeric
, 0},
100 /* Tamil: U+0B80–U+0BFF */
101 { Script_Tamil
, 0xb80, 0xbff, Script_Tamil_Numeric
, 0},
102 /* Telugu: U+0C00–U+0C7F */
103 { Script_Telugu
, 0xc00, 0xc7f, Script_Telugu_Numeric
, 0},
104 /* Kannada: U+0C80–U+0CFF */
105 { Script_Kannada
, 0xc80, 0xcff, Script_Kannada_Numeric
, 0},
106 /* Malayalam: U+0D00–U+0D7F */
107 { Script_Malayalam
, 0xd00, 0xd7f, Script_Malayalam_Numeric
, 0},
108 /* Sinhala: U+0D80–U+0DFF */
109 { Script_Sinhala
, 0xd80, 0xdff, 0, 0},
110 /* Thai: U+0E00–U+0E7F */
111 { Script_Thai
, 0xe00, 0xe7f, Script_Thai_Numeric
, 0},
112 /* Lao: U+0E80–U+0EFF */
113 { Script_Lao
, 0xe80, 0xeff, Script_Lao_Numeric
, 0},
114 /* Tibetan: U+0F00–U+0FFF */
115 { Script_Tibetan
, 0xf00, 0xfff, 0, 0},
116 /* Myanmar: U+1000–U+109F */
117 { Script_Myanmar
, 0x1000, 0x109f, Script_Myanmar_Numeric
, 0},
118 /* Georgian: U+10A0–U+10FF */
119 { Script_Georgian
, 0x10a0, 0x10ff, 0, 0},
120 /* Hangul Jamo: U+1100–U+11FF */
121 { Script_Hangul
, 0x1100, 0x11ff, 0, 0},
122 /* Ethiopic: U+1200–U+137F */
123 /* Ethiopic Extensions: U+1380–U+139F */
124 { Script_Ethiopic
, 0x1200, 0x139f, 0, 0},
125 /* Cherokee: U+13A0–U+13FF */
126 { Script_Cherokee
, 0x13a0, 0x13ff, 0, 0},
127 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
128 { Script_Canadian
, 0x1400, 0x167f, 0, 0},
129 /* Ogham: U+1680–U+169F */
130 { Script_Ogham
, 0x1680, 0x169f, 0, 0},
131 /* Runic: U+16A0–U+16F0 */
132 { Script_Runic
, 0x16a0, 0x16f0, 0, 0},
133 /* Khmer: U+1780–U+17FF */
134 { Script_Khmer
, 0x1780, 0x17ff, Script_Khmer_Numeric
, 0},
135 /* Mongolian: U+1800–U+18AF */
136 { Script_Mongolian
, 0x1800, 0x18af, Script_Mongolian_Numeric
, 0},
137 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
138 { Script_Canadian
, 0x18b0, 0x18ff, 0, 0},
139 /* Tai Le: U+1950–U+197F */
140 { Script_Tai_Le
, 0x1950, 0x197f, 0, 0},
141 /* New Tai Lue: U+1980–U+19DF */
142 { Script_New_Tai_Lue
,0x1980, 0x19df, Script_New_Tai_Lue_Numeric
, 0},
143 /* Khmer Symbols: U+19E0–U+19FF */
144 { Script_Khmer
, 0x19e0, 0x19ff, Script_Khmer_Numeric
, 0},
145 /* Vedic Extensions: U+1CD0-U+1CFF */
146 { Script_Devanagari
, 0x1cd0, 0x1cff, Script_Devanagari_Numeric
, 0},
147 /* Phonetic Extensions: U+1D00–U+1DBF */
148 { Script_Latin
, 0x1d00, 0x1dbf, 0, 0},
149 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
150 { Script_Diacritical
,0x1dc0, 0x1dff, 0, 0},
151 /* Latin Extended Additional: U+1E00–U+1EFF */
152 { Script_Latin
, 0x1e00, 0x1eff, 0, 0},
153 /* Greek Extended: U+1F00–U+1FFF */
154 { Script_Greek
, 0x1f00, 0x1fff, 0, 0},
155 /* General Punctuation: U+2000 –U+206f */
156 { Script_Latin
, 0x2000, 0x206f, 0, 0},
157 /* Superscripts and Subscripts : U+2070 –U+209f */
158 /* Currency Symbols : U+20a0 –U+20cf */
159 { Script_Numeric2
, 0x2070, 0x2070, 0, 0},
160 { Script_Latin
, 0x2071, 0x2073, 0, 0},
161 { Script_Numeric2
, 0x2074, 0x2079, 0, 0},
162 { Script_Latin
, 0x207a, 0x207f, 0, 0},
163 { Script_Numeric2
, 0x2080, 0x2089, 0, 0},
164 { Script_Latin
, 0x208a, 0x20cf, 0, 0},
165 /* Letterlike Symbols : U+2100 –U+214f */
166 /* Number Forms : U+2150 –U+218f */
167 /* Arrows : U+2190 –U+21ff */
168 /* Mathematical Operators : U+2200 –U+22ff */
169 /* Miscellaneous Technical : U+2300 –U+23ff */
170 /* Control Pictures : U+2400 –U+243f */
171 /* Optical Character Recognition : U+2440 –U+245f */
172 /* Enclosed Alphanumerics : U+2460 –U+24ff */
173 /* Box Drawing : U+2500 –U+25ff */
174 /* Block Elements : U+2580 –U+259f */
175 /* Geometric Shapes : U+25a0 –U+25ff */
176 /* Miscellaneous Symbols : U+2600 –U+26ff */
177 /* Dingbats : U+2700 –U+27bf */
178 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
179 /* Supplemental Arrows-A : U+27f0 –U+27ff */
180 { Script_Latin
, 0x2100, 0x27ff, 0, 0},
181 /* Braille Patterns: U+2800–U+28FF */
182 { Script_Braille
, 0x2800, 0x28ff, 0, 0},
183 /* Supplemental Arrows-B : U+2900 –U+297f */
184 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
185 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
186 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
187 { Script_Latin
, 0x2900, 0x2bff, 0, 0},
188 /* Latin Extended-C: U+2C60–U+2C7F */
189 { Script_Latin
, 0x2c60, 0x2c7f, 0, 0},
190 /* Georgian: U+2D00–U+2D2F */
191 { Script_Georgian
, 0x2d00, 0x2d2f, 0, 0},
192 /* Tifinagh: U+2D30–U+2D7F */
193 { Script_Tifinagh
, 0x2d30, 0x2d7f, 0, 0},
194 /* Ethiopic Extensions: U+2D80–U+2DDF */
195 { Script_Ethiopic
, 0x2d80, 0x2ddf, 0, 0},
196 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
197 { Script_Cyrillic
, 0x2de0, 0x2dff, 0, 0},
198 /* CJK Radicals Supplement: U+2E80–U+2EFF */
199 /* Kangxi Radicals: U+2F00–U+2FDF */
200 { Script_CJK_Han
, 0x2e80, 0x2fdf, 0, 0},
201 /* Ideographic Description Characters: U+2FF0–U+2FFF */
202 { Script_Ideograph
,0x2ff0, 0x2fff, 0, 0},
203 /* CJK Symbols and Punctuation: U+3000–U+303F */
204 { Script_Ideograph
,0x3000, 0x3004, 0, 0},
205 { Script_CJK_Han
,0x3005, 0x3005, 0, 0},
206 { Script_Ideograph
,0x3006, 0x3006, 0, 0},
207 { Script_CJK_Han
,0x3007, 0x3007, 0, 0},
208 { Script_Ideograph
,0x3008, 0x3020, 0, 0},
209 { Script_CJK_Han
,0x3021, 0x3029, 0, 0},
210 { Script_Ideograph
,0x302a, 0x3030, 0, 0},
212 { Script_Kana
,0x3031, 0x3035, 0, 0},
213 { Script_Ideograph
,0x3036, 0x3037, 0, 0},
214 { Script_CJK_Han
,0x3038, 0x303b, 0, 0},
215 { Script_Ideograph
,0x303c, 0x303f, 0, 0},
216 /* Hiragana: U+3040–U+309F */
217 /* Katakana: U+30A0–U+30FF */
218 { Script_Kana
,0x3040, 0x30ff, 0, 0},
219 /* Bopomofo: U+3100–U+312F */
220 { Script_Bopomofo
,0x3100, 0x312f, 0, 0},
221 /* Hangul Compatibility Jamo: U+3130–U+318F */
222 { Script_Hangul
,0x3130, 0x318f, 0, 0},
223 /* Kanbun: U+3190–U+319F */
224 { Script_Ideograph
,0x3190, 0x319f, 0, 0},
225 /* Bopomofo Extended: U+31A0–U+31BF */
226 { Script_Bopomofo
,0x31a0, 0x31bf, 0, 0},
227 /* CJK Strokes: U+31C0–U+31EF */
228 { Script_Ideograph
,0x31c0, 0x31ef, 0, 0},
229 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
230 { Script_Kana
,0x31f0, 0x31ff, 0, 0},
231 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
232 { Script_Hangul
,0x3200, 0x321f, 0, 0},
233 { Script_Ideograph
,0x3220, 0x325f, 0, 0},
234 { Script_Hangul
,0x3260, 0x327f, 0, 0},
235 { Script_Ideograph
,0x3280, 0x32ef, 0, 0},
236 { Script_Kana
,0x32d0, 0x31ff, 0, 0},
237 /* CJK Compatibility: U+3300–U+33FF*/
238 { Script_Kana
,0x3300, 0x3357, 0, 0},
239 { Script_Ideograph
,0x3358, 0x33ff, 0, 0},
240 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
241 { Script_CJK_Han
,0x3400, 0x4dbf, 0, 0},
242 /* CJK Unified Ideographs: U+4E00–U+9FFF */
243 { Script_CJK_Han
,0x4e00, 0x9fff, 0, 0},
244 /* Yi: U+A000–U+A4CF */
245 { Script_Yi
,0xa000, 0xa4cf, 0, 0},
246 /* Vai: U+A500–U+A63F */
247 { Script_Vai
,0xa500, 0xa63f, Script_Vai_Numeric
, 0},
248 /* Cyrillic Extended-B: U+A640–U+A69F */
249 { Script_Cyrillic
, 0xa640, 0xa69f, 0, 0},
250 /* Modifier Tone Letters: U+A700–U+A71F */
251 /* Latin Extended-D: U+A720–U+A7FF */
252 { Script_Latin
, 0xa700, 0xa7ff, 0, 0},
253 /* Phags-pa: U+A840–U+A87F */
254 { Script_Phags_pa
, 0xa840, 0xa87f, 0, 0},
255 /* Devanagari Extended: U+A8E0-U+A8FF */
256 { Script_Devanagari
, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric
, 0},
257 /* Myanmar Extended-A: U+AA60–U+AA7F */
258 { Script_Myanmar
, 0xaa60, 0xaa7f, Script_Myanmar_Numeric
, 0},
259 /* Hangul Jamo Extended-A: U+A960–U+A97F */
260 { Script_Hangul
, 0xa960, 0xa97f, 0, 0},
261 /* Hangul Syllables: U+AC00–U+D7A3 */
262 { Script_Hangul
, 0xac00, 0xd7a3, 0, 0},
263 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
264 { Script_Hangul
, 0xd7b0, 0xd7ff, 0, 0},
265 /* Surrogates Area: U+D800–U+DFFF */
266 { Script_Surrogates
, 0xd800, 0xdbfe, 0, 0},
267 { Script_Private
, 0xdbff, 0xdc00, 0, 0},
268 { Script_Surrogates
, 0xdc01, 0xdfff, 0, 0},
269 /* Private Use Area: U+E000–U+F8FF */
270 { Script_Private
, 0xe000, 0xf8ff, 0, 0},
271 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
272 { Script_CJK_Han
,0xf900, 0xfaff, 0, 0},
273 /* Latin Ligatures: U+FB00–U+FB06 */
274 { Script_Latin
, 0xfb00, 0xfb06, 0, 0},
275 /* Armenian ligatures U+FB13..U+FB17 */
276 { Script_Armenian
, 0xfb13, 0xfb17, 0, 0},
277 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
278 { Script_Hebrew
, 0xfb1d, 0xfb4f, 0, 0},
279 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
280 { Script_Arabic
, 0xfb50, 0xfdff, 0, 0},
281 /* Vertical Forms: U+FE10–U+FE1F */
282 /* Combining Half Marks: U+FE20–U+FE2F */
283 /* CJK Compatibility Forms: U+FE30–U+FE4F */
284 /* Small Form Variants: U+FE50–U+FE6F */
285 { Script_Ideograph
,0xfe10, 0xfe6f, 0, 0},
286 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
287 { Script_Arabic
, 0xfe70, 0xfeff, 0, 0},
288 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
289 { Script_Ideograph
,0xff00, 0xff64, Script_Numeric2
, 0},
290 { Script_Kana
,0xff65, 0xff9f, 0, 0},
291 { Script_Hangul
,0xffa0, 0xffdf, 0, 0},
292 { Script_Ideograph
,0xffe0, 0xffef, 0, 0},
294 /* Deseret: U+10400–U+1044F */
295 { Script_Deseret
, 0x10400, 0x1044F, 0, 0},
296 /* Osmanya: U+10480–U+104AF */
297 { Script_Osmanya
, 0x10480, 0x104AF, Script_Osmanya_Numeric
, 0},
298 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
299 { Script_MathAlpha
, 0x1D400, 0x1D7FF, 0, 0},
302 /* this must be in order so that the index matches the Script value */
303 const scriptData scriptInformation
[] = {
304 {{SCRIPT_UNDEFINED
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
305 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
308 {{Script_Latin
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
309 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
310 MS_MAKE_TAG('l','a','t','n'),
311 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
312 {{Script_CR
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
313 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
316 {{Script_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
317 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
319 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
320 {{Script_Control
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
321 {LANG_ENGLISH
, 0, 1, 0, 0, ANSI_CHARSET
, 1, 0, 0, 0, 0, 0, 1, 0, 0},
324 {{Script_Punctuation
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
325 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
327 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
328 {{Script_Arabic
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
329 {LANG_ARABIC
, 0, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 1, 0},
330 MS_MAKE_TAG('a','r','a','b'),
331 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
332 {{Script_Arabic_Numeric
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
333 {LANG_ARABIC
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
334 MS_MAKE_TAG('a','r','a','b'),
335 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
336 {{Script_Hebrew
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
337 {LANG_HEBREW
, 0, 1, 0, 1, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
338 MS_MAKE_TAG('h','e','b','r'),
339 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
340 {{Script_Syriac
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
341 {LANG_SYRIAC
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 1, 0},
342 MS_MAKE_TAG('s','y','r','c'),
343 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
344 {{Script_Persian
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
345 {LANG_PERSIAN
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
346 MS_MAKE_TAG('a','r','a','b'),
347 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
348 {{Script_Thaana
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
349 {LANG_DIVEHI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
350 MS_MAKE_TAG('t','h','a','a'),
351 {'M','V',' ','B','o','l','i',0}},
352 {{Script_Greek
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
353 {LANG_GREEK
, 0, 0, 0, 0, GREEK_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
354 MS_MAKE_TAG('g','r','e','k'),
355 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
356 {{Script_Cyrillic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
357 {LANG_RUSSIAN
, 0, 0, 0, 0, RUSSIAN_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
358 MS_MAKE_TAG('c','y','r','l'),
359 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
360 {{Script_Armenian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
361 {LANG_ARMENIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
362 MS_MAKE_TAG('a','r','m','n'),
363 {'S','y','l','f','a','e','n',0}},
364 {{Script_Georgian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
365 {LANG_GEORGIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
366 MS_MAKE_TAG('g','e','o','r'),
367 {'S','y','l','f','a','e','n',0}},
368 {{Script_Sinhala
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
369 {LANG_SINHALESE
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
370 MS_MAKE_TAG('s','i','n','h'),
371 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
372 {{Script_Tibetan
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
373 {LANG_TIBETAN
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
374 MS_MAKE_TAG('t','i','b','t'),
375 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
376 {{Script_Tibetan_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
377 {LANG_TIBETAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
378 MS_MAKE_TAG('t','i','b','t'),
379 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
380 {{Script_Phags_pa
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
381 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
382 MS_MAKE_TAG('p','h','a','g'),
383 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
384 {{Script_Thai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
385 {LANG_THAI
, 0, 1, 1, 1, THAI_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 1},
386 MS_MAKE_TAG('t','h','a','i'),
387 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
388 {{Script_Thai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
389 {LANG_THAI
, 1, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
390 MS_MAKE_TAG('t','h','a','i'),
391 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
392 {{Script_Lao
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
393 {LANG_LAO
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
394 MS_MAKE_TAG('l','a','o',' '),
395 {'D','o','k','C','h','a','m','p','a',0}},
396 {{Script_Lao_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
397 {LANG_LAO
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
398 MS_MAKE_TAG('l','a','o',' '),
399 {'D','o','k','C','h','a','m','p','a',0}},
400 {{Script_Devanagari
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
401 {LANG_HINDI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
402 MS_MAKE_TAG('d','e','v','a'),
403 {'M','a','n','g','a','l',0}},
404 {{Script_Devanagari_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
405 {LANG_HINDI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
406 MS_MAKE_TAG('d','e','v','a'),
407 {'M','a','n','g','a','l',0}},
408 {{Script_Bengali
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
409 {LANG_BENGALI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
410 MS_MAKE_TAG('b','e','n','g'),
411 {'V','r','i','n','d','a',0}},
412 {{Script_Bengali_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
413 {LANG_BENGALI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
414 MS_MAKE_TAG('b','e','n','g'),
415 {'V','r','i','n','d','a',0}},
416 {{Script_Bengali_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
417 {LANG_BENGALI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
418 MS_MAKE_TAG('b','e','n','g'),
419 {'V','r','i','n','d','a',0}},
420 {{Script_Gurmukhi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
421 {LANG_PUNJABI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
422 MS_MAKE_TAG('g','u','r','u'),
423 {'R','a','a','v','i',0}},
424 {{Script_Gurmukhi_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
425 {LANG_PUNJABI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
426 MS_MAKE_TAG('g','u','r','u'),
427 {'R','a','a','v','i',0}},
428 {{Script_Gujarati
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
429 {LANG_GUJARATI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
430 MS_MAKE_TAG('g','u','j','r'),
431 {'S','h','r','u','t','i',0}},
432 {{Script_Gujarati_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
433 {LANG_GUJARATI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
434 MS_MAKE_TAG('g','u','j','r'),
435 {'S','h','r','u','t','i',0}},
436 {{Script_Gujarati_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
437 {LANG_GUJARATI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
438 MS_MAKE_TAG('g','u','j','r'),
439 {'S','h','r','u','t','i',0}},
440 {{Script_Oriya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
441 {LANG_ORIYA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
442 MS_MAKE_TAG('o','r','y','a'),
443 {'K','a','l','i','n','g','a',0}},
444 {{Script_Oriya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
445 {LANG_ORIYA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
446 MS_MAKE_TAG('o','r','y','a'),
447 {'K','a','l','i','n','g','a',0}},
448 {{Script_Tamil
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
449 {LANG_TAMIL
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
450 MS_MAKE_TAG('t','a','m','l'),
451 {'L','a','t','h','a',0}},
452 {{Script_Tamil_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
453 {LANG_TAMIL
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
454 MS_MAKE_TAG('t','a','m','l'),
455 {'L','a','t','h','a',0}},
456 {{Script_Telugu
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
457 {LANG_TELUGU
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
458 MS_MAKE_TAG('t','e','l','u'),
459 {'G','a','u','t','a','m','i',0}},
460 {{Script_Telugu_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
461 {LANG_TELUGU
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
462 MS_MAKE_TAG('t','e','l','u'),
463 {'G','a','u','t','a','m','i',0}},
464 {{Script_Kannada
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
465 {LANG_KANNADA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
466 MS_MAKE_TAG('k','n','d','a'),
467 {'T','u','n','g','a',0}},
468 {{Script_Kannada_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
469 {LANG_KANNADA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
470 MS_MAKE_TAG('k','n','d','a'),
471 {'T','u','n','g','a',0}},
472 {{Script_Malayalam
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
473 {LANG_MALAYALAM
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
474 MS_MAKE_TAG('m','l','y','m'),
475 {'K','a','r','t','i','k','a',0}},
476 {{Script_Malayalam_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
477 {LANG_MALAYALAM
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
478 MS_MAKE_TAG('m','l','y','m'),
479 {'K','a','r','t','i','k','a',0}},
480 {{Script_Diacritical
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
481 {LANG_ENGLISH
, 0, 1, 0, 1, ANSI_CHARSET
, 0, 0, 0, 0, 0, 1, 1, 0, 0},
484 {{Script_Punctuation2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
485 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
486 MS_MAKE_TAG('l','a','t','n'),
487 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
488 {{Script_Numeric2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
489 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
492 {{Script_Myanmar
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
493 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
494 MS_MAKE_TAG('m','y','m','r'),
495 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
496 {{Script_Myanmar_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
497 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
498 MS_MAKE_TAG('m','y','m','r'),
500 {{Script_Tai_Le
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
501 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
502 MS_MAKE_TAG('t','a','l','e'),
503 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
504 {{Script_New_Tai_Lue
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
505 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
506 MS_MAKE_TAG('t','a','l','u'),
507 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
508 {{Script_New_Tai_Lue_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
509 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
510 MS_MAKE_TAG('t','a','l','u'),
511 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
512 {{Script_Khmer
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
513 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
514 MS_MAKE_TAG('k','h','m','r'),
515 {'D','a','u','n','P','e','n','h',0}},
516 {{Script_Khmer_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
517 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
518 MS_MAKE_TAG('k','h','m','r'),
519 {'D','a','u','n','P','e','n','h',0}},
520 {{Script_CJK_Han
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
521 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
522 MS_MAKE_TAG('h','a','n','i'),
524 {{Script_Ideograph
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
525 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
526 MS_MAKE_TAG('h','a','n','i'),
528 {{Script_Bopomofo
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
529 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
530 MS_MAKE_TAG('b','o','p','o'),
532 {{Script_Kana
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
533 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
534 MS_MAKE_TAG('k','a','n','a'),
536 {{Script_Hangul
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
537 {LANG_KOREAN
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
538 MS_MAKE_TAG('h','a','n','g'),
540 {{Script_Yi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
541 {LANG_ENGLISH
, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
542 MS_MAKE_TAG('y','i',' ',' '),
543 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
544 {{Script_Ethiopic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
545 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
546 MS_MAKE_TAG('e','t','h','i'),
547 {'N','y','a','l','a',0}},
548 {{Script_Ethiopic_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
549 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
550 MS_MAKE_TAG('e','t','h','i'),
551 {'N','y','a','l','a',0}},
552 {{Script_Mongolian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
553 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
554 MS_MAKE_TAG('m','o','n','g'),
555 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
556 {{Script_Mongolian_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
557 {LANG_MONGOLIAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
558 MS_MAKE_TAG('m','o','n','g'),
559 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
560 {{Script_Tifinagh
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
561 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
562 MS_MAKE_TAG('t','f','n','g'),
563 {'E','b','r','i','m','a',0}},
564 {{Script_NKo
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
565 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
566 MS_MAKE_TAG('n','k','o',' '),
567 {'E','b','r','i','m','a',0}},
568 {{Script_Vai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
569 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
570 MS_MAKE_TAG('v','a','i',' '),
571 {'E','b','r','i','m','a',0}},
572 {{Script_Vai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
573 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
574 MS_MAKE_TAG('v','a','i',' '),
575 {'E','b','r','i','m','a',0}},
576 {{Script_Cherokee
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
577 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
578 MS_MAKE_TAG('c','h','e','r'),
579 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
580 {{Script_Canadian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
581 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
582 MS_MAKE_TAG('c','a','n','s'),
583 {'E','u','p','h','e','m','i','a',0}},
584 {{Script_Ogham
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
585 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
586 MS_MAKE_TAG('o','g','a','m'),
587 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
588 {{Script_Runic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
589 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
590 MS_MAKE_TAG('r','u','n','r'),
591 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
592 {{Script_Braille
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
593 {LANG_ENGLISH
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
594 MS_MAKE_TAG('b','r','a','i'),
595 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
596 {{Script_Surrogates
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
597 {LANG_ENGLISH
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
600 {{Script_Private
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
601 {0, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 1, 0, 0, 0, 0, 1, 0, 0},
604 {{Script_Deseret
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
605 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
606 MS_MAKE_TAG('d','s','r','t'),
607 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
608 {{Script_Osmanya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
609 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
610 MS_MAKE_TAG('o','s','m','a'),
611 {'E','b','r','i','m','a',0}},
612 {{Script_Osmanya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
613 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
614 MS_MAKE_TAG('o','s','m','a'),
615 {'E','b','r','i','m','a',0}},
616 {{Script_MathAlpha
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
617 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
618 MS_MAKE_TAG('m','a','t','h'),
619 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
620 {{Script_Hebrew_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
621 {LANG_HEBREW
, 0, 1, 0, 0, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
622 MS_MAKE_TAG('h','e','b','r'),
623 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
624 {{Script_Vietnamese_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
625 {LANG_VIETNAMESE
, 0, 0, 0, 0, VIETNAMESE_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
626 MS_MAKE_TAG('l','a','t','n'),
627 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
628 {{Script_Thai_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
629 {LANG_THAI
, 0, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
630 MS_MAKE_TAG('t','h','a','i'),
631 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
634 static const SCRIPT_PROPERTIES
*script_props
[] =
636 &scriptInformation
[0].props
, &scriptInformation
[1].props
,
637 &scriptInformation
[2].props
, &scriptInformation
[3].props
,
638 &scriptInformation
[4].props
, &scriptInformation
[5].props
,
639 &scriptInformation
[6].props
, &scriptInformation
[7].props
,
640 &scriptInformation
[8].props
, &scriptInformation
[9].props
,
641 &scriptInformation
[10].props
, &scriptInformation
[11].props
,
642 &scriptInformation
[12].props
, &scriptInformation
[13].props
,
643 &scriptInformation
[14].props
, &scriptInformation
[15].props
,
644 &scriptInformation
[16].props
, &scriptInformation
[17].props
,
645 &scriptInformation
[18].props
, &scriptInformation
[19].props
,
646 &scriptInformation
[20].props
, &scriptInformation
[21].props
,
647 &scriptInformation
[22].props
, &scriptInformation
[23].props
,
648 &scriptInformation
[24].props
, &scriptInformation
[25].props
,
649 &scriptInformation
[26].props
, &scriptInformation
[27].props
,
650 &scriptInformation
[28].props
, &scriptInformation
[29].props
,
651 &scriptInformation
[30].props
, &scriptInformation
[31].props
,
652 &scriptInformation
[32].props
, &scriptInformation
[33].props
,
653 &scriptInformation
[34].props
, &scriptInformation
[35].props
,
654 &scriptInformation
[36].props
, &scriptInformation
[37].props
,
655 &scriptInformation
[38].props
, &scriptInformation
[39].props
,
656 &scriptInformation
[40].props
, &scriptInformation
[41].props
,
657 &scriptInformation
[42].props
, &scriptInformation
[43].props
,
658 &scriptInformation
[44].props
, &scriptInformation
[45].props
,
659 &scriptInformation
[46].props
, &scriptInformation
[47].props
,
660 &scriptInformation
[48].props
, &scriptInformation
[49].props
,
661 &scriptInformation
[50].props
, &scriptInformation
[51].props
,
662 &scriptInformation
[52].props
, &scriptInformation
[53].props
,
663 &scriptInformation
[54].props
, &scriptInformation
[55].props
,
664 &scriptInformation
[56].props
, &scriptInformation
[57].props
,
665 &scriptInformation
[58].props
, &scriptInformation
[59].props
,
666 &scriptInformation
[60].props
, &scriptInformation
[61].props
,
667 &scriptInformation
[62].props
, &scriptInformation
[63].props
,
668 &scriptInformation
[64].props
, &scriptInformation
[65].props
,
669 &scriptInformation
[66].props
, &scriptInformation
[67].props
,
670 &scriptInformation
[68].props
, &scriptInformation
[69].props
,
671 &scriptInformation
[70].props
, &scriptInformation
[71].props
,
672 &scriptInformation
[72].props
, &scriptInformation
[73].props
,
673 &scriptInformation
[74].props
, &scriptInformation
[75].props
,
674 &scriptInformation
[76].props
, &scriptInformation
[77].props
,
675 &scriptInformation
[78].props
, &scriptInformation
[79].props
,
676 &scriptInformation
[80].props
, &scriptInformation
[81].props
679 static CRITICAL_SECTION cs_script_cache
;
680 static CRITICAL_SECTION_DEBUG cs_script_cache_dbg
=
682 0, 0, &cs_script_cache
,
683 { &cs_script_cache_dbg
.ProcessLocksList
, &cs_script_cache_dbg
.ProcessLocksList
},
684 0, 0, { (DWORD_PTR
)(__FILE__
": script_cache") }
686 static CRITICAL_SECTION cs_script_cache
= { &cs_script_cache_dbg
, -1, 0, 0, 0, 0 };
687 static struct list script_cache_list
= LIST_INIT(script_cache_list
);
695 SCRIPT_VISATTR
* psva
;
702 enum stringanalysis_flags
704 SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
= 0x1,
705 SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
= 0x2,
717 StringGlyphs
* glyphs
;
718 SCRIPT_LOGATTR
* logattrs
;
728 BOOL
usp10_array_reserve(void **elements
, SIZE_T
*capacity
, SIZE_T count
, SIZE_T size
)
730 SIZE_T max_capacity
, new_capacity
;
733 if (count
<= *capacity
)
736 max_capacity
= ~(SIZE_T
)0 / size
;
737 if (count
> max_capacity
)
740 new_capacity
= max(1, *capacity
);
741 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
743 if (new_capacity
< count
)
744 new_capacity
= count
;
747 new_elements
= heap_alloc_zero(new_capacity
* size
);
749 new_elements
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *elements
, new_capacity
* size
);
753 *elements
= new_elements
;
754 *capacity
= new_capacity
;
758 /* TODO Fix font properties on Arabic locale */
759 static inline BOOL
set_cache_font_properties(const HDC hdc
, ScriptCache
*sc
)
761 sc
->sfp
.cBytes
= sizeof(sc
->sfp
);
765 sc
->sfp
.wgBlank
= sc
->tm
.tmBreakChar
;
766 sc
->sfp
.wgDefault
= sc
->tm
.tmDefaultChar
;
767 sc
->sfp
.wgInvalid
= sc
->sfp
.wgBlank
;
768 sc
->sfp
.wgKashida
= 0xFFFF;
769 sc
->sfp
.iKashidaWidth
= 0;
773 static const WCHAR chars
[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
774 /* U+0020: numeric space
775 U+200B: zero width space
776 U+F71B: unknown char found by black box testing
780 if (GetGlyphIndicesW(hdc
, chars
, 4, gi
, GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
782 if(gi
[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
783 sc
->sfp
.wgBlank
= gi
[0];
787 sc
->sfp
.wgDefault
= 0;
790 sc
->sfp
.wgInvalid
= gi
[2];
791 else if (gi
[1] != 0xFFFF)
792 sc
->sfp
.wgInvalid
= gi
[1];
793 else if (gi
[0] != 0xFFFF)
794 sc
->sfp
.wgInvalid
= gi
[0];
796 sc
->sfp
.wgInvalid
= 0;
798 sc
->sfp
.wgKashida
= gi
[3];
800 sc
->sfp
.iKashidaWidth
= 0; /* TODO */
808 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES
*sfp
, ScriptCache
*sc
)
813 static inline LONG
get_cache_height(SCRIPT_CACHE
*psc
)
815 return ((ScriptCache
*)*psc
)->tm
.tmHeight
;
818 static inline BYTE
get_cache_pitch_family(SCRIPT_CACHE
*psc
)
820 return ((ScriptCache
*)*psc
)->tm
.tmPitchAndFamily
;
823 static inline WORD
get_cache_glyph(SCRIPT_CACHE
*psc
, DWORD c
)
825 CacheGlyphPage
*page
= ((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
829 block
= page
->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
830 if (!block
) return 0;
831 return block
[(c
% 0x10000) & GLYPH_BLOCK_MASK
];
834 static inline WORD
set_cache_glyph(SCRIPT_CACHE
*psc
, WCHAR c
, WORD glyph
)
836 CacheGlyphPage
**page
= &((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
838 if (!*page
&& !(*page
= heap_alloc_zero(sizeof(CacheGlyphPage
)))) return 0;
840 block
= &(*page
)->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
841 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(WORD
) * GLYPH_BLOCK_SIZE
))) return 0;
842 return ((*block
)[(c
% 0x10000) & GLYPH_BLOCK_MASK
] = glyph
);
845 static inline BOOL
get_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
847 static const ABC nil
;
848 ABC
*block
= ((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
850 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(ABC
))) return FALSE
;
851 memcpy(abc
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(ABC
));
855 static inline BOOL
set_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
857 ABC
**block
= &((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
859 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(ABC
) * GLYPH_BLOCK_SIZE
))) return FALSE
;
860 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], abc
, sizeof(ABC
));
864 static HRESULT
init_script_cache(const HDC hdc
, SCRIPT_CACHE
*psc
)
870 if (!psc
) return E_INVALIDARG
;
871 if (*psc
) return S_OK
;
872 if (!hdc
) return E_PENDING
;
874 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
))
878 /* Ensure canonical result by zeroing extra space in lfFaceName */
879 size
= strlenW(lf
.lfFaceName
);
880 memset(lf
.lfFaceName
+ size
, 0, sizeof(lf
.lfFaceName
) - size
* sizeof(WCHAR
));
882 EnterCriticalSection(&cs_script_cache
);
883 LIST_FOR_EACH_ENTRY(sc
, &script_cache_list
, ScriptCache
, entry
)
885 if (!memcmp(&sc
->lf
, &lf
, sizeof(lf
)))
888 LeaveCriticalSection(&cs_script_cache
);
893 LeaveCriticalSection(&cs_script_cache
);
895 if (!(sc
= heap_alloc_zero(sizeof(ScriptCache
)))) return E_OUTOFMEMORY
;
896 if (!GetTextMetricsW(hdc
, &sc
->tm
))
901 size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
904 sc
->otm
= heap_alloc(size
);
905 sc
->otm
->otmSize
= size
;
906 GetOutlineTextMetricsW(hdc
, size
, sc
->otm
);
908 sc
->sfnt
= (GetFontData(hdc
, MS_MAKE_TAG('h','e','a','d'), 0, NULL
, 0)!=GDI_ERROR
);
909 if (!set_cache_font_properties(hdc
, sc
))
918 EnterCriticalSection(&cs_script_cache
);
919 list_add_head(&script_cache_list
, &sc
->entry
);
920 LIST_FOR_EACH_ENTRY(sc
, &script_cache_list
, ScriptCache
, entry
)
922 if (sc
!= *psc
&& !memcmp(&sc
->lf
, &lf
, sizeof(lf
)))
924 /* Another thread won the race. Use their cache instead of ours */
925 list_remove(&sc
->entry
);
927 LeaveCriticalSection(&cs_script_cache
);
933 LeaveCriticalSection(&cs_script_cache
);
934 TRACE("<- %p\n", sc
);
938 static WCHAR
mirror_char( WCHAR ch
)
940 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
941 return ch
+ wine_mirror_map
[wine_mirror_map
[ch
>> 8] + (ch
& 0xff)];
944 static DWORD
decode_surrogate_pair(const WCHAR
*str
, unsigned int index
, unsigned int end
)
946 if (index
< end
-1 && IS_SURROGATE_PAIR(str
[index
],str
[index
+1]))
948 DWORD ch
= 0x10000 + ((str
[index
] - 0xd800) << 10) + (str
[index
+1] - 0xdc00);
949 TRACE("Surrogate Pair %x %x => %x\n",str
[index
], str
[index
+1], ch
);
955 static int usp10_compare_script_range(const void *key
, const void *value
)
957 const struct usp10_script_range
*range
= value
;
958 const DWORD
*ch
= key
;
960 if (*ch
< range
->rangeFirst
)
962 if (*ch
> range
->rangeLast
)
967 static enum usp10_script
get_char_script(const WCHAR
*str
, unsigned int index
,
968 unsigned int end
, unsigned int *consumed
)
970 static const WCHAR latin_punc
[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
971 struct usp10_script_range
*range
;
972 WORD type
= 0, type2
= 0;
977 if (str
[index
] == 0xc || str
[index
] == 0x20 || str
[index
] == 0x202f)
980 /* These punctuation characters are separated out as Latin punctuation */
981 if (strchrW(latin_punc
,str
[index
]))
982 return Script_Punctuation2
;
984 /* These chars are itemized as Punctuation by Windows */
985 if (str
[index
] == 0x2212 || str
[index
] == 0x2044)
986 return Script_Punctuation
;
988 /* Currency Symbols by Unicode point */
992 case 0x09f3: return Script_Bengali_Currency
;
993 case 0x0af1: return Script_Gujarati_Currency
;
994 case 0x0e3f: return Script_Thai_Currency
;
995 case 0x20aa: return Script_Hebrew_Currency
;
996 case 0x20ab: return Script_Vietnamese_Currency
;
997 case 0xfb29: return Script_Hebrew_Currency
;
1000 GetStringTypeW(CT_CTYPE1
, &str
[index
], 1, &type
);
1001 GetStringTypeW(CT_CTYPE2
, &str
[index
], 1, &type2
);
1004 return SCRIPT_UNDEFINED
;
1006 if (type
& C1_CNTRL
)
1007 return Script_Control
;
1009 ch
= decode_surrogate_pair(str
, index
, end
);
1015 if (!(range
= bsearch(&ch
, script_ranges
, ARRAY_SIZE(script_ranges
),
1016 sizeof(*script_ranges
), usp10_compare_script_range
)))
1017 return (*consumed
== 2) ? Script_Surrogates
: Script_Undefined
;
1019 if (range
->numericScript
&& (type
& C1_DIGIT
|| type2
== C2_ARABICNUMBER
))
1020 return range
->numericScript
;
1021 if (range
->punctScript
&& type
& C1_PUNCT
)
1022 return range
->punctScript
;
1023 return range
->script
;
1026 static int compare_FindGlyph(const void *a
, const void* b
)
1028 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
1029 const WORD
*idx
= (WORD
*)b
;
1032 if ( find
->target
> *idx
)
1034 else if (find
->target
< *idx
)
1037 if (!find
->ascending
)
1042 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
1044 FindGlyph_struct fgs
;
1048 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
1049 fgs
.ascending
= TRUE
;
1051 fgs
.ascending
= FALSE
;
1053 fgs
.target
= target
;
1054 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
1059 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
1066 /***********************************************************************
1067 * ScriptFreeCache (USP10.@)
1069 * Free a script cache.
1072 * psc [I/O] Script cache.
1076 * Failure: Non-zero HRESULT value.
1078 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1087 EnterCriticalSection(&cs_script_cache
);
1088 if (--((ScriptCache
*)*psc
)->refcount
> 0)
1090 LeaveCriticalSection(&cs_script_cache
);
1094 list_remove(&((ScriptCache
*)*psc
)->entry
);
1095 LeaveCriticalSection(&cs_script_cache
);
1097 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1099 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1101 for (i
= 0; i
< NUM_PAGES
; i
++)
1104 if (((ScriptCache
*)*psc
)->page
[i
])
1105 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1106 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1107 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1109 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1110 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1111 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1112 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1113 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1116 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1119 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1120 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1121 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1123 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1124 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1125 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1126 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1128 heap_free(((ScriptCache
*)*psc
)->scripts
);
1129 heap_free(((ScriptCache
*)*psc
)->otm
);
1136 /***********************************************************************
1137 * ScriptGetProperties (USP10.@)
1139 * Retrieve a list of script properties.
1142 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1143 * num [I] Pointer to the number of scripts.
1147 * Failure: Non-zero HRESULT value.
1150 * Behaviour matches WinXP.
1152 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1154 TRACE("(%p,%p)\n", props
, num
);
1156 if (!props
&& !num
) return E_INVALIDARG
;
1158 if (num
) *num
= sizeof(script_props
)/sizeof(script_props
[0]);
1159 if (props
) *props
= script_props
;
1164 /***********************************************************************
1165 * ScriptGetFontProperties (USP10.@)
1167 * Get information on special glyphs.
1170 * hdc [I] Device context.
1171 * psc [I/O] Opaque pointer to a script cache.
1172 * sfp [O] Font properties structure.
1174 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1178 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1180 if (!sfp
) return E_INVALIDARG
;
1181 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1183 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1184 return E_INVALIDARG
;
1186 get_cache_font_properties(sfp
, *psc
);
1191 /***********************************************************************
1192 * ScriptRecordDigitSubstitution (USP10.@)
1194 * Record digit substitution settings for a given locale.
1197 * locale [I] Locale identifier.
1198 * sds [I] Structure to record substitution settings.
1202 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1205 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1207 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1211 TRACE("0x%x, %p\n", locale
, sds
);
1213 /* This implementation appears to be correct for all languages, but it's
1214 * not clear if sds->DigitSubstitute is ever set to anything except
1215 * CONTEXT or NONE in reality */
1217 if (!sds
) return E_POINTER
;
1219 locale
= ConvertDefaultLocale(locale
);
1221 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1222 return E_INVALIDARG
;
1224 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1225 sds
->TraditionalDigitLanguage
= plgid
;
1227 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1228 sds
->NationalDigitLanguage
= plgid
;
1230 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1232 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1233 (WCHAR
*)&sub
, sizeof(sub
) / sizeof(WCHAR
)))
1234 return E_INVALIDARG
;
1239 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1240 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1242 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1245 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1248 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1251 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1255 sds
->dwReserved
= 0;
1259 /***********************************************************************
1260 * ScriptApplyDigitSubstitution (USP10.@)
1262 * Apply digit substitution settings.
1265 * sds [I] Structure with recorded substitution settings.
1266 * sc [I] Script control structure.
1267 * ss [I] Script state structure.
1271 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1273 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1274 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1276 SCRIPT_DIGITSUBSTITUTE psds
;
1278 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1280 if (!sc
|| !ss
) return E_POINTER
;
1284 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1285 return E_INVALIDARG
;
1288 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1289 sc
->fContextDigits
= 0;
1290 ss
->fDigitSubstitute
= 0;
1292 switch (sds
->DigitSubstitute
) {
1293 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1294 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1295 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1296 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1299 return E_INVALIDARG
;
1303 static inline BOOL
is_indic(enum usp10_script script
)
1305 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1308 static inline enum usp10_script
base_indic(enum usp10_script script
)
1312 case Script_Devanagari
:
1313 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1314 case Script_Bengali
:
1315 case Script_Bengali_Numeric
:
1316 case Script_Bengali_Currency
: return Script_Bengali
;
1317 case Script_Gurmukhi
:
1318 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1319 case Script_Gujarati
:
1320 case Script_Gujarati_Numeric
:
1321 case Script_Gujarati_Currency
: return Script_Gujarati
;
1323 case Script_Oriya_Numeric
: return Script_Oriya
;
1325 case Script_Tamil_Numeric
: return Script_Tamil
;
1327 case Script_Telugu_Numeric
: return Script_Telugu
;
1328 case Script_Kannada
:
1329 case Script_Kannada_Numeric
: return Script_Kannada
;
1330 case Script_Malayalam
:
1331 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1333 return Script_Undefined
;
1337 static BOOL
script_is_numeric(enum usp10_script script
)
1339 return scriptInformation
[script
].props
.fNumeric
;
1342 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1343 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1344 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1345 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1348 #define Numeric_space 0x0020
1353 enum usp10_script last_indic
= Script_Undefined
;
1354 int cnt
= 0, index
= 0, str
= 0;
1355 enum usp10_script New_Script
= -1;
1357 WORD
*levels
= NULL
;
1358 WORD
*layout_levels
= NULL
;
1359 WORD
*overrides
= NULL
;
1360 WORD
*strength
= NULL
;
1361 enum usp10_script
*scripts
;
1363 WORD baselayout
= 0;
1366 BOOL forceLevels
= FALSE
;
1367 unsigned int consumed
= 0;
1368 HRESULT res
= E_OUTOFMEMORY
;
1370 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1371 psControl
, psState
, pItems
, pcItems
);
1373 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1374 return E_INVALIDARG
;
1376 if (!(scripts
= heap_alloc(cInChars
* sizeof(*scripts
))))
1377 return E_OUTOFMEMORY
;
1379 for (i
= 0; i
< cInChars
; i
++)
1383 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1388 scripts
[i
] = scripts
[i
-1];
1391 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1392 all Indic scripts */
1393 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
!= Script_Undefined
)
1394 scripts
[i
] = last_indic
;
1395 else if (is_indic(scripts
[i
]))
1396 last_indic
= base_indic(scripts
[i
]);
1398 /* Some unicode points :
1399 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1400 (Left Right Embed U+202A - Left Right Override U+202D)
1401 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1402 will force us into bidi mode */
1403 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1404 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1405 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1409 /* Diacritical marks merge with other scripts */
1410 if (scripts
[i
] == Script_Diacritical
)
1415 scripts
[i
] = scripts
[i
-1];
1420 enum usp10_script first_script
= scripts
[i
-1];
1421 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1423 enum usp10_script original
= scripts
[j
];
1424 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1429 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1431 scripts
[j
] = scripts
[i
];
1432 if (original
== Script_Punctuation2
)
1435 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1436 scripts
[i
] = scripts
[j
];
1442 for (i
= 0; i
< cInChars
; i
++)
1444 /* Joiners get merged preferencially right */
1445 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1448 if (i
+1 == cInChars
)
1449 scripts
[i
] = scripts
[i
-1];
1452 for (j
= i
+1; j
< cInChars
; j
++)
1454 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1455 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1457 scripts
[i
] = scripts
[j
];
1465 if (psState
&& psControl
)
1467 levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1471 overrides
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1475 layout_levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1479 if (psState
->fOverrideDirection
)
1483 SCRIPT_STATE s
= *psState
;
1484 s
.fOverrideDirection
= FALSE
;
1485 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1486 if (odd(layout_levels
[0]))
1488 else for (i
= 0; i
< cInChars
; i
++)
1489 if (layout_levels
[i
]!=layout_levels
[0])
1496 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1500 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1501 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1503 baselevel
= levels
[0];
1504 baselayout
= layout_levels
[0];
1505 for (i
= 0; i
< cInChars
; i
++)
1506 if (levels
[i
]!=levels
[0])
1508 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1511 heap_free(overrides
);
1512 heap_free(layout_levels
);
1515 layout_levels
= NULL
;
1519 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1520 static const WCHAR repeatable_math_punc
[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1522 strength
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1525 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1527 /* We currently mis-level leading Diacriticals */
1528 if (scripts
[0] == Script_Diacritical
)
1529 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1531 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1532 strength
[i
] = BIDI_STRONG
;
1535 /* Math punctuation bordered on both sides by numbers can be
1536 merged into the number */
1537 for (i
= 0; i
< cInChars
; i
++)
1539 if (i
> 0 && i
< cInChars
-1 &&
1540 script_is_numeric(scripts
[i
-1]) &&
1541 strchrW(math_punc
, pwcInChars
[i
]))
1543 if (script_is_numeric(scripts
[i
+1]))
1545 scripts
[i
] = scripts
[i
+1];
1546 levels
[i
] = levels
[i
-1];
1547 strength
[i
] = strength
[i
-1];
1550 else if (strchrW(repeatable_math_punc
, pwcInChars
[i
]))
1553 for (j
= i
+1; j
< cInChars
; j
++)
1555 if (script_is_numeric(scripts
[j
]))
1559 scripts
[i
] = scripts
[j
];
1560 levels
[i
] = levels
[i
-1];
1561 strength
[i
] = strength
[i
-1];
1564 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1570 for (i
= 0; i
< cInChars
; i
++)
1572 /* Numerics at level 0 get bumped to level 2 */
1573 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
)
1574 && levels
[i
] == psState
->uBidiLevel
+ 1)) && script_is_numeric(scripts
[i
]))
1579 /* Joiners get merged preferencially right */
1580 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1583 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1584 strength
[i
] = strength
[i
-1];
1586 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1587 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1588 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1590 strength
[i
] = strength
[j
];
1595 if (psControl
->fMergeNeutralItems
)
1597 /* Merge the neutrals */
1598 for (i
= 0; i
< cInChars
; i
++)
1600 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1603 for (j
= i
; j
> 0; j
--)
1605 if (levels
[i
] != levels
[j
])
1607 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1609 scripts
[i
] = scripts
[j
];
1610 strength
[i
] = strength
[j
];
1615 /* Try going the other way */
1616 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1619 for (j
= i
; j
< cInChars
; j
++)
1621 if (levels
[i
] != levels
[j
])
1623 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1625 scripts
[i
] = scripts
[j
];
1626 strength
[i
] = strength
[j
];
1636 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1637 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1640 if (cnt
== cInChars
) /* All Spaces */
1643 New_Script
= scripts
[cnt
];
1646 pItems
[index
].iCharPos
= 0;
1647 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1649 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1651 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1652 str
= strength
[cnt
];
1660 if (strength
[cnt
] == BIDI_STRONG
)
1661 layoutRTL
= odd(layout_levels
[cnt
]);
1663 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1665 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1666 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1667 if (script_is_numeric(pItems
[index
].a
.eScript
))
1668 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1670 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1671 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1673 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1675 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1676 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1677 layoutRTL
= odd(baselayout
);
1678 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1679 pItems
[index
].a
.fRTL
= odd(baselevel
);
1680 if (script_is_numeric(pItems
[index
].a
.eScript
))
1681 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1683 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1686 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1687 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1688 pItems
[index
].iCharPos
);
1690 for (cnt
=1; cnt
< cInChars
; cnt
++)
1692 if(pwcInChars
[cnt
] != Numeric_space
)
1693 New_Script
= scripts
[cnt
];
1697 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1699 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1700 New_Script
= scripts
[cnt
+j
];
1702 New_Script
= scripts
[cnt
];
1706 /* merge space strengths*/
1707 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1710 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1713 /* changes in level */
1714 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1716 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1719 /* changes in strength */
1720 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1722 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1725 /* changes in script */
1726 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1728 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1732 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1734 layoutRTL
= odd(layout_levels
[cnt
]);
1735 if (script_is_numeric(pItems
[index
].a
.eScript
))
1736 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1741 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
);
1744 if (index
+1 > cMaxItems
)
1748 str
= strength
[cnt
];
1750 pItems
[index
].iCharPos
= cnt
;
1751 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1753 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1755 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1759 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1760 if (layout_levels
[cnt
] == 0)
1763 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1764 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1765 if (script_is_numeric(pItems
[index
].a
.eScript
))
1766 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1768 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1769 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1771 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1773 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1774 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1775 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1776 pItems
[index
].a
.fRTL
= odd(baselevel
);
1777 if (script_is_numeric(pItems
[index
].a
.eScript
))
1778 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1780 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1783 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1787 /* While not strictly necessary according to the spec, make sure the n+1
1788 * item is set up to prevent random behaviour if the caller erroneously
1789 * checks the n+1 structure */
1791 if (index
+ 1 > cMaxItems
) goto nomemory
;
1792 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1794 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1796 /* Set one SCRIPT_STATE item being returned */
1797 if (pcItems
) *pcItems
= index
;
1799 /* Set SCRIPT_ITEM */
1800 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1804 heap_free(overrides
);
1805 heap_free(layout_levels
);
1806 heap_free(strength
);
1811 /***********************************************************************
1812 * ScriptItemizeOpenType (USP10.@)
1814 * Split a Unicode string into shapeable parts.
1817 * pwcInChars [I] String to split.
1818 * cInChars [I] Number of characters in pwcInChars.
1819 * cMaxItems [I] Maximum number of items to return.
1820 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1821 * psState [I] Pointer to a SCRIPT_STATE structure.
1822 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1823 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1824 * pcItems [O] Number of script items returned.
1828 * Failure: Non-zero HRESULT value.
1830 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1831 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1832 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1834 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1837 /***********************************************************************
1838 * ScriptItemize (USP10.@)
1840 * Split a Unicode string into shapeable parts.
1843 * pwcInChars [I] String to split.
1844 * cInChars [I] Number of characters in pwcInChars.
1845 * cMaxItems [I] Maximum number of items to return.
1846 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1847 * psState [I] Pointer to a SCRIPT_STATE structure.
1848 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1849 * pcItems [O] Number of script items returned.
1853 * Failure: Non-zero HRESULT value.
1855 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1856 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1857 SCRIPT_ITEM
*pItems
, int *pcItems
)
1859 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1862 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1866 INT
*lpTabPos
= NULL
;
1871 lpTabPos
= pTabdef
->pTabStops
;
1873 if (pTabdef
&& pTabdef
->iTabOrigin
)
1875 if (pTabdef
->iScale
)
1876 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1878 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1882 cTabStops
= pTabdef
->cTabStops
;
1886 if (pTabdef
->iScale
)
1887 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1889 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1894 if (pTabdef
->iScale
)
1895 defWidth
= (32 * pTabdef
->iScale
) / 4;
1897 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1900 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1902 int position
= *lpTabPos
;
1904 position
= -1 * position
;
1905 if (pTabdef
->iScale
)
1906 position
= (position
* pTabdef
->iScale
) / 4;
1908 position
= position
* psc
->tm
.tmAveCharWidth
;
1910 if( nTabOrg
+ position
> current_x
)
1914 /* a left aligned tab */
1915 x
= (nTabOrg
+ position
) - current_x
;
1920 FIXME("Negative tabstop\n");
1925 if ((!cTabStops
) && (defWidth
> 0))
1926 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1927 else if ((!cTabStops
) && (defWidth
< 0))
1928 FIXME("TODO: Negative defWidth\n");
1933 /***********************************************************************
1934 * Helper function for ScriptStringAnalyse
1936 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1937 const WCHAR
*pwcInChars
, int cChars
)
1939 /* FIXME: When to properly fallback is still a bit of a mystery */
1942 if (psa
->fNoGlyphIndex
)
1945 if (init_script_cache(hdc
, psc
) != S_OK
)
1948 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1951 glyphs
= heap_alloc(sizeof(WORD
) * cChars
);
1954 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1964 static void find_fallback_font(enum usp10_script scriptid
, WCHAR
*FaceName
)
1968 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1970 static const WCHAR szFmt
[] = {'%','x',0};
1972 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1975 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1976 if (RegQueryValueExW(hkey
, value
, 0, &type
, (BYTE
*)FaceName
, &count
))
1977 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1981 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1984 /***********************************************************************
1985 * ScriptStringAnalyse (USP10.@)
1988 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1989 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1990 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1991 SCRIPT_STATE
*psState
, const int *piDx
,
1992 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1993 SCRIPT_STRING_ANALYSIS
*pssa
)
1995 HRESULT hr
= E_OUTOFMEMORY
;
1996 StringAnalysis
*analysis
= NULL
;
1997 SCRIPT_CONTROL sControl
;
1998 SCRIPT_STATE sState
;
1999 int i
, num_items
= 255;
2001 WCHAR
*iString
= NULL
;
2003 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
2004 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
2005 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
2009 FIXME("Only Unicode strings are supported\n");
2010 return E_INVALIDARG
;
2012 if (cString
< 1 || !pString
) return E_INVALIDARG
;
2013 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
2015 if (!(analysis
= heap_alloc_zero(sizeof(StringAnalysis
)))) return E_OUTOFMEMORY
;
2016 if (!(analysis
->pItem
= heap_alloc_zero(num_items
* sizeof(SCRIPT_ITEM
) + 1))) goto error
;
2018 /* FIXME: handle clipping */
2019 analysis
->clip_len
= cString
;
2020 analysis
->hdc
= hdc
;
2021 analysis
->ssa_flags
= dwFlags
;
2026 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
2029 sControl
= *psControl
;
2031 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
2033 if (dwFlags
& SSA_PASSWORD
)
2035 iString
= heap_alloc(sizeof(WCHAR
)*cString
);
2041 for (i
= 0; i
< cString
; i
++)
2042 iString
[i
] = *((const WCHAR
*)pString
);
2046 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
2047 &analysis
->numItems
);
2051 if (hr
== E_OUTOFMEMORY
)
2056 /* set back to out of memory for default goto error behaviour */
2059 if (dwFlags
& SSA_BREAK
)
2061 if ((analysis
->logattrs
= heap_alloc(sizeof(SCRIPT_LOGATTR
) * cString
)))
2063 for (i
= 0; i
< analysis
->numItems
; i
++)
2064 ScriptBreak(&((WCHAR
*)pString
)[analysis
->pItem
[i
].iCharPos
],
2065 analysis
->pItem
[i
+ 1].iCharPos
- analysis
->pItem
[i
].iCharPos
,
2066 &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
2072 if (!(analysis
->logical2visual
= heap_alloc_zero(sizeof(int) * analysis
->numItems
)))
2074 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
2077 if (dwFlags
& SSA_GLYPHS
)
2080 if (!(analysis
->glyphs
= heap_alloc_zero(sizeof(StringGlyphs
) * analysis
->numItems
)))
2082 heap_free(BidiLevel
);
2086 for (i
= 0; i
< analysis
->numItems
; i
++)
2088 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
2089 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2090 int numGlyphs
= 1.5 * cChar
+ 16;
2091 WORD
*glyphs
= heap_alloc_zero(sizeof(WORD
) * numGlyphs
);
2092 WORD
*pwLogClust
= heap_alloc_zero(sizeof(WORD
) * cChar
);
2093 int *piAdvance
= heap_alloc_zero(sizeof(int) * numGlyphs
);
2094 SCRIPT_VISATTR
*psva
= heap_alloc_zero(sizeof(SCRIPT_VISATTR
) * numGlyphs
);
2095 GOFFSET
*pGoffset
= heap_alloc_zero(sizeof(GOFFSET
) * numGlyphs
);
2096 int numGlyphsReturned
;
2097 HFONT originalFont
= 0x0;
2099 /* FIXME: non unicode strings */
2100 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2101 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2103 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
)
2105 heap_free (BidiLevel
);
2107 heap_free (pwLogClust
);
2108 heap_free (piAdvance
);
2110 heap_free (pGoffset
);
2115 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2118 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2119 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2120 lf
.lfFaceName
[0] = 0;
2121 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2122 if (lf
.lfFaceName
[0])
2124 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2125 if (analysis
->glyphs
[i
].fallbackFont
)
2127 ScriptFreeCache(sc
);
2128 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2133 /* FIXME: When we properly shape Hangul remove this check */
2134 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2135 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2137 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2138 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2140 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2141 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2142 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2143 piAdvance
, pGoffset
, &analysis
->glyphs
[i
].abc
);
2145 SelectObject(hdc
,originalFont
);
2147 if (dwFlags
& SSA_TAB
)
2150 for (tabi
= 0; tabi
< cChar
; tabi
++)
2152 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2153 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2154 tab_x
+=piAdvance
[tabi
];
2158 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2159 analysis
->glyphs
[i
].glyphs
= glyphs
;
2160 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2161 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2162 analysis
->glyphs
[i
].psva
= psva
;
2163 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2164 analysis
->glyphs
[i
].iMaxPosX
= -1;
2166 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2171 for (i
= 0; i
< analysis
->numItems
; i
++)
2172 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2175 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2176 heap_free(BidiLevel
);
2184 heap_free(analysis
->glyphs
);
2185 heap_free(analysis
->logattrs
);
2186 heap_free(analysis
->pItem
);
2187 heap_free(analysis
->logical2visual
);
2188 heap_free(analysis
);
2192 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2194 if (pva
[glyph
].fClusterStart
)
2196 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2203 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2214 StringAnalysis
*analysis
;
2217 COLORREF BkColor
= 0x0;
2218 COLORREF TextColor
= 0x0;
2220 INT runStart
, runEnd
;
2221 INT iGlyph
, cGlyphs
;
2222 HFONT oldFont
= 0x0;
2226 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2227 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2229 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2231 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2232 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2238 BkMode
= GetBkMode(analysis
->hdc
);
2239 SetBkMode( analysis
->hdc
, OPAQUE
);
2240 BkColor
= GetBkColor(analysis
->hdc
);
2241 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2244 TextColor
= GetTextColor(analysis
->hdc
);
2245 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2248 if (analysis
->glyphs
[iItem
].fallbackFont
)
2249 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2251 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2252 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2255 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2256 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2258 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2260 if (analysis
->pItem
[iItem
].a
.fRTL
)
2262 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2263 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2265 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2266 crc
.left
= iX
+ off_x
;
2270 if (cStart
>=0 && runStart
)
2271 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2273 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2274 crc
.left
= iX
+ off_x
;
2277 if (analysis
->pItem
[iItem
].a
.fRTL
)
2278 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2280 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2282 if (analysis
->pItem
[iItem
].a
.fRTL
)
2283 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2285 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2289 /* adjust for cluster glyphs when starting */
2290 if (analysis
->pItem
[iItem
].a
.fRTL
)
2291 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2293 i
= analysis
->pItem
[iItem
].iCharPos
;
2295 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2297 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2299 if (analysis
->pItem
[iItem
].a
.fRTL
)
2300 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2302 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2307 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2312 clust_glyph
= iGlyph
+ cGlyphs
;
2313 if (analysis
->pItem
[iItem
].a
.fRTL
)
2318 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2319 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2326 hr
= ScriptTextOut(analysis
->hdc
,
2327 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2328 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2329 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2330 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2331 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2333 TRACE("ScriptTextOut hr=%08x\n", hr
);
2337 SetBkColor(analysis
->hdc
, BkColor
);
2338 SetBkMode( analysis
->hdc
, BkMode
);
2340 SetTextColor(analysis
->hdc
, TextColor
);
2342 if (analysis
->glyphs
[iItem
].fallbackFont
)
2343 SelectObject(analysis
->hdc
, oldFont
);
2348 /***********************************************************************
2349 * ScriptStringOut (USP10.@)
2351 * This function takes the output of ScriptStringAnalyse and joins the segments
2352 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2353 * only processes glyphs.
2356 * ssa [I] buffer to hold the analysed string components
2357 * iX [I] X axis displacement for output
2358 * iY [I] Y axis displacement for output
2359 * uOptions [I] flags controlling output processing
2360 * prc [I] rectangle coordinates
2361 * iMinSel [I] starting pos for substringing output string
2362 * iMaxSel [I] ending pos for substringing output string
2363 * fDisabled [I] controls text highlighting
2367 * Failure: is the value returned by ScriptTextOut
2369 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2378 StringAnalysis
*analysis
;
2382 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2383 ssa
, iX
, iY
, uOptions
, wine_dbgstr_rect(prc
), iMinSel
, iMaxSel
, fDisabled
);
2385 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2386 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2388 for (item
= 0; item
< analysis
->numItems
; item
++)
2390 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2395 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2397 if (iMaxSel
> 0 && iMinSel
< 0)
2399 for (item
= 0; item
< analysis
->numItems
; item
++)
2401 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2410 /***********************************************************************
2411 * ScriptStringCPtoX (USP10.@)
2414 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2418 StringAnalysis
* analysis
= ssa
;
2420 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2422 if (!ssa
|| !pX
) return S_FALSE
;
2423 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2425 /* icp out of range */
2428 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2429 return E_INVALIDARG
;
2432 for(item
=0; item
<analysis
->numItems
; item
++)
2437 i
= analysis
->logical2visual
[item
];
2438 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2439 /* initialize max extents for uninitialized runs */
2440 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2442 if (analysis
->pItem
[i
].a
.fRTL
)
2443 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2444 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2445 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2447 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2448 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2449 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2452 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2454 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2458 icp
-= analysis
->pItem
[i
].iCharPos
;
2459 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2460 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2461 &analysis
->pItem
[i
].a
, &offset
);
2468 /* icp out of range */
2469 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2470 return E_INVALIDARG
;
2473 /***********************************************************************
2474 * ScriptStringXtoCP (USP10.@)
2477 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2479 StringAnalysis
* analysis
= ssa
;
2482 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2484 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2485 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2490 if (analysis
->pItem
[0].a
.fRTL
)
2493 *piTrailing
= FALSE
;
2503 for(item
=0; item
<analysis
->numItems
; item
++)
2508 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2511 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2512 /* initialize max extents for uninitialized runs */
2513 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2515 if (analysis
->pItem
[i
].a
.fRTL
)
2516 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2517 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2518 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2520 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2521 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2522 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2525 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2527 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2531 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2532 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2533 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2534 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2540 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2541 *piTrailing
= FALSE
;
2547 /***********************************************************************
2548 * ScriptStringFree (USP10.@)
2550 * Free a string analysis.
2553 * pssa [I] string analysis.
2557 * Failure: Non-zero HRESULT value.
2559 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2561 StringAnalysis
* analysis
;
2565 TRACE("(%p)\n", pssa
);
2567 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2569 invalid
= analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2571 if (analysis
->glyphs
)
2573 for (i
= 0; i
< analysis
->numItems
; i
++)
2575 heap_free(analysis
->glyphs
[i
].glyphs
);
2576 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2577 heap_free(analysis
->glyphs
[i
].piAdvance
);
2578 heap_free(analysis
->glyphs
[i
].psva
);
2579 heap_free(analysis
->glyphs
[i
].pGoffset
);
2580 if (analysis
->glyphs
[i
].fallbackFont
)
2581 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2582 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2583 heap_free(analysis
->glyphs
[i
].sc
);
2585 heap_free(analysis
->glyphs
);
2588 heap_free(analysis
->pItem
);
2589 heap_free(analysis
->logattrs
);
2590 heap_free(analysis
->logical2visual
);
2591 heap_free(analysis
);
2593 if (invalid
) return E_INVALIDARG
;
2597 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2598 int direction
, int* iCluster
, int *check_out
)
2602 WORD clust
= pwLogClust
[item
];
2604 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2606 if (pwLogClust
[check
] == clust
)
2609 if (iCluster
&& *iCluster
== -1)
2621 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
)
2626 advance
= piAdvance
[glyph
];
2628 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2629 log_clust_max
= pwLogClust
[0];
2631 log_clust_max
= pwLogClust
[cChars
-1];
2633 if (glyph
> log_clust_max
)
2636 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2639 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2641 if (glyph
> log_clust_max
)
2643 advance
+= piAdvance
[glyph
];
2649 /***********************************************************************
2650 * ScriptCPtoX (USP10.@)
2653 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2657 const WORD
*pwLogClust
,
2658 const SCRIPT_VISATTR
*psva
,
2659 const int *piAdvance
,
2660 const SCRIPT_ANALYSIS
*psa
,
2668 float special_size
= 0.0;
2673 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2674 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2677 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2685 int max_clust
= pwLogClust
[0];
2687 for (item
=0; item
< cGlyphs
; item
++)
2688 if (pwLogClust
[item
] > max_clust
)
2690 ERR("We do not handle non reversed clusters properly\n");
2695 for (item
= max_clust
; item
>=0; item
--)
2696 iMaxPos
+= piAdvance
[item
];
2700 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2702 if (iSpecial
== -1 && (iCluster
== -1 || iCluster
+clust_size
<= item
))
2705 int clust
= pwLogClust
[item
];
2708 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2711 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2713 if (check
>= cChars
&& !iMaxPos
)
2716 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2717 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2719 special_size
/= (cChars
- item
);
2720 iPosX
+= special_size
;
2724 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2727 if (clust_size
== 0)
2731 iPosX
+= advance
/ (float)clust_size
;
2734 else if (iSpecial
!= -1)
2735 iPosX
+= special_size
;
2736 else /* (iCluster != -1) */
2738 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2739 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2742 if (clust_size
== 0)
2746 iPosX
+= adv
/ (float)clust_size
;
2752 iPosX
= iMaxPos
- iPosX
;
2758 TRACE("*piX=%d\n", *piX
);
2762 /* Count the number of characters in a cluster and its starting index*/
2763 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2768 for (i
= 0; i
< cChars
; i
++)
2770 if (pwLogClust
[i
] == cluster_index
)
2772 if (!size
&& start_index
)
2780 else if (size
) break;
2783 *cluster_size
= size
;
2789 To handle multi-glyph clusters we need to find all the glyphs that are
2790 represented in the cluster. This involves finding the glyph whose
2791 index is the cluster index as well as whose glyph indices are greater than
2792 our cluster index but not part of a new cluster.
2794 Then we sum all those glyphs' advances.
2796 static inline int get_cluster_advance(const int* piAdvance
,
2797 const SCRIPT_VISATTR
*psva
,
2798 const WORD
*pwLogClust
, int cGlyphs
,
2799 int cChars
, int cluster
, int direction
)
2810 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2812 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2813 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2814 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2819 glyph_end
= cGlyphs
;
2822 /* Don't fully understand multi-glyph reversed clusters yet,
2823 * do they occur for real or just in our test? */
2824 FIXME("multi-glyph reversed clusters found\n");
2825 glyph_end
= glyph_start
+ 1;
2829 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2830 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2832 if (psva
[i
].fClusterStart
)
2839 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2840 advance
+= piAdvance
[i
];
2846 /***********************************************************************
2847 * ScriptXtoCP (USP10.@)
2850 * Use piAdvance to find the cluster we are looking at.
2851 * Find the character that is the first character of the cluster.
2852 * That is our base piCP.
2853 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2854 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2855 * determine how far through the cluster to advance the cursor.
2857 HRESULT WINAPI
ScriptXtoCP(int iX
,
2860 const WORD
*pwLogClust
,
2861 const SCRIPT_VISATTR
*psva
,
2862 const int *piAdvance
,
2863 const SCRIPT_ANALYSIS
*psa
,
2870 int glyph_index
, cluster_index
;
2873 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2874 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2875 psa
, piCP
, piTrailing
);
2877 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2880 /* Handle an iX < 0 */
2896 /* Looking for non-reversed clusters in a reversed string */
2899 int max_clust
= pwLogClust
[0];
2900 for (i
=0; i
< cChars
; i
++)
2901 if (pwLogClust
[i
] > max_clust
)
2903 FIXME("We do not handle non reversed clusters properly\n");
2908 /* find the glyph_index based in iX */
2911 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2916 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2920 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2923 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2925 /* find the cluster */
2927 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2930 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2933 TRACE("cluster_index %i\n", cluster_index
);
2935 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2937 /* We are off the end of the string */
2943 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2945 TRACE("first char index %i\n",i
);
2946 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2948 /* Check trailing */
2949 if (glyph_index
!= cluster_index
||
2950 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2951 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2952 *piTrailing
= cluster_size
;
2956 if (cluster_size
> 1)
2958 /* Be part way through the glyph cluster based on size and position */
2959 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2960 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2964 /* back up to the beginning of the cluster */
2965 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2966 adv
+= piAdvance
[part_index
];
2967 if (adv
> iX
) adv
= iX
;
2969 TRACE("Multi-char cluster, no snap\n");
2970 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2971 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2974 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2976 if (part_index
) part_index
--;
2980 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2982 if (part_index
> cluster_size
)
2984 adv
+= cluster_part_width
;
2985 part_index
=cluster_size
;
2989 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2994 i
+= (cluster_size
- part_index
);
2996 /* Check trailing */
2997 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2998 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
3003 /* Check trailing */
3004 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
3005 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
3012 TRACE("Point falls outside of string\n");
3013 if (glyph_index
< 0)
3015 else /* (glyph_index >= cGlyphs) */
3018 /* If not snaping in the reverse direction (such as Hebrew) Then 0
3019 point flow to the next character */
3022 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
3031 TRACE("*piCP=%d\n", *piCP
);
3032 TRACE("*piTrailing=%d\n", *piTrailing
);
3036 /***********************************************************************
3037 * ScriptBreak (USP10.@)
3039 * Retrieve line break information.
3042 * chars [I] Array of characters.
3043 * sa [I] Script analysis.
3044 * la [I] Array of logical attribute structures.
3050 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
3052 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
3054 if (count
< 0 || !la
) return E_INVALIDARG
;
3055 if (count
== 0) return E_FAIL
;
3057 BREAK_line(chars
, count
, sa
, la
);
3062 /***********************************************************************
3063 * ScriptIsComplex (USP10.@)
3065 * Determine if a string is complex.
3068 * chars [I] Array of characters to test.
3069 * len [I] Length in characters.
3077 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
3079 enum usp10_script script
;
3080 unsigned int i
, consumed
;
3082 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
3084 if (!chars
|| len
< 0)
3085 return E_INVALIDARG
;
3087 for (i
= 0; i
< len
; i
+=consumed
)
3089 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3092 script
= get_char_script(chars
,i
,len
, &consumed
);
3093 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3094 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3100 /***********************************************************************
3101 * ScriptShapeOpenType (USP10.@)
3103 * Produce glyphs and visual attributes for a run.
3106 * hdc [I] Device context.
3107 * psc [I/O] Opaque pointer to a script cache.
3108 * psa [I/O] Script analysis.
3109 * tagScript [I] The OpenType tag for the Script
3110 * tagLangSys [I] The OpenType tag for the Language
3111 * rcRangeChars[I] Array of Character counts in each range
3112 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3113 * cRanges [I] Count of ranges
3114 * pwcChars [I] Array of characters specifying the run.
3115 * cChars [I] Number of characters in pwcChars.
3116 * cMaxGlyphs [I] Length of pwOutGlyphs.
3117 * pwLogClust [O] Array of logical cluster info.
3118 * pCharProps [O] Array of character property values
3119 * pwOutGlyphs [O] Array of glyphs.
3120 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3121 * pcGlyphs [O] Number of glyphs returned.
3125 * Failure: Non-zero HRESULT value.
3127 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3128 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3129 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3130 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3131 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3132 int cMaxGlyphs
, WORD
*pwLogClust
,
3133 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3134 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3141 static int once
= 0;
3143 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3145 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3146 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3147 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3149 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3150 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3152 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3153 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3156 if(!once
++) FIXME("Ranges not supported yet\n");
3158 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3161 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3162 if (!pwLogClust
) return E_FAIL
;
3164 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3165 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3167 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3168 for (i
= 0; i
< cChars
; i
++)
3171 if (rtl
) idx
= cChars
- 1 - i
;
3172 /* FIXME: set to better values */
3173 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3174 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3175 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3176 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3177 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3178 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3180 /* FIXME: have the shaping engine set this */
3181 pCharProps
[i
].fCanGlyphAlone
= 0;
3183 pwLogClust
[i
] = idx
;
3186 if (psa
&& !psa
->fNoGlyphIndex
&& ((ScriptCache
*)*psc
)->sfnt
)
3189 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3191 rChars
= heap_alloc(sizeof(WCHAR
) * cChars
);
3192 if (!rChars
) return E_OUTOFMEMORY
;
3193 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3198 if (rtl
) idx
= cChars
- 1 - i
;
3201 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3205 chInput
= mirror_char(pwcChars
[idx
]);
3207 chInput
= pwcChars
[idx
];
3208 rChars
[i
] = chInput
;
3212 rChars
[i
] = pwcChars
[idx
];
3213 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3216 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3224 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3229 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3237 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3238 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3244 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3245 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3246 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3248 for (i
= 0; i
< cChars
; ++i
)
3250 /* Special case for tabs and joiners. As control characters, ZWNJ
3251 * and ZWJ would in principle get handled by the corresponding
3252 * shaping functions. However, since ZWNJ and ZWJ can get merged
3253 * into adjoining runs during itemisation, these don't generally
3254 * get classified as Script_Control. */
3255 if (pwcChars
[i
] == 0x0009 || pwcChars
[i
] == ZWSP
|| pwcChars
[i
] == ZWNJ
|| pwcChars
[i
] == ZWJ
)
3257 pwOutGlyphs
[pwLogClust
[i
]] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3258 pOutGlyphProps
[pwLogClust
[i
]].sva
.fZeroWidth
= 1;
3265 TRACE("no glyph translation\n");
3266 for (i
= 0; i
< cChars
; i
++)
3269 /* No mirroring done here */
3270 if (rtl
) idx
= cChars
- 1 - i
;
3271 pwOutGlyphs
[i
] = pwcChars
[idx
];
3276 /* overwrite some basic control glyphs to blank */
3277 if (psa
->fNoGlyphIndex
)
3279 if (pwcChars
[idx
] == ZWSP
|| pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3281 pwOutGlyphs
[i
] = 0x20;
3282 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3285 else if (psa
->eScript
== Script_Control
|| pwcChars
[idx
] == ZWSP
3286 || pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3288 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3289 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3291 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3292 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3302 /***********************************************************************
3303 * ScriptShape (USP10.@)
3305 * Produce glyphs and visual attributes for a run.
3308 * hdc [I] Device context.
3309 * psc [I/O] Opaque pointer to a script cache.
3310 * pwcChars [I] Array of characters specifying the run.
3311 * cChars [I] Number of characters in pwcChars.
3312 * cMaxGlyphs [I] Length of pwOutGlyphs.
3313 * psa [I/O] Script analysis.
3314 * pwOutGlyphs [O] Array of glyphs.
3315 * pwLogClust [O] Array of logical cluster info.
3316 * psva [O] Array of visual attributes.
3317 * pcGlyphs [O] Number of glyphs returned.
3321 * Failure: Non-zero HRESULT value.
3323 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3324 int cChars
, int cMaxGlyphs
,
3325 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3326 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3330 SCRIPT_CHARPROP
*charProps
;
3331 SCRIPT_GLYPHPROP
*glyphProps
;
3333 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3334 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3336 charProps
= heap_alloc_zero(sizeof(SCRIPT_CHARPROP
)*cChars
);
3337 if (!charProps
) return E_OUTOFMEMORY
;
3338 glyphProps
= heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP
)*cMaxGlyphs
);
3341 heap_free(charProps
);
3342 return E_OUTOFMEMORY
;
3345 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3349 for (i
= 0; i
< *pcGlyphs
; i
++)
3350 psva
[i
] = glyphProps
[i
].sva
;
3353 heap_free(charProps
);
3354 heap_free(glyphProps
);
3359 /***********************************************************************
3360 * ScriptPlaceOpenType (USP10.@)
3362 * Produce advance widths for a run.
3365 * hdc [I] Device context.
3366 * psc [I/O] Opaque pointer to a script cache.
3367 * psa [I/O] Script analysis.
3368 * tagScript [I] The OpenType tag for the Script
3369 * tagLangSys [I] The OpenType tag for the Language
3370 * rcRangeChars[I] Array of Character counts in each range
3371 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3372 * cRanges [I] Count of ranges
3373 * pwcChars [I] Array of characters specifying the run.
3374 * pwLogClust [I] Array of logical cluster info
3375 * pCharProps [I] Array of character property values
3376 * cChars [I] Number of characters in pwcChars.
3377 * pwGlyphs [I] Array of glyphs.
3378 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3379 * cGlyphs [I] Count of Glyphs
3380 * piAdvance [O] Array of advance widths.
3381 * pGoffset [O] Glyph offsets.
3382 * pABC [O] Combined ABC width.
3386 * Failure: Non-zero HRESULT value.
3389 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3390 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3391 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3392 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3393 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3394 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3395 int cGlyphs
, int *piAdvance
,
3396 GOFFSET
*pGoffset
, ABC
*pABC
3401 static int once
= 0;
3403 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3405 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3406 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3407 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3410 if (!pGlyphProps
) return E_INVALIDARG
;
3411 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3412 if (!pGoffset
) return E_FAIL
;
3415 if (!once
++) FIXME("Ranges not supported yet\n");
3417 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3418 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3420 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3421 for (i
= 0; i
< cGlyphs
; i
++)
3424 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3426 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3428 else if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3431 if (!hdc
) return E_PENDING
;
3432 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3434 if (psa
->fNoGlyphIndex
)
3435 ret
= GetCharABCWidthsW(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &abc
);
3437 ret
= GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
);
3438 if (!ret
) return S_FALSE
;
3443 if (psa
->fNoGlyphIndex
)
3444 ret
= GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
);
3446 ret
= GetCharWidthI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &width
);
3447 if (!ret
) return S_FALSE
;
3449 abc
.abcA
= abc
.abcC
= 0;
3451 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3455 pABC
->abcA
+= abc
.abcA
;
3456 pABC
->abcB
+= abc
.abcB
;
3457 pABC
->abcC
+= abc
.abcC
;
3459 /* FIXME: set to more reasonable values */
3460 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3461 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3464 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3466 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3470 /***********************************************************************
3471 * ScriptPlace (USP10.@)
3473 * Produce advance widths for a run.
3476 * hdc [I] Device context.
3477 * psc [I/O] Opaque pointer to a script cache.
3478 * pwGlyphs [I] Array of glyphs.
3479 * cGlyphs [I] Number of glyphs in pwGlyphs.
3480 * psva [I] Array of visual attributes.
3481 * psa [I/O] String analysis.
3482 * piAdvance [O] Array of advance widths.
3483 * pGoffset [O] Glyph offsets.
3484 * pABC [O] Combined ABC width.
3488 * Failure: Non-zero HRESULT value.
3490 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3491 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3492 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3495 SCRIPT_GLYPHPROP
*glyphProps
;
3498 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3499 piAdvance
, pGoffset
, pABC
);
3501 if (!psva
) return E_INVALIDARG
;
3502 if (!pGoffset
) return E_FAIL
;
3504 glyphProps
= heap_alloc(sizeof(SCRIPT_GLYPHPROP
)*cGlyphs
);
3505 if (!glyphProps
) return E_OUTOFMEMORY
;
3507 for (i
= 0; i
< cGlyphs
; i
++)
3508 glyphProps
[i
].sva
= psva
[i
];
3510 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3512 heap_free(glyphProps
);
3517 /***********************************************************************
3518 * ScriptGetCMap (USP10.@)
3520 * Retrieve glyph indices.
3523 * hdc [I] Device context.
3524 * psc [I/O] Opaque pointer to a script cache.
3525 * pwcInChars [I] Array of Unicode characters.
3526 * cChars [I] Number of characters in pwcInChars.
3527 * dwFlags [I] Flags.
3528 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3532 * Failure: Non-zero HRESULT value.
3534 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3535 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3540 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3541 cChars
, dwFlags
, pwOutGlyphs
);
3543 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3547 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3549 for (i
= 0; i
< cChars
; i
++)
3552 if (dwFlags
== SGCM_RTL
)
3553 inChar
= mirror_char(pwcInChars
[i
]);
3555 inChar
= pwcInChars
[i
];
3556 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3559 if (!hdc
) return E_PENDING
;
3560 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3561 if (glyph
== 0xffff)
3566 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3572 TRACE("no glyph translation\n");
3573 for (i
= 0; i
< cChars
; i
++)
3576 if (dwFlags
== SGCM_RTL
)
3577 inChar
= mirror_char(pwcInChars
[i
]);
3579 inChar
= pwcInChars
[i
];
3580 pwOutGlyphs
[i
] = inChar
;
3586 /***********************************************************************
3587 * ScriptTextOut (USP10.@)
3590 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3591 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3592 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3593 const int *piJustify
, const GOFFSET
*pGoffset
)
3598 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3600 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3601 hdc
, psc
, x
, y
, fuOptions
, wine_dbgstr_rect(lprc
), psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3602 piAdvance
, piJustify
, pGoffset
);
3604 if (!hdc
|| !psc
) return E_INVALIDARG
;
3605 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3607 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3608 fuOptions
|= ETO_IGNORELANGUAGE
;
3609 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3610 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3612 lpDx
= heap_alloc(cGlyphs
* sizeof(INT
) * 2);
3613 if (!lpDx
) return E_OUTOFMEMORY
;
3614 fuOptions
|= ETO_PDY
;
3616 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3618 reordered_glyphs
= heap_alloc( cGlyphs
* sizeof(WORD
) );
3619 if (!reordered_glyphs
)
3622 return E_OUTOFMEMORY
;
3625 for (i
= 0; i
< cGlyphs
; i
++)
3626 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3630 for (i
= 0; i
< cGlyphs
; i
++)
3632 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3633 lpDx
[i
* 2] = piAdvance
[orig_index
];
3634 lpDx
[i
* 2 + 1] = 0;
3640 x
+= pGoffset
[orig_index
].du
* dir
;
3641 y
+= pGoffset
[orig_index
].dv
;
3645 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3646 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3648 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3649 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3653 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3656 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3662 /***********************************************************************
3663 * ScriptCacheGetHeight (USP10.@)
3665 * Retrieve the height of the font in the cache.
3668 * hdc [I] Device context.
3669 * psc [I/O] Opaque pointer to a script cache.
3670 * height [O] Receives font height.
3674 * Failure: Non-zero HRESULT value.
3676 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3680 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3682 if (!height
) return E_INVALIDARG
;
3683 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3685 *height
= get_cache_height(psc
);
3689 /***********************************************************************
3690 * ScriptGetGlyphABCWidth (USP10.@)
3692 * Retrieve the width of a glyph.
3695 * hdc [I] Device context.
3696 * psc [I/O] Opaque pointer to a script cache.
3697 * glyph [I] Glyph to retrieve the width for.
3698 * abc [O] ABC widths of the glyph.
3702 * Failure: Non-zero HRESULT value.
3704 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3708 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3710 if (!abc
) return E_INVALIDARG
;
3711 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3713 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3715 if (!hdc
) return E_PENDING
;
3716 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3718 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3723 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3725 abc
->abcA
= abc
->abcC
= 0;
3727 set_cache_glyph_widths(psc
, glyph
, abc
);
3732 /***********************************************************************
3733 * ScriptLayout (USP10.@)
3735 * Map embedding levels to visual and/or logical order.
3738 * runs [I] Size of level array.
3739 * level [I] Array of embedding levels.
3740 * vistolog [O] Map of embedding levels from visual to logical order.
3741 * logtovis [O] Map of embedding levels from logical to visual order.
3745 * Failure: Non-zero HRESULT value.
3748 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3753 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3755 if (!level
|| (!vistolog
&& !logtovis
))
3756 return E_INVALIDARG
;
3758 indexs
= heap_alloc(sizeof(int) * runs
);
3760 return E_OUTOFMEMORY
;
3764 for( ich
= 0; ich
< runs
; ich
++)
3769 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3770 memcpy(vistolog
, indexs
, runs
* sizeof(*vistolog
));
3775 for( ich
= 0; ich
< runs
; ich
++)
3780 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3781 memcpy(logtovis
, indexs
, runs
* sizeof(*logtovis
));
3788 /***********************************************************************
3789 * ScriptStringGetLogicalWidths (USP10.@)
3791 * Returns logical widths from a string analysis.
3794 * ssa [I] string analysis.
3795 * piDx [O] logical widths returned.
3799 * Failure: a non-zero HRESULT.
3801 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3804 StringAnalysis
*analysis
= ssa
;
3806 TRACE("%p, %p\n", ssa
, piDx
);
3808 if (!analysis
) return S_FALSE
;
3809 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3811 for (i
= 0; i
< analysis
->numItems
; i
++)
3813 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3816 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3819 for (j
= 0; j
< cChar
; j
++)
3822 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3823 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3824 cChar
, j
, direction
, NULL
, NULL
);
3825 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
);
3827 for (k
= 0; k
< clust_size
; k
++)
3829 piDx
[next
] = advance
/ clust_size
;
3838 /***********************************************************************
3839 * ScriptStringValidate (USP10.@)
3841 * Validate a string analysis.
3844 * ssa [I] string analysis.
3848 * Failure: S_FALSE if invalid sequences are found
3849 * or a non-zero HRESULT if it fails.
3851 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3853 StringAnalysis
*analysis
= ssa
;
3855 TRACE("(%p)\n", ssa
);
3857 if (!analysis
) return E_INVALIDARG
;
3858 return analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
? S_FALSE
: S_OK
;
3861 /***********************************************************************
3862 * ScriptString_pSize (USP10.@)
3864 * Retrieve width and height of an analysed string.
3867 * ssa [I] string analysis.
3870 * Success: Pointer to a SIZE structure.
3873 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3876 StringAnalysis
*analysis
= ssa
;
3878 TRACE("(%p)\n", ssa
);
3880 if (!analysis
) return NULL
;
3881 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return NULL
;
3883 if (!(analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
))
3885 analysis
->sz
.cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3887 analysis
->sz
.cx
= 0;
3888 for (i
= 0; i
< analysis
->numItems
; i
++)
3890 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
.cy
)
3891 analysis
->sz
.cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3892 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3893 analysis
->sz
.cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3896 return &analysis
->sz
;
3899 /***********************************************************************
3900 * ScriptString_pLogAttr (USP10.@)
3902 * Retrieve logical attributes of an analysed string.
3905 * ssa [I] string analysis.
3908 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3911 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3913 StringAnalysis
*analysis
= ssa
;
3915 TRACE("(%p)\n", ssa
);
3917 if (!analysis
) return NULL
;
3918 if (!(analysis
->ssa_flags
& SSA_BREAK
)) return NULL
;
3919 return analysis
->logattrs
;
3922 /***********************************************************************
3923 * ScriptString_pcOutChars (USP10.@)
3925 * Retrieve the length of a string after clipping.
3928 * ssa [I] String analysis.
3931 * Success: Pointer to the length.
3934 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3936 StringAnalysis
*analysis
= ssa
;
3938 TRACE("(%p)\n", ssa
);
3940 if (!analysis
) return NULL
;
3941 return &analysis
->clip_len
;
3944 /***********************************************************************
3945 * ScriptStringGetOrder (USP10.@)
3947 * Retrieve a glyph order map.
3950 * ssa [I] String analysis.
3951 * order [I/O] Array of glyph positions.
3955 * Failure: a non-zero HRESULT.
3957 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3961 StringAnalysis
*analysis
= ssa
;
3963 TRACE("(%p)\n", ssa
);
3965 if (!analysis
) return S_FALSE
;
3966 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3968 /* FIXME: handle RTL scripts */
3969 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3970 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3976 /***********************************************************************
3977 * ScriptGetLogicalWidths (USP10.@)
3979 * Convert advance widths to logical widths.
3982 * sa [I] Script analysis.
3983 * nbchars [I] Number of characters.
3984 * nbglyphs [I] Number of glyphs.
3985 * glyph_width [I] Array of glyph widths.
3986 * log_clust [I] Array of logical clusters.
3987 * sva [I] Visual attributes.
3988 * widths [O] Array of logical widths.
3992 * Failure: a non-zero HRESULT.
3994 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3995 const int *advances
, const WORD
*log_clust
,
3996 const SCRIPT_VISATTR
*sva
, int *widths
)
3998 int i
, next
= 0, direction
;
4000 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
4001 sa
, nbchars
, nbglyphs
, advances
, log_clust
, sva
, widths
);
4003 if (sa
->fRTL
&& !sa
->fLogicalOrder
)
4008 for (i
= 0; i
< nbchars
; i
++)
4010 int clust_size
= get_cluster_size(log_clust
, nbchars
, i
, direction
, NULL
, NULL
);
4011 int advance
= get_glyph_cluster_advance(advances
, sva
, log_clust
, nbglyphs
, nbchars
, log_clust
[i
], direction
);
4014 for (j
= 0; j
< clust_size
; j
++)
4016 widths
[next
] = advance
/ clust_size
;
4025 /***********************************************************************
4026 * ScriptApplyLogicalWidth (USP10.@)
4028 * Generate glyph advance widths.
4031 * dx [I] Array of logical advance widths.
4032 * num_chars [I] Number of characters.
4033 * num_glyphs [I] Number of glyphs.
4034 * log_clust [I] Array of logical clusters.
4035 * sva [I] Visual attributes.
4036 * advance [I] Array of glyph advance widths.
4037 * sa [I] Script analysis.
4038 * abc [I/O] Summed ABC widths.
4039 * justify [O] Array of glyph advance widths.
4043 * Failure: a non-zero HRESULT.
4045 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
4046 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
4047 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
4048 ABC
*abc
, int *justify
)
4052 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
4053 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
4055 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
4059 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
4060 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
4064 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
4066 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
4070 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
4073 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4074 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4076 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
4079 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
4082 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4083 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4085 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
4088 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
4091 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4092 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4094 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);