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 typedef struct _scriptRange
55 static const scriptRange scriptRanges
[] = {
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},
300 { SCRIPT_UNDEFINED
, 0, 0, 0}
303 /* the must be in order so that the index matches the Script value */
304 const scriptData scriptInformation
[] = {
305 {{SCRIPT_UNDEFINED
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
306 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
309 {{Script_Latin
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
310 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
311 MS_MAKE_TAG('l','a','t','n'),
312 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
313 {{Script_CR
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
314 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
317 {{Script_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
318 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
320 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
321 {{Script_Control
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
322 {LANG_ENGLISH
, 0, 1, 0, 0, ANSI_CHARSET
, 1, 0, 0, 0, 0, 0, 1, 0, 0},
325 {{Script_Punctuation
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
326 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
328 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
329 {{Script_Arabic
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
330 {LANG_ARABIC
, 0, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 1, 0},
331 MS_MAKE_TAG('a','r','a','b'),
332 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
333 {{Script_Arabic_Numeric
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
334 {LANG_ARABIC
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
335 MS_MAKE_TAG('a','r','a','b'),
336 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
337 {{Script_Hebrew
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
338 {LANG_HEBREW
, 0, 1, 0, 1, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
339 MS_MAKE_TAG('h','e','b','r'),
340 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
341 {{Script_Syriac
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
342 {LANG_SYRIAC
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 1, 0},
343 MS_MAKE_TAG('s','y','r','c'),
344 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
345 {{Script_Persian
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
346 {LANG_PERSIAN
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
347 MS_MAKE_TAG('s','y','r','c'),
348 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
349 {{Script_Thaana
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
350 {LANG_DIVEHI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
351 MS_MAKE_TAG('t','h','a','a'),
352 {'M','V',' ','B','o','l','i',0}},
353 {{Script_Greek
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
354 {LANG_GREEK
, 0, 0, 0, 0, GREEK_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
355 MS_MAKE_TAG('g','r','e','k'),
356 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
357 {{Script_Cyrillic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
358 {LANG_RUSSIAN
, 0, 0, 0, 0, RUSSIAN_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
359 MS_MAKE_TAG('c','y','r','l'),
360 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
361 {{Script_Armenian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
362 {LANG_ARMENIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
363 MS_MAKE_TAG('a','r','m','n'),
364 {'S','y','l','f','a','e','n',0}},
365 {{Script_Georgian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
366 {LANG_GEORGIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
367 MS_MAKE_TAG('g','e','o','r'),
368 {'S','y','l','f','a','e','n',0}},
369 {{Script_Sinhala
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
370 {LANG_SINHALESE
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
371 MS_MAKE_TAG('s','i','n','h'),
372 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
373 {{Script_Tibetan
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
374 {LANG_TIBETAN
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
375 MS_MAKE_TAG('t','i','b','t'),
376 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
377 {{Script_Tibetan_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
378 {LANG_TIBETAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
379 MS_MAKE_TAG('t','i','b','t'),
380 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
381 {{Script_Phags_pa
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
382 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
383 MS_MAKE_TAG('p','h','a','g'),
384 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
385 {{Script_Thai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
386 {LANG_THAI
, 0, 1, 1, 1, THAI_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 1},
387 MS_MAKE_TAG('t','h','a','i'),
388 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
389 {{Script_Thai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
390 {LANG_THAI
, 1, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
391 MS_MAKE_TAG('t','h','a','i'),
392 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
393 {{Script_Lao
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
394 {LANG_LAO
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
395 MS_MAKE_TAG('l','a','o',' '),
396 {'D','o','k','C','h','a','m','p','a',0}},
397 {{Script_Lao_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
398 {LANG_LAO
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
399 MS_MAKE_TAG('l','a','o',' '),
400 {'D','o','k','C','h','a','m','p','a',0}},
401 {{Script_Devanagari
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
402 {LANG_HINDI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
403 MS_MAKE_TAG('d','e','v','a'),
404 {'M','a','n','g','a','l',0}},
405 {{Script_Devanagari_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
406 {LANG_HINDI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
407 MS_MAKE_TAG('d','e','v','a'),
408 {'M','a','n','g','a','l',0}},
409 {{Script_Bengali
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
410 {LANG_BENGALI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
411 MS_MAKE_TAG('b','e','n','g'),
412 {'V','r','i','n','d','a',0}},
413 {{Script_Bengali_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
414 {LANG_BENGALI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
415 MS_MAKE_TAG('b','e','n','g'),
416 {'V','r','i','n','d','a',0}},
417 {{Script_Bengali_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
418 {LANG_BENGALI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
419 MS_MAKE_TAG('b','e','n','g'),
420 {'V','r','i','n','d','a',0}},
421 {{Script_Gurmukhi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
422 {LANG_PUNJABI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
423 MS_MAKE_TAG('g','u','r','u'),
424 {'R','a','a','v','i',0}},
425 {{Script_Gurmukhi_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
426 {LANG_PUNJABI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
427 MS_MAKE_TAG('g','u','r','u'),
428 {'R','a','a','v','i',0}},
429 {{Script_Gujarati
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
430 {LANG_GUJARATI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
431 MS_MAKE_TAG('g','u','j','r'),
432 {'S','h','r','u','t','i',0}},
433 {{Script_Gujarati_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
434 {LANG_GUJARATI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
435 MS_MAKE_TAG('g','u','j','r'),
436 {'S','h','r','u','t','i',0}},
437 {{Script_Gujarati_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
438 {LANG_GUJARATI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
439 MS_MAKE_TAG('g','u','j','r'),
440 {'S','h','r','u','t','i',0}},
441 {{Script_Oriya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
442 {LANG_ORIYA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
443 MS_MAKE_TAG('o','r','y','a'),
444 {'K','a','l','i','n','g','a',0}},
445 {{Script_Oriya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
446 {LANG_ORIYA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
447 MS_MAKE_TAG('o','r','y','a'),
448 {'K','a','l','i','n','g','a',0}},
449 {{Script_Tamil
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
450 {LANG_TAMIL
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
451 MS_MAKE_TAG('t','a','m','l'),
452 {'L','a','t','h','a',0}},
453 {{Script_Tamil_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
454 {LANG_TAMIL
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
455 MS_MAKE_TAG('t','a','m','l'),
456 {'L','a','t','h','a',0}},
457 {{Script_Telugu
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
458 {LANG_TELUGU
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
459 MS_MAKE_TAG('t','e','l','u'),
460 {'G','a','u','t','a','m','i',0}},
461 {{Script_Telugu_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
462 {LANG_TELUGU
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
463 MS_MAKE_TAG('t','e','l','u'),
464 {'G','a','u','t','a','m','i',0}},
465 {{Script_Kannada
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
466 {LANG_KANNADA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
467 MS_MAKE_TAG('k','n','d','a'),
468 {'T','u','n','g','a',0}},
469 {{Script_Kannada_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
470 {LANG_KANNADA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
471 MS_MAKE_TAG('k','n','d','a'),
472 {'T','u','n','g','a',0}},
473 {{Script_Malayalam
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
474 {LANG_MALAYALAM
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
475 MS_MAKE_TAG('m','l','y','m'),
476 {'K','a','r','t','i','k','a',0}},
477 {{Script_Malayalam_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
478 {LANG_MALAYALAM
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
479 MS_MAKE_TAG('m','l','y','m'),
480 {'K','a','r','t','i','k','a',0}},
481 {{Script_Diacritical
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
482 {LANG_ENGLISH
, 0, 1, 0, 1, ANSI_CHARSET
, 0, 0, 0, 0, 0, 1, 1, 0, 0},
485 {{Script_Punctuation2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
486 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
487 MS_MAKE_TAG('l','a','t','n'),
488 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
489 {{Script_Numeric2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
490 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
493 {{Script_Myanmar
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
494 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
495 MS_MAKE_TAG('m','y','m','r'),
496 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
497 {{Script_Myanmar_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
498 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
499 MS_MAKE_TAG('m','y','m','r'),
501 {{Script_Tai_Le
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
502 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
503 MS_MAKE_TAG('t','a','l','e'),
504 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
505 {{Script_New_Tai_Lue
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
506 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
507 MS_MAKE_TAG('t','a','l','u'),
508 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
509 {{Script_New_Tai_Lue_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
510 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
511 MS_MAKE_TAG('t','a','l','u'),
512 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
513 {{Script_Khmer
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
514 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
515 MS_MAKE_TAG('k','h','m','r'),
516 {'D','a','u','n','P','e','n','h',0}},
517 {{Script_Khmer_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
518 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
519 MS_MAKE_TAG('k','h','m','r'),
520 {'D','a','u','n','P','e','n','h',0}},
521 {{Script_CJK_Han
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
522 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
523 MS_MAKE_TAG('h','a','n','i'),
525 {{Script_Ideograph
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
526 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
527 MS_MAKE_TAG('h','a','n','i'),
529 {{Script_Bopomofo
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
530 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
531 MS_MAKE_TAG('b','o','p','o'),
533 {{Script_Kana
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
534 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
535 MS_MAKE_TAG('k','a','n','a'),
537 {{Script_Hangul
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
538 {LANG_KOREAN
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
539 MS_MAKE_TAG('h','a','n','g'),
541 {{Script_Yi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
542 {LANG_ENGLISH
, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
543 MS_MAKE_TAG('y','i',' ',' '),
544 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
545 {{Script_Ethiopic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
546 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
547 MS_MAKE_TAG('e','t','h','i'),
548 {'N','y','a','l','a',0}},
549 {{Script_Ethiopic_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
550 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
551 MS_MAKE_TAG('e','t','h','i'),
552 {'N','y','a','l','a',0}},
553 {{Script_Mongolian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
554 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
555 MS_MAKE_TAG('m','o','n','g'),
556 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
557 {{Script_Mongolian_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
558 {LANG_MONGOLIAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
559 MS_MAKE_TAG('m','o','n','g'),
560 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
561 {{Script_Tifinagh
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
562 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
563 MS_MAKE_TAG('t','f','n','g'),
564 {'E','b','r','i','m','a',0}},
565 {{Script_NKo
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
566 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
567 MS_MAKE_TAG('n','k','o',' '),
568 {'E','b','r','i','m','a',0}},
569 {{Script_Vai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
570 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
571 MS_MAKE_TAG('v','a','i',' '),
572 {'E','b','r','i','m','a',0}},
573 {{Script_Vai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
574 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
575 MS_MAKE_TAG('v','a','i',' '),
576 {'E','b','r','i','m','a',0}},
577 {{Script_Cherokee
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
578 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
579 MS_MAKE_TAG('c','h','e','r'),
580 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
581 {{Script_Canadian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
582 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
583 MS_MAKE_TAG('c','a','n','s'),
584 {'E','u','p','h','e','m','i','a',0}},
585 {{Script_Ogham
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
586 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
587 MS_MAKE_TAG('o','g','a','m'),
588 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
589 {{Script_Runic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
590 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
591 MS_MAKE_TAG('r','u','n','r'),
592 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
593 {{Script_Braille
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
594 {LANG_ENGLISH
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
595 MS_MAKE_TAG('b','r','a','i'),
596 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
597 {{Script_Surrogates
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
598 {LANG_ENGLISH
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
601 {{Script_Private
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
602 {0, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 1, 0, 0, 0, 0, 1, 0, 0},
605 {{Script_Deseret
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
606 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
607 MS_MAKE_TAG('d','s','r','t'),
608 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
609 {{Script_Osmanya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
610 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
611 MS_MAKE_TAG('o','s','m','a'),
612 {'E','b','r','i','m','a',0}},
613 {{Script_Osmanya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
614 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
615 MS_MAKE_TAG('o','s','m','a'),
616 {'E','b','r','i','m','a',0}},
617 {{Script_MathAlpha
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
618 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
619 MS_MAKE_TAG('m','a','t','h'),
620 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
621 {{Script_Hebrew_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
622 {LANG_HEBREW
, 0, 1, 0, 0, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
623 MS_MAKE_TAG('h','e','b','r'),
624 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
625 {{Script_Vietnamese_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
626 {LANG_VIETNAMESE
, 0, 0, 0, 0, VIETNAMESE_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
627 MS_MAKE_TAG('l','a','t','n'),
628 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
629 {{Script_Thai_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
630 {LANG_THAI
, 0, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
631 MS_MAKE_TAG('t','h','a','i'),
632 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
635 static const SCRIPT_PROPERTIES
*script_props
[] =
637 &scriptInformation
[0].props
, &scriptInformation
[1].props
,
638 &scriptInformation
[2].props
, &scriptInformation
[3].props
,
639 &scriptInformation
[4].props
, &scriptInformation
[5].props
,
640 &scriptInformation
[6].props
, &scriptInformation
[7].props
,
641 &scriptInformation
[8].props
, &scriptInformation
[9].props
,
642 &scriptInformation
[10].props
, &scriptInformation
[11].props
,
643 &scriptInformation
[12].props
, &scriptInformation
[13].props
,
644 &scriptInformation
[14].props
, &scriptInformation
[15].props
,
645 &scriptInformation
[16].props
, &scriptInformation
[17].props
,
646 &scriptInformation
[18].props
, &scriptInformation
[19].props
,
647 &scriptInformation
[20].props
, &scriptInformation
[21].props
,
648 &scriptInformation
[22].props
, &scriptInformation
[23].props
,
649 &scriptInformation
[24].props
, &scriptInformation
[25].props
,
650 &scriptInformation
[26].props
, &scriptInformation
[27].props
,
651 &scriptInformation
[28].props
, &scriptInformation
[29].props
,
652 &scriptInformation
[30].props
, &scriptInformation
[31].props
,
653 &scriptInformation
[32].props
, &scriptInformation
[33].props
,
654 &scriptInformation
[34].props
, &scriptInformation
[35].props
,
655 &scriptInformation
[36].props
, &scriptInformation
[37].props
,
656 &scriptInformation
[38].props
, &scriptInformation
[39].props
,
657 &scriptInformation
[40].props
, &scriptInformation
[41].props
,
658 &scriptInformation
[42].props
, &scriptInformation
[43].props
,
659 &scriptInformation
[44].props
, &scriptInformation
[45].props
,
660 &scriptInformation
[46].props
, &scriptInformation
[47].props
,
661 &scriptInformation
[48].props
, &scriptInformation
[49].props
,
662 &scriptInformation
[50].props
, &scriptInformation
[51].props
,
663 &scriptInformation
[52].props
, &scriptInformation
[53].props
,
664 &scriptInformation
[54].props
, &scriptInformation
[55].props
,
665 &scriptInformation
[56].props
, &scriptInformation
[57].props
,
666 &scriptInformation
[58].props
, &scriptInformation
[59].props
,
667 &scriptInformation
[60].props
, &scriptInformation
[61].props
,
668 &scriptInformation
[62].props
, &scriptInformation
[63].props
,
669 &scriptInformation
[64].props
, &scriptInformation
[65].props
,
670 &scriptInformation
[66].props
, &scriptInformation
[67].props
,
671 &scriptInformation
[68].props
, &scriptInformation
[69].props
,
672 &scriptInformation
[70].props
, &scriptInformation
[71].props
,
673 &scriptInformation
[72].props
, &scriptInformation
[73].props
,
674 &scriptInformation
[74].props
, &scriptInformation
[75].props
,
675 &scriptInformation
[76].props
, &scriptInformation
[77].props
,
676 &scriptInformation
[78].props
, &scriptInformation
[79].props
,
677 &scriptInformation
[80].props
, &scriptInformation
[81].props
686 SCRIPT_VISATTR
* psva
;
702 StringGlyphs
* glyphs
;
703 SCRIPT_LOGATTR
* logattrs
;
713 static inline void *heap_alloc(SIZE_T size
)
715 return HeapAlloc(GetProcessHeap(), 0, size
);
718 static inline void *heap_alloc_zero(SIZE_T size
)
720 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
723 static inline BOOL
heap_free(LPVOID mem
)
725 return HeapFree(GetProcessHeap(), 0, mem
);
728 /* TODO Fix font properties on Arabic locale */
729 static inline BOOL
set_cache_font_properties(const HDC hdc
, ScriptCache
*sc
)
733 sc
->sfp
.wgBlank
= sc
->tm
.tmBreakChar
;
734 sc
->sfp
.wgDefault
= sc
->tm
.tmDefaultChar
;
735 sc
->sfp
.wgInvalid
= sc
->sfp
.wgBlank
;
736 sc
->sfp
.wgKashida
= 0xFFFF;
737 sc
->sfp
.iKashidaWidth
= 0;
741 static const WCHAR chars
[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
742 /* U+0020: numeric space
743 U+200B: zero width space
744 U+F71B: unknow char found by black box testing
748 if (GetGlyphIndicesW(hdc
, chars
, 4, gi
, GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
750 if(gi
[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
751 sc
->sfp
.wgBlank
= gi
[0];
755 sc
->sfp
.wgDefault
= 0;
758 sc
->sfp
.wgInvalid
= gi
[2];
759 else if (gi
[1] != 0xFFFF)
760 sc
->sfp
.wgInvalid
= gi
[1];
761 else if (gi
[0] != 0xFFFF)
762 sc
->sfp
.wgInvalid
= gi
[0];
764 sc
->sfp
.wgInvalid
= 0;
766 sc
->sfp
.wgKashida
= gi
[3];
768 sc
->sfp
.iKashidaWidth
= 0; /* TODO */
776 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES
*sfp
, ScriptCache
*sc
)
778 sfp
->wgBlank
= sc
->sfp
.wgBlank
;
779 sfp
->wgDefault
= sc
->sfp
.wgDefault
;
780 sfp
->wgInvalid
= sc
->sfp
.wgInvalid
;
781 sfp
->wgKashida
= sc
->sfp
.wgKashida
;
782 sfp
->iKashidaWidth
= sc
->sfp
.iKashidaWidth
;
785 static inline LONG
get_cache_height(SCRIPT_CACHE
*psc
)
787 return ((ScriptCache
*)*psc
)->tm
.tmHeight
;
790 static inline BYTE
get_cache_pitch_family(SCRIPT_CACHE
*psc
)
792 return ((ScriptCache
*)*psc
)->tm
.tmPitchAndFamily
;
795 static inline WORD
get_cache_glyph(SCRIPT_CACHE
*psc
, DWORD c
)
797 CacheGlyphPage
*page
= ((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
801 block
= page
->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
802 if (!block
) return 0;
803 return block
[(c
% 0x10000) & GLYPH_BLOCK_MASK
];
806 static inline WORD
set_cache_glyph(SCRIPT_CACHE
*psc
, WCHAR c
, WORD glyph
)
808 CacheGlyphPage
**page
= &((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
810 if (!*page
&& !(*page
= heap_alloc_zero(sizeof(CacheGlyphPage
)))) return 0;
812 block
= &(*page
)->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
813 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(WORD
) * GLYPH_BLOCK_SIZE
))) return 0;
814 return ((*block
)[(c
% 0x10000) & GLYPH_BLOCK_MASK
] = glyph
);
817 static inline BOOL
get_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
819 static const ABC nil
;
820 ABC
*block
= ((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
822 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(ABC
))) return FALSE
;
823 memcpy(abc
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(ABC
));
827 static inline BOOL
set_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
829 ABC
**block
= &((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
831 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(ABC
) * GLYPH_BLOCK_SIZE
))) return FALSE
;
832 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], abc
, sizeof(ABC
));
836 static HRESULT
init_script_cache(const HDC hdc
, SCRIPT_CACHE
*psc
)
841 if (!psc
) return E_INVALIDARG
;
842 if (*psc
) return S_OK
;
843 if (!hdc
) return E_PENDING
;
845 if (!(sc
= heap_alloc_zero(sizeof(ScriptCache
)))) return E_OUTOFMEMORY
;
846 if (!GetTextMetricsW(hdc
, &sc
->tm
))
851 size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
854 sc
->otm
= heap_alloc(size
);
855 sc
->otm
->otmSize
= size
;
856 GetOutlineTextMetricsW(hdc
, size
, sc
->otm
);
858 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(LOGFONTW
), &sc
->lf
))
863 sc
->sfnt
= (GetFontData(hdc
, MS_MAKE_TAG('h','e','a','d'), 0, NULL
, 0)!=GDI_ERROR
);
864 if (!set_cache_font_properties(hdc
, sc
))
870 TRACE("<- %p\n", sc
);
874 static WCHAR
mirror_char( WCHAR ch
)
876 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
877 return ch
+ wine_mirror_map
[wine_mirror_map
[ch
>> 8] + (ch
& 0xff)];
880 static inline DWORD
decode_surrogate_pair(LPCWSTR str
, INT index
, INT end
)
882 if (index
< end
-1 && IS_SURROGATE_PAIR(str
[index
],str
[index
+1]))
884 DWORD ch
= 0x10000 + ((str
[index
] - 0xd800) << 10) + (str
[index
+1] - 0xdc00);
885 TRACE("Surrogate Pair %x %x => %x\n",str
[index
], str
[index
+1], ch
);
891 static WORD
get_char_script( LPCWSTR str
, INT index
, INT end
, INT
*consumed
)
893 static const WCHAR latin_punc
[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
900 if (str
[index
] == 0xc || str
[index
] == 0x20 || str
[index
] == 0x202f)
903 /* These punctuation characters are separated out as Latin punctuation */
904 if (strchrW(latin_punc
,str
[index
]))
905 return Script_Punctuation2
;
907 /* These chars are itemized as Punctuation by Windows */
908 if (str
[index
] == 0x2212 || str
[index
] == 0x2044)
909 return Script_Punctuation
;
911 /* Currency Symboles by Unicode point */
915 case 0x09f3: return Script_Bengali_Currency
;
916 case 0x0af1: return Script_Gujarati_Currency
;
917 case 0x0e3f: return Script_Thai_Currency
;
918 case 0x20aa: return Script_Hebrew_Currency
;
919 case 0x20ab: return Script_Vietnamese_Currency
;
920 case 0xfb29: return Script_Hebrew_Currency
;
923 GetStringTypeW(CT_CTYPE1
, &str
[index
], 1, &type
);
926 return SCRIPT_UNDEFINED
;
929 return Script_Control
;
931 ch
= decode_surrogate_pair(str
, index
, end
);
940 if (ch
< scriptRanges
[i
].rangeFirst
|| scriptRanges
[i
].script
== SCRIPT_UNDEFINED
)
943 if (ch
>= scriptRanges
[i
].rangeFirst
&& ch
<= scriptRanges
[i
].rangeLast
)
945 if (scriptRanges
[i
].numericScript
&& type
& C1_DIGIT
)
946 return scriptRanges
[i
].numericScript
;
947 if (scriptRanges
[i
].punctScript
&& type
& C1_PUNCT
)
948 return scriptRanges
[i
].punctScript
;
949 return scriptRanges
[i
].script
;
954 return SCRIPT_UNDEFINED
;
957 static int compare_FindGlyph(const void *a
, const void* b
)
959 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
960 const WORD
*idx
= (WORD
*)b
;
963 if ( find
->target
> *idx
)
965 else if (find
->target
< *idx
)
968 if (!find
->ascending
)
973 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
975 FindGlyph_struct fgs
;
979 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
980 fgs
.ascending
= TRUE
;
982 fgs
.ascending
= FALSE
;
985 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
990 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
997 /***********************************************************************
998 * ScriptFreeCache (USP10.@)
1000 * Free a script cache.
1003 * psc [I/O] Script cache.
1007 * Failure: Non-zero HRESULT value.
1009 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1017 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1019 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1021 for (i
= 0; i
< 0x10; i
++)
1024 if (((ScriptCache
*)*psc
)->page
[i
])
1025 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1026 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1027 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1029 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1030 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1031 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1032 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1033 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1036 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1039 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1040 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1041 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1043 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1044 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1045 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1046 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1048 heap_free(((ScriptCache
*)*psc
)->scripts
);
1049 heap_free(((ScriptCache
*)*psc
)->otm
);
1056 /***********************************************************************
1057 * ScriptGetProperties (USP10.@)
1059 * Retrieve a list of script properties.
1062 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1063 * num [I] Pointer to the number of scripts.
1067 * Failure: Non-zero HRESULT value.
1070 * Behaviour matches WinXP.
1072 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1074 TRACE("(%p,%p)\n", props
, num
);
1076 if (!props
&& !num
) return E_INVALIDARG
;
1078 if (num
) *num
= sizeof(script_props
)/sizeof(script_props
[0]);
1079 if (props
) *props
= script_props
;
1084 /***********************************************************************
1085 * ScriptGetFontProperties (USP10.@)
1087 * Get information on special glyphs.
1090 * hdc [I] Device context.
1091 * psc [I/O] Opaque pointer to a script cache.
1092 * sfp [O] Font properties structure.
1094 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1098 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1100 if (!sfp
) return E_INVALIDARG
;
1101 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1103 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1104 return E_INVALIDARG
;
1106 get_cache_font_properties(sfp
, *psc
);
1111 /***********************************************************************
1112 * ScriptRecordDigitSubstitution (USP10.@)
1114 * Record digit substitution settings for a given locale.
1117 * locale [I] Locale identifier.
1118 * sds [I] Structure to record substitution settings.
1122 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1125 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1127 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1131 TRACE("0x%x, %p\n", locale
, sds
);
1133 /* This implementation appears to be correct for all languages, but it's
1134 * not clear if sds->DigitSubstitute is ever set to anything except
1135 * CONTEXT or NONE in reality */
1137 if (!sds
) return E_POINTER
;
1139 locale
= ConvertDefaultLocale(locale
);
1141 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1142 return E_INVALIDARG
;
1144 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1145 sds
->TraditionalDigitLanguage
= plgid
;
1147 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1148 sds
->NationalDigitLanguage
= plgid
;
1150 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1152 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1153 (LPWSTR
)&sub
, sizeof(sub
)/sizeof(WCHAR
))) return E_INVALIDARG
;
1158 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1159 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1161 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1164 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1167 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1170 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1174 sds
->dwReserved
= 0;
1178 /***********************************************************************
1179 * ScriptApplyDigitSubstitution (USP10.@)
1181 * Apply digit substitution settings.
1184 * sds [I] Structure with recorded substitution settings.
1185 * sc [I] Script control structure.
1186 * ss [I] Script state structure.
1190 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1192 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1193 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1195 SCRIPT_DIGITSUBSTITUTE psds
;
1197 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1199 if (!sc
|| !ss
) return E_POINTER
;
1203 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1204 return E_INVALIDARG
;
1207 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1208 sc
->fContextDigits
= 0;
1209 ss
->fDigitSubstitute
= 0;
1211 switch (sds
->DigitSubstitute
) {
1212 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1213 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1214 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1215 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1218 return E_INVALIDARG
;
1222 static inline BOOL
is_indic(WORD script
)
1224 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1227 static inline WORD
base_indic(WORD script
)
1231 case Script_Devanagari
:
1232 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1233 case Script_Bengali
:
1234 case Script_Bengali_Numeric
:
1235 case Script_Bengali_Currency
: return Script_Bengali
;
1236 case Script_Gurmukhi
:
1237 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1238 case Script_Gujarati
:
1239 case Script_Gujarati_Numeric
:
1240 case Script_Gujarati_Currency
: return Script_Gujarati
;
1242 case Script_Oriya_Numeric
: return Script_Oriya
;
1244 case Script_Tamil_Numeric
: return Script_Tamil
;
1246 case Script_Telugu_Numeric
: return Script_Telugu
;
1247 case Script_Kannada
:
1248 case Script_Kannada_Numeric
: return Script_Kannada
;
1249 case Script_Malayalam
:
1250 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1257 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1258 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1259 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1260 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1263 #define Numeric_space 0x0020
1267 int cnt
= 0, index
= 0, str
= 0;
1268 int New_Script
= -1;
1270 WORD
*levels
= NULL
;
1271 WORD
*layout_levels
= NULL
;
1272 WORD
*overrides
= NULL
;
1273 WORD
*strength
= NULL
;
1274 WORD
*scripts
= NULL
;
1276 WORD baselayout
= 0;
1278 WORD last_indic
= -1;
1280 BOOL forceLevels
= FALSE
;
1282 HRESULT res
= E_OUTOFMEMORY
;
1284 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1285 psControl
, psState
, pItems
, pcItems
);
1287 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1288 return E_INVALIDARG
;
1290 scripts
= heap_alloc(cInChars
* sizeof(WORD
));
1292 return E_OUTOFMEMORY
;
1294 for (i
= 0; i
< cInChars
; i
++)
1298 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1303 scripts
[i
] = scripts
[i
-1];
1306 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1307 all Indic scripts */
1308 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
> 0)
1309 scripts
[i
] = last_indic
;
1310 else if (is_indic(scripts
[i
]))
1311 last_indic
= base_indic(scripts
[i
]);
1313 /* Some unicode points :
1314 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1315 (Left Right Embed U+202A - Left Right Override U+202D)
1316 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1317 will force us into bidi mode */
1318 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1319 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1320 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1324 /* Diacritical marks merge with other scripts */
1325 if (scripts
[i
] == Script_Diacritical
)
1330 scripts
[i
] = scripts
[i
-1];
1335 WORD first_script
= scripts
[i
-1];
1336 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1338 WORD original
= scripts
[j
];
1339 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1344 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1346 scripts
[j
] = scripts
[i
];
1347 if (original
== Script_Punctuation2
)
1350 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1351 scripts
[i
] = scripts
[j
];
1357 for (i
= 0; i
< cInChars
; i
++)
1359 /* Joiners get merged preferencially right */
1360 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1363 if (i
+1 == cInChars
)
1364 scripts
[i
] = scripts
[i
-1];
1367 for (j
= i
+1; j
< cInChars
; j
++)
1369 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1371 scripts
[i
] = scripts
[j
];
1379 if (psState
&& psControl
)
1381 levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1385 overrides
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1389 layout_levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1393 if (psState
->fOverrideDirection
)
1397 SCRIPT_STATE s
= *psState
;
1398 s
.fOverrideDirection
= FALSE
;
1399 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1400 if (odd(layout_levels
[0]))
1402 else for (i
= 0; i
< cInChars
; i
++)
1403 if (layout_levels
[i
]!=layout_levels
[0])
1410 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1414 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1415 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1417 baselevel
= levels
[0];
1418 baselayout
= layout_levels
[0];
1419 for (i
= 0; i
< cInChars
; i
++)
1420 if (levels
[i
]!=levels
[0])
1422 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1425 heap_free(overrides
);
1426 heap_free(layout_levels
);
1429 layout_levels
= NULL
;
1433 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1434 static const WCHAR repeatable_math_punc
[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1436 strength
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1439 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1441 /* We currently mis-level leading Diacriticals */
1442 if (scripts
[0] == Script_Diacritical
)
1443 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1445 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1446 strength
[i
] = BIDI_STRONG
;
1449 /* Math punctuation bordered on both sides by numbers can be
1450 merged into the number */
1451 for (i
= 0; i
< cInChars
; i
++)
1453 if (i
> 0 && i
< cInChars
-1 &&
1454 scripts
[i
-1] == Script_Numeric
&&
1455 strchrW(math_punc
, pwcInChars
[i
]))
1457 if (scripts
[i
+1] == Script_Numeric
)
1459 scripts
[i
] = Script_Numeric
;
1460 levels
[i
] = levels
[i
-1];
1461 strength
[i
] = strength
[i
-1];
1464 else if (strchrW(repeatable_math_punc
, pwcInChars
[i
]))
1467 for (j
= i
+1; j
< cInChars
; j
++)
1469 if (scripts
[j
] == Script_Numeric
)
1473 scripts
[i
] = Script_Numeric
;
1474 levels
[i
] = levels
[i
-1];
1475 strength
[i
] = strength
[i
-1];
1478 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1484 for (i
= 0; i
< cInChars
; i
++)
1486 /* Script_Numeric at level 0 get bumped to level 2 */
1487 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
) && levels
[i
] == psState
->uBidiLevel
+1)) && scripts
[i
] == Script_Numeric
)
1492 /* Joiners get merged preferencially right */
1493 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1496 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1497 strength
[i
] = strength
[i
-1];
1499 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1500 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1502 strength
[i
] = strength
[j
];
1507 if (psControl
->fMergeNeutralItems
)
1509 /* Merge the neutrals */
1510 for (i
= 0; i
< cInChars
; i
++)
1512 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1515 for (j
= i
; j
> 0; j
--)
1517 if (levels
[i
] != levels
[j
])
1519 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1521 scripts
[i
] = scripts
[j
];
1522 strength
[i
] = strength
[j
];
1527 /* Try going the other way */
1528 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1531 for (j
= i
; j
< cInChars
; j
++)
1533 if (levels
[i
] != levels
[j
])
1535 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1537 scripts
[i
] = scripts
[j
];
1538 strength
[i
] = strength
[j
];
1548 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1549 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1552 if (cnt
== cInChars
) /* All Spaces */
1555 New_Script
= scripts
[cnt
];
1558 pItems
[index
].iCharPos
= 0;
1559 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1561 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1563 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1564 str
= strength
[cnt
];
1572 if (strength
[cnt
] == BIDI_STRONG
)
1573 layoutRTL
= odd(layout_levels
[cnt
]);
1575 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1577 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1578 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1579 if (pItems
[index
].a
.eScript
== Script_Numeric
||
1580 pItems
[index
].a
.eScript
== Script_Numeric2
)
1581 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1583 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1584 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1586 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1588 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1589 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1590 layoutRTL
= odd(baselayout
);
1591 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1592 pItems
[index
].a
.fRTL
= odd(baselevel
);
1593 if (pItems
[index
].a
.eScript
== Script_Numeric
||
1594 pItems
[index
].a
.eScript
== Script_Numeric2
)
1595 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1597 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1600 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1601 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1602 pItems
[index
].iCharPos
);
1604 for (cnt
=1; cnt
< cInChars
; cnt
++)
1606 if(pwcInChars
[cnt
] != Numeric_space
)
1607 New_Script
= scripts
[cnt
];
1611 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1613 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1614 New_Script
= scripts
[cnt
+j
];
1616 New_Script
= scripts
[cnt
];
1620 /* merge space strengths*/
1621 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1624 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1627 /* changes in level */
1628 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1630 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1633 /* changes in strength */
1634 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1636 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1639 /* changes in script */
1640 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1642 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1646 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1648 layoutRTL
= odd(layout_levels
[cnt
]);
1649 if (pItems
[index
].a
.eScript
== Script_Numeric
||
1650 pItems
[index
].a
.eScript
== Script_Numeric2
)
1651 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1656 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
);
1659 if (index
+1 > cMaxItems
)
1663 str
= strength
[cnt
];
1665 pItems
[index
].iCharPos
= cnt
;
1666 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1668 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1670 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1674 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1675 if (layout_levels
[cnt
] == 0)
1678 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1679 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1680 if (pItems
[index
].a
.eScript
== Script_Numeric
||
1681 pItems
[index
].a
.eScript
== Script_Numeric2
)
1682 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1684 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1685 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1687 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1689 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1690 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1691 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1692 pItems
[index
].a
.fRTL
= odd(baselevel
);
1693 if (pItems
[index
].a
.eScript
== Script_Numeric
||
1694 pItems
[index
].a
.eScript
== Script_Numeric2
)
1695 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1697 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1700 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1704 /* While not strictly necessary according to the spec, make sure the n+1
1705 * item is set up to prevent random behaviour if the caller erroneously
1706 * checks the n+1 structure */
1708 if (index
+ 1 > cMaxItems
) goto nomemory
;
1709 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1711 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1713 /* Set one SCRIPT_STATE item being returned */
1714 if (pcItems
) *pcItems
= index
;
1716 /* Set SCRIPT_ITEM */
1717 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1721 heap_free(overrides
);
1722 heap_free(layout_levels
);
1723 heap_free(strength
);
1728 /***********************************************************************
1729 * ScriptItemizeOpenType (USP10.@)
1731 * Split a Unicode string into shapeable parts.
1734 * pwcInChars [I] String to split.
1735 * cInChars [I] Number of characters in pwcInChars.
1736 * cMaxItems [I] Maximum number of items to return.
1737 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1738 * psState [I] Pointer to a SCRIPT_STATE structure.
1739 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1740 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1741 * pcItems [O] Number of script items returned.
1745 * Failure: Non-zero HRESULT value.
1747 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1748 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1749 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1751 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1754 /***********************************************************************
1755 * ScriptItemize (USP10.@)
1757 * Split a Unicode string into shapeable parts.
1760 * pwcInChars [I] String to split.
1761 * cInChars [I] Number of characters in pwcInChars.
1762 * cMaxItems [I] Maximum number of items to return.
1763 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1764 * psState [I] Pointer to a SCRIPT_STATE structure.
1765 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1766 * pcItems [O] Number of script items returned.
1770 * Failure: Non-zero HRESULT value.
1772 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1773 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1774 SCRIPT_ITEM
*pItems
, int *pcItems
)
1776 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1779 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1783 INT
*lpTabPos
= NULL
;
1788 lpTabPos
= pTabdef
->pTabStops
;
1790 if (pTabdef
&& pTabdef
->iTabOrigin
)
1792 if (pTabdef
->iScale
)
1793 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1795 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1799 cTabStops
= pTabdef
->cTabStops
;
1803 if (pTabdef
->iScale
)
1804 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1806 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1810 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1812 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1814 int position
= *lpTabPos
;
1816 position
= -1 * position
;
1817 if (pTabdef
->iScale
)
1818 position
= (position
* pTabdef
->iScale
) / 4;
1820 position
= position
* psc
->tm
.tmAveCharWidth
;
1822 if( nTabOrg
+ position
> current_x
)
1826 /* a left aligned tab */
1827 x
= (nTabOrg
+ *lpTabPos
) - current_x
;
1832 FIXME("Negative tabstop\n");
1837 if ((!cTabStops
) && (defWidth
> 0))
1838 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1839 else if ((!cTabStops
) && (defWidth
< 0))
1840 FIXME("TODO: Negative defWidth\n");
1845 /***********************************************************************
1846 * Helper function for ScriptStringAnalyse
1848 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1849 const WCHAR
*pwcInChars
, int cChars
)
1851 /* FIXME: When to properly fallback is still a bit of a mystery */
1854 if (psa
->fNoGlyphIndex
)
1857 if (init_script_cache(hdc
, psc
) != S_OK
)
1860 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1863 glyphs
= heap_alloc(sizeof(WORD
) * cChars
);
1866 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1876 static void find_fallback_font(DWORD scriptid
, LPWSTR FaceName
)
1880 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1882 static const WCHAR szFmt
[] = {'%','x',0};
1884 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1887 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1888 if (RegQueryValueExW(hkey
, value
, 0, &type
, (LPBYTE
)FaceName
, &count
))
1889 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1893 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1896 /***********************************************************************
1897 * ScriptStringAnalyse (USP10.@)
1900 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1901 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1902 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1903 SCRIPT_STATE
*psState
, const int *piDx
,
1904 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1905 SCRIPT_STRING_ANALYSIS
*pssa
)
1907 HRESULT hr
= E_OUTOFMEMORY
;
1908 StringAnalysis
*analysis
= NULL
;
1909 SCRIPT_CONTROL sControl
;
1910 SCRIPT_STATE sState
;
1911 int i
, num_items
= 255;
1913 WCHAR
*iString
= NULL
;
1915 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1916 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1917 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
1921 FIXME("Only Unicode strings are supported\n");
1922 return E_INVALIDARG
;
1924 if (cString
< 1 || !pString
) return E_INVALIDARG
;
1925 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
1927 if (!(analysis
= heap_alloc_zero(sizeof(StringAnalysis
)))) return E_OUTOFMEMORY
;
1928 if (!(analysis
->pItem
= heap_alloc_zero(num_items
* sizeof(SCRIPT_ITEM
) + 1))) goto error
;
1930 /* FIXME: handle clipping */
1931 analysis
->clip_len
= cString
;
1932 analysis
->hdc
= hdc
;
1933 analysis
->dwFlags
= dwFlags
;
1938 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
1941 sControl
= *psControl
;
1943 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
1945 if (dwFlags
& SSA_PASSWORD
)
1947 iString
= heap_alloc(sizeof(WCHAR
)*cString
);
1953 for (i
= 0; i
< cString
; i
++)
1954 iString
[i
] = *((const WCHAR
*)pString
);
1958 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
1959 &analysis
->numItems
);
1963 if (hr
== E_OUTOFMEMORY
)
1968 /* set back to out of memory for default goto error behaviour */
1971 if (dwFlags
& SSA_BREAK
)
1973 if ((analysis
->logattrs
= heap_alloc(sizeof(SCRIPT_LOGATTR
) * cString
)))
1975 for (i
= 0; i
< analysis
->numItems
; i
++)
1976 ScriptBreak(&((LPWSTR
)pString
)[analysis
->pItem
[i
].iCharPos
], analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
, &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
1982 if (!(analysis
->logical2visual
= heap_alloc_zero(sizeof(int) * analysis
->numItems
)))
1984 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
1987 if (dwFlags
& SSA_GLYPHS
)
1990 if (!(analysis
->glyphs
= heap_alloc_zero(sizeof(StringGlyphs
) * analysis
->numItems
)))
1992 heap_free(BidiLevel
);
1996 for (i
= 0; i
< analysis
->numItems
; i
++)
1998 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
1999 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2000 int numGlyphs
= 1.5 * cChar
+ 16;
2001 WORD
*glyphs
= heap_alloc_zero(sizeof(WORD
) * numGlyphs
);
2002 WORD
*pwLogClust
= heap_alloc_zero(sizeof(WORD
) * cChar
);
2003 int *piAdvance
= heap_alloc_zero(sizeof(int) * numGlyphs
);
2004 SCRIPT_VISATTR
*psva
= heap_alloc_zero(sizeof(SCRIPT_VISATTR
) * numGlyphs
);
2005 GOFFSET
*pGoffset
= heap_alloc_zero(sizeof(GOFFSET
) * numGlyphs
);
2006 ABC
*abc
= heap_alloc_zero(sizeof(ABC
));
2007 int numGlyphsReturned
;
2008 HFONT originalFont
= 0x0;
2010 /* FIXME: non unicode strings */
2011 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2012 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2014 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
|| !abc
)
2016 heap_free (BidiLevel
);
2018 heap_free (pwLogClust
);
2019 heap_free (piAdvance
);
2021 heap_free (pGoffset
);
2027 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2030 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2031 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2032 lf
.lfFaceName
[0] = 0;
2033 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2034 if (lf
.lfFaceName
[0])
2036 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2037 if (analysis
->glyphs
[i
].fallbackFont
)
2039 ScriptFreeCache(sc
);
2040 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2045 /* FIXME: When we properly shape Hangul remove this check */
2046 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2047 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2049 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2050 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2052 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2053 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2054 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2055 piAdvance
, pGoffset
, abc
);
2057 SelectObject(hdc
,originalFont
);
2059 if (dwFlags
& SSA_TAB
)
2062 for (tabi
= 0; tabi
< cChar
; tabi
++)
2064 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2065 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2066 tab_x
+=piAdvance
[tabi
];
2070 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2071 analysis
->glyphs
[i
].glyphs
= glyphs
;
2072 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2073 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2074 analysis
->glyphs
[i
].psva
= psva
;
2075 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2076 analysis
->glyphs
[i
].abc
= abc
;
2077 analysis
->glyphs
[i
].iMaxPosX
= -1;
2079 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2084 for (i
= 0; i
< analysis
->numItems
; i
++)
2085 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2088 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2089 heap_free(BidiLevel
);
2097 heap_free(analysis
->glyphs
);
2098 heap_free(analysis
->logattrs
);
2099 heap_free(analysis
->pItem
);
2100 heap_free(analysis
->logical2visual
);
2101 heap_free(analysis
);
2105 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2107 if (pva
[glyph
].fClusterStart
)
2109 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2116 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2127 StringAnalysis
*analysis
;
2130 COLORREF BkColor
= 0x0;
2131 COLORREF TextColor
= 0x0;
2133 INT runStart
, runEnd
;
2134 INT iGlyph
, cGlyphs
;
2135 HFONT oldFont
= 0x0;
2139 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2140 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2142 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2144 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2145 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2151 BkMode
= GetBkMode(analysis
->hdc
);
2152 SetBkMode( analysis
->hdc
, OPAQUE
);
2153 BkColor
= GetBkColor(analysis
->hdc
);
2154 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2157 TextColor
= GetTextColor(analysis
->hdc
);
2158 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2161 if (analysis
->glyphs
[iItem
].fallbackFont
)
2162 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2164 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2165 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2168 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2169 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2171 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2173 if (analysis
->pItem
[iItem
].a
.fRTL
)
2175 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2176 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2178 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2179 crc
.left
= iX
+ off_x
;
2183 if (cStart
>=0 && runStart
)
2184 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2186 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2187 crc
.left
= iX
+ off_x
;
2190 if (analysis
->pItem
[iItem
].a
.fRTL
)
2191 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2193 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2195 if (analysis
->pItem
[iItem
].a
.fRTL
)
2196 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2198 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2202 /* adjust for cluster glyphs when starting */
2203 if (analysis
->pItem
[iItem
].a
.fRTL
)
2204 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2206 i
= analysis
->pItem
[iItem
].iCharPos
;
2208 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2210 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2212 if (analysis
->pItem
[iItem
].a
.fRTL
)
2213 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2215 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2220 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2225 clust_glyph
= iGlyph
+ cGlyphs
;
2226 if (analysis
->pItem
[iItem
].a
.fRTL
)
2231 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2232 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2239 hr
= ScriptTextOut(analysis
->hdc
,
2240 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2241 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2242 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2243 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2244 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2246 TRACE("ScriptTextOut hr=%08x\n", hr
);
2250 SetBkColor(analysis
->hdc
, BkColor
);
2251 SetBkMode( analysis
->hdc
, BkMode
);
2253 SetTextColor(analysis
->hdc
, TextColor
);
2255 if (analysis
->glyphs
[iItem
].fallbackFont
)
2256 SelectObject(analysis
->hdc
, oldFont
);
2261 /***********************************************************************
2262 * ScriptStringOut (USP10.@)
2264 * This function takes the output of ScriptStringAnalyse and joins the segments
2265 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2266 * only processes glyphs.
2269 * ssa [I] buffer to hold the analysed string components
2270 * iX [I] X axis displacement for output
2271 * iY [I] Y axis displacement for output
2272 * uOptions [I] flags controlling output processing
2273 * prc [I] rectangle coordinates
2274 * iMinSel [I] starting pos for substringing output string
2275 * iMaxSel [I] ending pos for substringing output string
2276 * fDisabled [I] controls text highlighting
2280 * Failure: is the value returned by ScriptTextOut
2282 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2291 StringAnalysis
*analysis
;
2295 TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
2296 ssa
, iX
, iY
, uOptions
, prc
, iMinSel
, iMaxSel
, fDisabled
);
2298 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2299 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2301 for (item
= 0; item
< analysis
->numItems
; item
++)
2303 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2308 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2310 if (iMaxSel
> 0 && iMinSel
< 0)
2312 for (item
= 0; item
< analysis
->numItems
; item
++)
2314 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2323 /***********************************************************************
2324 * ScriptStringCPtoX (USP10.@)
2327 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2331 StringAnalysis
* analysis
= ssa
;
2333 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2335 if (!ssa
|| !pX
) return S_FALSE
;
2336 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2338 /* icp out of range */
2341 analysis
->invalid
= TRUE
;
2342 return E_INVALIDARG
;
2345 for(item
=0; item
<analysis
->numItems
; item
++)
2350 i
= analysis
->logical2visual
[item
];
2351 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2352 /* initialize max extents for uninitialized runs */
2353 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2355 if (analysis
->pItem
[i
].a
.fRTL
)
2356 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2357 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2358 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2360 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2361 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2362 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2365 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2367 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2371 icp
-= analysis
->pItem
[i
].iCharPos
;
2372 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2373 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2374 &analysis
->pItem
[i
].a
, &offset
);
2381 /* icp out of range */
2382 analysis
->invalid
= TRUE
;
2383 return E_INVALIDARG
;
2386 /***********************************************************************
2387 * ScriptStringXtoCP (USP10.@)
2390 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2392 StringAnalysis
* analysis
= ssa
;
2395 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2397 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2398 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2403 if (analysis
->pItem
[0].a
.fRTL
)
2406 *piTrailing
= FALSE
;
2416 for(item
=0; item
<analysis
->numItems
; item
++)
2421 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2424 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2425 /* initialize max extents for uninitialized runs */
2426 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2428 if (analysis
->pItem
[i
].a
.fRTL
)
2429 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2430 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2431 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2433 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2434 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2435 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2438 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2440 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2444 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2445 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2446 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2447 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2453 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2454 *piTrailing
= FALSE
;
2460 /***********************************************************************
2461 * ScriptStringFree (USP10.@)
2463 * Free a string analysis.
2466 * pssa [I] string analysis.
2470 * Failure: Non-zero HRESULT value.
2472 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2474 StringAnalysis
* analysis
;
2478 TRACE("(%p)\n", pssa
);
2480 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2482 invalid
= analysis
->invalid
;
2484 if (analysis
->glyphs
)
2486 for (i
= 0; i
< analysis
->numItems
; i
++)
2488 heap_free(analysis
->glyphs
[i
].glyphs
);
2489 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2490 heap_free(analysis
->glyphs
[i
].piAdvance
);
2491 heap_free(analysis
->glyphs
[i
].psva
);
2492 heap_free(analysis
->glyphs
[i
].pGoffset
);
2493 heap_free(analysis
->glyphs
[i
].abc
);
2494 if (analysis
->glyphs
[i
].fallbackFont
)
2495 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2496 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2497 heap_free(analysis
->glyphs
[i
].sc
);
2499 heap_free(analysis
->glyphs
);
2502 heap_free(analysis
->pItem
);
2503 heap_free(analysis
->logattrs
);
2504 heap_free(analysis
->sz
);
2505 heap_free(analysis
->logical2visual
);
2506 heap_free(analysis
);
2508 if (invalid
) return E_INVALIDARG
;
2512 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2513 int direction
, int* iCluster
, int *check_out
)
2517 WORD clust
= pwLogClust
[item
];
2519 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2521 if (pwLogClust
[check
] == clust
)
2524 if (iCluster
&& *iCluster
== -1)
2536 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
)
2541 advance
= piAdvance
[glyph
];
2543 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2544 log_clust_max
= pwLogClust
[0];
2546 log_clust_max
= pwLogClust
[cChars
-1];
2548 if (glyph
> log_clust_max
)
2551 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2554 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2556 if (glyph
> log_clust_max
)
2558 advance
+= piAdvance
[glyph
];
2564 /***********************************************************************
2565 * ScriptCPtoX (USP10.@)
2568 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2572 const WORD
*pwLogClust
,
2573 const SCRIPT_VISATTR
*psva
,
2574 const int *piAdvance
,
2575 const SCRIPT_ANALYSIS
*psa
,
2583 float special_size
= 0.0;
2588 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2589 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2592 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2600 int max_clust
= pwLogClust
[0];
2602 for (item
=0; item
< cGlyphs
; item
++)
2603 if (pwLogClust
[item
] > max_clust
)
2605 ERR("We do not handle non reversed clusters properly\n");
2610 for (item
= max_clust
; item
>=0; item
--)
2611 iMaxPos
+= piAdvance
[item
];
2615 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2617 if (iSpecial
== -1 && (iCluster
== -1 || (iCluster
!= -1 && iCluster
+clust_size
<= item
)))
2620 int clust
= pwLogClust
[item
];
2623 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2626 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2628 if (check
>= cChars
&& !iMaxPos
)
2631 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2632 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2634 special_size
/= (cChars
- item
);
2635 iPosX
+= special_size
;
2639 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2642 if (clust_size
== 0)
2646 iPosX
+= advance
/ (float)clust_size
;
2649 else if (iSpecial
!= -1)
2650 iPosX
+= special_size
;
2651 else /* (iCluster != -1) */
2653 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2654 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2657 if (clust_size
== 0)
2661 iPosX
+= adv
/ (float)clust_size
;
2667 iPosX
= iMaxPos
- iPosX
;
2673 TRACE("*piX=%d\n", *piX
);
2677 /* Count the number of characters in a cluster and its starting index*/
2678 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2683 for (i
= 0; i
< cChars
; i
++)
2685 if (pwLogClust
[i
] == cluster_index
)
2687 if (!size
&& start_index
)
2695 else if (size
) break;
2698 *cluster_size
= size
;
2704 To handle multi-glyph clusters we need to find all the glyphs that are
2705 represented in the cluster. This involves finding the glyph whose
2706 index is the cluster index as well as whose glyph indices are greater than
2707 our cluster index but not part of a new cluster.
2709 Then we sum all those glyphs' advances.
2711 static inline int get_cluster_advance(const int* piAdvance
,
2712 const SCRIPT_VISATTR
*psva
,
2713 const WORD
*pwLogClust
, int cGlyphs
,
2714 int cChars
, int cluster
, int direction
)
2725 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2727 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2728 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2729 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2734 glyph_end
= cGlyphs
;
2737 /* Don't fully understand multi-glyph reversed clusters yet,
2738 * do they occur for real or just in our test? */
2739 FIXME("multi-glyph reversed clusters found\n");
2740 glyph_end
= glyph_start
+ 1;
2744 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2745 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2747 if (psva
[i
].fClusterStart
)
2754 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2755 advance
+= piAdvance
[i
];
2761 /***********************************************************************
2762 * ScriptXtoCP (USP10.@)
2765 * use piAdvance to find the cluster we are looking at
2766 * Find the character that is the first character of the cluster
2767 * That is our base piCP
2768 * If the script snaps to cluster boundries (Hebrew, Indic, Thai) then we
2769 * are good Otherwise if the cluster is larger than 1 glyph we need to
2770 * determine how far through the cluster to advance the cursor.
2772 HRESULT WINAPI
ScriptXtoCP(int iX
,
2775 const WORD
*pwLogClust
,
2776 const SCRIPT_VISATTR
*psva
,
2777 const int *piAdvance
,
2778 const SCRIPT_ANALYSIS
*psa
,
2785 int glyph_index
, cluster_index
;
2788 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2789 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2790 psa
, piCP
, piTrailing
);
2792 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2795 /* Handle an iX < 0 */
2811 /* Looking for non-reversed clusters in a reversed string */
2814 int max_clust
= pwLogClust
[0];
2815 for (i
=0; i
< cChars
; i
++)
2816 if (pwLogClust
[i
] > max_clust
)
2818 FIXME("We do not handle non reversed clusters properly\n");
2823 /* find the glyph_index based in iX */
2826 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2831 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2835 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2838 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2840 /* find the cluster */
2842 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2845 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2848 TRACE("cluster_index %i\n", cluster_index
);
2850 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2852 /* We are off the end of the string */
2858 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2860 TRACE("first char index %i\n",i
);
2861 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2863 /* Check trailing */
2864 if (glyph_index
!= cluster_index
||
2865 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2866 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2867 *piTrailing
= cluster_size
;
2871 if (cluster_size
> 1)
2873 /* Be part way through the glyph cluster based on size and position */
2874 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2875 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2879 /* back up to the beginning of the cluster */
2880 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2881 adv
+= piAdvance
[part_index
];
2882 if (adv
> iX
) adv
= iX
;
2884 TRACE("Multi-char cluster, no snap\n");
2885 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2886 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2889 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2891 if (part_index
) part_index
--;
2895 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2897 if (part_index
> cluster_size
)
2899 adv
+= cluster_part_width
;
2900 part_index
=cluster_size
;
2904 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2909 i
+= (cluster_size
- part_index
);
2911 /* Check trailing */
2912 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2913 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2918 /* Check trailing */
2919 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2920 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2927 TRACE("Point falls outside of string\n");
2928 if (glyph_index
< 0)
2930 else /* (glyph_index >= cGlyphs) */
2933 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2934 point flow to the next character */
2937 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
2946 TRACE("*piCP=%d\n", *piCP
);
2947 TRACE("*piTrailing=%d\n", *piTrailing
);
2951 /***********************************************************************
2952 * ScriptBreak (USP10.@)
2954 * Retrieve line break information.
2957 * chars [I] Array of characters.
2958 * sa [I] String analysis.
2959 * la [I] Array of logical attribute structures.
2965 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
2967 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
2969 if (count
< 0 || !la
) return E_INVALIDARG
;
2970 if (count
== 0) return E_FAIL
;
2972 BREAK_line(chars
, count
, sa
, la
);
2977 /***********************************************************************
2978 * ScriptIsComplex (USP10.@)
2980 * Determine if a string is complex.
2983 * chars [I] Array of characters to test.
2984 * len [I] Length in characters.
2992 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
2997 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
2999 for (i
= 0; i
< len
; i
+=consumed
)
3005 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3008 script
= get_char_script(chars
,i
,len
, &consumed
);
3009 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3010 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3016 /***********************************************************************
3017 * ScriptShapeOpenType (USP10.@)
3019 * Produce glyphs and visual attributes for a run.
3022 * hdc [I] Device context.
3023 * psc [I/O] Opaque pointer to a script cache.
3024 * psa [I/O] Script analysis.
3025 * tagScript [I] The OpenType tag for the Script
3026 * tagLangSys [I] The OpenType tag for the Language
3027 * rcRangeChars[I] Array of Character counts in each range
3028 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3029 * cRanges [I] Count of ranges
3030 * pwcChars [I] Array of characters specifying the run.
3031 * cChars [I] Number of characters in pwcChars.
3032 * cMaxGlyphs [I] Length of pwOutGlyphs.
3033 * pwLogClust [O] Array of logical cluster info.
3034 * pCharProps [O] Array of character property values
3035 * pwOutGlyphs [O] Array of glyphs.
3036 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3037 * pcGlyphs [O] Number of glyphs returned.
3041 * Failure: Non-zero HRESULT value.
3043 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3044 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3045 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3046 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3047 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3048 int cMaxGlyphs
, WORD
*pwLogClust
,
3049 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3050 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3057 static int once
= 0;
3059 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3061 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3062 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3063 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3065 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3066 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3068 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3069 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3072 if(!once
++) FIXME("Ranges not supported yet\n");
3074 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3077 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3078 if (!pwLogClust
) return E_FAIL
;
3080 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3081 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3083 /* set fNoGlyphIndex non truetype/opentype fonts */
3084 if (psa
&& !psa
->fNoGlyphIndex
&& !((ScriptCache
*)*psc
)->sfnt
)
3085 psa
->fNoGlyphIndex
= TRUE
;
3087 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3088 for (i
= 0; i
< cChars
; i
++)
3091 if (rtl
) idx
= cChars
- 1 - i
;
3092 /* FIXME: set to better values */
3093 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3094 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3095 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3096 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3097 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3098 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3100 /* FIXME: have the shaping engine set this */
3101 pCharProps
[i
].fCanGlyphAlone
= 0;
3103 pwLogClust
[i
] = idx
;
3106 if (psa
&& !psa
->fNoGlyphIndex
)
3109 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3111 rChars
= heap_alloc(sizeof(WCHAR
) * cChars
);
3112 if (!rChars
) return E_OUTOFMEMORY
;
3113 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3118 if (rtl
) idx
= cChars
- 1 - i
;
3121 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3125 chInput
= mirror_char(pwcChars
[idx
]);
3127 chInput
= pwcChars
[idx
];
3128 /* special case for tabs */
3129 if (chInput
== 0x0009)
3131 rChars
[i
] = chInput
;
3135 rChars
[i
] = pwcChars
[idx
];
3136 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3139 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3147 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3152 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3160 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3161 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3167 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3168 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3169 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3174 TRACE("no glyph translation\n");
3175 for (i
= 0; i
< cChars
; i
++)
3178 /* No mirroring done here */
3179 if (rtl
) idx
= cChars
- 1 - i
;
3180 pwOutGlyphs
[i
] = pwcChars
[idx
];
3182 /* overwrite some basic control glyphs to blank */
3183 if (psa
&& psa
->eScript
== Script_Control
&&
3184 pwcChars
[idx
] < ((ScriptCache
*)*psc
)->tm
.tmFirstChar
)
3186 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3187 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3188 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3197 /***********************************************************************
3198 * ScriptShape (USP10.@)
3200 * Produce glyphs and visual attributes for a run.
3203 * hdc [I] Device context.
3204 * psc [I/O] Opaque pointer to a script cache.
3205 * pwcChars [I] Array of characters specifying the run.
3206 * cChars [I] Number of characters in pwcChars.
3207 * cMaxGlyphs [I] Length of pwOutGlyphs.
3208 * psa [I/O] Script analysis.
3209 * pwOutGlyphs [O] Array of glyphs.
3210 * pwLogClust [O] Array of logical cluster info.
3211 * psva [O] Array of visual attributes.
3212 * pcGlyphs [O] Number of glyphs returned.
3216 * Failure: Non-zero HRESULT value.
3218 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3219 int cChars
, int cMaxGlyphs
,
3220 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3221 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3225 SCRIPT_CHARPROP
*charProps
;
3226 SCRIPT_GLYPHPROP
*glyphProps
;
3228 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3229 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3231 charProps
= heap_alloc_zero(sizeof(SCRIPT_CHARPROP
)*cChars
);
3232 if (!charProps
) return E_OUTOFMEMORY
;
3233 glyphProps
= heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP
)*cMaxGlyphs
);
3236 heap_free(charProps
);
3237 return E_OUTOFMEMORY
;
3240 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3244 for (i
= 0; i
< *pcGlyphs
; i
++)
3245 psva
[i
] = glyphProps
[i
].sva
;
3248 heap_free(charProps
);
3249 heap_free(glyphProps
);
3254 /***********************************************************************
3255 * ScriptPlaceOpenType (USP10.@)
3257 * Produce advance widths for a run.
3260 * hdc [I] Device context.
3261 * psc [I/O] Opaque pointer to a script cache.
3262 * psa [I/O] String analysis.
3263 * tagScript [I] The OpenType tag for the Script
3264 * tagLangSys [I] The OpenType tag for the Language
3265 * rcRangeChars[I] Array of Character counts in each range
3266 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3267 * cRanges [I] Count of ranges
3268 * pwcChars [I] Array of characters specifying the run.
3269 * pwLogClust [I] Array of logical cluster info
3270 * pCharProps [I] Array of character property values
3271 * cChars [I] Number of characters in pwcChars.
3272 * pwGlyphs [I] Array of glyphs.
3273 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3274 * cGlyphs [I] Count of Glyphs
3275 * piAdvance [O] Array of advance widths.
3276 * pGoffset [O] Glyph offsets.
3277 * pABC [O] Combined ABC width.
3281 * Failure: Non-zero HRESULT value.
3284 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3285 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3286 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3287 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3288 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3289 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3290 int cGlyphs
, int *piAdvance
,
3291 GOFFSET
*pGoffset
, ABC
*pABC
3296 static int once
= 0;
3298 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3300 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3301 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3302 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3305 if (!pGlyphProps
) return E_INVALIDARG
;
3306 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3307 if (!pGoffset
) return E_FAIL
;
3310 if (!once
++) FIXME("Ranges not supported yet\n");
3312 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3313 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3315 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3316 for (i
= 0; i
< cGlyphs
; i
++)
3319 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3321 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3323 else if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3325 if (!hdc
) return E_PENDING
;
3326 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
) && !psa
->fNoGlyphIndex
)
3328 if (!GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
)) return S_FALSE
;
3333 if (!GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
)) return S_FALSE
;
3335 abc
.abcA
= abc
.abcC
= 0;
3337 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3341 pABC
->abcA
+= abc
.abcA
;
3342 pABC
->abcB
+= abc
.abcB
;
3343 pABC
->abcC
+= abc
.abcC
;
3345 /* FIXME: set to more reasonable values */
3346 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3347 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3350 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3352 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3356 /***********************************************************************
3357 * ScriptPlace (USP10.@)
3359 * Produce advance widths for a run.
3362 * hdc [I] Device context.
3363 * psc [I/O] Opaque pointer to a script cache.
3364 * pwGlyphs [I] Array of glyphs.
3365 * cGlyphs [I] Number of glyphs in pwGlyphs.
3366 * psva [I] Array of visual attributes.
3367 * psa [I/O] String analysis.
3368 * piAdvance [O] Array of advance widths.
3369 * pGoffset [O] Glyph offsets.
3370 * pABC [O] Combined ABC width.
3374 * Failure: Non-zero HRESULT value.
3376 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3377 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3378 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3381 SCRIPT_GLYPHPROP
*glyphProps
;
3384 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3385 piAdvance
, pGoffset
, pABC
);
3387 if (!psva
) return E_INVALIDARG
;
3388 if (!pGoffset
) return E_FAIL
;
3390 glyphProps
= heap_alloc(sizeof(SCRIPT_GLYPHPROP
)*cGlyphs
);
3391 if (!glyphProps
) return E_OUTOFMEMORY
;
3393 for (i
= 0; i
< cGlyphs
; i
++)
3394 glyphProps
[i
].sva
= psva
[i
];
3396 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3398 heap_free(glyphProps
);
3403 /***********************************************************************
3404 * ScriptGetCMap (USP10.@)
3406 * Retrieve glyph indices.
3409 * hdc [I] Device context.
3410 * psc [I/O] Opaque pointer to a script cache.
3411 * pwcInChars [I] Array of Unicode characters.
3412 * cChars [I] Number of characters in pwcInChars.
3413 * dwFlags [I] Flags.
3414 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3418 * Failure: Non-zero HRESULT value.
3420 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3421 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3426 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3427 cChars
, dwFlags
, pwOutGlyphs
);
3429 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3433 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3435 for (i
= 0; i
< cChars
; i
++)
3438 if (dwFlags
== SGCM_RTL
)
3439 inChar
= mirror_char(pwcInChars
[i
]);
3441 inChar
= pwcInChars
[i
];
3442 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3445 if (!hdc
) return E_PENDING
;
3446 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3447 if (glyph
== 0xffff)
3452 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3458 TRACE("no glyph translation\n");
3459 for (i
= 0; i
< cChars
; i
++)
3462 if (dwFlags
== SGCM_RTL
)
3463 inChar
= mirror_char(pwcInChars
[i
]);
3465 inChar
= pwcInChars
[i
];
3466 pwOutGlyphs
[i
] = inChar
;
3472 /***********************************************************************
3473 * ScriptTextOut (USP10.@)
3476 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3477 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3478 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3479 const int *piJustify
, const GOFFSET
*pGoffset
)
3484 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3486 TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3487 hdc
, psc
, x
, y
, fuOptions
, lprc
, psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3488 piAdvance
, piJustify
, pGoffset
);
3490 if (!hdc
|| !psc
) return E_INVALIDARG
;
3491 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3493 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3494 fuOptions
|= ETO_IGNORELANGUAGE
;
3495 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3496 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3498 lpDx
= heap_alloc(cGlyphs
* sizeof(INT
) * 2);
3499 if (!lpDx
) return E_OUTOFMEMORY
;
3500 fuOptions
|= ETO_PDY
;
3502 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3504 reordered_glyphs
= heap_alloc( cGlyphs
* sizeof(WORD
) );
3505 if (!reordered_glyphs
)
3508 return E_OUTOFMEMORY
;
3511 for (i
= 0; i
< cGlyphs
; i
++)
3512 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3516 for (i
= 0; i
< cGlyphs
; i
++)
3518 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3519 lpDx
[i
* 2] = piAdvance
[orig_index
];
3520 lpDx
[i
* 2 + 1] = 0;
3526 x
+= pGoffset
[orig_index
].du
* dir
;
3527 y
+= pGoffset
[orig_index
].dv
;
3531 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3532 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3534 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3535 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3539 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3542 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3548 /***********************************************************************
3549 * ScriptCacheGetHeight (USP10.@)
3551 * Retrieve the height of the font in the cache.
3554 * hdc [I] Device context.
3555 * psc [I/O] Opaque pointer to a script cache.
3556 * height [O] Receives font height.
3560 * Failure: Non-zero HRESULT value.
3562 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3566 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3568 if (!height
) return E_INVALIDARG
;
3569 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3571 *height
= get_cache_height(psc
);
3575 /***********************************************************************
3576 * ScriptGetGlyphABCWidth (USP10.@)
3578 * Retrieve the width of a glyph.
3581 * hdc [I] Device context.
3582 * psc [I/O] Opaque pointer to a script cache.
3583 * glyph [I] Glyph to retrieve the width for.
3584 * abc [O] ABC widths of the glyph.
3588 * Failure: Non-zero HRESULT value.
3590 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3594 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3596 if (!abc
) return E_INVALIDARG
;
3597 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3599 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3601 if (!hdc
) return E_PENDING
;
3602 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3604 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3609 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3611 abc
->abcA
= abc
->abcC
= 0;
3613 set_cache_glyph_widths(psc
, glyph
, abc
);
3618 /***********************************************************************
3619 * ScriptLayout (USP10.@)
3621 * Map embedding levels to visual and/or logical order.
3624 * runs [I] Size of level array.
3625 * level [I] Array of embedding levels.
3626 * vistolog [O] Map of embedding levels from visual to logical order.
3627 * logtovis [O] Map of embedding levels from logical to visual order.
3631 * Failure: Non-zero HRESULT value.
3634 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3639 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3641 if (!level
|| (!vistolog
&& !logtovis
))
3642 return E_INVALIDARG
;
3644 indexs
= heap_alloc(sizeof(int) * runs
);
3646 return E_OUTOFMEMORY
;
3650 for( ich
= 0; ich
< runs
; ich
++)
3655 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3656 memcpy(vistolog
, indexs
, runs
* sizeof(*vistolog
));
3661 for( ich
= 0; ich
< runs
; ich
++)
3666 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3667 memcpy(logtovis
, indexs
, runs
* sizeof(*logtovis
));
3674 /***********************************************************************
3675 * ScriptStringGetLogicalWidths (USP10.@)
3677 * Returns logical widths from a string analysis.
3680 * ssa [I] string analysis.
3681 * piDx [O] logical widths returned.
3685 * Failure: a non-zero HRESULT.
3687 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3690 StringAnalysis
*analysis
= ssa
;
3692 TRACE("%p, %p\n", ssa
, piDx
);
3694 if (!analysis
) return S_FALSE
;
3695 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3697 for (i
= 0; i
< analysis
->numItems
; i
++)
3699 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3702 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3705 for (j
= 0; j
< cChar
; j
++)
3708 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3709 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3710 cChar
, j
, direction
, NULL
, NULL
);
3711 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
);
3713 for (k
= 0; k
< clust_size
; k
++)
3715 piDx
[next
] = advance
/ clust_size
;
3724 /***********************************************************************
3725 * ScriptStringValidate (USP10.@)
3727 * Validate a string analysis.
3730 * ssa [I] string analysis.
3734 * Failure: S_FALSE if invalid sequences are found
3735 * or a non-zero HRESULT if it fails.
3737 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3739 StringAnalysis
*analysis
= ssa
;
3741 TRACE("(%p)\n", ssa
);
3743 if (!analysis
) return E_INVALIDARG
;
3744 return (analysis
->invalid
) ? S_FALSE
: S_OK
;
3747 /***********************************************************************
3748 * ScriptString_pSize (USP10.@)
3750 * Retrieve width and height of an analysed string.
3753 * ssa [I] string analysis.
3756 * Success: Pointer to a SIZE structure.
3759 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3762 StringAnalysis
*analysis
= ssa
;
3764 TRACE("(%p)\n", ssa
);
3766 if (!analysis
) return NULL
;
3767 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return NULL
;
3771 if (!(analysis
->sz
= heap_alloc(sizeof(SIZE
)))) return NULL
;
3772 analysis
->sz
->cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3774 analysis
->sz
->cx
= 0;
3775 for (i
= 0; i
< analysis
->numItems
; i
++)
3777 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
->cy
)
3778 analysis
->sz
->cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3779 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3780 analysis
->sz
->cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3783 return analysis
->sz
;
3786 /***********************************************************************
3787 * ScriptString_pLogAttr (USP10.@)
3789 * Retrieve logical attributes of an analysed string.
3792 * ssa [I] string analysis.
3795 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3798 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3800 StringAnalysis
*analysis
= ssa
;
3802 TRACE("(%p)\n", ssa
);
3804 if (!analysis
) return NULL
;
3805 if (!(analysis
->dwFlags
& SSA_BREAK
)) return NULL
;
3806 return analysis
->logattrs
;
3809 /***********************************************************************
3810 * ScriptString_pcOutChars (USP10.@)
3812 * Retrieve the length of a string after clipping.
3815 * ssa [I] String analysis.
3818 * Success: Pointer to the length.
3821 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3823 StringAnalysis
*analysis
= ssa
;
3825 TRACE("(%p)\n", ssa
);
3827 if (!analysis
) return NULL
;
3828 return &analysis
->clip_len
;
3831 /***********************************************************************
3832 * ScriptStringGetOrder (USP10.@)
3834 * Retrieve a glyph order map.
3837 * ssa [I] String analysis.
3838 * order [I/O] Array of glyph positions.
3842 * Failure: a non-zero HRESULT.
3844 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3848 StringAnalysis
*analysis
= ssa
;
3850 TRACE("(%p)\n", ssa
);
3852 if (!analysis
) return S_FALSE
;
3853 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3855 /* FIXME: handle RTL scripts */
3856 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3857 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3863 /***********************************************************************
3864 * ScriptGetLogicalWidths (USP10.@)
3866 * Convert advance widths to logical widths.
3869 * sa [I] Script analysis.
3870 * nbchars [I] Number of characters.
3871 * nbglyphs [I] Number of glyphs.
3872 * glyph_width [I] Array of glyph widths.
3873 * log_clust [I] Array of logical clusters.
3874 * sva [I] Visual attributes.
3875 * widths [O] Array of logical widths.
3879 * Failure: a non-zero HRESULT.
3881 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3882 const int *glyph_width
, const WORD
*log_clust
,
3883 const SCRIPT_VISATTR
*sva
, int *widths
)
3887 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3888 sa
, nbchars
, nbglyphs
, glyph_width
, log_clust
, sva
, widths
);
3891 for (i
= 0; i
< nbchars
; i
++) widths
[i
] = glyph_width
[i
];
3895 /***********************************************************************
3896 * ScriptApplyLogicalWidth (USP10.@)
3898 * Generate glyph advance widths.
3901 * dx [I] Array of logical advance widths.
3902 * num_chars [I] Number of characters.
3903 * num_glyphs [I] Number of glyphs.
3904 * log_clust [I] Array of logical clusters.
3905 * sva [I] Visual attributes.
3906 * advance [I] Array of glyph advance widths.
3907 * sa [I] Script analysis.
3908 * abc [I/O] Summed ABC widths.
3909 * justify [O] Array of glyph advance widths.
3913 * Failure: a non-zero HRESULT.
3915 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
3916 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
3917 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
3918 ABC
*abc
, int *justify
)
3922 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3923 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
3925 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
3929 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
3930 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
3934 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
3936 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
3940 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
3943 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3944 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3946 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
3949 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
3952 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3953 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3955 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
3958 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
3961 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3962 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3964 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);