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
= ARRAY_SIZE(script_props
);
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_calloc(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 if (!(levels
= heap_calloc(cInChars
, sizeof(*levels
))))
1470 if (!(overrides
= heap_calloc(cInChars
, sizeof(*overrides
))))
1473 if (!(layout_levels
= heap_calloc(cInChars
, sizeof(*layout_levels
))))
1476 if (psState
->fOverrideDirection
)
1480 SCRIPT_STATE s
= *psState
;
1481 s
.fOverrideDirection
= FALSE
;
1482 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1483 if (odd(layout_levels
[0]))
1485 else for (i
= 0; i
< cInChars
; i
++)
1486 if (layout_levels
[i
]!=layout_levels
[0])
1493 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1497 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1498 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1500 baselevel
= levels
[0];
1501 baselayout
= layout_levels
[0];
1502 for (i
= 0; i
< cInChars
; i
++)
1503 if (levels
[i
]!=levels
[0])
1505 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1508 heap_free(overrides
);
1509 heap_free(layout_levels
);
1512 layout_levels
= NULL
;
1516 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1517 static const WCHAR repeatable_math_punc
[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1519 if (!(strength
= heap_calloc(cInChars
, sizeof(*strength
))))
1521 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1523 /* We currently mis-level leading Diacriticals */
1524 if (scripts
[0] == Script_Diacritical
)
1525 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1527 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1528 strength
[i
] = BIDI_STRONG
;
1531 /* Math punctuation bordered on both sides by numbers can be
1532 merged into the number */
1533 for (i
= 0; i
< cInChars
; i
++)
1535 if (i
> 0 && i
< cInChars
-1 &&
1536 script_is_numeric(scripts
[i
-1]) &&
1537 strchrW(math_punc
, pwcInChars
[i
]))
1539 if (script_is_numeric(scripts
[i
+1]))
1541 scripts
[i
] = scripts
[i
+1];
1542 levels
[i
] = levels
[i
-1];
1543 strength
[i
] = strength
[i
-1];
1546 else if (strchrW(repeatable_math_punc
, pwcInChars
[i
]))
1549 for (j
= i
+1; j
< cInChars
; j
++)
1551 if (script_is_numeric(scripts
[j
]))
1555 scripts
[i
] = scripts
[j
];
1556 levels
[i
] = levels
[i
-1];
1557 strength
[i
] = strength
[i
-1];
1560 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1566 for (i
= 0; i
< cInChars
; i
++)
1568 /* Numerics at level 0 get bumped to level 2 */
1569 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
)
1570 && levels
[i
] == psState
->uBidiLevel
+ 1)) && script_is_numeric(scripts
[i
]))
1575 /* Joiners get merged preferencially right */
1576 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1579 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1580 strength
[i
] = strength
[i
-1];
1582 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1583 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1584 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1586 strength
[i
] = strength
[j
];
1591 if (psControl
->fMergeNeutralItems
)
1593 /* Merge the neutrals */
1594 for (i
= 0; i
< cInChars
; i
++)
1596 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1599 for (j
= i
; j
> 0; j
--)
1601 if (levels
[i
] != levels
[j
])
1603 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1605 scripts
[i
] = scripts
[j
];
1606 strength
[i
] = strength
[j
];
1611 /* Try going the other way */
1612 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1615 for (j
= i
; j
< cInChars
; j
++)
1617 if (levels
[i
] != levels
[j
])
1619 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1621 scripts
[i
] = scripts
[j
];
1622 strength
[i
] = strength
[j
];
1632 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1633 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1636 if (cnt
== cInChars
) /* All Spaces */
1639 New_Script
= scripts
[cnt
];
1642 pItems
[index
].iCharPos
= 0;
1643 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1645 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1647 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1648 str
= strength
[cnt
];
1656 if (strength
[cnt
] == BIDI_STRONG
)
1657 layoutRTL
= odd(layout_levels
[cnt
]);
1659 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1661 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1662 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1663 if (script_is_numeric(pItems
[index
].a
.eScript
))
1664 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1666 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1667 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1669 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1671 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1672 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1673 layoutRTL
= odd(baselayout
);
1674 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1675 pItems
[index
].a
.fRTL
= odd(baselevel
);
1676 if (script_is_numeric(pItems
[index
].a
.eScript
))
1677 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1679 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1682 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1683 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1684 pItems
[index
].iCharPos
);
1686 for (cnt
=1; cnt
< cInChars
; cnt
++)
1688 if(pwcInChars
[cnt
] != Numeric_space
)
1689 New_Script
= scripts
[cnt
];
1693 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1695 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1696 New_Script
= scripts
[cnt
+j
];
1698 New_Script
= scripts
[cnt
];
1702 /* merge space strengths*/
1703 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1706 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1709 /* changes in level */
1710 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1712 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1715 /* changes in strength */
1716 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1718 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1721 /* changes in script */
1722 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1724 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1728 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1730 layoutRTL
= odd(layout_levels
[cnt
]);
1731 if (script_is_numeric(pItems
[index
].a
.eScript
))
1732 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1737 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
);
1740 if (index
+1 > cMaxItems
)
1744 str
= strength
[cnt
];
1746 pItems
[index
].iCharPos
= cnt
;
1747 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1749 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1751 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1755 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1756 if (layout_levels
[cnt
] == 0)
1759 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1760 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1761 if (script_is_numeric(pItems
[index
].a
.eScript
))
1762 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1764 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1765 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1767 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1769 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1770 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1771 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1772 pItems
[index
].a
.fRTL
= odd(baselevel
);
1773 if (script_is_numeric(pItems
[index
].a
.eScript
))
1774 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1776 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1779 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1783 /* While not strictly necessary according to the spec, make sure the n+1
1784 * item is set up to prevent random behaviour if the caller erroneously
1785 * checks the n+1 structure */
1787 if (index
+ 1 > cMaxItems
) goto nomemory
;
1788 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1790 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1792 /* Set one SCRIPT_STATE item being returned */
1793 if (pcItems
) *pcItems
= index
;
1795 /* Set SCRIPT_ITEM */
1796 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1800 heap_free(overrides
);
1801 heap_free(layout_levels
);
1802 heap_free(strength
);
1807 /***********************************************************************
1808 * ScriptItemizeOpenType (USP10.@)
1810 * Split a Unicode string into shapeable parts.
1813 * pwcInChars [I] String to split.
1814 * cInChars [I] Number of characters in pwcInChars.
1815 * cMaxItems [I] Maximum number of items to return.
1816 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1817 * psState [I] Pointer to a SCRIPT_STATE structure.
1818 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1819 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1820 * pcItems [O] Number of script items returned.
1824 * Failure: Non-zero HRESULT value.
1826 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1827 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1828 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1830 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1833 /***********************************************************************
1834 * ScriptItemize (USP10.@)
1836 * Split a Unicode string into shapeable parts.
1839 * pwcInChars [I] String to split.
1840 * cInChars [I] Number of characters in pwcInChars.
1841 * cMaxItems [I] Maximum number of items to return.
1842 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1843 * psState [I] Pointer to a SCRIPT_STATE structure.
1844 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1845 * pcItems [O] Number of script items returned.
1849 * Failure: Non-zero HRESULT value.
1851 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1852 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1853 SCRIPT_ITEM
*pItems
, int *pcItems
)
1855 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1858 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1862 INT
*lpTabPos
= NULL
;
1867 lpTabPos
= pTabdef
->pTabStops
;
1869 if (pTabdef
&& pTabdef
->iTabOrigin
)
1871 if (pTabdef
->iScale
)
1872 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1874 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1878 cTabStops
= pTabdef
->cTabStops
;
1882 if (pTabdef
->iScale
)
1883 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1885 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1890 if (pTabdef
->iScale
)
1891 defWidth
= (32 * pTabdef
->iScale
) / 4;
1893 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1896 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1898 int position
= *lpTabPos
;
1900 position
= -1 * position
;
1901 if (pTabdef
->iScale
)
1902 position
= (position
* pTabdef
->iScale
) / 4;
1904 position
= position
* psc
->tm
.tmAveCharWidth
;
1906 if( nTabOrg
+ position
> current_x
)
1910 /* a left aligned tab */
1911 x
= (nTabOrg
+ position
) - current_x
;
1916 FIXME("Negative tabstop\n");
1921 if ((!cTabStops
) && (defWidth
> 0))
1922 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1923 else if ((!cTabStops
) && (defWidth
< 0))
1924 FIXME("TODO: Negative defWidth\n");
1929 /***********************************************************************
1930 * Helper function for ScriptStringAnalyse
1932 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1933 const WCHAR
*pwcInChars
, int cChars
)
1935 /* FIXME: When to properly fallback is still a bit of a mystery */
1938 if (psa
->fNoGlyphIndex
)
1941 if (init_script_cache(hdc
, psc
) != S_OK
)
1944 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1947 if (!(glyphs
= heap_calloc(cChars
, sizeof(*glyphs
))))
1949 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1959 static void find_fallback_font(enum usp10_script scriptid
, WCHAR
*FaceName
)
1963 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1965 static const WCHAR szFmt
[] = {'%','x',0};
1967 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1970 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1971 if (RegQueryValueExW(hkey
, value
, 0, &type
, (BYTE
*)FaceName
, &count
))
1972 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1976 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1979 /***********************************************************************
1980 * ScriptStringAnalyse (USP10.@)
1983 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1984 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1985 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1986 SCRIPT_STATE
*psState
, const int *piDx
,
1987 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1988 SCRIPT_STRING_ANALYSIS
*pssa
)
1990 HRESULT hr
= E_OUTOFMEMORY
;
1991 StringAnalysis
*analysis
= NULL
;
1992 SCRIPT_CONTROL sControl
;
1993 SCRIPT_STATE sState
;
1994 int i
, num_items
= 255;
1996 WCHAR
*iString
= NULL
;
1998 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1999 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
2000 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
2004 FIXME("Only Unicode strings are supported\n");
2005 return E_INVALIDARG
;
2007 if (cString
< 1 || !pString
) return E_INVALIDARG
;
2008 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
2010 if (!(analysis
= heap_alloc_zero(sizeof(*analysis
))))
2011 return E_OUTOFMEMORY
;
2012 if (!(analysis
->pItem
= heap_calloc(num_items
+ 1, sizeof(*analysis
->pItem
))))
2015 /* FIXME: handle clipping */
2016 analysis
->clip_len
= cString
;
2017 analysis
->hdc
= hdc
;
2018 analysis
->ssa_flags
= dwFlags
;
2023 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
2026 sControl
= *psControl
;
2028 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
2030 if (dwFlags
& SSA_PASSWORD
)
2032 if (!(iString
= heap_calloc(cString
, sizeof(*iString
))))
2037 for (i
= 0; i
< cString
; i
++)
2038 iString
[i
] = *((const WCHAR
*)pString
);
2042 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
2043 &analysis
->numItems
);
2047 if (hr
== E_OUTOFMEMORY
)
2052 /* set back to out of memory for default goto error behaviour */
2055 if (dwFlags
& SSA_BREAK
)
2057 if (!(analysis
->logattrs
= heap_calloc(cString
, sizeof(*analysis
->logattrs
))))
2060 for (i
= 0; i
< analysis
->numItems
; ++i
)
2061 ScriptBreak(&((const WCHAR
*)pString
)[analysis
->pItem
[i
].iCharPos
],
2062 analysis
->pItem
[i
+ 1].iCharPos
- analysis
->pItem
[i
].iCharPos
,
2063 &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
2066 if (!(analysis
->logical2visual
= heap_calloc(analysis
->numItems
, sizeof(*analysis
->logical2visual
))))
2068 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
2071 if (dwFlags
& SSA_GLYPHS
)
2075 if (!(analysis
->glyphs
= heap_calloc(analysis
->numItems
, sizeof(*analysis
->glyphs
))))
2077 heap_free(BidiLevel
);
2081 for (i
= 0; i
< analysis
->numItems
; i
++)
2083 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
2084 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2085 int numGlyphs
= 1.5 * cChar
+ 16;
2086 WORD
*glyphs
= heap_calloc(numGlyphs
, sizeof(*glyphs
));
2087 WORD
*pwLogClust
= heap_calloc(cChar
, sizeof(*pwLogClust
));
2088 int *piAdvance
= heap_calloc(numGlyphs
, sizeof(*piAdvance
));
2089 SCRIPT_VISATTR
*psva
= heap_calloc(numGlyphs
, sizeof(*psva
));
2090 GOFFSET
*pGoffset
= heap_calloc(numGlyphs
, sizeof(*pGoffset
));
2091 int numGlyphsReturned
;
2092 HFONT originalFont
= 0x0;
2094 /* FIXME: non unicode strings */
2095 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2096 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2098 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
)
2100 heap_free (BidiLevel
);
2102 heap_free (pwLogClust
);
2103 heap_free (piAdvance
);
2105 heap_free (pGoffset
);
2110 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2113 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2114 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2115 lf
.lfFaceName
[0] = 0;
2116 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2117 if (lf
.lfFaceName
[0])
2119 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2120 if (analysis
->glyphs
[i
].fallbackFont
)
2122 ScriptFreeCache(sc
);
2123 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2128 /* FIXME: When we properly shape Hangul remove this check */
2129 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2130 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2132 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2133 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2135 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2136 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2137 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2138 piAdvance
, pGoffset
, &analysis
->glyphs
[i
].abc
);
2140 SelectObject(hdc
,originalFont
);
2142 if (dwFlags
& SSA_TAB
)
2145 for (tabi
= 0; tabi
< cChar
; tabi
++)
2147 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2148 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2149 tab_x
+=piAdvance
[tabi
];
2153 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2154 analysis
->glyphs
[i
].glyphs
= glyphs
;
2155 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2156 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2157 analysis
->glyphs
[i
].psva
= psva
;
2158 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2159 analysis
->glyphs
[i
].iMaxPosX
= -1;
2161 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2166 for (i
= 0; i
< analysis
->numItems
; i
++)
2167 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2170 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2171 heap_free(BidiLevel
);
2179 heap_free(analysis
->glyphs
);
2180 heap_free(analysis
->logattrs
);
2181 heap_free(analysis
->pItem
);
2182 heap_free(analysis
->logical2visual
);
2183 heap_free(analysis
);
2187 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2189 if (pva
[glyph
].fClusterStart
)
2191 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2198 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2209 StringAnalysis
*analysis
;
2212 COLORREF BkColor
= 0x0;
2213 COLORREF TextColor
= 0x0;
2215 INT runStart
, runEnd
;
2216 INT iGlyph
, cGlyphs
;
2217 HFONT oldFont
= 0x0;
2221 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2222 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2224 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2226 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2227 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2233 BkMode
= GetBkMode(analysis
->hdc
);
2234 SetBkMode( analysis
->hdc
, OPAQUE
);
2235 BkColor
= GetBkColor(analysis
->hdc
);
2236 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2239 TextColor
= GetTextColor(analysis
->hdc
);
2240 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2243 if (analysis
->glyphs
[iItem
].fallbackFont
)
2244 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2246 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2247 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2250 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2251 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2253 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2255 if (analysis
->pItem
[iItem
].a
.fRTL
)
2257 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2258 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2260 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2261 crc
.left
= iX
+ off_x
;
2265 if (cStart
>=0 && runStart
)
2266 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2268 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2269 crc
.left
= iX
+ off_x
;
2272 if (analysis
->pItem
[iItem
].a
.fRTL
)
2273 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2275 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2277 if (analysis
->pItem
[iItem
].a
.fRTL
)
2278 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2280 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2284 /* adjust for cluster glyphs when starting */
2285 if (analysis
->pItem
[iItem
].a
.fRTL
)
2286 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2288 i
= analysis
->pItem
[iItem
].iCharPos
;
2290 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2292 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2294 if (analysis
->pItem
[iItem
].a
.fRTL
)
2295 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2297 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2302 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2307 clust_glyph
= iGlyph
+ cGlyphs
;
2308 if (analysis
->pItem
[iItem
].a
.fRTL
)
2313 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2314 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2321 hr
= ScriptTextOut(analysis
->hdc
,
2322 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2323 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2324 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2325 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2326 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2328 TRACE("ScriptTextOut hr=%08x\n", hr
);
2332 SetBkColor(analysis
->hdc
, BkColor
);
2333 SetBkMode( analysis
->hdc
, BkMode
);
2335 SetTextColor(analysis
->hdc
, TextColor
);
2337 if (analysis
->glyphs
[iItem
].fallbackFont
)
2338 SelectObject(analysis
->hdc
, oldFont
);
2343 /***********************************************************************
2344 * ScriptStringOut (USP10.@)
2346 * This function takes the output of ScriptStringAnalyse and joins the segments
2347 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2348 * only processes glyphs.
2351 * ssa [I] buffer to hold the analysed string components
2352 * iX [I] X axis displacement for output
2353 * iY [I] Y axis displacement for output
2354 * uOptions [I] flags controlling output processing
2355 * prc [I] rectangle coordinates
2356 * iMinSel [I] starting pos for substringing output string
2357 * iMaxSel [I] ending pos for substringing output string
2358 * fDisabled [I] controls text highlighting
2362 * Failure: is the value returned by ScriptTextOut
2364 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2373 StringAnalysis
*analysis
;
2377 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2378 ssa
, iX
, iY
, uOptions
, wine_dbgstr_rect(prc
), iMinSel
, iMaxSel
, fDisabled
);
2380 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2381 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2383 for (item
= 0; item
< analysis
->numItems
; item
++)
2385 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2390 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2392 if (iMaxSel
> 0 && iMinSel
< 0)
2394 for (item
= 0; item
< analysis
->numItems
; item
++)
2396 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2405 /***********************************************************************
2406 * ScriptStringCPtoX (USP10.@)
2409 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2413 StringAnalysis
* analysis
= ssa
;
2415 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2417 if (!ssa
|| !pX
) return S_FALSE
;
2418 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2420 /* icp out of range */
2423 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2424 return E_INVALIDARG
;
2427 for(item
=0; item
<analysis
->numItems
; item
++)
2432 i
= analysis
->logical2visual
[item
];
2433 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2434 /* initialize max extents for uninitialized runs */
2435 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2437 if (analysis
->pItem
[i
].a
.fRTL
)
2438 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2439 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2440 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2442 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2443 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2444 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2447 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2449 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2453 icp
-= analysis
->pItem
[i
].iCharPos
;
2454 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2455 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2456 &analysis
->pItem
[i
].a
, &offset
);
2463 /* icp out of range */
2464 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2465 return E_INVALIDARG
;
2468 /***********************************************************************
2469 * ScriptStringXtoCP (USP10.@)
2472 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2474 StringAnalysis
* analysis
= ssa
;
2477 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2479 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2480 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2485 if (analysis
->pItem
[0].a
.fRTL
)
2488 *piTrailing
= FALSE
;
2498 for(item
=0; item
<analysis
->numItems
; item
++)
2503 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2506 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2507 /* initialize max extents for uninitialized runs */
2508 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2510 if (analysis
->pItem
[i
].a
.fRTL
)
2511 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2512 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2513 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2515 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2516 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2517 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2520 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2522 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2526 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2527 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2528 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2529 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2535 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2536 *piTrailing
= FALSE
;
2542 /***********************************************************************
2543 * ScriptStringFree (USP10.@)
2545 * Free a string analysis.
2548 * pssa [I] string analysis.
2552 * Failure: Non-zero HRESULT value.
2554 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2556 StringAnalysis
* analysis
;
2560 TRACE("(%p)\n", pssa
);
2562 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2564 invalid
= analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2566 if (analysis
->glyphs
)
2568 for (i
= 0; i
< analysis
->numItems
; i
++)
2570 heap_free(analysis
->glyphs
[i
].glyphs
);
2571 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2572 heap_free(analysis
->glyphs
[i
].piAdvance
);
2573 heap_free(analysis
->glyphs
[i
].psva
);
2574 heap_free(analysis
->glyphs
[i
].pGoffset
);
2575 if (analysis
->glyphs
[i
].fallbackFont
)
2576 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2577 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2578 heap_free(analysis
->glyphs
[i
].sc
);
2580 heap_free(analysis
->glyphs
);
2583 heap_free(analysis
->pItem
);
2584 heap_free(analysis
->logattrs
);
2585 heap_free(analysis
->logical2visual
);
2586 heap_free(analysis
);
2588 if (invalid
) return E_INVALIDARG
;
2592 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2593 int direction
, int* iCluster
, int *check_out
)
2597 WORD clust
= pwLogClust
[item
];
2599 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2601 if (pwLogClust
[check
] == clust
)
2604 if (iCluster
&& *iCluster
== -1)
2616 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
)
2621 advance
= piAdvance
[glyph
];
2623 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2624 log_clust_max
= pwLogClust
[0];
2626 log_clust_max
= pwLogClust
[cChars
-1];
2628 if (glyph
> log_clust_max
)
2631 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2634 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2636 if (glyph
> log_clust_max
)
2638 advance
+= piAdvance
[glyph
];
2644 /***********************************************************************
2645 * ScriptCPtoX (USP10.@)
2648 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2652 const WORD
*pwLogClust
,
2653 const SCRIPT_VISATTR
*psva
,
2654 const int *piAdvance
,
2655 const SCRIPT_ANALYSIS
*psa
,
2663 float special_size
= 0.0;
2668 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2669 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2672 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2680 int max_clust
= pwLogClust
[0];
2682 for (item
=0; item
< cGlyphs
; item
++)
2683 if (pwLogClust
[item
] > max_clust
)
2685 ERR("We do not handle non reversed clusters properly\n");
2690 for (item
= max_clust
; item
>=0; item
--)
2691 iMaxPos
+= piAdvance
[item
];
2695 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2697 if (iSpecial
== -1 && (iCluster
== -1 || iCluster
+clust_size
<= item
))
2700 int clust
= pwLogClust
[item
];
2703 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2706 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2708 if (check
>= cChars
&& !iMaxPos
)
2711 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2712 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2714 special_size
/= (cChars
- item
);
2715 iPosX
+= special_size
;
2719 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2722 if (clust_size
== 0)
2726 iPosX
+= advance
/ (float)clust_size
;
2729 else if (iSpecial
!= -1)
2730 iPosX
+= special_size
;
2731 else /* (iCluster != -1) */
2733 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2734 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2737 if (clust_size
== 0)
2741 iPosX
+= adv
/ (float)clust_size
;
2747 iPosX
= iMaxPos
- iPosX
;
2753 TRACE("*piX=%d\n", *piX
);
2757 /* Count the number of characters in a cluster and its starting index*/
2758 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2763 for (i
= 0; i
< cChars
; i
++)
2765 if (pwLogClust
[i
] == cluster_index
)
2767 if (!size
&& start_index
)
2775 else if (size
) break;
2778 *cluster_size
= size
;
2784 To handle multi-glyph clusters we need to find all the glyphs that are
2785 represented in the cluster. This involves finding the glyph whose
2786 index is the cluster index as well as whose glyph indices are greater than
2787 our cluster index but not part of a new cluster.
2789 Then we sum all those glyphs' advances.
2791 static inline int get_cluster_advance(const int* piAdvance
,
2792 const SCRIPT_VISATTR
*psva
,
2793 const WORD
*pwLogClust
, int cGlyphs
,
2794 int cChars
, int cluster
, int direction
)
2805 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2807 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2808 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2809 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2814 glyph_end
= cGlyphs
;
2817 /* Don't fully understand multi-glyph reversed clusters yet,
2818 * do they occur for real or just in our test? */
2819 FIXME("multi-glyph reversed clusters found\n");
2820 glyph_end
= glyph_start
+ 1;
2824 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2825 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2827 if (psva
[i
].fClusterStart
)
2834 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2835 advance
+= piAdvance
[i
];
2841 /***********************************************************************
2842 * ScriptXtoCP (USP10.@)
2845 * Use piAdvance to find the cluster we are looking at.
2846 * Find the character that is the first character of the cluster.
2847 * That is our base piCP.
2848 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2849 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2850 * determine how far through the cluster to advance the cursor.
2852 HRESULT WINAPI
ScriptXtoCP(int iX
,
2855 const WORD
*pwLogClust
,
2856 const SCRIPT_VISATTR
*psva
,
2857 const int *piAdvance
,
2858 const SCRIPT_ANALYSIS
*psa
,
2865 int glyph_index
, cluster_index
;
2868 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2869 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2870 psa
, piCP
, piTrailing
);
2872 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2875 /* Handle an iX < 0 */
2891 /* Looking for non-reversed clusters in a reversed string */
2894 int max_clust
= pwLogClust
[0];
2895 for (i
=0; i
< cChars
; i
++)
2896 if (pwLogClust
[i
] > max_clust
)
2898 FIXME("We do not handle non reversed clusters properly\n");
2903 /* find the glyph_index based in iX */
2906 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2911 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2915 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2918 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2920 /* find the cluster */
2922 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2925 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2928 TRACE("cluster_index %i\n", cluster_index
);
2930 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2932 /* We are off the end of the string */
2938 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2940 TRACE("first char index %i\n",i
);
2941 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2943 /* Check trailing */
2944 if (glyph_index
!= cluster_index
||
2945 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2946 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2947 *piTrailing
= cluster_size
;
2951 if (cluster_size
> 1)
2953 /* Be part way through the glyph cluster based on size and position */
2954 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2955 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2959 /* back up to the beginning of the cluster */
2960 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2961 adv
+= piAdvance
[part_index
];
2962 if (adv
> iX
) adv
= iX
;
2964 TRACE("Multi-char cluster, no snap\n");
2965 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2966 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2969 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2971 if (part_index
) part_index
--;
2975 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2977 if (part_index
> cluster_size
)
2979 adv
+= cluster_part_width
;
2980 part_index
=cluster_size
;
2984 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2989 i
+= (cluster_size
- part_index
);
2991 /* Check trailing */
2992 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2993 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2998 /* Check trailing */
2999 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
3000 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
3007 TRACE("Point falls outside of string\n");
3008 if (glyph_index
< 0)
3010 else /* (glyph_index >= cGlyphs) */
3013 /* If not snaping in the reverse direction (such as Hebrew) Then 0
3014 point flow to the next character */
3017 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
3026 TRACE("*piCP=%d\n", *piCP
);
3027 TRACE("*piTrailing=%d\n", *piTrailing
);
3031 /***********************************************************************
3032 * ScriptBreak (USP10.@)
3034 * Retrieve line break information.
3037 * chars [I] Array of characters.
3038 * sa [I] Script analysis.
3039 * la [I] Array of logical attribute structures.
3045 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
3047 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
3049 if (count
< 0 || !la
) return E_INVALIDARG
;
3050 if (count
== 0) return E_FAIL
;
3052 BREAK_line(chars
, count
, sa
, la
);
3057 /***********************************************************************
3058 * ScriptIsComplex (USP10.@)
3060 * Determine if a string is complex.
3063 * chars [I] Array of characters to test.
3064 * len [I] Length in characters.
3072 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
3074 enum usp10_script script
;
3075 unsigned int i
, consumed
;
3077 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
3079 if (!chars
|| len
< 0)
3080 return E_INVALIDARG
;
3082 for (i
= 0; i
< len
; i
+=consumed
)
3084 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3087 script
= get_char_script(chars
,i
,len
, &consumed
);
3088 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3089 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3095 /***********************************************************************
3096 * ScriptShapeOpenType (USP10.@)
3098 * Produce glyphs and visual attributes for a run.
3101 * hdc [I] Device context.
3102 * psc [I/O] Opaque pointer to a script cache.
3103 * psa [I/O] Script analysis.
3104 * tagScript [I] The OpenType tag for the Script
3105 * tagLangSys [I] The OpenType tag for the Language
3106 * rcRangeChars[I] Array of Character counts in each range
3107 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3108 * cRanges [I] Count of ranges
3109 * pwcChars [I] Array of characters specifying the run.
3110 * cChars [I] Number of characters in pwcChars.
3111 * cMaxGlyphs [I] Length of pwOutGlyphs.
3112 * pwLogClust [O] Array of logical cluster info.
3113 * pCharProps [O] Array of character property values
3114 * pwOutGlyphs [O] Array of glyphs.
3115 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3116 * pcGlyphs [O] Number of glyphs returned.
3120 * Failure: Non-zero HRESULT value.
3122 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3123 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3124 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3125 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3126 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3127 int cMaxGlyphs
, WORD
*pwLogClust
,
3128 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3129 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3136 static int once
= 0;
3138 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3140 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3141 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3142 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3144 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3145 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3147 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3148 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3151 if(!once
++) FIXME("Ranges not supported yet\n");
3153 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3156 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3157 if (!pwLogClust
) return E_FAIL
;
3159 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3160 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3162 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3163 for (i
= 0; i
< cChars
; i
++)
3166 if (rtl
) idx
= cChars
- 1 - i
;
3167 /* FIXME: set to better values */
3168 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3169 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3170 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3171 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3172 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3173 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3175 /* FIXME: have the shaping engine set this */
3176 pCharProps
[i
].fCanGlyphAlone
= 0;
3178 pwLogClust
[i
] = idx
;
3181 if (psa
&& !psa
->fNoGlyphIndex
&& ((ScriptCache
*)*psc
)->sfnt
)
3184 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3186 if (!(rChars
= heap_calloc(cChars
, sizeof(*rChars
))))
3187 return E_OUTOFMEMORY
;
3189 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3194 if (rtl
) idx
= cChars
- 1 - i
;
3197 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3201 chInput
= mirror_char(pwcChars
[idx
]);
3203 chInput
= pwcChars
[idx
];
3204 rChars
[i
] = chInput
;
3208 rChars
[i
] = pwcChars
[idx
];
3209 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3212 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3220 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3225 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3233 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3234 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3240 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3241 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3242 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3244 for (i
= 0; i
< cChars
; ++i
)
3246 /* Special case for tabs and joiners. As control characters, ZWNJ
3247 * and ZWJ would in principle get handled by the corresponding
3248 * shaping functions. However, since ZWNJ and ZWJ can get merged
3249 * into adjoining runs during itemisation, these don't generally
3250 * get classified as Script_Control. */
3251 if (pwcChars
[i
] == 0x0009 || pwcChars
[i
] == ZWSP
|| pwcChars
[i
] == ZWNJ
|| pwcChars
[i
] == ZWJ
)
3253 pwOutGlyphs
[pwLogClust
[i
]] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3254 pOutGlyphProps
[pwLogClust
[i
]].sva
.fZeroWidth
= 1;
3261 TRACE("no glyph translation\n");
3262 for (i
= 0; i
< cChars
; i
++)
3265 /* No mirroring done here */
3266 if (rtl
) idx
= cChars
- 1 - i
;
3267 pwOutGlyphs
[i
] = pwcChars
[idx
];
3272 /* overwrite some basic control glyphs to blank */
3273 if (psa
->fNoGlyphIndex
)
3275 if (pwcChars
[idx
] == ZWSP
|| pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3277 pwOutGlyphs
[i
] = 0x20;
3278 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3281 else if (psa
->eScript
== Script_Control
|| pwcChars
[idx
] == ZWSP
3282 || pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3284 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3285 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3287 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3288 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3298 /***********************************************************************
3299 * ScriptShape (USP10.@)
3301 * Produce glyphs and visual attributes for a run.
3304 * hdc [I] Device context.
3305 * psc [I/O] Opaque pointer to a script cache.
3306 * pwcChars [I] Array of characters specifying the run.
3307 * cChars [I] Number of characters in pwcChars.
3308 * cMaxGlyphs [I] Length of pwOutGlyphs.
3309 * psa [I/O] Script analysis.
3310 * pwOutGlyphs [O] Array of glyphs.
3311 * pwLogClust [O] Array of logical cluster info.
3312 * psva [O] Array of visual attributes.
3313 * pcGlyphs [O] Number of glyphs returned.
3317 * Failure: Non-zero HRESULT value.
3319 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3320 int cChars
, int cMaxGlyphs
,
3321 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3322 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3326 SCRIPT_CHARPROP
*charProps
;
3327 SCRIPT_GLYPHPROP
*glyphProps
;
3329 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3330 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3332 if (!(charProps
= heap_calloc(cChars
, sizeof(*charProps
))))
3333 return E_OUTOFMEMORY
;
3335 if (!(glyphProps
= heap_calloc(cMaxGlyphs
, sizeof(*glyphProps
))))
3337 heap_free(charProps
);
3338 return E_OUTOFMEMORY
;
3341 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3345 for (i
= 0; i
< *pcGlyphs
; i
++)
3346 psva
[i
] = glyphProps
[i
].sva
;
3349 heap_free(charProps
);
3350 heap_free(glyphProps
);
3355 /***********************************************************************
3356 * ScriptPlaceOpenType (USP10.@)
3358 * Produce advance widths for a run.
3361 * hdc [I] Device context.
3362 * psc [I/O] Opaque pointer to a script cache.
3363 * psa [I/O] Script analysis.
3364 * tagScript [I] The OpenType tag for the Script
3365 * tagLangSys [I] The OpenType tag for the Language
3366 * rcRangeChars[I] Array of Character counts in each range
3367 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3368 * cRanges [I] Count of ranges
3369 * pwcChars [I] Array of characters specifying the run.
3370 * pwLogClust [I] Array of logical cluster info
3371 * pCharProps [I] Array of character property values
3372 * cChars [I] Number of characters in pwcChars.
3373 * pwGlyphs [I] Array of glyphs.
3374 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3375 * cGlyphs [I] Count of Glyphs
3376 * piAdvance [O] Array of advance widths.
3377 * pGoffset [O] Glyph offsets.
3378 * pABC [O] Combined ABC width.
3382 * Failure: Non-zero HRESULT value.
3385 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3386 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3387 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3388 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3389 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3390 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3391 int cGlyphs
, int *piAdvance
,
3392 GOFFSET
*pGoffset
, ABC
*pABC
3397 static int once
= 0;
3399 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3401 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3402 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3403 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3406 if (!pGlyphProps
) return E_INVALIDARG
;
3407 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3408 if (!pGoffset
) return E_FAIL
;
3411 if (!once
++) FIXME("Ranges not supported yet\n");
3413 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3414 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3416 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3417 for (i
= 0; i
< cGlyphs
; i
++)
3420 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3422 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3424 else if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3427 if (!hdc
) return E_PENDING
;
3428 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3430 if (psa
->fNoGlyphIndex
)
3431 ret
= GetCharABCWidthsW(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &abc
);
3433 ret
= GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
);
3434 if (!ret
) return S_FALSE
;
3439 if (psa
->fNoGlyphIndex
)
3440 ret
= GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
);
3442 ret
= GetCharWidthI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &width
);
3443 if (!ret
) return S_FALSE
;
3445 abc
.abcA
= abc
.abcC
= 0;
3447 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3451 pABC
->abcA
+= abc
.abcA
;
3452 pABC
->abcB
+= abc
.abcB
;
3453 pABC
->abcC
+= abc
.abcC
;
3455 /* FIXME: set to more reasonable values */
3456 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3457 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3460 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3462 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3466 /***********************************************************************
3467 * ScriptPlace (USP10.@)
3469 * Produce advance widths for a run.
3472 * hdc [I] Device context.
3473 * psc [I/O] Opaque pointer to a script cache.
3474 * pwGlyphs [I] Array of glyphs.
3475 * cGlyphs [I] Number of glyphs in pwGlyphs.
3476 * psva [I] Array of visual attributes.
3477 * psa [I/O] String analysis.
3478 * piAdvance [O] Array of advance widths.
3479 * pGoffset [O] Glyph offsets.
3480 * pABC [O] Combined ABC width.
3484 * Failure: Non-zero HRESULT value.
3486 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3487 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3488 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3491 SCRIPT_GLYPHPROP
*glyphProps
;
3494 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3495 piAdvance
, pGoffset
, pABC
);
3497 if (!psva
) return E_INVALIDARG
;
3498 if (!pGoffset
) return E_FAIL
;
3500 if (!(glyphProps
= heap_calloc(cGlyphs
, sizeof(*glyphProps
))))
3501 return E_OUTOFMEMORY
;
3503 for (i
= 0; i
< cGlyphs
; i
++)
3504 glyphProps
[i
].sva
= psva
[i
];
3506 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3508 heap_free(glyphProps
);
3513 /***********************************************************************
3514 * ScriptGetCMap (USP10.@)
3516 * Retrieve glyph indices.
3519 * hdc [I] Device context.
3520 * psc [I/O] Opaque pointer to a script cache.
3521 * pwcInChars [I] Array of Unicode characters.
3522 * cChars [I] Number of characters in pwcInChars.
3523 * dwFlags [I] Flags.
3524 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3528 * Failure: Non-zero HRESULT value.
3530 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3531 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3536 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3537 cChars
, dwFlags
, pwOutGlyphs
);
3539 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3543 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3545 for (i
= 0; i
< cChars
; i
++)
3548 if (dwFlags
== SGCM_RTL
)
3549 inChar
= mirror_char(pwcInChars
[i
]);
3551 inChar
= pwcInChars
[i
];
3552 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3555 if (!hdc
) return E_PENDING
;
3556 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3557 if (glyph
== 0xffff)
3562 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3568 TRACE("no glyph translation\n");
3569 for (i
= 0; i
< cChars
; i
++)
3572 if (dwFlags
== SGCM_RTL
)
3573 inChar
= mirror_char(pwcInChars
[i
]);
3575 inChar
= pwcInChars
[i
];
3576 pwOutGlyphs
[i
] = inChar
;
3582 /***********************************************************************
3583 * ScriptTextOut (USP10.@)
3586 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3587 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3588 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3589 const int *piJustify
, const GOFFSET
*pGoffset
)
3594 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3596 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3597 hdc
, psc
, x
, y
, fuOptions
, wine_dbgstr_rect(lprc
), psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3598 piAdvance
, piJustify
, pGoffset
);
3600 if (!hdc
|| !psc
) return E_INVALIDARG
;
3601 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3603 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3604 fuOptions
|= ETO_IGNORELANGUAGE
;
3605 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3606 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3608 if (!(lpDx
= heap_calloc(cGlyphs
, 2 * sizeof(*lpDx
))))
3609 return E_OUTOFMEMORY
;
3610 fuOptions
|= ETO_PDY
;
3612 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3614 if (!(reordered_glyphs
= heap_calloc(cGlyphs
, sizeof(*reordered_glyphs
))))
3617 return E_OUTOFMEMORY
;
3620 for (i
= 0; i
< cGlyphs
; i
++)
3621 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3625 for (i
= 0; i
< cGlyphs
; i
++)
3627 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3628 lpDx
[i
* 2] = piAdvance
[orig_index
];
3629 lpDx
[i
* 2 + 1] = 0;
3635 x
+= pGoffset
[orig_index
].du
* dir
;
3636 y
+= pGoffset
[orig_index
].dv
;
3640 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3641 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3643 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3644 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3648 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3651 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3657 /***********************************************************************
3658 * ScriptCacheGetHeight (USP10.@)
3660 * Retrieve the height of the font in the cache.
3663 * hdc [I] Device context.
3664 * psc [I/O] Opaque pointer to a script cache.
3665 * height [O] Receives font height.
3669 * Failure: Non-zero HRESULT value.
3671 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3675 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3677 if (!height
) return E_INVALIDARG
;
3678 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3680 *height
= get_cache_height(psc
);
3684 /***********************************************************************
3685 * ScriptGetGlyphABCWidth (USP10.@)
3687 * Retrieve the width of a glyph.
3690 * hdc [I] Device context.
3691 * psc [I/O] Opaque pointer to a script cache.
3692 * glyph [I] Glyph to retrieve the width for.
3693 * abc [O] ABC widths of the glyph.
3697 * Failure: Non-zero HRESULT value.
3699 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3703 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3705 if (!abc
) return E_INVALIDARG
;
3706 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3708 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3710 if (!hdc
) return E_PENDING
;
3711 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3713 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3718 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3720 abc
->abcA
= abc
->abcC
= 0;
3722 set_cache_glyph_widths(psc
, glyph
, abc
);
3727 /***********************************************************************
3728 * ScriptLayout (USP10.@)
3730 * Map embedding levels to visual and/or logical order.
3733 * runs [I] Size of level array.
3734 * level [I] Array of embedding levels.
3735 * vistolog [O] Map of embedding levels from visual to logical order.
3736 * logtovis [O] Map of embedding levels from logical to visual order.
3740 * Failure: Non-zero HRESULT value.
3743 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3748 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3750 if (!level
|| (!vistolog
&& !logtovis
))
3751 return E_INVALIDARG
;
3753 if (!(indexs
= heap_calloc(runs
, sizeof(*indexs
))))
3754 return E_OUTOFMEMORY
;
3758 for( ich
= 0; ich
< runs
; ich
++)
3763 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3764 memcpy(vistolog
, indexs
, runs
* sizeof(*vistolog
));
3769 for( ich
= 0; ich
< runs
; ich
++)
3774 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3775 memcpy(logtovis
, indexs
, runs
* sizeof(*logtovis
));
3782 /***********************************************************************
3783 * ScriptStringGetLogicalWidths (USP10.@)
3785 * Returns logical widths from a string analysis.
3788 * ssa [I] string analysis.
3789 * piDx [O] logical widths returned.
3793 * Failure: a non-zero HRESULT.
3795 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3798 StringAnalysis
*analysis
= ssa
;
3800 TRACE("%p, %p\n", ssa
, piDx
);
3802 if (!analysis
) return S_FALSE
;
3803 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3805 for (i
= 0; i
< analysis
->numItems
; i
++)
3807 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3810 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3813 for (j
= 0; j
< cChar
; j
++)
3816 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3817 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3818 cChar
, j
, direction
, NULL
, NULL
);
3819 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
);
3821 for (k
= 0; k
< clust_size
; k
++)
3823 piDx
[next
] = advance
/ clust_size
;
3832 /***********************************************************************
3833 * ScriptStringValidate (USP10.@)
3835 * Validate a string analysis.
3838 * ssa [I] string analysis.
3842 * Failure: S_FALSE if invalid sequences are found
3843 * or a non-zero HRESULT if it fails.
3845 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3847 StringAnalysis
*analysis
= ssa
;
3849 TRACE("(%p)\n", ssa
);
3851 if (!analysis
) return E_INVALIDARG
;
3852 return analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
? S_FALSE
: S_OK
;
3855 /***********************************************************************
3856 * ScriptString_pSize (USP10.@)
3858 * Retrieve width and height of an analysed string.
3861 * ssa [I] string analysis.
3864 * Success: Pointer to a SIZE structure.
3867 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3870 StringAnalysis
*analysis
= ssa
;
3872 TRACE("(%p)\n", ssa
);
3874 if (!analysis
) return NULL
;
3875 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return NULL
;
3877 if (!(analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
))
3879 analysis
->sz
.cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3881 analysis
->sz
.cx
= 0;
3882 for (i
= 0; i
< analysis
->numItems
; i
++)
3884 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
.cy
)
3885 analysis
->sz
.cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3886 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3887 analysis
->sz
.cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3890 return &analysis
->sz
;
3893 /***********************************************************************
3894 * ScriptString_pLogAttr (USP10.@)
3896 * Retrieve logical attributes of an analysed string.
3899 * ssa [I] string analysis.
3902 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3905 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3907 StringAnalysis
*analysis
= ssa
;
3909 TRACE("(%p)\n", ssa
);
3911 if (!analysis
) return NULL
;
3912 if (!(analysis
->ssa_flags
& SSA_BREAK
)) return NULL
;
3913 return analysis
->logattrs
;
3916 /***********************************************************************
3917 * ScriptString_pcOutChars (USP10.@)
3919 * Retrieve the length of a string after clipping.
3922 * ssa [I] String analysis.
3925 * Success: Pointer to the length.
3928 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3930 StringAnalysis
*analysis
= ssa
;
3932 TRACE("(%p)\n", ssa
);
3934 if (!analysis
) return NULL
;
3935 return &analysis
->clip_len
;
3938 /***********************************************************************
3939 * ScriptStringGetOrder (USP10.@)
3941 * Retrieve a glyph order map.
3944 * ssa [I] String analysis.
3945 * order [I/O] Array of glyph positions.
3949 * Failure: a non-zero HRESULT.
3951 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3955 StringAnalysis
*analysis
= ssa
;
3957 TRACE("(%p)\n", ssa
);
3959 if (!analysis
) return S_FALSE
;
3960 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3962 /* FIXME: handle RTL scripts */
3963 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3964 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3970 /***********************************************************************
3971 * ScriptGetLogicalWidths (USP10.@)
3973 * Convert advance widths to logical widths.
3976 * sa [I] Script analysis.
3977 * nbchars [I] Number of characters.
3978 * nbglyphs [I] Number of glyphs.
3979 * glyph_width [I] Array of glyph widths.
3980 * log_clust [I] Array of logical clusters.
3981 * sva [I] Visual attributes.
3982 * widths [O] Array of logical widths.
3986 * Failure: a non-zero HRESULT.
3988 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3989 const int *advances
, const WORD
*log_clust
,
3990 const SCRIPT_VISATTR
*sva
, int *widths
)
3992 int i
, next
= 0, direction
;
3994 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3995 sa
, nbchars
, nbglyphs
, advances
, log_clust
, sva
, widths
);
3997 if (sa
->fRTL
&& !sa
->fLogicalOrder
)
4002 for (i
= 0; i
< nbchars
; i
++)
4004 int clust_size
= get_cluster_size(log_clust
, nbchars
, i
, direction
, NULL
, NULL
);
4005 int advance
= get_glyph_cluster_advance(advances
, sva
, log_clust
, nbglyphs
, nbchars
, log_clust
[i
], direction
);
4008 for (j
= 0; j
< clust_size
; j
++)
4010 widths
[next
] = advance
/ clust_size
;
4019 /***********************************************************************
4020 * ScriptApplyLogicalWidth (USP10.@)
4022 * Generate glyph advance widths.
4025 * dx [I] Array of logical advance widths.
4026 * num_chars [I] Number of characters.
4027 * num_glyphs [I] Number of glyphs.
4028 * log_clust [I] Array of logical clusters.
4029 * sva [I] Visual attributes.
4030 * advance [I] Array of glyph advance widths.
4031 * sa [I] Script analysis.
4032 * abc [I/O] Summed ABC widths.
4033 * justify [O] Array of glyph advance widths.
4037 * Failure: a non-zero HRESULT.
4039 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
4040 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
4041 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
4042 ABC
*abc
, int *justify
)
4046 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
4047 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
4049 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
4053 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
4054 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
4058 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
4060 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
4064 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
4067 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4068 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4070 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
4073 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
4076 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4077 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4079 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
4082 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
4085 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4086 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4088 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);