2 * Implementation of Uniscribe Script Processor (usp10.dll)
4 * Copyright 2005 Steven Edwards for CodeWeavers
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * Uniscribe allows for processing of complex scripts such as joining
24 * and filtering characters and bi-directional text with custom line breaks.
39 #include "usp10_internal.h"
41 #include "wine/debug.h"
42 #include "wine/heap.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe
);
46 static const struct usp10_script_range
48 enum usp10_script script
;
51 enum usp10_script numericScript
;
52 enum usp10_script punctScript
;
56 /* Basic Latin: U+0000–U+007A */
57 { Script_Latin
, 0x00, 0x07a , Script_Numeric
, Script_Punctuation
},
58 /* Latin-1 Supplement: U+0080–U+00FF */
59 /* Latin Extended-A: U+0100–U+017F */
60 /* Latin Extended-B: U+0180–U+024F */
61 /* IPA Extensions: U+0250–U+02AF */
62 /* Spacing Modifier Letters:U+02B0–U+02FF */
63 { Script_Latin
, 0x80, 0x2ff , Script_Numeric2
, Script_Punctuation
},
64 /* Combining Diacritical Marks : U+0300–U+036F */
65 { Script_Diacritical
,0x300, 0x36f, 0, 0},
66 /* Greek: U+0370–U+03FF */
67 { Script_Greek
, 0x370, 0x3ff, 0, 0},
68 /* Cyrillic: U+0400–U+04FF */
69 /* Cyrillic Supplement: U+0500–U+052F */
70 { Script_Cyrillic
, 0x400, 0x52f, 0, 0},
71 /* Armenian: U+0530–U+058F */
72 { Script_Armenian
, 0x530, 0x58f, 0, 0},
73 /* Hebrew: U+0590–U+05FF */
74 { Script_Hebrew
, 0x590, 0x5ff, 0, 0},
75 /* Arabic: U+0600–U+06FF */
76 { Script_Arabic
, 0x600, 0x6ef, Script_Arabic_Numeric
, 0},
77 /* Defined by Windows */
78 { Script_Persian
, 0x6f0, 0x6f9, 0, 0},
79 /* Continue Arabic: U+0600–U+06FF */
80 { Script_Arabic
, 0x6fa, 0x6ff, 0, 0},
81 /* Syriac: U+0700–U+074F*/
82 { Script_Syriac
, 0x700, 0x74f, 0, 0},
83 /* Arabic Supplement: U+0750–U+077F */
84 { Script_Arabic
, 0x750, 0x77f, 0, 0},
85 /* Thaana: U+0780–U+07BF */
86 { Script_Thaana
, 0x780, 0x7bf, 0, 0},
87 /* N’Ko: U+07C0–U+07FF */
88 { Script_NKo
, 0x7c0, 0x7ff, 0, 0},
89 /* Devanagari: U+0900–U+097F */
90 { Script_Devanagari
, 0x900, 0x97f, Script_Devanagari_Numeric
, 0},
91 /* Bengali: U+0980–U+09FF */
92 { Script_Bengali
, 0x980, 0x9ff, Script_Bengali_Numeric
, 0},
93 /* Gurmukhi: U+0A00–U+0A7F*/
94 { Script_Gurmukhi
, 0xa00, 0xa7f, Script_Gurmukhi_Numeric
, 0},
95 /* Gujarati: U+0A80–U+0AFF*/
96 { Script_Gujarati
, 0xa80, 0xaff, Script_Gujarati_Numeric
, 0},
97 /* Oriya: U+0B00–U+0B7F */
98 { Script_Oriya
, 0xb00, 0xb7f, Script_Oriya_Numeric
, 0},
99 /* Tamil: U+0B80–U+0BFF */
100 { Script_Tamil
, 0xb80, 0xbff, Script_Tamil_Numeric
, 0},
101 /* Telugu: U+0C00–U+0C7F */
102 { Script_Telugu
, 0xc00, 0xc7f, Script_Telugu_Numeric
, 0},
103 /* Kannada: U+0C80–U+0CFF */
104 { Script_Kannada
, 0xc80, 0xcff, Script_Kannada_Numeric
, 0},
105 /* Malayalam: U+0D00–U+0D7F */
106 { Script_Malayalam
, 0xd00, 0xd7f, Script_Malayalam_Numeric
, 0},
107 /* Sinhala: U+0D80–U+0DFF */
108 { Script_Sinhala
, 0xd80, 0xdff, 0, 0},
109 /* Thai: U+0E00–U+0E7F */
110 { Script_Thai
, 0xe00, 0xe7f, Script_Thai_Numeric
, 0},
111 /* Lao: U+0E80–U+0EFF */
112 { Script_Lao
, 0xe80, 0xeff, Script_Lao_Numeric
, 0},
113 /* Tibetan: U+0F00–U+0FFF */
114 { Script_Tibetan
, 0xf00, 0xfff, 0, 0},
115 /* Myanmar: U+1000–U+109F */
116 { Script_Myanmar
, 0x1000, 0x109f, Script_Myanmar_Numeric
, 0},
117 /* Georgian: U+10A0–U+10FF */
118 { Script_Georgian
, 0x10a0, 0x10ff, 0, 0},
119 /* Hangul Jamo: U+1100–U+11FF */
120 { Script_Hangul
, 0x1100, 0x11ff, 0, 0},
121 /* Ethiopic: U+1200–U+137F */
122 /* Ethiopic Extensions: U+1380–U+139F */
123 { Script_Ethiopic
, 0x1200, 0x139f, 0, 0},
124 /* Cherokee: U+13A0–U+13FF */
125 { Script_Cherokee
, 0x13a0, 0x13ff, 0, 0},
126 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
127 { Script_Canadian
, 0x1400, 0x167f, 0, 0},
128 /* Ogham: U+1680–U+169F */
129 { Script_Ogham
, 0x1680, 0x169f, 0, 0},
130 /* Runic: U+16A0–U+16F0 */
131 { Script_Runic
, 0x16a0, 0x16f0, 0, 0},
132 /* Khmer: U+1780–U+17FF */
133 { Script_Khmer
, 0x1780, 0x17ff, Script_Khmer_Numeric
, 0},
134 /* Mongolian: U+1800–U+18AF */
135 { Script_Mongolian
, 0x1800, 0x18af, Script_Mongolian_Numeric
, 0},
136 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
137 { Script_Canadian
, 0x18b0, 0x18ff, 0, 0},
138 /* Tai Le: U+1950–U+197F */
139 { Script_Tai_Le
, 0x1950, 0x197f, 0, 0},
140 /* New Tai Lue: U+1980–U+19DF */
141 { Script_New_Tai_Lue
,0x1980, 0x19df, Script_New_Tai_Lue_Numeric
, 0},
142 /* Khmer Symbols: U+19E0–U+19FF */
143 { Script_Khmer
, 0x19e0, 0x19ff, Script_Khmer_Numeric
, 0},
144 /* Vedic Extensions: U+1CD0-U+1CFF */
145 { Script_Devanagari
, 0x1cd0, 0x1cff, Script_Devanagari_Numeric
, 0},
146 /* Phonetic Extensions: U+1D00–U+1DBF */
147 { Script_Latin
, 0x1d00, 0x1dbf, 0, 0},
148 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
149 { Script_Diacritical
,0x1dc0, 0x1dff, 0, 0},
150 /* Latin Extended Additional: U+1E00–U+1EFF */
151 { Script_Latin
, 0x1e00, 0x1eff, 0, 0},
152 /* Greek Extended: U+1F00–U+1FFF */
153 { Script_Greek
, 0x1f00, 0x1fff, 0, 0},
154 /* General Punctuation: U+2000 –U+206f */
155 { Script_Latin
, 0x2000, 0x206f, 0, 0},
156 /* Superscripts and Subscripts : U+2070 –U+209f */
157 /* Currency Symbols : U+20a0 –U+20cf */
158 { Script_Numeric2
, 0x2070, 0x2070, 0, 0},
159 { Script_Latin
, 0x2071, 0x2073, 0, 0},
160 { Script_Numeric2
, 0x2074, 0x2079, 0, 0},
161 { Script_Latin
, 0x207a, 0x207f, 0, 0},
162 { Script_Numeric2
, 0x2080, 0x2089, 0, 0},
163 { Script_Latin
, 0x208a, 0x20cf, 0, 0},
164 /* Letterlike Symbols : U+2100 –U+214f */
165 /* Number Forms : U+2150 –U+218f */
166 /* Arrows : U+2190 –U+21ff */
167 /* Mathematical Operators : U+2200 –U+22ff */
168 /* Miscellaneous Technical : U+2300 –U+23ff */
169 /* Control Pictures : U+2400 –U+243f */
170 /* Optical Character Recognition : U+2440 –U+245f */
171 /* Enclosed Alphanumerics : U+2460 –U+24ff */
172 /* Box Drawing : U+2500 –U+257f */
173 /* Block Elements : U+2580 –U+259f */
174 /* Geometric Shapes : U+25a0 –U+25ff */
175 /* Miscellaneous Symbols : U+2600 –U+26ff */
176 /* Dingbats : U+2700 –U+27bf */
177 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
178 /* Supplemental Arrows-A : U+27f0 –U+27ff */
179 { Script_Latin
, 0x2100, 0x27ff, 0, 0},
180 /* Braille Patterns: U+2800–U+28FF */
181 { Script_Braille
, 0x2800, 0x28ff, 0, 0},
182 /* Supplemental Arrows-B : U+2900 –U+297f */
183 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
184 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
185 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
186 { Script_Latin
, 0x2900, 0x2bff, 0, 0},
187 /* Latin Extended-C: U+2C60–U+2C7F */
188 { Script_Latin
, 0x2c60, 0x2c7f, 0, 0},
189 /* Georgian: U+2D00–U+2D2F */
190 { Script_Georgian
, 0x2d00, 0x2d2f, 0, 0},
191 /* Tifinagh: U+2D30–U+2D7F */
192 { Script_Tifinagh
, 0x2d30, 0x2d7f, 0, 0},
193 /* Ethiopic Extensions: U+2D80–U+2DDF */
194 { Script_Ethiopic
, 0x2d80, 0x2ddf, 0, 0},
195 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
196 { Script_Cyrillic
, 0x2de0, 0x2dff, 0, 0},
197 /* CJK Radicals Supplement: U+2E80–U+2EFF */
198 /* Kangxi Radicals: U+2F00–U+2FDF */
199 { Script_CJK_Han
, 0x2e80, 0x2fdf, 0, 0},
200 /* Ideographic Description Characters: U+2FF0–U+2FFF */
201 { Script_Ideograph
,0x2ff0, 0x2fff, 0, 0},
202 /* CJK Symbols and Punctuation: U+3000–U+303F */
203 { Script_Ideograph
,0x3000, 0x3004, 0, 0},
204 { Script_CJK_Han
,0x3005, 0x3005, 0, 0},
205 { Script_Ideograph
,0x3006, 0x3006, 0, 0},
206 { Script_CJK_Han
,0x3007, 0x3007, 0, 0},
207 { Script_Ideograph
,0x3008, 0x3020, 0, 0},
208 { Script_CJK_Han
,0x3021, 0x3029, 0, 0},
209 { Script_Ideograph
,0x302a, 0x3030, 0, 0},
211 { Script_Kana
,0x3031, 0x3035, 0, 0},
212 { Script_Ideograph
,0x3036, 0x3037, 0, 0},
213 { Script_CJK_Han
,0x3038, 0x303b, 0, 0},
214 { Script_Ideograph
,0x303c, 0x303f, 0, 0},
215 /* Hiragana: U+3040–U+309F */
216 /* Katakana: U+30A0–U+30FF */
217 { Script_Kana
,0x3040, 0x30ff, 0, 0},
218 /* Bopomofo: U+3100–U+312F */
219 { Script_Bopomofo
,0x3100, 0x312f, 0, 0},
220 /* Hangul Compatibility Jamo: U+3130–U+318F */
221 { Script_Hangul
,0x3130, 0x318f, 0, 0},
222 /* Kanbun: U+3190–U+319F */
223 { Script_Ideograph
,0x3190, 0x319f, 0, 0},
224 /* Bopomofo Extended: U+31A0–U+31BF */
225 { Script_Bopomofo
,0x31a0, 0x31bf, 0, 0},
226 /* CJK Strokes: U+31C0–U+31EF */
227 { Script_Ideograph
,0x31c0, 0x31ef, 0, 0},
228 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
229 { Script_Kana
,0x31f0, 0x31ff, 0, 0},
230 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
231 { Script_Hangul
,0x3200, 0x321f, 0, 0},
232 { Script_Ideograph
,0x3220, 0x325f, 0, 0},
233 { Script_Hangul
,0x3260, 0x327f, 0, 0},
234 { Script_Ideograph
,0x3280, 0x32ef, 0, 0},
235 { Script_Kana
,0x32d0, 0x31ff, 0, 0},
236 /* CJK Compatibility: U+3300–U+33FF*/
237 { Script_Kana
,0x3300, 0x3357, 0, 0},
238 { Script_Ideograph
,0x3358, 0x33ff, 0, 0},
239 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
240 { Script_CJK_Han
,0x3400, 0x4dbf, 0, 0},
241 /* CJK Unified Ideographs: U+4E00–U+9FFF */
242 { Script_CJK_Han
,0x4e00, 0x9fff, 0, 0},
243 /* Yi: U+A000–U+A4CF */
244 { Script_Yi
,0xa000, 0xa4cf, 0, 0},
245 /* Vai: U+A500–U+A63F */
246 { Script_Vai
,0xa500, 0xa63f, Script_Vai_Numeric
, 0},
247 /* Cyrillic Extended-B: U+A640–U+A69F */
248 { Script_Cyrillic
, 0xa640, 0xa69f, 0, 0},
249 /* Modifier Tone Letters: U+A700–U+A71F */
250 /* Latin Extended-D: U+A720–U+A7FF */
251 { Script_Latin
, 0xa700, 0xa7ff, 0, 0},
252 /* Phags-pa: U+A840–U+A87F */
253 { Script_Phags_pa
, 0xa840, 0xa87f, 0, 0},
254 /* Devanagari Extended: U+A8E0-U+A8FF */
255 { Script_Devanagari
, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric
, 0},
256 /* Myanmar Extended-A: U+AA60–U+AA7F */
257 { Script_Myanmar
, 0xaa60, 0xaa7f, Script_Myanmar_Numeric
, 0},
258 /* Hangul Jamo Extended-A: U+A960–U+A97F */
259 { Script_Hangul
, 0xa960, 0xa97f, 0, 0},
260 /* Hangul Syllables: U+AC00–U+D7A3 */
261 { Script_Hangul
, 0xac00, 0xd7a3, 0, 0},
262 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
263 { Script_Hangul
, 0xd7b0, 0xd7ff, 0, 0},
264 /* Surrogates Area: U+D800–U+DFFF */
265 { Script_Surrogates
, 0xd800, 0xdbfe, 0, 0},
266 { Script_Private
, 0xdbff, 0xdc00, 0, 0},
267 { Script_Surrogates
, 0xdc01, 0xdfff, 0, 0},
268 /* Private Use Area: U+E000–U+F8FF */
269 { Script_Private
, 0xe000, 0xf8ff, 0, 0},
270 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
271 { Script_CJK_Han
,0xf900, 0xfaff, 0, 0},
272 /* Latin Ligatures: U+FB00–U+FB06 */
273 { Script_Latin
, 0xfb00, 0xfb06, 0, 0},
274 /* Armenian ligatures U+FB13..U+FB17 */
275 { Script_Armenian
, 0xfb13, 0xfb17, 0, 0},
276 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
277 { Script_Hebrew
, 0xfb1d, 0xfb4f, 0, 0},
278 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
279 { Script_Arabic
, 0xfb50, 0xfdff, 0, 0},
280 /* Vertical Forms: U+FE10–U+FE1F */
281 /* Combining Half Marks: U+FE20–U+FE2F */
282 /* CJK Compatibility Forms: U+FE30–U+FE4F */
283 /* Small Form Variants: U+FE50–U+FE6F */
284 { Script_Ideograph
,0xfe10, 0xfe6f, 0, 0},
285 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
286 { Script_Arabic
, 0xfe70, 0xfeff, 0, 0},
287 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
288 { Script_Ideograph
,0xff00, 0xff64, Script_Numeric2
, 0},
289 { Script_Kana
,0xff65, 0xff9f, 0, 0},
290 { Script_Hangul
,0xffa0, 0xffdf, 0, 0},
291 { Script_Ideograph
,0xffe0, 0xffef, 0, 0},
293 /* Deseret: U+10400–U+1044F */
294 { Script_Deseret
, 0x10400, 0x1044F, 0, 0},
295 /* Osmanya: U+10480–U+104AF */
296 { Script_Osmanya
, 0x10480, 0x104AF, Script_Osmanya_Numeric
, 0},
297 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
298 { Script_MathAlpha
, 0x1D400, 0x1D7FF, 0, 0},
301 /* this must be in order so that the index matches the Script value */
302 const scriptData scriptInformation
[] = {
303 {{SCRIPT_UNDEFINED
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
304 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
306 {{Script_Latin
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
307 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
308 MS_MAKE_TAG('l','a','t','n'), L
"Microsoft Sans Serif"},
309 {{Script_CR
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
310 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
312 {{Script_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
313 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
314 0x00000000, L
"Microsoft Sans Serif"},
315 {{Script_Control
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
316 {LANG_ENGLISH
, 0, 1, 0, 0, ANSI_CHARSET
, 1, 0, 0, 0, 0, 0, 1, 0, 0},
318 {{Script_Punctuation
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
319 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
320 0x00000000, L
"Microsoft Sans Serif"},
321 {{Script_Arabic
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
322 {LANG_ARABIC
, 0, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 1, 0},
323 MS_MAKE_TAG('a','r','a','b'), L
"Microsoft Sans Serif"},
324 {{Script_Arabic_Numeric
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
325 {LANG_ARABIC
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
326 MS_MAKE_TAG('a','r','a','b'), L
"Microsoft Sans Serif"},
327 {{Script_Hebrew
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
328 {LANG_HEBREW
, 0, 1, 0, 1, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
329 MS_MAKE_TAG('h','e','b','r'), L
"Microsoft Sans Serif"},
330 {{Script_Syriac
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
331 {LANG_SYRIAC
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 1, 0},
332 MS_MAKE_TAG('s','y','r','c'), L
"Estrangelo Edessa"},
333 {{Script_Persian
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
334 {LANG_PERSIAN
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
335 MS_MAKE_TAG('a','r','a','b'), L
"Microsoft Sans Serif"},
336 {{Script_Thaana
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
337 {LANG_DIVEHI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
338 MS_MAKE_TAG('t','h','a','a'), L
"MV Boli"},
339 {{Script_Greek
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
340 {LANG_GREEK
, 0, 0, 0, 0, GREEK_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
341 MS_MAKE_TAG('g','r','e','k'), L
"Microsoft Sans Serif"},
342 {{Script_Cyrillic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
343 {LANG_RUSSIAN
, 0, 0, 0, 0, RUSSIAN_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
344 MS_MAKE_TAG('c','y','r','l'), L
"Microsoft Sans Serif"},
345 {{Script_Armenian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
346 {LANG_ARMENIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
347 MS_MAKE_TAG('a','r','m','n'), L
"Sylfaen"},
348 {{Script_Georgian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
349 {LANG_GEORGIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
350 MS_MAKE_TAG('g','e','o','r'), L
"Sylfaen"},
351 {{Script_Sinhala
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
352 {LANG_SINHALESE
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
353 MS_MAKE_TAG('s','i','n','h'), L
"Iskoola Pota"},
354 {{Script_Tibetan
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
355 {LANG_TIBETAN
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
356 MS_MAKE_TAG('t','i','b','t'), L
"Microsoft Himalaya"},
357 {{Script_Tibetan_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
358 {LANG_TIBETAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
359 MS_MAKE_TAG('t','i','b','t'), L
"Microsoft Himalaya"},
360 {{Script_Phags_pa
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
361 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
362 MS_MAKE_TAG('p','h','a','g'), L
"Microsoft PhagsPa"},
363 {{Script_Thai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
364 {LANG_THAI
, 0, 1, 1, 1, THAI_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 1},
365 MS_MAKE_TAG('t','h','a','i'), L
"Microsoft Sans Serif"},
366 {{Script_Thai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
367 {LANG_THAI
, 1, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
368 MS_MAKE_TAG('t','h','a','i'), L
"Microsoft Sans Serif"},
369 {{Script_Lao
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
370 {LANG_LAO
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
371 MS_MAKE_TAG('l','a','o',' '), L
"DokChampa"},
372 {{Script_Lao_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
373 {LANG_LAO
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
374 MS_MAKE_TAG('l','a','o',' '), L
"DokChampa"},
375 {{Script_Devanagari
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
376 {LANG_HINDI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
377 MS_MAKE_TAG('d','e','v','a'), L
"Mangal"},
378 {{Script_Devanagari_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
379 {LANG_HINDI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
380 MS_MAKE_TAG('d','e','v','a'), L
"Mangal"},
381 {{Script_Bengali
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
382 {LANG_BENGALI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
383 MS_MAKE_TAG('b','e','n','g'), L
"Vrinda"},
384 {{Script_Bengali_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
385 {LANG_BENGALI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
386 MS_MAKE_TAG('b','e','n','g'), L
"Vrinda"},
387 {{Script_Bengali_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
388 {LANG_BENGALI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
389 MS_MAKE_TAG('b','e','n','g'), L
"Vrinda"},
390 {{Script_Gurmukhi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
391 {LANG_PUNJABI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
392 MS_MAKE_TAG('g','u','r','u'), L
"Raavi"},
393 {{Script_Gurmukhi_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
394 {LANG_PUNJABI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
395 MS_MAKE_TAG('g','u','r','u'), L
"Raavi"},
396 {{Script_Gujarati
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
397 {LANG_GUJARATI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
398 MS_MAKE_TAG('g','u','j','r'), L
"Shruti"},
399 {{Script_Gujarati_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
400 {LANG_GUJARATI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
401 MS_MAKE_TAG('g','u','j','r'), L
"Shruti"},
402 {{Script_Gujarati_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
403 {LANG_GUJARATI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
404 MS_MAKE_TAG('g','u','j','r'), L
"Shruti"},
405 {{Script_Oriya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
406 {LANG_ORIYA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
407 MS_MAKE_TAG('o','r','y','a'), L
"Kalinga"},
408 {{Script_Oriya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
409 {LANG_ORIYA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
410 MS_MAKE_TAG('o','r','y','a'), L
"Kalinga"},
411 {{Script_Tamil
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
412 {LANG_TAMIL
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
413 MS_MAKE_TAG('t','a','m','l'), L
"Latha"},
414 {{Script_Tamil_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
415 {LANG_TAMIL
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
416 MS_MAKE_TAG('t','a','m','l'), L
"Latha"},
417 {{Script_Telugu
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
418 {LANG_TELUGU
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
419 MS_MAKE_TAG('t','e','l','u'), L
"Gautami"},
420 {{Script_Telugu_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
421 {LANG_TELUGU
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
422 MS_MAKE_TAG('t','e','l','u'), L
"Gautami"},
423 {{Script_Kannada
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
424 {LANG_KANNADA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
425 MS_MAKE_TAG('k','n','d','a'), L
"Tunga"},
426 {{Script_Kannada_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
427 {LANG_KANNADA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
428 MS_MAKE_TAG('k','n','d','a'), L
"Tunga"},
429 {{Script_Malayalam
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
430 {LANG_MALAYALAM
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
431 MS_MAKE_TAG('m','l','y','m'), L
"Kartika"},
432 {{Script_Malayalam_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
433 {LANG_MALAYALAM
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
434 MS_MAKE_TAG('m','l','y','m'), L
"Kartika"},
435 {{Script_Diacritical
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
436 {LANG_ENGLISH
, 0, 1, 0, 1, ANSI_CHARSET
, 0, 0, 0, 0, 0, 1, 1, 0, 0},
438 {{Script_Punctuation2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
439 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
440 MS_MAKE_TAG('l','a','t','n'), L
"Microsoft Sans Serif"},
441 {{Script_Numeric2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
442 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
444 {{Script_Myanmar
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
445 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
446 MS_MAKE_TAG('m','y','m','r'), L
"Myanmar Text"},
447 {{Script_Myanmar_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
448 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
449 MS_MAKE_TAG('m','y','m','r'), L
""},
450 {{Script_Tai_Le
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
451 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
452 MS_MAKE_TAG('t','a','l','e'), L
"Microsoft Tai Le"},
453 {{Script_New_Tai_Lue
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
454 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
455 MS_MAKE_TAG('t','a','l','u'), L
"Microsoft New Tai Lue"},
456 {{Script_New_Tai_Lue_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
457 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
458 MS_MAKE_TAG('t','a','l','u'), L
"Microsoft New Tai Lue"},
459 {{Script_Khmer
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
460 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
461 MS_MAKE_TAG('k','h','m','r'), L
"DaunPenh"},
462 {{Script_Khmer_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
463 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
464 MS_MAKE_TAG('k','h','m','r'), L
"DaunPenh"},
465 {{Script_CJK_Han
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
466 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
467 MS_MAKE_TAG('h','a','n','i'), L
""},
468 {{Script_Ideograph
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
469 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
470 MS_MAKE_TAG('h','a','n','i'), L
""},
471 {{Script_Bopomofo
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
472 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
473 MS_MAKE_TAG('b','o','p','o'), L
""},
474 {{Script_Kana
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
475 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
476 MS_MAKE_TAG('k','a','n','a'), L
""},
477 {{Script_Hangul
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
478 {LANG_KOREAN
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
479 MS_MAKE_TAG('h','a','n','g'), L
""},
480 {{Script_Yi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
481 {LANG_ENGLISH
, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
482 MS_MAKE_TAG('y','i',' ',' '), L
"Microsoft Yi Baiti"},
483 {{Script_Ethiopic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
484 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
485 MS_MAKE_TAG('e','t','h','i'), L
"Nyala"},
486 {{Script_Ethiopic_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
487 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
488 MS_MAKE_TAG('e','t','h','i'), L
"Nyala"},
489 {{Script_Mongolian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
490 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
491 MS_MAKE_TAG('m','o','n','g'), L
"Mongolian Baiti"},
492 {{Script_Mongolian_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
493 {LANG_MONGOLIAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
494 MS_MAKE_TAG('m','o','n','g'), L
"Mongolian Baiti"},
495 {{Script_Tifinagh
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
496 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
497 MS_MAKE_TAG('t','f','n','g'), L
"Ebrima"},
498 {{Script_NKo
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
499 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
500 MS_MAKE_TAG('n','k','o',' '), L
"Ebrima"},
501 {{Script_Vai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
502 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
503 MS_MAKE_TAG('v','a','i',' '), L
"Ebrima"},
504 {{Script_Vai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
505 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
506 MS_MAKE_TAG('v','a','i',' '), L
"Ebrima"},
507 {{Script_Cherokee
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
508 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
509 MS_MAKE_TAG('c','h','e','r'), L
"Plantagenet Cherokee"},
510 {{Script_Canadian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
511 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
512 MS_MAKE_TAG('c','a','n','s'), L
"Euphemia"},
513 {{Script_Ogham
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
514 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
515 MS_MAKE_TAG('o','g','a','m'), L
"Segoe UI Symbol"},
516 {{Script_Runic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
517 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
518 MS_MAKE_TAG('r','u','n','r'), L
"Segoe UI Symbol"},
519 {{Script_Braille
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
520 {LANG_ENGLISH
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
521 MS_MAKE_TAG('b','r','a','i'), L
"Segoe UI Symbol"},
522 {{Script_Surrogates
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
523 {LANG_ENGLISH
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
525 {{Script_Private
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
526 {0, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 1, 0, 0, 0, 0, 1, 0, 0},
528 {{Script_Deseret
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
529 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
530 MS_MAKE_TAG('d','s','r','t'), L
"Segoe UI Symbol"},
531 {{Script_Osmanya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
532 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
533 MS_MAKE_TAG('o','s','m','a'), L
"Ebrima"},
534 {{Script_Osmanya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
535 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
536 MS_MAKE_TAG('o','s','m','a'), L
"Ebrima"},
537 {{Script_MathAlpha
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
538 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
539 MS_MAKE_TAG('m','a','t','h'), L
"Cambria Math"},
540 {{Script_Hebrew_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
541 {LANG_HEBREW
, 0, 1, 0, 0, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
542 MS_MAKE_TAG('h','e','b','r'), L
"Microsoft Sans Serif"},
543 {{Script_Vietnamese_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
544 {LANG_VIETNAMESE
, 0, 0, 0, 0, VIETNAMESE_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
545 MS_MAKE_TAG('l','a','t','n'), L
"Microsoft Sans Serif"},
546 {{Script_Thai_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
547 {LANG_THAI
, 0, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
548 MS_MAKE_TAG('t','h','a','i'), L
"Microsoft Sans Serif"},
551 static const SCRIPT_PROPERTIES
*script_props
[] =
553 &scriptInformation
[0].props
, &scriptInformation
[1].props
,
554 &scriptInformation
[2].props
, &scriptInformation
[3].props
,
555 &scriptInformation
[4].props
, &scriptInformation
[5].props
,
556 &scriptInformation
[6].props
, &scriptInformation
[7].props
,
557 &scriptInformation
[8].props
, &scriptInformation
[9].props
,
558 &scriptInformation
[10].props
, &scriptInformation
[11].props
,
559 &scriptInformation
[12].props
, &scriptInformation
[13].props
,
560 &scriptInformation
[14].props
, &scriptInformation
[15].props
,
561 &scriptInformation
[16].props
, &scriptInformation
[17].props
,
562 &scriptInformation
[18].props
, &scriptInformation
[19].props
,
563 &scriptInformation
[20].props
, &scriptInformation
[21].props
,
564 &scriptInformation
[22].props
, &scriptInformation
[23].props
,
565 &scriptInformation
[24].props
, &scriptInformation
[25].props
,
566 &scriptInformation
[26].props
, &scriptInformation
[27].props
,
567 &scriptInformation
[28].props
, &scriptInformation
[29].props
,
568 &scriptInformation
[30].props
, &scriptInformation
[31].props
,
569 &scriptInformation
[32].props
, &scriptInformation
[33].props
,
570 &scriptInformation
[34].props
, &scriptInformation
[35].props
,
571 &scriptInformation
[36].props
, &scriptInformation
[37].props
,
572 &scriptInformation
[38].props
, &scriptInformation
[39].props
,
573 &scriptInformation
[40].props
, &scriptInformation
[41].props
,
574 &scriptInformation
[42].props
, &scriptInformation
[43].props
,
575 &scriptInformation
[44].props
, &scriptInformation
[45].props
,
576 &scriptInformation
[46].props
, &scriptInformation
[47].props
,
577 &scriptInformation
[48].props
, &scriptInformation
[49].props
,
578 &scriptInformation
[50].props
, &scriptInformation
[51].props
,
579 &scriptInformation
[52].props
, &scriptInformation
[53].props
,
580 &scriptInformation
[54].props
, &scriptInformation
[55].props
,
581 &scriptInformation
[56].props
, &scriptInformation
[57].props
,
582 &scriptInformation
[58].props
, &scriptInformation
[59].props
,
583 &scriptInformation
[60].props
, &scriptInformation
[61].props
,
584 &scriptInformation
[62].props
, &scriptInformation
[63].props
,
585 &scriptInformation
[64].props
, &scriptInformation
[65].props
,
586 &scriptInformation
[66].props
, &scriptInformation
[67].props
,
587 &scriptInformation
[68].props
, &scriptInformation
[69].props
,
588 &scriptInformation
[70].props
, &scriptInformation
[71].props
,
589 &scriptInformation
[72].props
, &scriptInformation
[73].props
,
590 &scriptInformation
[74].props
, &scriptInformation
[75].props
,
591 &scriptInformation
[76].props
, &scriptInformation
[77].props
,
592 &scriptInformation
[78].props
, &scriptInformation
[79].props
,
593 &scriptInformation
[80].props
, &scriptInformation
[81].props
596 static CRITICAL_SECTION cs_script_cache
;
597 static CRITICAL_SECTION_DEBUG cs_script_cache_dbg
=
599 0, 0, &cs_script_cache
,
600 { &cs_script_cache_dbg
.ProcessLocksList
, &cs_script_cache_dbg
.ProcessLocksList
},
601 0, 0, { (DWORD_PTR
)(__FILE__
": script_cache") }
603 static CRITICAL_SECTION cs_script_cache
= { &cs_script_cache_dbg
, -1, 0, 0, 0, 0 };
604 static struct list script_cache_list
= LIST_INIT(script_cache_list
);
612 SCRIPT_VISATTR
* psva
;
619 enum stringanalysis_flags
621 SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
= 0x1,
622 SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
= 0x2,
634 StringGlyphs
* glyphs
;
635 SCRIPT_LOGATTR
* logattrs
;
645 BOOL
usp10_array_reserve(void **elements
, SIZE_T
*capacity
, SIZE_T count
, SIZE_T size
)
647 SIZE_T max_capacity
, new_capacity
;
650 if (count
<= *capacity
)
653 max_capacity
= ~(SIZE_T
)0 / size
;
654 if (count
> max_capacity
)
657 new_capacity
= max(1, *capacity
);
658 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
660 if (new_capacity
< count
)
661 new_capacity
= count
;
664 new_elements
= heap_alloc_zero(new_capacity
* size
);
666 new_elements
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *elements
, new_capacity
* size
);
670 *elements
= new_elements
;
671 *capacity
= new_capacity
;
675 /* TODO Fix font properties on Arabic locale */
676 static inline BOOL
set_cache_font_properties(const HDC hdc
, ScriptCache
*sc
)
678 sc
->sfp
.cBytes
= sizeof(sc
->sfp
);
682 sc
->sfp
.wgBlank
= sc
->tm
.tmBreakChar
;
683 sc
->sfp
.wgDefault
= sc
->tm
.tmDefaultChar
;
684 sc
->sfp
.wgInvalid
= sc
->sfp
.wgBlank
;
685 sc
->sfp
.wgKashida
= 0xFFFF;
686 sc
->sfp
.iKashidaWidth
= 0;
690 static const WCHAR chars
[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
691 /* U+0020: numeric space
692 U+200B: zero width space
693 U+F71B: unknown char found by black box testing
697 if (GetGlyphIndicesW(hdc
, chars
, 4, gi
, GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
699 if(gi
[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
700 sc
->sfp
.wgBlank
= gi
[0];
704 sc
->sfp
.wgDefault
= 0;
707 sc
->sfp
.wgInvalid
= gi
[2];
708 else if (gi
[1] != 0xFFFF)
709 sc
->sfp
.wgInvalid
= gi
[1];
710 else if (gi
[0] != 0xFFFF)
711 sc
->sfp
.wgInvalid
= gi
[0];
713 sc
->sfp
.wgInvalid
= 0;
715 sc
->sfp
.wgKashida
= gi
[3];
717 sc
->sfp
.iKashidaWidth
= 0; /* TODO */
725 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES
*sfp
, ScriptCache
*sc
)
730 static inline LONG
get_cache_height(SCRIPT_CACHE
*psc
)
732 return ((ScriptCache
*)*psc
)->tm
.tmHeight
;
735 static inline BYTE
get_cache_pitch_family(SCRIPT_CACHE
*psc
)
737 return ((ScriptCache
*)*psc
)->tm
.tmPitchAndFamily
;
740 static inline WORD
get_cache_glyph(SCRIPT_CACHE
*psc
, DWORD c
)
742 CacheGlyphPage
*page
= ((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
746 block
= page
->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
747 if (!block
) return 0;
748 return block
[(c
% 0x10000) & GLYPH_BLOCK_MASK
];
751 static inline WORD
set_cache_glyph(SCRIPT_CACHE
*psc
, WCHAR c
, WORD glyph
)
753 CacheGlyphPage
**page
= &((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
755 if (!*page
&& !(*page
= heap_alloc_zero(sizeof(CacheGlyphPage
)))) return 0;
757 block
= &(*page
)->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
758 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(WORD
) * GLYPH_BLOCK_SIZE
))) return 0;
759 return ((*block
)[(c
% 0x10000) & GLYPH_BLOCK_MASK
] = glyph
);
762 static inline BOOL
get_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
764 static const ABC nil
;
765 ABC
*block
= ((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
767 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(ABC
))) return FALSE
;
768 memcpy(abc
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(ABC
));
772 static inline BOOL
set_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
774 ABC
**block
= &((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
776 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(ABC
) * GLYPH_BLOCK_SIZE
))) return FALSE
;
777 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], abc
, sizeof(ABC
));
781 static HRESULT
init_script_cache(const HDC hdc
, SCRIPT_CACHE
*psc
)
787 if (!psc
) return E_INVALIDARG
;
788 if (*psc
) return S_OK
;
789 if (!hdc
) return E_PENDING
;
791 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
))
795 /* Ensure canonical result by zeroing extra space in lfFaceName */
796 size
= lstrlenW(lf
.lfFaceName
);
797 memset(lf
.lfFaceName
+ size
, 0, sizeof(lf
.lfFaceName
) - size
* sizeof(WCHAR
));
799 EnterCriticalSection(&cs_script_cache
);
800 LIST_FOR_EACH_ENTRY(sc
, &script_cache_list
, ScriptCache
, entry
)
802 if (!memcmp(&sc
->lf
, &lf
, sizeof(lf
)))
805 LeaveCriticalSection(&cs_script_cache
);
810 LeaveCriticalSection(&cs_script_cache
);
812 if (!(sc
= heap_alloc_zero(sizeof(ScriptCache
)))) return E_OUTOFMEMORY
;
813 if (!GetTextMetricsW(hdc
, &sc
->tm
))
818 size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
821 sc
->otm
= heap_alloc(size
);
822 sc
->otm
->otmSize
= size
;
823 GetOutlineTextMetricsW(hdc
, size
, sc
->otm
);
825 sc
->sfnt
= (GetFontData(hdc
, MS_MAKE_TAG('h','e','a','d'), 0, NULL
, 0)!=GDI_ERROR
);
826 if (!set_cache_font_properties(hdc
, sc
))
835 EnterCriticalSection(&cs_script_cache
);
836 list_add_head(&script_cache_list
, &sc
->entry
);
837 LIST_FOR_EACH_ENTRY(sc
, &script_cache_list
, ScriptCache
, entry
)
839 if (sc
!= *psc
&& !memcmp(&sc
->lf
, &lf
, sizeof(lf
)))
841 /* Another thread won the race. Use their cache instead of ours */
842 list_remove(&sc
->entry
);
844 LeaveCriticalSection(&cs_script_cache
);
850 LeaveCriticalSection(&cs_script_cache
);
851 TRACE("<- %p\n", sc
);
855 static WCHAR
mirror_char( WCHAR ch
)
857 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
858 WCHAR mirror
= get_table_entry( wine_mirror_map
, ch
);
859 return mirror
? mirror
: ch
;
862 static DWORD
decode_surrogate_pair(const WCHAR
*str
, unsigned int index
, unsigned int end
)
864 if (index
< end
-1 && IS_SURROGATE_PAIR(str
[index
],str
[index
+1]))
866 DWORD ch
= 0x10000 + ((str
[index
] - 0xd800) << 10) + (str
[index
+1] - 0xdc00);
867 TRACE("Surrogate Pair %x %x => %x\n",str
[index
], str
[index
+1], ch
);
873 static int __cdecl
usp10_compare_script_range(const void *key
, const void *value
)
875 const struct usp10_script_range
*range
= value
;
876 const DWORD
*ch
= key
;
878 if (*ch
< range
->rangeFirst
)
880 if (*ch
> range
->rangeLast
)
885 static enum usp10_script
get_char_script(const WCHAR
*str
, unsigned int index
,
886 unsigned int end
, unsigned int *consumed
)
888 struct usp10_script_range
*range
;
889 WORD type
= 0, type2
= 0;
894 if (str
[index
] == 0xc || str
[index
] == 0x20 || str
[index
] == 0x202f)
897 /* These punctuation characters are separated out as Latin punctuation */
898 if (wcschr(L
"#$&',;<>?@\\^_`{|}~\x00a0", str
[index
]))
899 return Script_Punctuation2
;
901 /* These chars are itemized as Punctuation by Windows */
902 if (str
[index
] == 0x2212 || str
[index
] == 0x2044)
903 return Script_Punctuation
;
905 /* Currency Symbols by Unicode point */
909 case 0x09f3: return Script_Bengali_Currency
;
910 case 0x0af1: return Script_Gujarati_Currency
;
911 case 0x0e3f: return Script_Thai_Currency
;
912 case 0x20aa: return Script_Hebrew_Currency
;
913 case 0x20ab: return Script_Vietnamese_Currency
;
914 case 0xfb29: return Script_Hebrew_Currency
;
917 GetStringTypeW(CT_CTYPE1
, &str
[index
], 1, &type
);
918 GetStringTypeW(CT_CTYPE2
, &str
[index
], 1, &type2
);
921 return SCRIPT_UNDEFINED
;
924 return Script_Control
;
926 ch
= decode_surrogate_pair(str
, index
, end
);
932 if (!(range
= bsearch(&ch
, script_ranges
, ARRAY_SIZE(script_ranges
),
933 sizeof(*script_ranges
), usp10_compare_script_range
)))
934 return (*consumed
== 2) ? Script_Surrogates
: Script_Undefined
;
936 if (range
->numericScript
&& (type
& C1_DIGIT
|| type2
== C2_ARABICNUMBER
))
937 return range
->numericScript
;
938 if (range
->punctScript
&& type
& C1_PUNCT
)
939 return range
->punctScript
;
940 return range
->script
;
943 static int __cdecl
compare_FindGlyph(const void *a
, const void* b
)
945 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
946 const WORD
*idx
= (WORD
*)b
;
949 if ( find
->target
> *idx
)
951 else if (find
->target
< *idx
)
954 if (!find
->ascending
)
959 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
961 FindGlyph_struct fgs
;
965 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
966 fgs
.ascending
= TRUE
;
968 fgs
.ascending
= FALSE
;
971 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
976 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
983 /***********************************************************************
984 * ScriptFreeCache (USP10.@)
986 * Free a script cache.
989 * psc [I/O] Script cache.
993 * Failure: Non-zero HRESULT value.
995 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1004 EnterCriticalSection(&cs_script_cache
);
1005 if (--((ScriptCache
*)*psc
)->refcount
> 0)
1007 LeaveCriticalSection(&cs_script_cache
);
1011 list_remove(&((ScriptCache
*)*psc
)->entry
);
1012 LeaveCriticalSection(&cs_script_cache
);
1014 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1016 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1018 for (i
= 0; i
< NUM_PAGES
; i
++)
1021 if (((ScriptCache
*)*psc
)->page
[i
])
1022 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1023 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1024 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1026 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1027 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1028 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1029 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1030 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1033 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1036 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1037 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1038 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1040 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1041 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1042 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1043 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1045 heap_free(((ScriptCache
*)*psc
)->scripts
);
1046 heap_free(((ScriptCache
*)*psc
)->otm
);
1053 /***********************************************************************
1054 * ScriptGetProperties (USP10.@)
1056 * Retrieve a list of script properties.
1059 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1060 * num [I] Pointer to the number of scripts.
1064 * Failure: Non-zero HRESULT value.
1067 * Behaviour matches WinXP.
1069 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1071 TRACE("(%p,%p)\n", props
, num
);
1073 if (!props
&& !num
) return E_INVALIDARG
;
1075 if (num
) *num
= ARRAY_SIZE(script_props
);
1076 if (props
) *props
= script_props
;
1081 /***********************************************************************
1082 * ScriptGetFontProperties (USP10.@)
1084 * Get information on special glyphs.
1087 * hdc [I] Device context.
1088 * psc [I/O] Opaque pointer to a script cache.
1089 * sfp [O] Font properties structure.
1091 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1095 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1097 if (!sfp
) return E_INVALIDARG
;
1098 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1100 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1101 return E_INVALIDARG
;
1103 get_cache_font_properties(sfp
, *psc
);
1108 /***********************************************************************
1109 * ScriptRecordDigitSubstitution (USP10.@)
1111 * Record digit substitution settings for a given locale.
1114 * locale [I] Locale identifier.
1115 * sds [I] Structure to record substitution settings.
1119 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1122 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1124 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1128 TRACE("0x%x, %p\n", locale
, sds
);
1130 /* This implementation appears to be correct for all languages, but it's
1131 * not clear if sds->DigitSubstitute is ever set to anything except
1132 * CONTEXT or NONE in reality */
1134 if (!sds
) return E_POINTER
;
1136 locale
= ConvertDefaultLocale(locale
);
1138 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1139 return E_INVALIDARG
;
1141 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1142 sds
->TraditionalDigitLanguage
= plgid
;
1144 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1145 sds
->NationalDigitLanguage
= plgid
;
1147 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1149 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1150 (WCHAR
*)&sub
, sizeof(sub
) / sizeof(WCHAR
)))
1151 return E_INVALIDARG
;
1156 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1157 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1159 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1162 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1165 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1168 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1172 sds
->dwReserved
= 0;
1176 /***********************************************************************
1177 * ScriptApplyDigitSubstitution (USP10.@)
1179 * Apply digit substitution settings.
1182 * sds [I] Structure with recorded substitution settings.
1183 * sc [I] Script control structure.
1184 * ss [I] Script state structure.
1188 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1190 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1191 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1193 SCRIPT_DIGITSUBSTITUTE psds
;
1195 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1197 if (!sc
|| !ss
) return E_POINTER
;
1201 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1202 return E_INVALIDARG
;
1205 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1206 sc
->fContextDigits
= 0;
1207 ss
->fDigitSubstitute
= 0;
1209 switch (sds
->DigitSubstitute
) {
1210 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1211 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1212 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1213 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1216 return E_INVALIDARG
;
1220 static inline BOOL
is_indic(enum usp10_script script
)
1222 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1225 static inline enum usp10_script
base_indic(enum usp10_script script
)
1229 case Script_Devanagari
:
1230 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1231 case Script_Bengali
:
1232 case Script_Bengali_Numeric
:
1233 case Script_Bengali_Currency
: return Script_Bengali
;
1234 case Script_Gurmukhi
:
1235 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1236 case Script_Gujarati
:
1237 case Script_Gujarati_Numeric
:
1238 case Script_Gujarati_Currency
: return Script_Gujarati
;
1240 case Script_Oriya_Numeric
: return Script_Oriya
;
1242 case Script_Tamil_Numeric
: return Script_Tamil
;
1244 case Script_Telugu_Numeric
: return Script_Telugu
;
1245 case Script_Kannada
:
1246 case Script_Kannada_Numeric
: return Script_Kannada
;
1247 case Script_Malayalam
:
1248 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1250 return Script_Undefined
;
1254 static BOOL
script_is_numeric(enum usp10_script script
)
1256 return scriptInformation
[script
].props
.fNumeric
;
1259 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1260 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1261 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1262 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1265 #define Numeric_space 0x0020
1270 enum usp10_script last_indic
= Script_Undefined
;
1271 int cnt
= 0, index
= 0, str
= 0;
1272 enum usp10_script New_Script
= -1;
1274 WORD
*levels
= NULL
;
1275 WORD
*layout_levels
= NULL
;
1276 WORD
*overrides
= NULL
;
1277 WORD
*strength
= NULL
;
1278 enum usp10_script
*scripts
;
1280 WORD baselayout
= 0;
1283 BOOL forceLevels
= FALSE
;
1284 unsigned int consumed
= 0;
1285 HRESULT res
= E_OUTOFMEMORY
;
1287 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1288 psControl
, psState
, pItems
, pcItems
);
1290 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1291 return E_INVALIDARG
;
1293 if (!(scripts
= heap_calloc(cInChars
, sizeof(*scripts
))))
1294 return E_OUTOFMEMORY
;
1296 for (i
= 0; i
< cInChars
; i
++)
1300 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1305 scripts
[i
] = scripts
[i
-1];
1308 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1309 all Indic scripts */
1310 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
!= Script_Undefined
)
1311 scripts
[i
] = last_indic
;
1312 else if (is_indic(scripts
[i
]))
1313 last_indic
= base_indic(scripts
[i
]);
1315 /* Some unicode points :
1316 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1317 (Left Right Embed U+202A - Left Right Override U+202D)
1318 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1319 will force us into bidi mode */
1320 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1321 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1322 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1326 /* Diacritical marks merge with other scripts */
1327 if (scripts
[i
] == Script_Diacritical
)
1332 scripts
[i
] = scripts
[i
-1];
1337 enum usp10_script first_script
= scripts
[i
-1];
1338 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1340 enum usp10_script original
= scripts
[j
];
1341 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1346 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1348 scripts
[j
] = scripts
[i
];
1349 if (original
== Script_Punctuation2
)
1352 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1353 scripts
[i
] = scripts
[j
];
1359 for (i
= 0; i
< cInChars
; i
++)
1361 /* Joiners get merged preferencially right */
1362 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1365 if (i
+1 == cInChars
)
1366 scripts
[i
] = scripts
[i
-1];
1369 for (j
= i
+1; j
< cInChars
; j
++)
1371 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1372 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1374 scripts
[i
] = scripts
[j
];
1382 if (psState
&& psControl
)
1384 if (!(levels
= heap_calloc(cInChars
, sizeof(*levels
))))
1387 if (!(overrides
= heap_calloc(cInChars
, sizeof(*overrides
))))
1390 if (!(layout_levels
= heap_calloc(cInChars
, sizeof(*layout_levels
))))
1393 if (psState
->fOverrideDirection
)
1397 SCRIPT_STATE s
= *psState
;
1398 s
.fOverrideDirection
= FALSE
;
1399 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1400 if (odd(layout_levels
[0]))
1402 else for (i
= 0; i
< cInChars
; i
++)
1403 if (layout_levels
[i
]!=layout_levels
[0])
1410 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1414 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1415 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1417 baselevel
= levels
[0];
1418 baselayout
= layout_levels
[0];
1419 for (i
= 0; i
< cInChars
; i
++)
1420 if (levels
[i
]!=levels
[0])
1422 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1425 heap_free(overrides
);
1426 heap_free(layout_levels
);
1429 layout_levels
= NULL
;
1433 if (!(strength
= heap_calloc(cInChars
, sizeof(*strength
))))
1435 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1437 /* We currently mis-level leading Diacriticals */
1438 if (scripts
[0] == Script_Diacritical
)
1439 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1441 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1442 strength
[i
] = BIDI_STRONG
;
1445 /* Math punctuation bordered on both sides by numbers can be
1446 merged into the number */
1447 for (i
= 0; i
< cInChars
; i
++)
1449 if (i
> 0 && i
< cInChars
-1 &&
1450 script_is_numeric(scripts
[i
-1]) &&
1451 wcschr(L
"#$%+,-./:\x2212\x2044\x00a0", pwcInChars
[i
]))
1453 if (script_is_numeric(scripts
[i
+1]))
1455 scripts
[i
] = scripts
[i
+1];
1456 levels
[i
] = levels
[i
-1];
1457 strength
[i
] = strength
[i
-1];
1460 else if (wcschr(L
"#$%+-/\x2212\x2044", pwcInChars
[i
]))
1463 for (j
= i
+1; j
< cInChars
; j
++)
1465 if (script_is_numeric(scripts
[j
]))
1469 scripts
[i
] = scripts
[j
];
1470 levels
[i
] = levels
[i
-1];
1471 strength
[i
] = strength
[i
-1];
1474 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1480 for (i
= 0; i
< cInChars
; i
++)
1482 /* Numerics at level 0 get bumped to level 2 */
1483 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
)
1484 && levels
[i
] == psState
->uBidiLevel
+ 1)) && script_is_numeric(scripts
[i
]))
1489 /* Joiners get merged preferencially right */
1490 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1493 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1494 strength
[i
] = strength
[i
-1];
1496 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1497 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1498 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1500 strength
[i
] = strength
[j
];
1505 if (psControl
->fMergeNeutralItems
)
1507 /* Merge the neutrals */
1508 for (i
= 0; i
< cInChars
; i
++)
1510 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1513 for (j
= i
; j
> 0; j
--)
1515 if (levels
[i
] != levels
[j
])
1517 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1519 scripts
[i
] = scripts
[j
];
1520 strength
[i
] = strength
[j
];
1525 /* Try going the other way */
1526 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1529 for (j
= i
; j
< cInChars
; j
++)
1531 if (levels
[i
] != levels
[j
])
1533 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1535 scripts
[i
] = scripts
[j
];
1536 strength
[i
] = strength
[j
];
1546 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1547 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1550 if (cnt
== cInChars
) /* All Spaces */
1553 New_Script
= scripts
[cnt
];
1556 pItems
[index
].iCharPos
= 0;
1557 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1559 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1561 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1562 str
= strength
[cnt
];
1570 if (strength
[cnt
] == BIDI_STRONG
)
1571 layoutRTL
= odd(layout_levels
[cnt
]);
1573 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1575 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1576 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1577 if (script_is_numeric(pItems
[index
].a
.eScript
))
1578 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1580 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1581 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1583 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1585 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1586 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1587 layoutRTL
= odd(baselayout
);
1588 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1589 pItems
[index
].a
.fRTL
= odd(baselevel
);
1590 if (script_is_numeric(pItems
[index
].a
.eScript
))
1591 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1593 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1596 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1597 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1598 pItems
[index
].iCharPos
);
1600 for (cnt
=1; cnt
< cInChars
; cnt
++)
1602 if(pwcInChars
[cnt
] != Numeric_space
)
1603 New_Script
= scripts
[cnt
];
1607 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1609 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1610 New_Script
= scripts
[cnt
+j
];
1612 New_Script
= scripts
[cnt
];
1616 /* merge space strengths*/
1617 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1620 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1623 /* changes in level */
1624 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1626 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1629 /* changes in strength */
1630 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1632 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1635 /* changes in script */
1636 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1638 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1642 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1644 layoutRTL
= odd(layout_levels
[cnt
]);
1645 if (script_is_numeric(pItems
[index
].a
.eScript
))
1646 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1651 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
);
1654 if (index
+1 > cMaxItems
)
1658 str
= strength
[cnt
];
1660 pItems
[index
].iCharPos
= cnt
;
1661 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1663 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1665 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1669 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1670 if (layout_levels
[cnt
] == 0)
1673 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1674 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1675 if (script_is_numeric(pItems
[index
].a
.eScript
))
1676 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1678 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1679 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1681 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1683 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1684 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1685 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1686 pItems
[index
].a
.fRTL
= odd(baselevel
);
1687 if (script_is_numeric(pItems
[index
].a
.eScript
))
1688 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1690 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1693 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1697 /* While not strictly necessary according to the spec, make sure the n+1
1698 * item is set up to prevent random behaviour if the caller erroneously
1699 * checks the n+1 structure */
1701 if (index
+ 1 > cMaxItems
) goto nomemory
;
1702 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1704 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1706 /* Set one SCRIPT_STATE item being returned */
1707 if (pcItems
) *pcItems
= index
;
1709 /* Set SCRIPT_ITEM */
1710 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1714 heap_free(overrides
);
1715 heap_free(layout_levels
);
1716 heap_free(strength
);
1721 /***********************************************************************
1722 * ScriptItemizeOpenType (USP10.@)
1724 * Split a Unicode string into shapeable parts.
1727 * pwcInChars [I] String to split.
1728 * cInChars [I] Number of characters in pwcInChars.
1729 * cMaxItems [I] Maximum number of items to return.
1730 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1731 * psState [I] Pointer to a SCRIPT_STATE structure.
1732 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1733 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1734 * pcItems [O] Number of script items returned.
1738 * Failure: Non-zero HRESULT value.
1740 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1741 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1742 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1744 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1747 /***********************************************************************
1748 * ScriptItemize (USP10.@)
1750 * Split a Unicode string into shapeable parts.
1753 * pwcInChars [I] String to split.
1754 * cInChars [I] Number of characters in pwcInChars.
1755 * cMaxItems [I] Maximum number of items to return.
1756 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1757 * psState [I] Pointer to a SCRIPT_STATE structure.
1758 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1759 * pcItems [O] Number of script items returned.
1763 * Failure: Non-zero HRESULT value.
1765 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1766 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1767 SCRIPT_ITEM
*pItems
, int *pcItems
)
1769 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1772 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1776 INT
*lpTabPos
= NULL
;
1781 lpTabPos
= pTabdef
->pTabStops
;
1783 if (pTabdef
&& pTabdef
->iTabOrigin
)
1785 if (pTabdef
->iScale
)
1786 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1788 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1792 cTabStops
= pTabdef
->cTabStops
;
1796 if (pTabdef
->iScale
)
1797 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1799 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1804 if (pTabdef
->iScale
)
1805 defWidth
= (32 * pTabdef
->iScale
) / 4;
1807 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1810 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1812 int position
= *lpTabPos
;
1814 position
= -1 * position
;
1815 if (pTabdef
->iScale
)
1816 position
= (position
* pTabdef
->iScale
) / 4;
1818 position
= position
* psc
->tm
.tmAveCharWidth
;
1820 if( nTabOrg
+ position
> current_x
)
1824 /* a left aligned tab */
1825 x
= (nTabOrg
+ position
) - current_x
;
1830 FIXME("Negative tabstop\n");
1835 if ((!cTabStops
) && (defWidth
> 0))
1836 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1837 else if ((!cTabStops
) && (defWidth
< 0))
1838 FIXME("TODO: Negative defWidth\n");
1843 /***********************************************************************
1844 * Helper function for ScriptStringAnalyse
1846 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1847 const WCHAR
*pwcInChars
, int cChars
)
1849 /* FIXME: When to properly fallback is still a bit of a mystery */
1852 if (psa
->fNoGlyphIndex
)
1855 if (init_script_cache(hdc
, psc
) != S_OK
)
1858 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1861 if (!(glyphs
= heap_calloc(cChars
, sizeof(*glyphs
))))
1863 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1873 static void find_fallback_font(enum usp10_script scriptid
, WCHAR
*FaceName
)
1877 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1880 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1883 swprintf(value
, ARRAY_SIZE(value
), L
"%x", scriptInformation
[scriptid
].scriptTag
);
1884 if (RegQueryValueExW(hkey
, value
, 0, &type
, (BYTE
*)FaceName
, &count
))
1885 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1889 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1892 /***********************************************************************
1893 * ScriptStringAnalyse (USP10.@)
1896 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1897 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1898 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1899 SCRIPT_STATE
*psState
, const int *piDx
,
1900 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1901 SCRIPT_STRING_ANALYSIS
*pssa
)
1903 HRESULT hr
= E_OUTOFMEMORY
;
1904 StringAnalysis
*analysis
= NULL
;
1905 SCRIPT_CONTROL sControl
;
1906 SCRIPT_STATE sState
;
1907 int i
, num_items
= 255;
1909 WCHAR
*iString
= NULL
;
1911 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1912 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1913 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
1917 FIXME("Only Unicode strings are supported\n");
1918 return E_INVALIDARG
;
1920 if (cString
< 1 || !pString
) return E_INVALIDARG
;
1921 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
1923 if (!(analysis
= heap_alloc_zero(sizeof(*analysis
))))
1924 return E_OUTOFMEMORY
;
1925 if (!(analysis
->pItem
= heap_calloc(num_items
+ 1, sizeof(*analysis
->pItem
))))
1928 /* FIXME: handle clipping */
1929 analysis
->clip_len
= cString
;
1930 analysis
->hdc
= hdc
;
1931 analysis
->ssa_flags
= dwFlags
;
1936 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
1939 sControl
= *psControl
;
1941 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
1943 if (dwFlags
& SSA_PASSWORD
)
1945 if (!(iString
= heap_calloc(cString
, sizeof(*iString
))))
1950 for (i
= 0; i
< cString
; i
++)
1951 iString
[i
] = *((const WCHAR
*)pString
);
1955 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
1956 &analysis
->numItems
);
1960 if (hr
== E_OUTOFMEMORY
)
1965 /* set back to out of memory for default goto error behaviour */
1968 if (dwFlags
& SSA_BREAK
)
1970 if (!(analysis
->logattrs
= heap_calloc(cString
, sizeof(*analysis
->logattrs
))))
1973 for (i
= 0; i
< analysis
->numItems
; ++i
)
1974 ScriptBreak(&((const WCHAR
*)pString
)[analysis
->pItem
[i
].iCharPos
],
1975 analysis
->pItem
[i
+ 1].iCharPos
- analysis
->pItem
[i
].iCharPos
,
1976 &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
1979 if (!(analysis
->logical2visual
= heap_calloc(analysis
->numItems
, sizeof(*analysis
->logical2visual
))))
1981 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
1984 if (dwFlags
& SSA_GLYPHS
)
1988 if (!(analysis
->glyphs
= heap_calloc(analysis
->numItems
, sizeof(*analysis
->glyphs
))))
1990 heap_free(BidiLevel
);
1994 for (i
= 0; i
< analysis
->numItems
; i
++)
1996 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
1997 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
1998 int numGlyphs
= 1.5 * cChar
+ 16;
1999 WORD
*glyphs
= heap_calloc(numGlyphs
, sizeof(*glyphs
));
2000 WORD
*pwLogClust
= heap_calloc(cChar
, sizeof(*pwLogClust
));
2001 int *piAdvance
= heap_calloc(numGlyphs
, sizeof(*piAdvance
));
2002 SCRIPT_VISATTR
*psva
= heap_calloc(numGlyphs
, sizeof(*psva
));
2003 GOFFSET
*pGoffset
= heap_calloc(numGlyphs
, sizeof(*pGoffset
));
2004 int numGlyphsReturned
;
2005 HFONT originalFont
= 0x0;
2007 /* FIXME: non unicode strings */
2008 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2009 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2011 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
)
2013 heap_free (BidiLevel
);
2015 heap_free (pwLogClust
);
2016 heap_free (piAdvance
);
2018 heap_free (pGoffset
);
2023 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2026 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2027 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2028 lf
.lfFaceName
[0] = 0;
2029 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2030 if (lf
.lfFaceName
[0])
2032 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2033 if (analysis
->glyphs
[i
].fallbackFont
)
2035 ScriptFreeCache(sc
);
2036 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2041 /* FIXME: When we properly shape Hangul remove this check */
2042 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2043 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2045 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2046 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2048 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2049 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2050 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2051 piAdvance
, pGoffset
, &analysis
->glyphs
[i
].abc
);
2053 SelectObject(hdc
,originalFont
);
2055 if (dwFlags
& SSA_TAB
)
2058 for (tabi
= 0; tabi
< cChar
; tabi
++)
2060 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2061 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2062 tab_x
+=piAdvance
[tabi
];
2066 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2067 analysis
->glyphs
[i
].glyphs
= glyphs
;
2068 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2069 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2070 analysis
->glyphs
[i
].psva
= psva
;
2071 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2072 analysis
->glyphs
[i
].iMaxPosX
= -1;
2074 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2079 for (i
= 0; i
< analysis
->numItems
; i
++)
2080 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2083 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2084 heap_free(BidiLevel
);
2092 heap_free(analysis
->glyphs
);
2093 heap_free(analysis
->logattrs
);
2094 heap_free(analysis
->pItem
);
2095 heap_free(analysis
->logical2visual
);
2096 heap_free(analysis
);
2100 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2102 if (pva
[glyph
].fClusterStart
)
2104 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2110 static DWORD
get_sys_color(INT index
)
2112 static DWORD (WINAPI
*pGetSysColor
)(INT index
);
2116 HMODULE user
= GetModuleHandleW( L
"user32.dll" );
2117 if (user
) pGetSysColor
= (void *)GetProcAddress( user
, "GetSysColor" );
2120 return pGetSysColor(index
);
2123 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2134 StringAnalysis
*analysis
;
2137 COLORREF BkColor
= 0x0;
2138 COLORREF TextColor
= 0x0;
2140 INT runStart
, runEnd
;
2141 INT iGlyph
, cGlyphs
;
2142 HFONT oldFont
= 0x0;
2146 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2147 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2149 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2151 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2152 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2156 memcpy(&crc
, prc
, sizeof(crc
));
2159 BkMode
= GetBkMode(analysis
->hdc
);
2160 SetBkMode( analysis
->hdc
, OPAQUE
);
2161 BkColor
= GetBkColor(analysis
->hdc
);
2162 SetBkColor(analysis
->hdc
, get_sys_color(COLOR_HIGHLIGHT
));
2165 TextColor
= GetTextColor(analysis
->hdc
);
2166 SetTextColor(analysis
->hdc
, get_sys_color(COLOR_HIGHLIGHTTEXT
));
2169 if (analysis
->glyphs
[iItem
].fallbackFont
)
2170 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2172 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2173 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2176 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2177 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2179 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2181 if (analysis
->pItem
[iItem
].a
.fRTL
)
2183 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2184 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2186 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2187 crc
.left
= iX
+ off_x
;
2191 if (cStart
>=0 && runStart
)
2192 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2194 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2195 crc
.left
= iX
+ off_x
;
2198 if (analysis
->pItem
[iItem
].a
.fRTL
)
2199 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2201 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2203 if (analysis
->pItem
[iItem
].a
.fRTL
)
2204 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2206 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2210 /* adjust for cluster glyphs when starting */
2211 if (analysis
->pItem
[iItem
].a
.fRTL
)
2212 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2214 i
= analysis
->pItem
[iItem
].iCharPos
;
2216 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2218 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2220 if (analysis
->pItem
[iItem
].a
.fRTL
)
2221 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2223 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2228 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2233 clust_glyph
= iGlyph
+ cGlyphs
;
2234 if (analysis
->pItem
[iItem
].a
.fRTL
)
2239 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2240 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2247 hr
= ScriptTextOut(analysis
->hdc
,
2248 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2249 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2250 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2251 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2252 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2254 TRACE("ScriptTextOut hr=%08x\n", hr
);
2258 SetBkColor(analysis
->hdc
, BkColor
);
2259 SetBkMode( analysis
->hdc
, BkMode
);
2261 SetTextColor(analysis
->hdc
, TextColor
);
2263 if (analysis
->glyphs
[iItem
].fallbackFont
)
2264 SelectObject(analysis
->hdc
, oldFont
);
2269 /***********************************************************************
2270 * ScriptStringOut (USP10.@)
2272 * This function takes the output of ScriptStringAnalyse and joins the segments
2273 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2274 * only processes glyphs.
2277 * ssa [I] buffer to hold the analysed string components
2278 * iX [I] X axis displacement for output
2279 * iY [I] Y axis displacement for output
2280 * uOptions [I] flags controlling output processing
2281 * prc [I] rectangle coordinates
2282 * iMinSel [I] starting pos for substringing output string
2283 * iMaxSel [I] ending pos for substringing output string
2284 * fDisabled [I] controls text highlighting
2288 * Failure: is the value returned by ScriptTextOut
2290 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2299 StringAnalysis
*analysis
;
2303 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2304 ssa
, iX
, iY
, uOptions
, wine_dbgstr_rect(prc
), iMinSel
, iMaxSel
, fDisabled
);
2306 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2307 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2309 for (item
= 0; item
< analysis
->numItems
; item
++)
2311 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2316 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2318 if (iMaxSel
> 0 && iMinSel
< 0)
2320 for (item
= 0; item
< analysis
->numItems
; item
++)
2322 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2331 /***********************************************************************
2332 * ScriptStringCPtoX (USP10.@)
2335 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2339 StringAnalysis
* analysis
= ssa
;
2341 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2343 if (!ssa
|| !pX
) return S_FALSE
;
2344 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2346 /* icp out of range */
2349 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2350 return E_INVALIDARG
;
2353 for(item
=0; item
<analysis
->numItems
; item
++)
2358 i
= analysis
->logical2visual
[item
];
2359 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2360 /* initialize max extents for uninitialized runs */
2361 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2363 if (analysis
->pItem
[i
].a
.fRTL
)
2364 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2365 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2366 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2368 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2369 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2370 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2373 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2375 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2379 icp
-= analysis
->pItem
[i
].iCharPos
;
2380 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2381 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2382 &analysis
->pItem
[i
].a
, &offset
);
2389 /* icp out of range */
2390 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2391 return E_INVALIDARG
;
2394 /***********************************************************************
2395 * ScriptStringXtoCP (USP10.@)
2398 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2400 StringAnalysis
* analysis
= ssa
;
2403 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2405 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2406 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2411 if (analysis
->pItem
[0].a
.fRTL
)
2414 *piTrailing
= FALSE
;
2424 for(item
=0; item
<analysis
->numItems
; item
++)
2429 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2432 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2433 /* initialize max extents for uninitialized runs */
2434 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2436 if (analysis
->pItem
[i
].a
.fRTL
)
2437 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2438 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2439 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2441 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2442 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2443 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2446 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2448 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2452 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2453 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2454 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2455 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2461 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2462 *piTrailing
= FALSE
;
2468 /***********************************************************************
2469 * ScriptStringFree (USP10.@)
2471 * Free a string analysis.
2474 * pssa [I] string analysis.
2478 * Failure: Non-zero HRESULT value.
2480 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2482 StringAnalysis
* analysis
;
2486 TRACE("(%p)\n", pssa
);
2488 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2490 invalid
= analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2492 if (analysis
->glyphs
)
2494 for (i
= 0; i
< analysis
->numItems
; i
++)
2496 heap_free(analysis
->glyphs
[i
].glyphs
);
2497 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2498 heap_free(analysis
->glyphs
[i
].piAdvance
);
2499 heap_free(analysis
->glyphs
[i
].psva
);
2500 heap_free(analysis
->glyphs
[i
].pGoffset
);
2501 if (analysis
->glyphs
[i
].fallbackFont
)
2502 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2503 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2504 heap_free(analysis
->glyphs
[i
].sc
);
2506 heap_free(analysis
->glyphs
);
2509 heap_free(analysis
->pItem
);
2510 heap_free(analysis
->logattrs
);
2511 heap_free(analysis
->logical2visual
);
2512 heap_free(analysis
);
2514 if (invalid
) return E_INVALIDARG
;
2518 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2519 int direction
, int* iCluster
, int *check_out
)
2523 WORD clust
= pwLogClust
[item
];
2525 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2527 if (pwLogClust
[check
] == clust
)
2530 if (iCluster
&& *iCluster
== -1)
2542 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
)
2547 advance
= piAdvance
[glyph
];
2549 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2550 log_clust_max
= pwLogClust
[0];
2552 log_clust_max
= pwLogClust
[cChars
-1];
2554 if (glyph
> log_clust_max
)
2557 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2560 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2562 if (glyph
> log_clust_max
)
2564 advance
+= piAdvance
[glyph
];
2570 /***********************************************************************
2571 * ScriptCPtoX (USP10.@)
2574 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2578 const WORD
*pwLogClust
,
2579 const SCRIPT_VISATTR
*psva
,
2580 const int *piAdvance
,
2581 const SCRIPT_ANALYSIS
*psa
,
2589 float special_size
= 0.0;
2594 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2595 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2598 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2606 int max_clust
= pwLogClust
[0];
2608 for (item
=0; item
< cGlyphs
; item
++)
2609 if (pwLogClust
[item
] > max_clust
)
2611 ERR("We do not handle non reversed clusters properly\n");
2616 for (item
= max_clust
; item
>=0; item
--)
2617 iMaxPos
+= piAdvance
[item
];
2621 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2623 if (iSpecial
== -1 && (iCluster
== -1 || iCluster
+clust_size
<= item
))
2626 int clust
= pwLogClust
[item
];
2629 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2632 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2634 if (check
>= cChars
&& !iMaxPos
)
2637 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2638 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2640 special_size
/= (cChars
- item
);
2641 iPosX
+= special_size
;
2645 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2648 if (clust_size
== 0)
2652 iPosX
+= advance
/ (float)clust_size
;
2655 else if (iSpecial
!= -1)
2656 iPosX
+= special_size
;
2657 else /* (iCluster != -1) */
2659 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2660 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2663 if (clust_size
== 0)
2667 iPosX
+= adv
/ (float)clust_size
;
2673 iPosX
= iMaxPos
- iPosX
;
2679 TRACE("*piX=%d\n", *piX
);
2683 /* Count the number of characters in a cluster and its starting index*/
2684 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2689 for (i
= 0; i
< cChars
; i
++)
2691 if (pwLogClust
[i
] == cluster_index
)
2693 if (!size
&& start_index
)
2701 else if (size
) break;
2704 *cluster_size
= size
;
2710 To handle multi-glyph clusters we need to find all the glyphs that are
2711 represented in the cluster. This involves finding the glyph whose
2712 index is the cluster index as well as whose glyph indices are greater than
2713 our cluster index but not part of a new cluster.
2715 Then we sum all those glyphs' advances.
2717 static inline int get_cluster_advance(const int* piAdvance
,
2718 const SCRIPT_VISATTR
*psva
,
2719 const WORD
*pwLogClust
, int cGlyphs
,
2720 int cChars
, int cluster
, int direction
)
2731 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2733 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2734 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2735 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2740 glyph_end
= cGlyphs
;
2743 /* Don't fully understand multi-glyph reversed clusters yet,
2744 * do they occur for real or just in our test? */
2745 FIXME("multi-glyph reversed clusters found\n");
2746 glyph_end
= glyph_start
+ 1;
2750 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2751 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2753 if (psva
[i
].fClusterStart
)
2760 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2761 advance
+= piAdvance
[i
];
2767 /***********************************************************************
2768 * ScriptXtoCP (USP10.@)
2771 * Use piAdvance to find the cluster we are looking at.
2772 * Find the character that is the first character of the cluster.
2773 * That is our base piCP.
2774 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2775 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2776 * determine how far through the cluster to advance the cursor.
2778 HRESULT WINAPI
ScriptXtoCP(int iX
,
2781 const WORD
*pwLogClust
,
2782 const SCRIPT_VISATTR
*psva
,
2783 const int *piAdvance
,
2784 const SCRIPT_ANALYSIS
*psa
,
2791 int glyph_index
, cluster_index
;
2794 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2795 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2796 psa
, piCP
, piTrailing
);
2798 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2801 /* Handle an iX < 0 */
2817 /* Looking for non-reversed clusters in a reversed string */
2820 int max_clust
= pwLogClust
[0];
2821 for (i
=0; i
< cChars
; i
++)
2822 if (pwLogClust
[i
] > max_clust
)
2824 FIXME("We do not handle non reversed clusters properly\n");
2829 /* find the glyph_index based in iX */
2832 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2837 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2841 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2844 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2846 /* find the cluster */
2848 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2851 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2854 TRACE("cluster_index %i\n", cluster_index
);
2856 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2858 /* We are off the end of the string */
2864 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2866 TRACE("first char index %i\n",i
);
2867 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2869 /* Check trailing */
2870 if (glyph_index
!= cluster_index
||
2871 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2872 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2873 *piTrailing
= cluster_size
;
2877 if (cluster_size
> 1)
2879 /* Be part way through the glyph cluster based on size and position */
2880 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2881 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2885 /* back up to the beginning of the cluster */
2886 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2887 adv
+= piAdvance
[part_index
];
2888 if (adv
> iX
) adv
= iX
;
2890 TRACE("Multi-char cluster, no snap\n");
2891 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2892 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2895 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2897 if (part_index
) part_index
--;
2901 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2903 if (part_index
> cluster_size
)
2905 adv
+= cluster_part_width
;
2906 part_index
=cluster_size
;
2910 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2915 i
+= (cluster_size
- part_index
);
2917 /* Check trailing */
2918 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2919 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2924 /* Check trailing */
2925 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2926 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2933 TRACE("Point falls outside of string\n");
2934 if (glyph_index
< 0)
2936 else /* (glyph_index >= cGlyphs) */
2939 /* If not snapping in the reverse direction (such as Hebrew) Then 0
2940 point flow to the next character */
2943 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
2952 TRACE("*piCP=%d\n", *piCP
);
2953 TRACE("*piTrailing=%d\n", *piTrailing
);
2957 /***********************************************************************
2958 * ScriptBreak (USP10.@)
2960 * Retrieve line break information.
2963 * chars [I] Array of characters.
2964 * sa [I] Script analysis.
2965 * la [I] Array of logical attribute structures.
2971 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
2973 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
2975 if (count
< 0 || !la
) return E_INVALIDARG
;
2976 if (count
== 0) return E_FAIL
;
2978 BREAK_line(chars
, count
, sa
, la
);
2983 /***********************************************************************
2984 * ScriptIsComplex (USP10.@)
2986 * Determine if a string is complex.
2989 * chars [I] Array of characters to test.
2990 * len [I] Length in characters.
2998 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
3000 enum usp10_script script
;
3001 unsigned int i
, consumed
;
3003 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
3005 if (!chars
|| len
< 0)
3006 return E_INVALIDARG
;
3008 for (i
= 0; i
< len
; i
+=consumed
)
3010 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3013 script
= get_char_script(chars
,i
,len
, &consumed
);
3014 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3015 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3021 /***********************************************************************
3022 * ScriptShapeOpenType (USP10.@)
3024 * Produce glyphs and visual attributes for a run.
3027 * hdc [I] Device context.
3028 * psc [I/O] Opaque pointer to a script cache.
3029 * psa [I/O] Script analysis.
3030 * tagScript [I] The OpenType tag for the Script
3031 * tagLangSys [I] The OpenType tag for the Language
3032 * rcRangeChars[I] Array of Character counts in each range
3033 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3034 * cRanges [I] Count of ranges
3035 * pwcChars [I] Array of characters specifying the run.
3036 * cChars [I] Number of characters in pwcChars.
3037 * cMaxGlyphs [I] Length of pwOutGlyphs.
3038 * pwLogClust [O] Array of logical cluster info.
3039 * pCharProps [O] Array of character property values
3040 * pwOutGlyphs [O] Array of glyphs.
3041 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3042 * pcGlyphs [O] Number of glyphs returned.
3046 * Failure: Non-zero HRESULT value.
3048 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3049 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3050 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3051 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3052 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3053 int cMaxGlyphs
, WORD
*pwLogClust
,
3054 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3055 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3062 static int once
= 0;
3064 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3066 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3067 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3068 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3070 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3071 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3073 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3074 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3077 if(!once
++) FIXME("Ranges not supported yet\n");
3079 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3082 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3083 if (!pwLogClust
) return E_FAIL
;
3085 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3086 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
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
&& ((ScriptCache
*)*psc
)->sfnt
)
3110 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3112 if (!(rChars
= heap_calloc(cChars
, sizeof(*rChars
))))
3113 return E_OUTOFMEMORY
;
3115 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3120 if (rtl
) idx
= cChars
- 1 - i
;
3123 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3127 chInput
= mirror_char(pwcChars
[idx
]);
3129 chInput
= pwcChars
[idx
];
3130 rChars
[i
] = chInput
;
3134 rChars
[i
] = pwcChars
[idx
];
3135 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3138 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3146 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3151 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3159 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3160 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3166 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3167 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3168 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3170 for (i
= 0; i
< cChars
; ++i
)
3172 /* Special case for tabs and joiners. As control characters, ZWNJ
3173 * and ZWJ would in principle get handled by the corresponding
3174 * shaping functions. However, since ZWNJ and ZWJ can get merged
3175 * into adjoining runs during itemisation, these don't generally
3176 * get classified as Script_Control. */
3177 if (pwcChars
[i
] == 0x0009 || pwcChars
[i
] == ZWSP
|| pwcChars
[i
] == ZWNJ
|| pwcChars
[i
] == ZWJ
)
3179 pwOutGlyphs
[pwLogClust
[i
]] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3180 pOutGlyphProps
[pwLogClust
[i
]].sva
.fZeroWidth
= 1;
3187 TRACE("no glyph translation\n");
3188 for (i
= 0; i
< cChars
; i
++)
3191 /* No mirroring done here */
3192 if (rtl
) idx
= cChars
- 1 - i
;
3193 pwOutGlyphs
[i
] = pwcChars
[idx
];
3198 /* overwrite some basic control glyphs to blank */
3199 if (psa
->fNoGlyphIndex
)
3201 if (pwcChars
[idx
] == ZWSP
|| pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3203 pwOutGlyphs
[i
] = 0x20;
3204 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3207 else if (psa
->eScript
== Script_Control
|| pwcChars
[idx
] == ZWSP
3208 || pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3210 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3211 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3213 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3214 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3224 /***********************************************************************
3225 * ScriptShape (USP10.@)
3227 * Produce glyphs and visual attributes for a run.
3230 * hdc [I] Device context.
3231 * psc [I/O] Opaque pointer to a script cache.
3232 * pwcChars [I] Array of characters specifying the run.
3233 * cChars [I] Number of characters in pwcChars.
3234 * cMaxGlyphs [I] Length of pwOutGlyphs.
3235 * psa [I/O] Script analysis.
3236 * pwOutGlyphs [O] Array of glyphs.
3237 * pwLogClust [O] Array of logical cluster info.
3238 * psva [O] Array of visual attributes.
3239 * pcGlyphs [O] Number of glyphs returned.
3243 * Failure: Non-zero HRESULT value.
3245 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3246 int cChars
, int cMaxGlyphs
,
3247 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3248 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3252 SCRIPT_CHARPROP
*charProps
;
3253 SCRIPT_GLYPHPROP
*glyphProps
;
3255 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3256 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3258 if (!(charProps
= heap_calloc(cChars
, sizeof(*charProps
))))
3259 return E_OUTOFMEMORY
;
3261 if (!(glyphProps
= heap_calloc(cMaxGlyphs
, sizeof(*glyphProps
))))
3263 heap_free(charProps
);
3264 return E_OUTOFMEMORY
;
3267 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3271 for (i
= 0; i
< *pcGlyphs
; i
++)
3272 psva
[i
] = glyphProps
[i
].sva
;
3275 heap_free(charProps
);
3276 heap_free(glyphProps
);
3281 /***********************************************************************
3282 * ScriptPlaceOpenType (USP10.@)
3284 * Produce advance widths for a run.
3287 * hdc [I] Device context.
3288 * psc [I/O] Opaque pointer to a script cache.
3289 * psa [I/O] Script analysis.
3290 * tagScript [I] The OpenType tag for the Script
3291 * tagLangSys [I] The OpenType tag for the Language
3292 * rcRangeChars[I] Array of Character counts in each range
3293 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3294 * cRanges [I] Count of ranges
3295 * pwcChars [I] Array of characters specifying the run.
3296 * pwLogClust [I] Array of logical cluster info
3297 * pCharProps [I] Array of character property values
3298 * cChars [I] Number of characters in pwcChars.
3299 * pwGlyphs [I] Array of glyphs.
3300 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3301 * cGlyphs [I] Count of Glyphs
3302 * piAdvance [O] Array of advance widths.
3303 * pGoffset [O] Glyph offsets.
3304 * pABC [O] Combined ABC width.
3308 * Failure: Non-zero HRESULT value.
3311 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3312 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3313 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3314 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3315 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3316 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3317 int cGlyphs
, int *piAdvance
,
3318 GOFFSET
*pGoffset
, ABC
*pABC
3323 static int once
= 0;
3325 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3327 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3328 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3329 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3332 if (!pGlyphProps
) return E_INVALIDARG
;
3333 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3334 if (!pGoffset
) return E_FAIL
;
3337 if (!once
++) FIXME("Ranges not supported yet\n");
3339 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3340 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3342 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3343 for (i
= 0; i
< cGlyphs
; i
++)
3348 /* FIXME: set to more reasonable values */
3349 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3351 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3353 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3354 if (piAdvance
) piAdvance
[i
] = 0;
3358 if (psa
->fNoGlyphIndex
)
3360 if (FAILED(hr
= ScriptGetCMap(hdc
, psc
, &pwGlyphs
[i
], 1, 0, &glyph
))) return hr
;
3365 glyph
= pwGlyphs
[i
];
3370 if (!hdc
) return E_PENDING
;
3371 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3373 if (!GetCharABCWidthsW(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &abc
)) return S_FALSE
;
3378 if (!GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
)) return S_FALSE
;
3380 abc
.abcA
= abc
.abcC
= 0;
3383 else if (!get_cache_glyph_widths(psc
, glyph
, &abc
))
3385 if (!hdc
) return E_PENDING
;
3386 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3388 if (!GetCharABCWidthsI(hdc
, glyph
, 1, NULL
, &abc
)) return S_FALSE
;
3393 if (!GetCharWidthI(hdc
, glyph
, 1, NULL
, &width
)) return S_FALSE
;
3395 abc
.abcA
= abc
.abcC
= 0;
3397 set_cache_glyph_widths(psc
, glyph
, &abc
);
3401 pABC
->abcA
+= abc
.abcA
;
3402 pABC
->abcB
+= abc
.abcB
;
3403 pABC
->abcC
+= abc
.abcC
;
3405 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3408 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3410 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3414 /***********************************************************************
3415 * ScriptPlace (USP10.@)
3417 * Produce advance widths for a run.
3420 * hdc [I] Device context.
3421 * psc [I/O] Opaque pointer to a script cache.
3422 * pwGlyphs [I] Array of glyphs.
3423 * cGlyphs [I] Number of glyphs in pwGlyphs.
3424 * psva [I] Array of visual attributes.
3425 * psa [I/O] String analysis.
3426 * piAdvance [O] Array of advance widths.
3427 * pGoffset [O] Glyph offsets.
3428 * pABC [O] Combined ABC width.
3432 * Failure: Non-zero HRESULT value.
3434 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3435 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3436 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3439 SCRIPT_GLYPHPROP
*glyphProps
;
3442 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3443 piAdvance
, pGoffset
, pABC
);
3445 if (!psva
) return E_INVALIDARG
;
3446 if (!pGoffset
) return E_FAIL
;
3448 if (!(glyphProps
= heap_calloc(cGlyphs
, sizeof(*glyphProps
))))
3449 return E_OUTOFMEMORY
;
3451 for (i
= 0; i
< cGlyphs
; i
++)
3452 glyphProps
[i
].sva
= psva
[i
];
3454 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3456 heap_free(glyphProps
);
3461 /***********************************************************************
3462 * ScriptGetCMap (USP10.@)
3464 * Retrieve glyph indices.
3467 * hdc [I] Device context.
3468 * psc [I/O] Opaque pointer to a script cache.
3469 * pwcInChars [I] Array of Unicode characters.
3470 * cChars [I] Number of characters in pwcInChars.
3471 * dwFlags [I] Flags.
3472 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3476 * Failure: Non-zero HRESULT value.
3478 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3479 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3484 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3485 cChars
, dwFlags
, pwOutGlyphs
);
3487 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3491 for (i
= 0; i
< cChars
; i
++)
3494 if (dwFlags
== SGCM_RTL
)
3495 inChar
= mirror_char(pwcInChars
[i
]);
3497 inChar
= pwcInChars
[i
];
3498 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3501 if (!hdc
) return E_PENDING
;
3502 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3503 if (glyph
== 0xffff)
3508 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3515 /***********************************************************************
3516 * ScriptTextOut (USP10.@)
3519 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3520 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3521 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3522 const int *piJustify
, const GOFFSET
*pGoffset
)
3527 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3529 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3530 hdc
, psc
, x
, y
, fuOptions
, wine_dbgstr_rect(lprc
), psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3531 piAdvance
, piJustify
, pGoffset
);
3533 if (!hdc
|| !psc
) return E_INVALIDARG
;
3534 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3536 fuOptions
&= ETO_CLIPPED
| ETO_OPAQUE
;
3537 fuOptions
|= ETO_IGNORELANGUAGE
;
3538 if (!psa
->fNoGlyphIndex
&& *psc
&& ((ScriptCache
*)*psc
)->sfnt
)
3539 fuOptions
|= ETO_GLYPH_INDEX
; /* We do actually have glyph indices */
3541 if (!(lpDx
= heap_calloc(cGlyphs
, 2 * sizeof(*lpDx
))))
3542 return E_OUTOFMEMORY
;
3543 fuOptions
|= ETO_PDY
;
3545 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3547 if (!(reordered_glyphs
= heap_calloc(cGlyphs
, sizeof(*reordered_glyphs
))))
3550 return E_OUTOFMEMORY
;
3553 for (i
= 0; i
< cGlyphs
; i
++)
3554 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3558 for (i
= 0; i
< cGlyphs
; i
++)
3560 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3561 lpDx
[i
* 2] = piAdvance
[orig_index
];
3562 lpDx
[i
* 2 + 1] = 0;
3568 x
+= pGoffset
[orig_index
].du
* dir
;
3569 y
+= pGoffset
[orig_index
].dv
;
3573 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3574 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3576 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3577 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3581 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3584 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3590 /***********************************************************************
3591 * ScriptCacheGetHeight (USP10.@)
3593 * Retrieve the height of the font in the cache.
3596 * hdc [I] Device context.
3597 * psc [I/O] Opaque pointer to a script cache.
3598 * height [O] Receives font height.
3602 * Failure: Non-zero HRESULT value.
3604 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3608 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3610 if (!height
) return E_INVALIDARG
;
3611 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3613 *height
= get_cache_height(psc
);
3617 /***********************************************************************
3618 * ScriptGetGlyphABCWidth (USP10.@)
3620 * Retrieve the width of a glyph.
3623 * hdc [I] Device context.
3624 * psc [I/O] Opaque pointer to a script cache.
3625 * glyph [I] Glyph to retrieve the width for.
3626 * abc [O] ABC widths of the glyph.
3630 * Failure: Non-zero HRESULT value.
3632 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3636 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3638 if (!abc
) return E_INVALIDARG
;
3639 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3641 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3643 if (!hdc
) return E_PENDING
;
3644 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3646 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3651 if (!GetCharWidthI(hdc
, glyph
, 1, NULL
, &width
)) return S_FALSE
;
3653 abc
->abcA
= abc
->abcC
= 0;
3655 set_cache_glyph_widths(psc
, glyph
, abc
);
3660 /***********************************************************************
3661 * ScriptLayout (USP10.@)
3663 * Map embedding levels to visual and/or logical order.
3666 * runs [I] Size of level array.
3667 * level [I] Array of embedding levels.
3668 * vistolog [O] Map of embedding levels from visual to logical order.
3669 * logtovis [O] Map of embedding levels from logical to visual order.
3673 * Failure: Non-zero HRESULT value.
3676 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3681 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3683 if (!level
|| (!vistolog
&& !logtovis
))
3684 return E_INVALIDARG
;
3686 if (!(indices
= heap_calloc(runs
, sizeof(*indices
))))
3687 return E_OUTOFMEMORY
;
3691 for( ich
= 0; ich
< runs
; ich
++)
3696 ich
+= BIDI_ReorderV2lLevel(0, indices
+ich
, level
+ich
, runs
- ich
, FALSE
);
3697 memcpy(vistolog
, indices
, runs
* sizeof(*vistolog
));
3702 for( ich
= 0; ich
< runs
; ich
++)
3707 ich
+= BIDI_ReorderL2vLevel(0, indices
+ich
, level
+ich
, runs
- ich
, FALSE
);
3708 memcpy(logtovis
, indices
, runs
* sizeof(*logtovis
));
3715 /***********************************************************************
3716 * ScriptStringGetLogicalWidths (USP10.@)
3718 * Returns logical widths from a string analysis.
3721 * ssa [I] string analysis.
3722 * piDx [O] logical widths returned.
3726 * Failure: a non-zero HRESULT.
3728 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3731 StringAnalysis
*analysis
= ssa
;
3733 TRACE("%p, %p\n", ssa
, piDx
);
3735 if (!analysis
) return S_FALSE
;
3736 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3738 for (i
= 0; i
< analysis
->numItems
; i
++)
3740 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3743 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3746 for (j
= 0; j
< cChar
; j
++)
3749 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3750 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3751 cChar
, j
, direction
, NULL
, NULL
);
3752 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
);
3754 for (k
= 0; k
< clust_size
; k
++)
3756 piDx
[next
] = advance
/ clust_size
;
3765 /***********************************************************************
3766 * ScriptStringValidate (USP10.@)
3768 * Validate a string analysis.
3771 * ssa [I] string analysis.
3775 * Failure: S_FALSE if invalid sequences are found
3776 * or a non-zero HRESULT if it fails.
3778 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3780 StringAnalysis
*analysis
= ssa
;
3782 TRACE("(%p)\n", ssa
);
3784 if (!analysis
) return E_INVALIDARG
;
3785 return analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
? S_FALSE
: S_OK
;
3788 /***********************************************************************
3789 * ScriptString_pSize (USP10.@)
3791 * Retrieve width and height of an analysed string.
3794 * ssa [I] string analysis.
3797 * Success: Pointer to a SIZE structure.
3800 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3803 StringAnalysis
*analysis
= ssa
;
3805 TRACE("(%p)\n", ssa
);
3807 if (!analysis
) return NULL
;
3808 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return NULL
;
3810 if (!(analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
))
3812 analysis
->sz
.cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3814 analysis
->sz
.cx
= 0;
3815 for (i
= 0; i
< analysis
->numItems
; i
++)
3817 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
.cy
)
3818 analysis
->sz
.cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3819 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3820 analysis
->sz
.cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3822 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
;
3824 return &analysis
->sz
;
3827 /***********************************************************************
3828 * ScriptString_pLogAttr (USP10.@)
3830 * Retrieve logical attributes of an analysed string.
3833 * ssa [I] string analysis.
3836 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3839 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3841 StringAnalysis
*analysis
= ssa
;
3843 TRACE("(%p)\n", ssa
);
3845 if (!analysis
) return NULL
;
3846 if (!(analysis
->ssa_flags
& SSA_BREAK
)) return NULL
;
3847 return analysis
->logattrs
;
3850 /***********************************************************************
3851 * ScriptString_pcOutChars (USP10.@)
3853 * Retrieve the length of a string after clipping.
3856 * ssa [I] String analysis.
3859 * Success: Pointer to the length.
3862 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3864 StringAnalysis
*analysis
= ssa
;
3866 TRACE("(%p)\n", ssa
);
3868 if (!analysis
) return NULL
;
3869 return &analysis
->clip_len
;
3872 /***********************************************************************
3873 * ScriptStringGetOrder (USP10.@)
3875 * Retrieve a glyph order map.
3878 * ssa [I] String analysis.
3879 * order [I/O] Array of glyph positions.
3883 * Failure: a non-zero HRESULT.
3885 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3889 StringAnalysis
*analysis
= ssa
;
3891 TRACE("(%p)\n", ssa
);
3893 if (!analysis
) return S_FALSE
;
3894 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3896 /* FIXME: handle RTL scripts */
3897 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3898 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3904 /***********************************************************************
3905 * ScriptGetLogicalWidths (USP10.@)
3907 * Convert advance widths to logical widths.
3910 * sa [I] Script analysis.
3911 * nbchars [I] Number of characters.
3912 * nbglyphs [I] Number of glyphs.
3913 * glyph_width [I] Array of glyph widths.
3914 * log_clust [I] Array of logical clusters.
3915 * sva [I] Visual attributes.
3916 * widths [O] Array of logical widths.
3920 * Failure: a non-zero HRESULT.
3922 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3923 const int *advances
, const WORD
*log_clust
,
3924 const SCRIPT_VISATTR
*sva
, int *widths
)
3926 int i
, next
= 0, direction
;
3928 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3929 sa
, nbchars
, nbglyphs
, advances
, log_clust
, sva
, widths
);
3931 if (sa
->fRTL
&& !sa
->fLogicalOrder
)
3936 for (i
= 0; i
< nbchars
; i
++)
3938 int clust_size
= get_cluster_size(log_clust
, nbchars
, i
, direction
, NULL
, NULL
);
3939 int advance
= get_glyph_cluster_advance(advances
, sva
, log_clust
, nbglyphs
, nbchars
, log_clust
[i
], direction
);
3942 for (j
= 0; j
< clust_size
; j
++)
3944 widths
[next
] = advance
/ clust_size
;
3953 /***********************************************************************
3954 * ScriptApplyLogicalWidth (USP10.@)
3956 * Generate glyph advance widths.
3959 * dx [I] Array of logical advance widths.
3960 * num_chars [I] Number of characters.
3961 * num_glyphs [I] Number of glyphs.
3962 * log_clust [I] Array of logical clusters.
3963 * sva [I] Visual attributes.
3964 * advance [I] Array of glyph advance widths.
3965 * sa [I] Script analysis.
3966 * abc [I/O] Summed ABC widths.
3967 * justify [O] Array of glyph advance widths.
3971 * Failure: a non-zero HRESULT.
3973 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
3974 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
3975 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
3976 ABC
*abc
, int *justify
)
3980 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3981 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
3983 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
3987 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
3988 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
3992 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
3994 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
3998 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
4001 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4002 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4004 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
4007 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
4010 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4011 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4013 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
4016 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
4019 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4020 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4022 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);
4025 HRESULT WINAPI
ScriptGetFontAlternateGlyphs( HDC hdc
, SCRIPT_CACHE
*sc
, SCRIPT_ANALYSIS
*sa
, OPENTYPE_TAG tag_script
, OPENTYPE_TAG tag_langsys
, OPENTYPE_TAG tag_feature
,
4026 WORD id
, int size
, WORD
*list
, int *count
)
4028 FIXME("(%p, %p, %p, %s, %s, %s, 0x%04x, %d, %p, %p)\n", hdc
, sc
, sa
, debugstr_an((char*)&tag_script
,4), debugstr_an((char*)&tag_langsys
,4),
4029 debugstr_an((char*)&tag_feature
,4), id
, size
, list
, count
);