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 /* this 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
, 0, 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
, 0, 1, 0, 0, 0, 0, { 2,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('a','r','a','b'),
348 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',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: unknown 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};
894 WORD type
= 0, type2
= 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 Symbols 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
);
924 GetStringTypeW(CT_CTYPE2
, &str
[index
], 1, &type2
);
927 return SCRIPT_UNDEFINED
;
930 return Script_Control
;
932 ch
= decode_surrogate_pair(str
, index
, end
);
941 if (ch
< scriptRanges
[i
].rangeFirst
|| scriptRanges
[i
].script
== SCRIPT_UNDEFINED
)
944 if (ch
>= scriptRanges
[i
].rangeFirst
&& ch
<= scriptRanges
[i
].rangeLast
)
946 if (scriptRanges
[i
].numericScript
&& (type
& C1_DIGIT
|| type2
== C2_ARABICNUMBER
))
947 return scriptRanges
[i
].numericScript
;
948 if (scriptRanges
[i
].punctScript
&& type
& C1_PUNCT
)
949 return scriptRanges
[i
].punctScript
;
950 return scriptRanges
[i
].script
;
955 return SCRIPT_UNDEFINED
;
958 static int compare_FindGlyph(const void *a
, const void* b
)
960 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
961 const WORD
*idx
= (WORD
*)b
;
964 if ( find
->target
> *idx
)
966 else if (find
->target
< *idx
)
969 if (!find
->ascending
)
974 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
976 FindGlyph_struct fgs
;
980 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
981 fgs
.ascending
= TRUE
;
983 fgs
.ascending
= FALSE
;
986 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
991 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
998 /***********************************************************************
999 * ScriptFreeCache (USP10.@)
1001 * Free a script cache.
1004 * psc [I/O] Script cache.
1008 * Failure: Non-zero HRESULT value.
1010 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1018 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1020 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1022 for (i
= 0; i
< 0x10; i
++)
1025 if (((ScriptCache
*)*psc
)->page
[i
])
1026 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1027 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1028 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1030 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1031 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1032 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1033 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1034 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1037 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1040 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1041 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1042 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1044 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1045 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1046 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1047 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1049 heap_free(((ScriptCache
*)*psc
)->scripts
);
1050 heap_free(((ScriptCache
*)*psc
)->otm
);
1057 /***********************************************************************
1058 * ScriptGetProperties (USP10.@)
1060 * Retrieve a list of script properties.
1063 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1064 * num [I] Pointer to the number of scripts.
1068 * Failure: Non-zero HRESULT value.
1071 * Behaviour matches WinXP.
1073 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1075 TRACE("(%p,%p)\n", props
, num
);
1077 if (!props
&& !num
) return E_INVALIDARG
;
1079 if (num
) *num
= sizeof(script_props
)/sizeof(script_props
[0]);
1080 if (props
) *props
= script_props
;
1085 /***********************************************************************
1086 * ScriptGetFontProperties (USP10.@)
1088 * Get information on special glyphs.
1091 * hdc [I] Device context.
1092 * psc [I/O] Opaque pointer to a script cache.
1093 * sfp [O] Font properties structure.
1095 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1099 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1101 if (!sfp
) return E_INVALIDARG
;
1102 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1104 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1105 return E_INVALIDARG
;
1107 get_cache_font_properties(sfp
, *psc
);
1112 /***********************************************************************
1113 * ScriptRecordDigitSubstitution (USP10.@)
1115 * Record digit substitution settings for a given locale.
1118 * locale [I] Locale identifier.
1119 * sds [I] Structure to record substitution settings.
1123 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1126 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1128 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1132 TRACE("0x%x, %p\n", locale
, sds
);
1134 /* This implementation appears to be correct for all languages, but it's
1135 * not clear if sds->DigitSubstitute is ever set to anything except
1136 * CONTEXT or NONE in reality */
1138 if (!sds
) return E_POINTER
;
1140 locale
= ConvertDefaultLocale(locale
);
1142 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1143 return E_INVALIDARG
;
1145 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1146 sds
->TraditionalDigitLanguage
= plgid
;
1148 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1149 sds
->NationalDigitLanguage
= plgid
;
1151 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1153 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1154 (LPWSTR
)&sub
, sizeof(sub
)/sizeof(WCHAR
))) return E_INVALIDARG
;
1159 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1160 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1162 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1165 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1168 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1171 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1175 sds
->dwReserved
= 0;
1179 /***********************************************************************
1180 * ScriptApplyDigitSubstitution (USP10.@)
1182 * Apply digit substitution settings.
1185 * sds [I] Structure with recorded substitution settings.
1186 * sc [I] Script control structure.
1187 * ss [I] Script state structure.
1191 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1193 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1194 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1196 SCRIPT_DIGITSUBSTITUTE psds
;
1198 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1200 if (!sc
|| !ss
) return E_POINTER
;
1204 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1205 return E_INVALIDARG
;
1208 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1209 sc
->fContextDigits
= 0;
1210 ss
->fDigitSubstitute
= 0;
1212 switch (sds
->DigitSubstitute
) {
1213 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1214 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1215 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1216 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1219 return E_INVALIDARG
;
1223 static inline BOOL
is_indic(WORD script
)
1225 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1228 static inline WORD
base_indic(WORD script
)
1232 case Script_Devanagari
:
1233 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1234 case Script_Bengali
:
1235 case Script_Bengali_Numeric
:
1236 case Script_Bengali_Currency
: return Script_Bengali
;
1237 case Script_Gurmukhi
:
1238 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1239 case Script_Gujarati
:
1240 case Script_Gujarati_Numeric
:
1241 case Script_Gujarati_Currency
: return Script_Gujarati
;
1243 case Script_Oriya_Numeric
: return Script_Oriya
;
1245 case Script_Tamil_Numeric
: return Script_Tamil
;
1247 case Script_Telugu_Numeric
: return Script_Telugu
;
1248 case Script_Kannada
:
1249 case Script_Kannada_Numeric
: return Script_Kannada
;
1250 case Script_Malayalam
:
1251 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1257 static BOOL
script_is_numeric(WORD script
)
1259 return scriptInformation
[script
].props
.fNumeric
;
1262 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1263 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1264 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1265 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1268 #define Numeric_space 0x0020
1272 int cnt
= 0, index
= 0, str
= 0;
1273 int New_Script
= -1;
1275 WORD
*levels
= NULL
;
1276 WORD
*layout_levels
= NULL
;
1277 WORD
*overrides
= NULL
;
1278 WORD
*strength
= NULL
;
1279 WORD
*scripts
= NULL
;
1281 WORD baselayout
= 0;
1283 WORD last_indic
= -1;
1285 BOOL forceLevels
= FALSE
;
1287 HRESULT res
= E_OUTOFMEMORY
;
1289 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1290 psControl
, psState
, pItems
, pcItems
);
1292 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1293 return E_INVALIDARG
;
1295 scripts
= heap_alloc(cInChars
* sizeof(WORD
));
1297 return E_OUTOFMEMORY
;
1299 for (i
= 0; i
< cInChars
; i
++)
1303 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1308 scripts
[i
] = scripts
[i
-1];
1311 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1312 all Indic scripts */
1313 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
> 0)
1314 scripts
[i
] = last_indic
;
1315 else if (is_indic(scripts
[i
]))
1316 last_indic
= base_indic(scripts
[i
]);
1318 /* Some unicode points :
1319 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1320 (Left Right Embed U+202A - Left Right Override U+202D)
1321 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1322 will force us into bidi mode */
1323 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1324 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1325 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1329 /* Diacritical marks merge with other scripts */
1330 if (scripts
[i
] == Script_Diacritical
)
1335 scripts
[i
] = scripts
[i
-1];
1340 WORD first_script
= scripts
[i
-1];
1341 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1343 WORD original
= scripts
[j
];
1344 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1349 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1351 scripts
[j
] = scripts
[i
];
1352 if (original
== Script_Punctuation2
)
1355 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1356 scripts
[i
] = scripts
[j
];
1362 for (i
= 0; i
< cInChars
; i
++)
1364 /* Joiners get merged preferencially right */
1365 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1368 if (i
+1 == cInChars
)
1369 scripts
[i
] = scripts
[i
-1];
1372 for (j
= i
+1; j
< cInChars
; j
++)
1374 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1376 scripts
[i
] = scripts
[j
];
1384 if (psState
&& psControl
)
1386 levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1390 overrides
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1394 layout_levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1398 if (psState
->fOverrideDirection
)
1402 SCRIPT_STATE s
= *psState
;
1403 s
.fOverrideDirection
= FALSE
;
1404 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1405 if (odd(layout_levels
[0]))
1407 else for (i
= 0; i
< cInChars
; i
++)
1408 if (layout_levels
[i
]!=layout_levels
[0])
1415 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1419 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1420 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1422 baselevel
= levels
[0];
1423 baselayout
= layout_levels
[0];
1424 for (i
= 0; i
< cInChars
; i
++)
1425 if (levels
[i
]!=levels
[0])
1427 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1430 heap_free(overrides
);
1431 heap_free(layout_levels
);
1434 layout_levels
= NULL
;
1438 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1439 static const WCHAR repeatable_math_punc
[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1441 strength
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1444 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1446 /* We currently mis-level leading Diacriticals */
1447 if (scripts
[0] == Script_Diacritical
)
1448 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1450 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1451 strength
[i
] = BIDI_STRONG
;
1454 /* Math punctuation bordered on both sides by numbers can be
1455 merged into the number */
1456 for (i
= 0; i
< cInChars
; i
++)
1458 if (i
> 0 && i
< cInChars
-1 &&
1459 script_is_numeric(scripts
[i
-1]) &&
1460 strchrW(math_punc
, pwcInChars
[i
]))
1462 if (script_is_numeric(scripts
[i
+1]))
1464 scripts
[i
] = scripts
[i
+1];
1465 levels
[i
] = levels
[i
-1];
1466 strength
[i
] = strength
[i
-1];
1469 else if (strchrW(repeatable_math_punc
, pwcInChars
[i
]))
1472 for (j
= i
+1; j
< cInChars
; j
++)
1474 if (script_is_numeric(scripts
[j
]))
1478 scripts
[i
] = scripts
[j
];
1479 levels
[i
] = levels
[i
-1];
1480 strength
[i
] = strength
[i
-1];
1483 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1489 for (i
= 0; i
< cInChars
; i
++)
1491 /* Numerics at level 0 get bumped to level 2 */
1492 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
)
1493 && levels
[i
] == psState
->uBidiLevel
+ 1)) && script_is_numeric(scripts
[i
]))
1498 /* Joiners get merged preferencially right */
1499 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1502 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1503 strength
[i
] = strength
[i
-1];
1505 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1506 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1508 strength
[i
] = strength
[j
];
1513 if (psControl
->fMergeNeutralItems
)
1515 /* Merge the neutrals */
1516 for (i
= 0; i
< cInChars
; i
++)
1518 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1521 for (j
= i
; j
> 0; j
--)
1523 if (levels
[i
] != levels
[j
])
1525 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1527 scripts
[i
] = scripts
[j
];
1528 strength
[i
] = strength
[j
];
1533 /* Try going the other way */
1534 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1537 for (j
= i
; j
< cInChars
; j
++)
1539 if (levels
[i
] != levels
[j
])
1541 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1543 scripts
[i
] = scripts
[j
];
1544 strength
[i
] = strength
[j
];
1554 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1555 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1558 if (cnt
== cInChars
) /* All Spaces */
1561 New_Script
= scripts
[cnt
];
1564 pItems
[index
].iCharPos
= 0;
1565 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1567 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1569 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1570 str
= strength
[cnt
];
1578 if (strength
[cnt
] == BIDI_STRONG
)
1579 layoutRTL
= odd(layout_levels
[cnt
]);
1581 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1583 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1584 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1585 if (script_is_numeric(pItems
[index
].a
.eScript
))
1586 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1588 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1589 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1591 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1593 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1594 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1595 layoutRTL
= odd(baselayout
);
1596 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1597 pItems
[index
].a
.fRTL
= odd(baselevel
);
1598 if (script_is_numeric(pItems
[index
].a
.eScript
))
1599 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1601 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1604 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1605 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1606 pItems
[index
].iCharPos
);
1608 for (cnt
=1; cnt
< cInChars
; cnt
++)
1610 if(pwcInChars
[cnt
] != Numeric_space
)
1611 New_Script
= scripts
[cnt
];
1615 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1617 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1618 New_Script
= scripts
[cnt
+j
];
1620 New_Script
= scripts
[cnt
];
1624 /* merge space strengths*/
1625 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1628 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1631 /* changes in level */
1632 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1634 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1637 /* changes in strength */
1638 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1640 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1643 /* changes in script */
1644 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1646 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1650 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1652 layoutRTL
= odd(layout_levels
[cnt
]);
1653 if (script_is_numeric(pItems
[index
].a
.eScript
))
1654 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1659 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
);
1662 if (index
+1 > cMaxItems
)
1666 str
= strength
[cnt
];
1668 pItems
[index
].iCharPos
= cnt
;
1669 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1671 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1673 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1677 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1678 if (layout_levels
[cnt
] == 0)
1681 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1682 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1683 if (script_is_numeric(pItems
[index
].a
.eScript
))
1684 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1686 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1687 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1689 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1691 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1692 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1693 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1694 pItems
[index
].a
.fRTL
= odd(baselevel
);
1695 if (script_is_numeric(pItems
[index
].a
.eScript
))
1696 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1698 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1701 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1705 /* While not strictly necessary according to the spec, make sure the n+1
1706 * item is set up to prevent random behaviour if the caller erroneously
1707 * checks the n+1 structure */
1709 if (index
+ 1 > cMaxItems
) goto nomemory
;
1710 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1712 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1714 /* Set one SCRIPT_STATE item being returned */
1715 if (pcItems
) *pcItems
= index
;
1717 /* Set SCRIPT_ITEM */
1718 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1722 heap_free(overrides
);
1723 heap_free(layout_levels
);
1724 heap_free(strength
);
1729 /***********************************************************************
1730 * ScriptItemizeOpenType (USP10.@)
1732 * Split a Unicode string into shapeable parts.
1735 * pwcInChars [I] String to split.
1736 * cInChars [I] Number of characters in pwcInChars.
1737 * cMaxItems [I] Maximum number of items to return.
1738 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1739 * psState [I] Pointer to a SCRIPT_STATE structure.
1740 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1741 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1742 * pcItems [O] Number of script items returned.
1746 * Failure: Non-zero HRESULT value.
1748 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1749 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1750 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1752 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1755 /***********************************************************************
1756 * ScriptItemize (USP10.@)
1758 * Split a Unicode string into shapeable parts.
1761 * pwcInChars [I] String to split.
1762 * cInChars [I] Number of characters in pwcInChars.
1763 * cMaxItems [I] Maximum number of items to return.
1764 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1765 * psState [I] Pointer to a SCRIPT_STATE structure.
1766 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1767 * pcItems [O] Number of script items returned.
1771 * Failure: Non-zero HRESULT value.
1773 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1774 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1775 SCRIPT_ITEM
*pItems
, int *pcItems
)
1777 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1780 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1784 INT
*lpTabPos
= NULL
;
1789 lpTabPos
= pTabdef
->pTabStops
;
1791 if (pTabdef
&& pTabdef
->iTabOrigin
)
1793 if (pTabdef
->iScale
)
1794 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1796 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1800 cTabStops
= pTabdef
->cTabStops
;
1804 if (pTabdef
->iScale
)
1805 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1807 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1811 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1813 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1815 int position
= *lpTabPos
;
1817 position
= -1 * position
;
1818 if (pTabdef
->iScale
)
1819 position
= (position
* pTabdef
->iScale
) / 4;
1821 position
= position
* psc
->tm
.tmAveCharWidth
;
1823 if( nTabOrg
+ position
> current_x
)
1827 /* a left aligned tab */
1828 x
= (nTabOrg
+ *lpTabPos
) - current_x
;
1833 FIXME("Negative tabstop\n");
1838 if ((!cTabStops
) && (defWidth
> 0))
1839 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1840 else if ((!cTabStops
) && (defWidth
< 0))
1841 FIXME("TODO: Negative defWidth\n");
1846 /***********************************************************************
1847 * Helper function for ScriptStringAnalyse
1849 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1850 const WCHAR
*pwcInChars
, int cChars
)
1852 /* FIXME: When to properly fallback is still a bit of a mystery */
1855 if (psa
->fNoGlyphIndex
)
1858 if (init_script_cache(hdc
, psc
) != S_OK
)
1861 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1864 glyphs
= heap_alloc(sizeof(WORD
) * cChars
);
1867 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1877 static void find_fallback_font(DWORD scriptid
, LPWSTR FaceName
)
1881 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1883 static const WCHAR szFmt
[] = {'%','x',0};
1885 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1888 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1889 if (RegQueryValueExW(hkey
, value
, 0, &type
, (LPBYTE
)FaceName
, &count
))
1890 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1894 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1897 /***********************************************************************
1898 * ScriptStringAnalyse (USP10.@)
1901 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1902 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1903 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1904 SCRIPT_STATE
*psState
, const int *piDx
,
1905 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1906 SCRIPT_STRING_ANALYSIS
*pssa
)
1908 HRESULT hr
= E_OUTOFMEMORY
;
1909 StringAnalysis
*analysis
= NULL
;
1910 SCRIPT_CONTROL sControl
;
1911 SCRIPT_STATE sState
;
1912 int i
, num_items
= 255;
1914 WCHAR
*iString
= NULL
;
1916 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1917 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1918 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
1922 FIXME("Only Unicode strings are supported\n");
1923 return E_INVALIDARG
;
1925 if (cString
< 1 || !pString
) return E_INVALIDARG
;
1926 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
1928 if (!(analysis
= heap_alloc_zero(sizeof(StringAnalysis
)))) return E_OUTOFMEMORY
;
1929 if (!(analysis
->pItem
= heap_alloc_zero(num_items
* sizeof(SCRIPT_ITEM
) + 1))) goto error
;
1931 /* FIXME: handle clipping */
1932 analysis
->clip_len
= cString
;
1933 analysis
->hdc
= hdc
;
1934 analysis
->dwFlags
= dwFlags
;
1939 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
1942 sControl
= *psControl
;
1944 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
1946 if (dwFlags
& SSA_PASSWORD
)
1948 iString
= heap_alloc(sizeof(WCHAR
)*cString
);
1954 for (i
= 0; i
< cString
; i
++)
1955 iString
[i
] = *((const WCHAR
*)pString
);
1959 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
1960 &analysis
->numItems
);
1964 if (hr
== E_OUTOFMEMORY
)
1969 /* set back to out of memory for default goto error behaviour */
1972 if (dwFlags
& SSA_BREAK
)
1974 if ((analysis
->logattrs
= heap_alloc(sizeof(SCRIPT_LOGATTR
) * cString
)))
1976 for (i
= 0; i
< analysis
->numItems
; i
++)
1977 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
]);
1983 if (!(analysis
->logical2visual
= heap_alloc_zero(sizeof(int) * analysis
->numItems
)))
1985 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
1988 if (dwFlags
& SSA_GLYPHS
)
1991 if (!(analysis
->glyphs
= heap_alloc_zero(sizeof(StringGlyphs
) * analysis
->numItems
)))
1993 heap_free(BidiLevel
);
1997 for (i
= 0; i
< analysis
->numItems
; i
++)
1999 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
2000 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2001 int numGlyphs
= 1.5 * cChar
+ 16;
2002 WORD
*glyphs
= heap_alloc_zero(sizeof(WORD
) * numGlyphs
);
2003 WORD
*pwLogClust
= heap_alloc_zero(sizeof(WORD
) * cChar
);
2004 int *piAdvance
= heap_alloc_zero(sizeof(int) * numGlyphs
);
2005 SCRIPT_VISATTR
*psva
= heap_alloc_zero(sizeof(SCRIPT_VISATTR
) * numGlyphs
);
2006 GOFFSET
*pGoffset
= heap_alloc_zero(sizeof(GOFFSET
) * numGlyphs
);
2007 ABC
*abc
= heap_alloc_zero(sizeof(ABC
));
2008 int numGlyphsReturned
;
2009 HFONT originalFont
= 0x0;
2011 /* FIXME: non unicode strings */
2012 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2013 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2015 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
|| !abc
)
2017 heap_free (BidiLevel
);
2019 heap_free (pwLogClust
);
2020 heap_free (piAdvance
);
2022 heap_free (pGoffset
);
2028 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2031 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2032 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2033 lf
.lfFaceName
[0] = 0;
2034 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2035 if (lf
.lfFaceName
[0])
2037 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2038 if (analysis
->glyphs
[i
].fallbackFont
)
2040 ScriptFreeCache(sc
);
2041 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2046 /* FIXME: When we properly shape Hangul remove this check */
2047 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2048 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2050 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2051 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2053 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2054 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2055 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2056 piAdvance
, pGoffset
, abc
);
2058 SelectObject(hdc
,originalFont
);
2060 if (dwFlags
& SSA_TAB
)
2063 for (tabi
= 0; tabi
< cChar
; tabi
++)
2065 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2066 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2067 tab_x
+=piAdvance
[tabi
];
2071 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2072 analysis
->glyphs
[i
].glyphs
= glyphs
;
2073 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2074 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2075 analysis
->glyphs
[i
].psva
= psva
;
2076 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2077 analysis
->glyphs
[i
].abc
= abc
;
2078 analysis
->glyphs
[i
].iMaxPosX
= -1;
2080 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2085 for (i
= 0; i
< analysis
->numItems
; i
++)
2086 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2089 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2090 heap_free(BidiLevel
);
2098 heap_free(analysis
->glyphs
);
2099 heap_free(analysis
->logattrs
);
2100 heap_free(analysis
->pItem
);
2101 heap_free(analysis
->logical2visual
);
2102 heap_free(analysis
);
2106 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2108 if (pva
[glyph
].fClusterStart
)
2110 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2117 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2128 StringAnalysis
*analysis
;
2131 COLORREF BkColor
= 0x0;
2132 COLORREF TextColor
= 0x0;
2134 INT runStart
, runEnd
;
2135 INT iGlyph
, cGlyphs
;
2136 HFONT oldFont
= 0x0;
2140 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2141 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2143 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2145 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2146 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2152 BkMode
= GetBkMode(analysis
->hdc
);
2153 SetBkMode( analysis
->hdc
, OPAQUE
);
2154 BkColor
= GetBkColor(analysis
->hdc
);
2155 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2158 TextColor
= GetTextColor(analysis
->hdc
);
2159 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2162 if (analysis
->glyphs
[iItem
].fallbackFont
)
2163 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2165 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2166 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2169 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2170 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2172 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2174 if (analysis
->pItem
[iItem
].a
.fRTL
)
2176 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2177 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2179 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2180 crc
.left
= iX
+ off_x
;
2184 if (cStart
>=0 && runStart
)
2185 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2187 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2188 crc
.left
= iX
+ off_x
;
2191 if (analysis
->pItem
[iItem
].a
.fRTL
)
2192 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2194 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2196 if (analysis
->pItem
[iItem
].a
.fRTL
)
2197 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2199 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2203 /* adjust for cluster glyphs when starting */
2204 if (analysis
->pItem
[iItem
].a
.fRTL
)
2205 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2207 i
= analysis
->pItem
[iItem
].iCharPos
;
2209 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2211 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2213 if (analysis
->pItem
[iItem
].a
.fRTL
)
2214 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2216 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2221 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2226 clust_glyph
= iGlyph
+ cGlyphs
;
2227 if (analysis
->pItem
[iItem
].a
.fRTL
)
2232 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2233 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2240 hr
= ScriptTextOut(analysis
->hdc
,
2241 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2242 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2243 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2244 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2245 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2247 TRACE("ScriptTextOut hr=%08x\n", hr
);
2251 SetBkColor(analysis
->hdc
, BkColor
);
2252 SetBkMode( analysis
->hdc
, BkMode
);
2254 SetTextColor(analysis
->hdc
, TextColor
);
2256 if (analysis
->glyphs
[iItem
].fallbackFont
)
2257 SelectObject(analysis
->hdc
, oldFont
);
2262 /***********************************************************************
2263 * ScriptStringOut (USP10.@)
2265 * This function takes the output of ScriptStringAnalyse and joins the segments
2266 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2267 * only processes glyphs.
2270 * ssa [I] buffer to hold the analysed string components
2271 * iX [I] X axis displacement for output
2272 * iY [I] Y axis displacement for output
2273 * uOptions [I] flags controlling output processing
2274 * prc [I] rectangle coordinates
2275 * iMinSel [I] starting pos for substringing output string
2276 * iMaxSel [I] ending pos for substringing output string
2277 * fDisabled [I] controls text highlighting
2281 * Failure: is the value returned by ScriptTextOut
2283 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2292 StringAnalysis
*analysis
;
2296 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2297 ssa
, iX
, iY
, uOptions
, wine_dbgstr_rect(prc
), iMinSel
, iMaxSel
, fDisabled
);
2299 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2300 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2302 for (item
= 0; item
< analysis
->numItems
; item
++)
2304 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2309 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2311 if (iMaxSel
> 0 && iMinSel
< 0)
2313 for (item
= 0; item
< analysis
->numItems
; item
++)
2315 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2324 /***********************************************************************
2325 * ScriptStringCPtoX (USP10.@)
2328 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2332 StringAnalysis
* analysis
= ssa
;
2334 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2336 if (!ssa
|| !pX
) return S_FALSE
;
2337 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2339 /* icp out of range */
2342 analysis
->invalid
= TRUE
;
2343 return E_INVALIDARG
;
2346 for(item
=0; item
<analysis
->numItems
; item
++)
2351 i
= analysis
->logical2visual
[item
];
2352 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2353 /* initialize max extents for uninitialized runs */
2354 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2356 if (analysis
->pItem
[i
].a
.fRTL
)
2357 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2358 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2359 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2361 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2362 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2363 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2366 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2368 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2372 icp
-= analysis
->pItem
[i
].iCharPos
;
2373 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2374 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2375 &analysis
->pItem
[i
].a
, &offset
);
2382 /* icp out of range */
2383 analysis
->invalid
= TRUE
;
2384 return E_INVALIDARG
;
2387 /***********************************************************************
2388 * ScriptStringXtoCP (USP10.@)
2391 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2393 StringAnalysis
* analysis
= ssa
;
2396 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2398 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2399 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2404 if (analysis
->pItem
[0].a
.fRTL
)
2407 *piTrailing
= FALSE
;
2417 for(item
=0; item
<analysis
->numItems
; item
++)
2422 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2425 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2426 /* initialize max extents for uninitialized runs */
2427 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2429 if (analysis
->pItem
[i
].a
.fRTL
)
2430 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2431 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2432 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2434 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2435 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2436 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2439 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2441 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2445 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2446 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2447 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2448 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2454 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2455 *piTrailing
= FALSE
;
2461 /***********************************************************************
2462 * ScriptStringFree (USP10.@)
2464 * Free a string analysis.
2467 * pssa [I] string analysis.
2471 * Failure: Non-zero HRESULT value.
2473 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2475 StringAnalysis
* analysis
;
2479 TRACE("(%p)\n", pssa
);
2481 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2483 invalid
= analysis
->invalid
;
2485 if (analysis
->glyphs
)
2487 for (i
= 0; i
< analysis
->numItems
; i
++)
2489 heap_free(analysis
->glyphs
[i
].glyphs
);
2490 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2491 heap_free(analysis
->glyphs
[i
].piAdvance
);
2492 heap_free(analysis
->glyphs
[i
].psva
);
2493 heap_free(analysis
->glyphs
[i
].pGoffset
);
2494 heap_free(analysis
->glyphs
[i
].abc
);
2495 if (analysis
->glyphs
[i
].fallbackFont
)
2496 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2497 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2498 heap_free(analysis
->glyphs
[i
].sc
);
2500 heap_free(analysis
->glyphs
);
2503 heap_free(analysis
->pItem
);
2504 heap_free(analysis
->logattrs
);
2505 heap_free(analysis
->sz
);
2506 heap_free(analysis
->logical2visual
);
2507 heap_free(analysis
);
2509 if (invalid
) return E_INVALIDARG
;
2513 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2514 int direction
, int* iCluster
, int *check_out
)
2518 WORD clust
= pwLogClust
[item
];
2520 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2522 if (pwLogClust
[check
] == clust
)
2525 if (iCluster
&& *iCluster
== -1)
2537 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
)
2542 advance
= piAdvance
[glyph
];
2544 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2545 log_clust_max
= pwLogClust
[0];
2547 log_clust_max
= pwLogClust
[cChars
-1];
2549 if (glyph
> log_clust_max
)
2552 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2555 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2557 if (glyph
> log_clust_max
)
2559 advance
+= piAdvance
[glyph
];
2565 /***********************************************************************
2566 * ScriptCPtoX (USP10.@)
2569 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2573 const WORD
*pwLogClust
,
2574 const SCRIPT_VISATTR
*psva
,
2575 const int *piAdvance
,
2576 const SCRIPT_ANALYSIS
*psa
,
2584 float special_size
= 0.0;
2589 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2590 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2593 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2601 int max_clust
= pwLogClust
[0];
2603 for (item
=0; item
< cGlyphs
; item
++)
2604 if (pwLogClust
[item
] > max_clust
)
2606 ERR("We do not handle non reversed clusters properly\n");
2611 for (item
= max_clust
; item
>=0; item
--)
2612 iMaxPos
+= piAdvance
[item
];
2616 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2618 if (iSpecial
== -1 && (iCluster
== -1 || (iCluster
!= -1 && iCluster
+clust_size
<= item
)))
2621 int clust
= pwLogClust
[item
];
2624 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2627 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2629 if (check
>= cChars
&& !iMaxPos
)
2632 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2633 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2635 special_size
/= (cChars
- item
);
2636 iPosX
+= special_size
;
2640 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2643 if (clust_size
== 0)
2647 iPosX
+= advance
/ (float)clust_size
;
2650 else if (iSpecial
!= -1)
2651 iPosX
+= special_size
;
2652 else /* (iCluster != -1) */
2654 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2655 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2658 if (clust_size
== 0)
2662 iPosX
+= adv
/ (float)clust_size
;
2668 iPosX
= iMaxPos
- iPosX
;
2674 TRACE("*piX=%d\n", *piX
);
2678 /* Count the number of characters in a cluster and its starting index*/
2679 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2684 for (i
= 0; i
< cChars
; i
++)
2686 if (pwLogClust
[i
] == cluster_index
)
2688 if (!size
&& start_index
)
2696 else if (size
) break;
2699 *cluster_size
= size
;
2705 To handle multi-glyph clusters we need to find all the glyphs that are
2706 represented in the cluster. This involves finding the glyph whose
2707 index is the cluster index as well as whose glyph indices are greater than
2708 our cluster index but not part of a new cluster.
2710 Then we sum all those glyphs' advances.
2712 static inline int get_cluster_advance(const int* piAdvance
,
2713 const SCRIPT_VISATTR
*psva
,
2714 const WORD
*pwLogClust
, int cGlyphs
,
2715 int cChars
, int cluster
, int direction
)
2726 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2728 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2729 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2730 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2735 glyph_end
= cGlyphs
;
2738 /* Don't fully understand multi-glyph reversed clusters yet,
2739 * do they occur for real or just in our test? */
2740 FIXME("multi-glyph reversed clusters found\n");
2741 glyph_end
= glyph_start
+ 1;
2745 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2746 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2748 if (psva
[i
].fClusterStart
)
2755 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2756 advance
+= piAdvance
[i
];
2762 /***********************************************************************
2763 * ScriptXtoCP (USP10.@)
2766 * Use piAdvance to find the cluster we are looking at.
2767 * Find the character that is the first character of the cluster.
2768 * That is our base piCP.
2769 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2770 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2771 * determine how far through the cluster to advance the cursor.
2773 HRESULT WINAPI
ScriptXtoCP(int iX
,
2776 const WORD
*pwLogClust
,
2777 const SCRIPT_VISATTR
*psva
,
2778 const int *piAdvance
,
2779 const SCRIPT_ANALYSIS
*psa
,
2786 int glyph_index
, cluster_index
;
2789 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2790 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2791 psa
, piCP
, piTrailing
);
2793 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2796 /* Handle an iX < 0 */
2812 /* Looking for non-reversed clusters in a reversed string */
2815 int max_clust
= pwLogClust
[0];
2816 for (i
=0; i
< cChars
; i
++)
2817 if (pwLogClust
[i
] > max_clust
)
2819 FIXME("We do not handle non reversed clusters properly\n");
2824 /* find the glyph_index based in iX */
2827 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2832 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2836 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2839 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2841 /* find the cluster */
2843 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2846 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2849 TRACE("cluster_index %i\n", cluster_index
);
2851 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2853 /* We are off the end of the string */
2859 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2861 TRACE("first char index %i\n",i
);
2862 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2864 /* Check trailing */
2865 if (glyph_index
!= cluster_index
||
2866 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2867 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2868 *piTrailing
= cluster_size
;
2872 if (cluster_size
> 1)
2874 /* Be part way through the glyph cluster based on size and position */
2875 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2876 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2880 /* back up to the beginning of the cluster */
2881 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2882 adv
+= piAdvance
[part_index
];
2883 if (adv
> iX
) adv
= iX
;
2885 TRACE("Multi-char cluster, no snap\n");
2886 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2887 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2890 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2892 if (part_index
) part_index
--;
2896 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2898 if (part_index
> cluster_size
)
2900 adv
+= cluster_part_width
;
2901 part_index
=cluster_size
;
2905 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2910 i
+= (cluster_size
- part_index
);
2912 /* Check trailing */
2913 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2914 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2919 /* Check trailing */
2920 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2921 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2928 TRACE("Point falls outside of string\n");
2929 if (glyph_index
< 0)
2931 else /* (glyph_index >= cGlyphs) */
2934 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2935 point flow to the next character */
2938 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
2947 TRACE("*piCP=%d\n", *piCP
);
2948 TRACE("*piTrailing=%d\n", *piTrailing
);
2952 /***********************************************************************
2953 * ScriptBreak (USP10.@)
2955 * Retrieve line break information.
2958 * chars [I] Array of characters.
2959 * sa [I] Script analysis.
2960 * la [I] Array of logical attribute structures.
2966 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
2968 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
2970 if (count
< 0 || !la
) return E_INVALIDARG
;
2971 if (count
== 0) return E_FAIL
;
2973 BREAK_line(chars
, count
, sa
, la
);
2978 /***********************************************************************
2979 * ScriptIsComplex (USP10.@)
2981 * Determine if a string is complex.
2984 * chars [I] Array of characters to test.
2985 * len [I] Length in characters.
2993 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
2998 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
3000 for (i
= 0; i
< len
; i
+=consumed
)
3006 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3009 script
= get_char_script(chars
,i
,len
, &consumed
);
3010 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3011 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3017 /***********************************************************************
3018 * ScriptShapeOpenType (USP10.@)
3020 * Produce glyphs and visual attributes for a run.
3023 * hdc [I] Device context.
3024 * psc [I/O] Opaque pointer to a script cache.
3025 * psa [I/O] Script analysis.
3026 * tagScript [I] The OpenType tag for the Script
3027 * tagLangSys [I] The OpenType tag for the Language
3028 * rcRangeChars[I] Array of Character counts in each range
3029 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3030 * cRanges [I] Count of ranges
3031 * pwcChars [I] Array of characters specifying the run.
3032 * cChars [I] Number of characters in pwcChars.
3033 * cMaxGlyphs [I] Length of pwOutGlyphs.
3034 * pwLogClust [O] Array of logical cluster info.
3035 * pCharProps [O] Array of character property values
3036 * pwOutGlyphs [O] Array of glyphs.
3037 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3038 * pcGlyphs [O] Number of glyphs returned.
3042 * Failure: Non-zero HRESULT value.
3044 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3045 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3046 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3047 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3048 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3049 int cMaxGlyphs
, WORD
*pwLogClust
,
3050 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3051 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3058 static int once
= 0;
3060 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3062 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3063 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3064 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3066 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3067 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3069 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3070 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3073 if(!once
++) FIXME("Ranges not supported yet\n");
3075 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3078 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3079 if (!pwLogClust
) return E_FAIL
;
3081 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3082 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3084 /* set fNoGlyphIndex non truetype/opentype fonts */
3085 if (psa
&& !psa
->fNoGlyphIndex
&& !((ScriptCache
*)*psc
)->sfnt
)
3086 psa
->fNoGlyphIndex
= TRUE
;
3088 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3089 for (i
= 0; i
< cChars
; i
++)
3092 if (rtl
) idx
= cChars
- 1 - i
;
3093 /* FIXME: set to better values */
3094 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3095 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3096 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3097 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3098 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3099 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3101 /* FIXME: have the shaping engine set this */
3102 pCharProps
[i
].fCanGlyphAlone
= 0;
3104 pwLogClust
[i
] = idx
;
3107 if (psa
&& !psa
->fNoGlyphIndex
)
3110 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3112 rChars
= heap_alloc(sizeof(WCHAR
) * cChars
);
3113 if (!rChars
) return E_OUTOFMEMORY
;
3114 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3119 if (rtl
) idx
= cChars
- 1 - i
;
3122 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3126 chInput
= mirror_char(pwcChars
[idx
]);
3128 chInput
= pwcChars
[idx
];
3129 /* special case for tabs */
3130 if (chInput
== 0x0009)
3132 rChars
[i
] = chInput
;
3136 rChars
[i
] = pwcChars
[idx
];
3137 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3140 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3148 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3153 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3161 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3162 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3168 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3169 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3170 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3175 TRACE("no glyph translation\n");
3176 for (i
= 0; i
< cChars
; i
++)
3179 /* No mirroring done here */
3180 if (rtl
) idx
= cChars
- 1 - i
;
3181 pwOutGlyphs
[i
] = pwcChars
[idx
];
3183 /* overwrite some basic control glyphs to blank */
3184 if (psa
&& psa
->eScript
== Script_Control
&&
3185 pwcChars
[idx
] < ((ScriptCache
*)*psc
)->tm
.tmFirstChar
)
3187 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3188 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3189 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3198 /***********************************************************************
3199 * ScriptShape (USP10.@)
3201 * Produce glyphs and visual attributes for a run.
3204 * hdc [I] Device context.
3205 * psc [I/O] Opaque pointer to a script cache.
3206 * pwcChars [I] Array of characters specifying the run.
3207 * cChars [I] Number of characters in pwcChars.
3208 * cMaxGlyphs [I] Length of pwOutGlyphs.
3209 * psa [I/O] Script analysis.
3210 * pwOutGlyphs [O] Array of glyphs.
3211 * pwLogClust [O] Array of logical cluster info.
3212 * psva [O] Array of visual attributes.
3213 * pcGlyphs [O] Number of glyphs returned.
3217 * Failure: Non-zero HRESULT value.
3219 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3220 int cChars
, int cMaxGlyphs
,
3221 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3222 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3226 SCRIPT_CHARPROP
*charProps
;
3227 SCRIPT_GLYPHPROP
*glyphProps
;
3229 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3230 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3232 charProps
= heap_alloc_zero(sizeof(SCRIPT_CHARPROP
)*cChars
);
3233 if (!charProps
) return E_OUTOFMEMORY
;
3234 glyphProps
= heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP
)*cMaxGlyphs
);
3237 heap_free(charProps
);
3238 return E_OUTOFMEMORY
;
3241 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3245 for (i
= 0; i
< *pcGlyphs
; i
++)
3246 psva
[i
] = glyphProps
[i
].sva
;
3249 heap_free(charProps
);
3250 heap_free(glyphProps
);
3255 /***********************************************************************
3256 * ScriptPlaceOpenType (USP10.@)
3258 * Produce advance widths for a run.
3261 * hdc [I] Device context.
3262 * psc [I/O] Opaque pointer to a script cache.
3263 * psa [I/O] Script analysis.
3264 * tagScript [I] The OpenType tag for the Script
3265 * tagLangSys [I] The OpenType tag for the Language
3266 * rcRangeChars[I] Array of Character counts in each range
3267 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3268 * cRanges [I] Count of ranges
3269 * pwcChars [I] Array of characters specifying the run.
3270 * pwLogClust [I] Array of logical cluster info
3271 * pCharProps [I] Array of character property values
3272 * cChars [I] Number of characters in pwcChars.
3273 * pwGlyphs [I] Array of glyphs.
3274 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3275 * cGlyphs [I] Count of Glyphs
3276 * piAdvance [O] Array of advance widths.
3277 * pGoffset [O] Glyph offsets.
3278 * pABC [O] Combined ABC width.
3282 * Failure: Non-zero HRESULT value.
3285 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3286 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3287 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3288 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3289 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3290 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3291 int cGlyphs
, int *piAdvance
,
3292 GOFFSET
*pGoffset
, ABC
*pABC
3297 static int once
= 0;
3299 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3301 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3302 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3303 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3306 if (!pGlyphProps
) return E_INVALIDARG
;
3307 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3308 if (!pGoffset
) return E_FAIL
;
3311 if (!once
++) FIXME("Ranges not supported yet\n");
3313 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3314 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3316 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3317 for (i
= 0; i
< cGlyphs
; i
++)
3320 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3322 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3324 else if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3326 if (!hdc
) return E_PENDING
;
3327 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
) && !psa
->fNoGlyphIndex
)
3329 if (!GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
)) return S_FALSE
;
3334 if (!GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
)) return S_FALSE
;
3336 abc
.abcA
= abc
.abcC
= 0;
3338 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3342 pABC
->abcA
+= abc
.abcA
;
3343 pABC
->abcB
+= abc
.abcB
;
3344 pABC
->abcC
+= abc
.abcC
;
3346 /* FIXME: set to more reasonable values */
3347 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3348 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3351 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3353 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3357 /***********************************************************************
3358 * ScriptPlace (USP10.@)
3360 * Produce advance widths for a run.
3363 * hdc [I] Device context.
3364 * psc [I/O] Opaque pointer to a script cache.
3365 * pwGlyphs [I] Array of glyphs.
3366 * cGlyphs [I] Number of glyphs in pwGlyphs.
3367 * psva [I] Array of visual attributes.
3368 * psa [I/O] String analysis.
3369 * piAdvance [O] Array of advance widths.
3370 * pGoffset [O] Glyph offsets.
3371 * pABC [O] Combined ABC width.
3375 * Failure: Non-zero HRESULT value.
3377 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3378 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3379 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3382 SCRIPT_GLYPHPROP
*glyphProps
;
3385 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3386 piAdvance
, pGoffset
, pABC
);
3388 if (!psva
) return E_INVALIDARG
;
3389 if (!pGoffset
) return E_FAIL
;
3391 glyphProps
= heap_alloc(sizeof(SCRIPT_GLYPHPROP
)*cGlyphs
);
3392 if (!glyphProps
) return E_OUTOFMEMORY
;
3394 for (i
= 0; i
< cGlyphs
; i
++)
3395 glyphProps
[i
].sva
= psva
[i
];
3397 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3399 heap_free(glyphProps
);
3404 /***********************************************************************
3405 * ScriptGetCMap (USP10.@)
3407 * Retrieve glyph indices.
3410 * hdc [I] Device context.
3411 * psc [I/O] Opaque pointer to a script cache.
3412 * pwcInChars [I] Array of Unicode characters.
3413 * cChars [I] Number of characters in pwcInChars.
3414 * dwFlags [I] Flags.
3415 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3419 * Failure: Non-zero HRESULT value.
3421 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3422 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3427 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3428 cChars
, dwFlags
, pwOutGlyphs
);
3430 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3434 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3436 for (i
= 0; i
< cChars
; i
++)
3439 if (dwFlags
== SGCM_RTL
)
3440 inChar
= mirror_char(pwcInChars
[i
]);
3442 inChar
= pwcInChars
[i
];
3443 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3446 if (!hdc
) return E_PENDING
;
3447 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3448 if (glyph
== 0xffff)
3453 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3459 TRACE("no glyph translation\n");
3460 for (i
= 0; i
< cChars
; i
++)
3463 if (dwFlags
== SGCM_RTL
)
3464 inChar
= mirror_char(pwcInChars
[i
]);
3466 inChar
= pwcInChars
[i
];
3467 pwOutGlyphs
[i
] = inChar
;
3473 /***********************************************************************
3474 * ScriptTextOut (USP10.@)
3477 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3478 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3479 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3480 const int *piJustify
, const GOFFSET
*pGoffset
)
3485 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3487 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3488 hdc
, psc
, x
, y
, fuOptions
, wine_dbgstr_rect(lprc
), psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3489 piAdvance
, piJustify
, pGoffset
);
3491 if (!hdc
|| !psc
) return E_INVALIDARG
;
3492 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3494 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3495 fuOptions
|= ETO_IGNORELANGUAGE
;
3496 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3497 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3499 lpDx
= heap_alloc(cGlyphs
* sizeof(INT
) * 2);
3500 if (!lpDx
) return E_OUTOFMEMORY
;
3501 fuOptions
|= ETO_PDY
;
3503 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3505 reordered_glyphs
= heap_alloc( cGlyphs
* sizeof(WORD
) );
3506 if (!reordered_glyphs
)
3509 return E_OUTOFMEMORY
;
3512 for (i
= 0; i
< cGlyphs
; i
++)
3513 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3517 for (i
= 0; i
< cGlyphs
; i
++)
3519 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3520 lpDx
[i
* 2] = piAdvance
[orig_index
];
3521 lpDx
[i
* 2 + 1] = 0;
3527 x
+= pGoffset
[orig_index
].du
* dir
;
3528 y
+= pGoffset
[orig_index
].dv
;
3532 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3533 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3535 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3536 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3540 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3543 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3549 /***********************************************************************
3550 * ScriptCacheGetHeight (USP10.@)
3552 * Retrieve the height of the font in the cache.
3555 * hdc [I] Device context.
3556 * psc [I/O] Opaque pointer to a script cache.
3557 * height [O] Receives font height.
3561 * Failure: Non-zero HRESULT value.
3563 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3567 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3569 if (!height
) return E_INVALIDARG
;
3570 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3572 *height
= get_cache_height(psc
);
3576 /***********************************************************************
3577 * ScriptGetGlyphABCWidth (USP10.@)
3579 * Retrieve the width of a glyph.
3582 * hdc [I] Device context.
3583 * psc [I/O] Opaque pointer to a script cache.
3584 * glyph [I] Glyph to retrieve the width for.
3585 * abc [O] ABC widths of the glyph.
3589 * Failure: Non-zero HRESULT value.
3591 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3595 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3597 if (!abc
) return E_INVALIDARG
;
3598 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3600 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3602 if (!hdc
) return E_PENDING
;
3603 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3605 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3610 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3612 abc
->abcA
= abc
->abcC
= 0;
3614 set_cache_glyph_widths(psc
, glyph
, abc
);
3619 /***********************************************************************
3620 * ScriptLayout (USP10.@)
3622 * Map embedding levels to visual and/or logical order.
3625 * runs [I] Size of level array.
3626 * level [I] Array of embedding levels.
3627 * vistolog [O] Map of embedding levels from visual to logical order.
3628 * logtovis [O] Map of embedding levels from logical to visual order.
3632 * Failure: Non-zero HRESULT value.
3635 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3640 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3642 if (!level
|| (!vistolog
&& !logtovis
))
3643 return E_INVALIDARG
;
3645 indexs
= heap_alloc(sizeof(int) * runs
);
3647 return E_OUTOFMEMORY
;
3651 for( ich
= 0; ich
< runs
; ich
++)
3656 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3657 memcpy(vistolog
, indexs
, runs
* sizeof(*vistolog
));
3662 for( ich
= 0; ich
< runs
; ich
++)
3667 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3668 memcpy(logtovis
, indexs
, runs
* sizeof(*logtovis
));
3675 /***********************************************************************
3676 * ScriptStringGetLogicalWidths (USP10.@)
3678 * Returns logical widths from a string analysis.
3681 * ssa [I] string analysis.
3682 * piDx [O] logical widths returned.
3686 * Failure: a non-zero HRESULT.
3688 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3691 StringAnalysis
*analysis
= ssa
;
3693 TRACE("%p, %p\n", ssa
, piDx
);
3695 if (!analysis
) return S_FALSE
;
3696 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3698 for (i
= 0; i
< analysis
->numItems
; i
++)
3700 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3703 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3706 for (j
= 0; j
< cChar
; j
++)
3709 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3710 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3711 cChar
, j
, direction
, NULL
, NULL
);
3712 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
);
3714 for (k
= 0; k
< clust_size
; k
++)
3716 piDx
[next
] = advance
/ clust_size
;
3725 /***********************************************************************
3726 * ScriptStringValidate (USP10.@)
3728 * Validate a string analysis.
3731 * ssa [I] string analysis.
3735 * Failure: S_FALSE if invalid sequences are found
3736 * or a non-zero HRESULT if it fails.
3738 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3740 StringAnalysis
*analysis
= ssa
;
3742 TRACE("(%p)\n", ssa
);
3744 if (!analysis
) return E_INVALIDARG
;
3745 return (analysis
->invalid
) ? S_FALSE
: S_OK
;
3748 /***********************************************************************
3749 * ScriptString_pSize (USP10.@)
3751 * Retrieve width and height of an analysed string.
3754 * ssa [I] string analysis.
3757 * Success: Pointer to a SIZE structure.
3760 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3763 StringAnalysis
*analysis
= ssa
;
3765 TRACE("(%p)\n", ssa
);
3767 if (!analysis
) return NULL
;
3768 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return NULL
;
3772 if (!(analysis
->sz
= heap_alloc(sizeof(SIZE
)))) return NULL
;
3773 analysis
->sz
->cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3775 analysis
->sz
->cx
= 0;
3776 for (i
= 0; i
< analysis
->numItems
; i
++)
3778 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
->cy
)
3779 analysis
->sz
->cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3780 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3781 analysis
->sz
->cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3784 return analysis
->sz
;
3787 /***********************************************************************
3788 * ScriptString_pLogAttr (USP10.@)
3790 * Retrieve logical attributes of an analysed string.
3793 * ssa [I] string analysis.
3796 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3799 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3801 StringAnalysis
*analysis
= ssa
;
3803 TRACE("(%p)\n", ssa
);
3805 if (!analysis
) return NULL
;
3806 if (!(analysis
->dwFlags
& SSA_BREAK
)) return NULL
;
3807 return analysis
->logattrs
;
3810 /***********************************************************************
3811 * ScriptString_pcOutChars (USP10.@)
3813 * Retrieve the length of a string after clipping.
3816 * ssa [I] String analysis.
3819 * Success: Pointer to the length.
3822 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3824 StringAnalysis
*analysis
= ssa
;
3826 TRACE("(%p)\n", ssa
);
3828 if (!analysis
) return NULL
;
3829 return &analysis
->clip_len
;
3832 /***********************************************************************
3833 * ScriptStringGetOrder (USP10.@)
3835 * Retrieve a glyph order map.
3838 * ssa [I] String analysis.
3839 * order [I/O] Array of glyph positions.
3843 * Failure: a non-zero HRESULT.
3845 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3849 StringAnalysis
*analysis
= ssa
;
3851 TRACE("(%p)\n", ssa
);
3853 if (!analysis
) return S_FALSE
;
3854 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3856 /* FIXME: handle RTL scripts */
3857 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3858 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3864 /***********************************************************************
3865 * ScriptGetLogicalWidths (USP10.@)
3867 * Convert advance widths to logical widths.
3870 * sa [I] Script analysis.
3871 * nbchars [I] Number of characters.
3872 * nbglyphs [I] Number of glyphs.
3873 * glyph_width [I] Array of glyph widths.
3874 * log_clust [I] Array of logical clusters.
3875 * sva [I] Visual attributes.
3876 * widths [O] Array of logical widths.
3880 * Failure: a non-zero HRESULT.
3882 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3883 const int *glyph_width
, const WORD
*log_clust
,
3884 const SCRIPT_VISATTR
*sva
, int *widths
)
3888 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3889 sa
, nbchars
, nbglyphs
, glyph_width
, log_clust
, sva
, widths
);
3892 for (i
= 0; i
< nbchars
; i
++) widths
[i
] = glyph_width
[i
];
3896 /***********************************************************************
3897 * ScriptApplyLogicalWidth (USP10.@)
3899 * Generate glyph advance widths.
3902 * dx [I] Array of logical advance widths.
3903 * num_chars [I] Number of characters.
3904 * num_glyphs [I] Number of glyphs.
3905 * log_clust [I] Array of logical clusters.
3906 * sva [I] Visual attributes.
3907 * advance [I] Array of glyph advance widths.
3908 * sa [I] Script analysis.
3909 * abc [I/O] Summed ABC widths.
3910 * justify [O] Array of glyph advance widths.
3914 * Failure: a non-zero HRESULT.
3916 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
3917 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
3918 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
3919 ABC
*abc
, int *justify
)
3923 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3924 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
3926 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
3930 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
3931 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
3935 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
3937 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
3941 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
3944 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3945 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3947 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
3950 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
3953 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3954 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3956 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
3959 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
3962 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3963 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3965 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);