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