2 * Implementation of Uniscribe Script Processor (usp10.dll)
4 * Copyright 2005 Steven Edwards for CodeWeavers
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * Uniscribe allows for processing of complex scripts such as joining
24 * and filtering characters and bi-directional text with custom line breaks.
39 #include "usp10_internal.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe
);
46 static const struct usp10_script_range
48 enum usp10_script script
;
51 enum usp10_script numericScript
;
52 enum usp10_script punctScript
;
56 /* Basic Latin: U+0000–U+007A */
57 { Script_Latin
, 0x00, 0x07a , Script_Numeric
, Script_Punctuation
},
58 /* Latin-1 Supplement: U+0080–U+00FF */
59 /* Latin Extended-A: U+0100–U+017F */
60 /* Latin Extended-B: U+0180–U+024F */
61 /* IPA Extensions: U+0250–U+02AF */
62 /* Spacing Modifier Letters:U+02B0–U+02FF */
63 { Script_Latin
, 0x80, 0x2ff , Script_Numeric2
, Script_Punctuation
},
64 /* Combining Diacritical Marks : U+0300–U+036F */
65 { Script_Diacritical
,0x300, 0x36f, 0, 0},
66 /* Greek: U+0370–U+03FF */
67 { Script_Greek
, 0x370, 0x3ff, 0, 0},
68 /* Cyrillic: U+0400–U+04FF */
69 /* Cyrillic Supplement: U+0500–U+052F */
70 { Script_Cyrillic
, 0x400, 0x52f, 0, 0},
71 /* Armenian: U+0530–U+058F */
72 { Script_Armenian
, 0x530, 0x58f, 0, 0},
73 /* Hebrew: U+0590–U+05FF */
74 { Script_Hebrew
, 0x590, 0x5ff, 0, 0},
75 /* Arabic: U+0600–U+06FF */
76 { Script_Arabic
, 0x600, 0x6ef, Script_Arabic_Numeric
, 0},
77 /* Defined by Windows */
78 { Script_Persian
, 0x6f0, 0x6f9, 0, 0},
79 /* Continue Arabic: U+0600–U+06FF */
80 { Script_Arabic
, 0x6fa, 0x6ff, 0, 0},
81 /* Syriac: U+0700–U+074F*/
82 { Script_Syriac
, 0x700, 0x74f, 0, 0},
83 /* Arabic Supplement: U+0750–U+077F */
84 { Script_Arabic
, 0x750, 0x77f, 0, 0},
85 /* Thaana: U+0780–U+07BF */
86 { Script_Thaana
, 0x780, 0x7bf, 0, 0},
87 /* N’Ko: U+07C0–U+07FF */
88 { Script_NKo
, 0x7c0, 0x7ff, 0, 0},
89 /* Devanagari: U+0900–U+097F */
90 { Script_Devanagari
, 0x900, 0x97f, Script_Devanagari_Numeric
, 0},
91 /* Bengali: U+0980–U+09FF */
92 { Script_Bengali
, 0x980, 0x9ff, Script_Bengali_Numeric
, 0},
93 /* Gurmukhi: U+0A00–U+0A7F*/
94 { Script_Gurmukhi
, 0xa00, 0xa7f, Script_Gurmukhi_Numeric
, 0},
95 /* Gujarati: U+0A80–U+0AFF*/
96 { Script_Gujarati
, 0xa80, 0xaff, Script_Gujarati_Numeric
, 0},
97 /* Oriya: U+0B00–U+0B7F */
98 { Script_Oriya
, 0xb00, 0xb7f, Script_Oriya_Numeric
, 0},
99 /* Tamil: U+0B80–U+0BFF */
100 { Script_Tamil
, 0xb80, 0xbff, Script_Tamil_Numeric
, 0},
101 /* Telugu: U+0C00–U+0C7F */
102 { Script_Telugu
, 0xc00, 0xc7f, Script_Telugu_Numeric
, 0},
103 /* Kannada: U+0C80–U+0CFF */
104 { Script_Kannada
, 0xc80, 0xcff, Script_Kannada_Numeric
, 0},
105 /* Malayalam: U+0D00–U+0D7F */
106 { Script_Malayalam
, 0xd00, 0xd7f, Script_Malayalam_Numeric
, 0},
107 /* Sinhala: U+0D80–U+0DFF */
108 { Script_Sinhala
, 0xd80, 0xdff, 0, 0},
109 /* Thai: U+0E00–U+0E7F */
110 { Script_Thai
, 0xe00, 0xe7f, Script_Thai_Numeric
, 0},
111 /* Lao: U+0E80–U+0EFF */
112 { Script_Lao
, 0xe80, 0xeff, Script_Lao_Numeric
, 0},
113 /* Tibetan: U+0F00–U+0FFF */
114 { Script_Tibetan
, 0xf00, 0xfff, 0, 0},
115 /* Myanmar: U+1000–U+109F */
116 { Script_Myanmar
, 0x1000, 0x109f, Script_Myanmar_Numeric
, 0},
117 /* Georgian: U+10A0–U+10FF */
118 { Script_Georgian
, 0x10a0, 0x10ff, 0, 0},
119 /* Hangul Jamo: U+1100–U+11FF */
120 { Script_Hangul
, 0x1100, 0x11ff, 0, 0},
121 /* Ethiopic: U+1200–U+137F */
122 /* Ethiopic Extensions: U+1380–U+139F */
123 { Script_Ethiopic
, 0x1200, 0x139f, 0, 0},
124 /* Cherokee: U+13A0–U+13FF */
125 { Script_Cherokee
, 0x13a0, 0x13ff, 0, 0},
126 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
127 { Script_Canadian
, 0x1400, 0x167f, 0, 0},
128 /* Ogham: U+1680–U+169F */
129 { Script_Ogham
, 0x1680, 0x169f, 0, 0},
130 /* Runic: U+16A0–U+16F0 */
131 { Script_Runic
, 0x16a0, 0x16f0, 0, 0},
132 /* Khmer: U+1780–U+17FF */
133 { Script_Khmer
, 0x1780, 0x17ff, Script_Khmer_Numeric
, 0},
134 /* Mongolian: U+1800–U+18AF */
135 { Script_Mongolian
, 0x1800, 0x18af, Script_Mongolian_Numeric
, 0},
136 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
137 { Script_Canadian
, 0x18b0, 0x18ff, 0, 0},
138 /* Tai Le: U+1950–U+197F */
139 { Script_Tai_Le
, 0x1950, 0x197f, 0, 0},
140 /* New Tai Lue: U+1980–U+19DF */
141 { Script_New_Tai_Lue
,0x1980, 0x19df, Script_New_Tai_Lue_Numeric
, 0},
142 /* Khmer Symbols: U+19E0–U+19FF */
143 { Script_Khmer
, 0x19e0, 0x19ff, Script_Khmer_Numeric
, 0},
144 /* Vedic Extensions: U+1CD0-U+1CFF */
145 { Script_Devanagari
, 0x1cd0, 0x1cff, Script_Devanagari_Numeric
, 0},
146 /* Phonetic Extensions: U+1D00–U+1DBF */
147 { Script_Latin
, 0x1d00, 0x1dbf, 0, 0},
148 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
149 { Script_Diacritical
,0x1dc0, 0x1dff, 0, 0},
150 /* Latin Extended Additional: U+1E00–U+1EFF */
151 { Script_Latin
, 0x1e00, 0x1eff, 0, 0},
152 /* Greek Extended: U+1F00–U+1FFF */
153 { Script_Greek
, 0x1f00, 0x1fff, 0, 0},
154 /* General Punctuation: U+2000 –U+206f */
155 { Script_Latin
, 0x2000, 0x206f, 0, 0},
156 /* Superscripts and Subscripts : U+2070 –U+209f */
157 /* Currency Symbols : U+20a0 –U+20cf */
158 { Script_Numeric2
, 0x2070, 0x2070, 0, 0},
159 { Script_Latin
, 0x2071, 0x2073, 0, 0},
160 { Script_Numeric2
, 0x2074, 0x2079, 0, 0},
161 { Script_Latin
, 0x207a, 0x207f, 0, 0},
162 { Script_Numeric2
, 0x2080, 0x2089, 0, 0},
163 { Script_Latin
, 0x208a, 0x20cf, 0, 0},
164 /* Letterlike Symbols : U+2100 –U+214f */
165 /* Number Forms : U+2150 –U+218f */
166 /* Arrows : U+2190 –U+21ff */
167 /* Mathematical Operators : U+2200 –U+22ff */
168 /* Miscellaneous Technical : U+2300 –U+23ff */
169 /* Control Pictures : U+2400 –U+243f */
170 /* Optical Character Recognition : U+2440 –U+245f */
171 /* Enclosed Alphanumerics : U+2460 –U+24ff */
172 /* Box Drawing : U+2500 –U+25ff */
173 /* Block Elements : U+2580 –U+259f */
174 /* Geometric Shapes : U+25a0 –U+25ff */
175 /* Miscellaneous Symbols : U+2600 –U+26ff */
176 /* Dingbats : U+2700 –U+27bf */
177 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
178 /* Supplemental Arrows-A : U+27f0 –U+27ff */
179 { Script_Latin
, 0x2100, 0x27ff, 0, 0},
180 /* Braille Patterns: U+2800–U+28FF */
181 { Script_Braille
, 0x2800, 0x28ff, 0, 0},
182 /* Supplemental Arrows-B : U+2900 –U+297f */
183 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
184 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
185 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
186 { Script_Latin
, 0x2900, 0x2bff, 0, 0},
187 /* Latin Extended-C: U+2C60–U+2C7F */
188 { Script_Latin
, 0x2c60, 0x2c7f, 0, 0},
189 /* Georgian: U+2D00–U+2D2F */
190 { Script_Georgian
, 0x2d00, 0x2d2f, 0, 0},
191 /* Tifinagh: U+2D30–U+2D7F */
192 { Script_Tifinagh
, 0x2d30, 0x2d7f, 0, 0},
193 /* Ethiopic Extensions: U+2D80–U+2DDF */
194 { Script_Ethiopic
, 0x2d80, 0x2ddf, 0, 0},
195 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
196 { Script_Cyrillic
, 0x2de0, 0x2dff, 0, 0},
197 /* CJK Radicals Supplement: U+2E80–U+2EFF */
198 /* Kangxi Radicals: U+2F00–U+2FDF */
199 { Script_CJK_Han
, 0x2e80, 0x2fdf, 0, 0},
200 /* Ideographic Description Characters: U+2FF0–U+2FFF */
201 { Script_Ideograph
,0x2ff0, 0x2fff, 0, 0},
202 /* CJK Symbols and Punctuation: U+3000–U+303F */
203 { Script_Ideograph
,0x3000, 0x3004, 0, 0},
204 { Script_CJK_Han
,0x3005, 0x3005, 0, 0},
205 { Script_Ideograph
,0x3006, 0x3006, 0, 0},
206 { Script_CJK_Han
,0x3007, 0x3007, 0, 0},
207 { Script_Ideograph
,0x3008, 0x3020, 0, 0},
208 { Script_CJK_Han
,0x3021, 0x3029, 0, 0},
209 { Script_Ideograph
,0x302a, 0x3030, 0, 0},
211 { Script_Kana
,0x3031, 0x3035, 0, 0},
212 { Script_Ideograph
,0x3036, 0x3037, 0, 0},
213 { Script_CJK_Han
,0x3038, 0x303b, 0, 0},
214 { Script_Ideograph
,0x303c, 0x303f, 0, 0},
215 /* Hiragana: U+3040–U+309F */
216 /* Katakana: U+30A0–U+30FF */
217 { Script_Kana
,0x3040, 0x30ff, 0, 0},
218 /* Bopomofo: U+3100–U+312F */
219 { Script_Bopomofo
,0x3100, 0x312f, 0, 0},
220 /* Hangul Compatibility Jamo: U+3130–U+318F */
221 { Script_Hangul
,0x3130, 0x318f, 0, 0},
222 /* Kanbun: U+3190–U+319F */
223 { Script_Ideograph
,0x3190, 0x319f, 0, 0},
224 /* Bopomofo Extended: U+31A0–U+31BF */
225 { Script_Bopomofo
,0x31a0, 0x31bf, 0, 0},
226 /* CJK Strokes: U+31C0–U+31EF */
227 { Script_Ideograph
,0x31c0, 0x31ef, 0, 0},
228 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
229 { Script_Kana
,0x31f0, 0x31ff, 0, 0},
230 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
231 { Script_Hangul
,0x3200, 0x321f, 0, 0},
232 { Script_Ideograph
,0x3220, 0x325f, 0, 0},
233 { Script_Hangul
,0x3260, 0x327f, 0, 0},
234 { Script_Ideograph
,0x3280, 0x32ef, 0, 0},
235 { Script_Kana
,0x32d0, 0x31ff, 0, 0},
236 /* CJK Compatibility: U+3300–U+33FF*/
237 { Script_Kana
,0x3300, 0x3357, 0, 0},
238 { Script_Ideograph
,0x3358, 0x33ff, 0, 0},
239 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
240 { Script_CJK_Han
,0x3400, 0x4dbf, 0, 0},
241 /* CJK Unified Ideographs: U+4E00–U+9FFF */
242 { Script_CJK_Han
,0x4e00, 0x9fff, 0, 0},
243 /* Yi: U+A000–U+A4CF */
244 { Script_Yi
,0xa000, 0xa4cf, 0, 0},
245 /* Vai: U+A500–U+A63F */
246 { Script_Vai
,0xa500, 0xa63f, Script_Vai_Numeric
, 0},
247 /* Cyrillic Extended-B: U+A640–U+A69F */
248 { Script_Cyrillic
, 0xa640, 0xa69f, 0, 0},
249 /* Modifier Tone Letters: U+A700–U+A71F */
250 /* Latin Extended-D: U+A720–U+A7FF */
251 { Script_Latin
, 0xa700, 0xa7ff, 0, 0},
252 /* Phags-pa: U+A840–U+A87F */
253 { Script_Phags_pa
, 0xa840, 0xa87f, 0, 0},
254 /* Devanagari Extended: U+A8E0-U+A8FF */
255 { Script_Devanagari
, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric
, 0},
256 /* Myanmar Extended-A: U+AA60–U+AA7F */
257 { Script_Myanmar
, 0xaa60, 0xaa7f, Script_Myanmar_Numeric
, 0},
258 /* Hangul Jamo Extended-A: U+A960–U+A97F */
259 { Script_Hangul
, 0xa960, 0xa97f, 0, 0},
260 /* Hangul Syllables: U+AC00–U+D7A3 */
261 { Script_Hangul
, 0xac00, 0xd7a3, 0, 0},
262 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
263 { Script_Hangul
, 0xd7b0, 0xd7ff, 0, 0},
264 /* Surrogates Area: U+D800–U+DFFF */
265 { Script_Surrogates
, 0xd800, 0xdbfe, 0, 0},
266 { Script_Private
, 0xdbff, 0xdc00, 0, 0},
267 { Script_Surrogates
, 0xdc01, 0xdfff, 0, 0},
268 /* Private Use Area: U+E000–U+F8FF */
269 { Script_Private
, 0xe000, 0xf8ff, 0, 0},
270 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
271 { Script_CJK_Han
,0xf900, 0xfaff, 0, 0},
272 /* Latin Ligatures: U+FB00–U+FB06 */
273 { Script_Latin
, 0xfb00, 0xfb06, 0, 0},
274 /* Armenian ligatures U+FB13..U+FB17 */
275 { Script_Armenian
, 0xfb13, 0xfb17, 0, 0},
276 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
277 { Script_Hebrew
, 0xfb1d, 0xfb4f, 0, 0},
278 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
279 { Script_Arabic
, 0xfb50, 0xfdff, 0, 0},
280 /* Vertical Forms: U+FE10–U+FE1F */
281 /* Combining Half Marks: U+FE20–U+FE2F */
282 /* CJK Compatibility Forms: U+FE30–U+FE4F */
283 /* Small Form Variants: U+FE50–U+FE6F */
284 { Script_Ideograph
,0xfe10, 0xfe6f, 0, 0},
285 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
286 { Script_Arabic
, 0xfe70, 0xfeff, 0, 0},
287 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
288 { Script_Ideograph
,0xff00, 0xff64, Script_Numeric2
, 0},
289 { Script_Kana
,0xff65, 0xff9f, 0, 0},
290 { Script_Hangul
,0xffa0, 0xffdf, 0, 0},
291 { Script_Ideograph
,0xffe0, 0xffef, 0, 0},
293 /* Deseret: U+10400–U+1044F */
294 { Script_Deseret
, 0x10400, 0x1044F, 0, 0},
295 /* Osmanya: U+10480–U+104AF */
296 { Script_Osmanya
, 0x10480, 0x104AF, Script_Osmanya_Numeric
, 0},
297 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
298 { Script_MathAlpha
, 0x1D400, 0x1D7FF, 0, 0},
301 /* this must be in order so that the index matches the Script value */
302 const scriptData scriptInformation
[] = {
303 {{SCRIPT_UNDEFINED
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
304 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
307 {{Script_Latin
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
308 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
309 MS_MAKE_TAG('l','a','t','n'),
310 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
311 {{Script_CR
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
312 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
315 {{Script_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
316 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
318 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
319 {{Script_Control
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
320 {LANG_ENGLISH
, 0, 1, 0, 0, ANSI_CHARSET
, 1, 0, 0, 0, 0, 0, 1, 0, 0},
323 {{Script_Punctuation
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
324 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
326 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
327 {{Script_Arabic
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
328 {LANG_ARABIC
, 0, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 1, 0},
329 MS_MAKE_TAG('a','r','a','b'),
330 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
331 {{Script_Arabic_Numeric
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
332 {LANG_ARABIC
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
333 MS_MAKE_TAG('a','r','a','b'),
334 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
335 {{Script_Hebrew
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
336 {LANG_HEBREW
, 0, 1, 0, 1, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
337 MS_MAKE_TAG('h','e','b','r'),
338 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
339 {{Script_Syriac
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
340 {LANG_SYRIAC
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 1, 0},
341 MS_MAKE_TAG('s','y','r','c'),
342 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
343 {{Script_Persian
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
344 {LANG_PERSIAN
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
345 MS_MAKE_TAG('a','r','a','b'),
346 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
347 {{Script_Thaana
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
348 {LANG_DIVEHI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
349 MS_MAKE_TAG('t','h','a','a'),
350 {'M','V',' ','B','o','l','i',0}},
351 {{Script_Greek
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
352 {LANG_GREEK
, 0, 0, 0, 0, GREEK_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
353 MS_MAKE_TAG('g','r','e','k'),
354 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
355 {{Script_Cyrillic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
356 {LANG_RUSSIAN
, 0, 0, 0, 0, RUSSIAN_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
357 MS_MAKE_TAG('c','y','r','l'),
358 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
359 {{Script_Armenian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
360 {LANG_ARMENIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
361 MS_MAKE_TAG('a','r','m','n'),
362 {'S','y','l','f','a','e','n',0}},
363 {{Script_Georgian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
364 {LANG_GEORGIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
365 MS_MAKE_TAG('g','e','o','r'),
366 {'S','y','l','f','a','e','n',0}},
367 {{Script_Sinhala
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
368 {LANG_SINHALESE
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
369 MS_MAKE_TAG('s','i','n','h'),
370 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
371 {{Script_Tibetan
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
372 {LANG_TIBETAN
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
373 MS_MAKE_TAG('t','i','b','t'),
374 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
375 {{Script_Tibetan_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
376 {LANG_TIBETAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
377 MS_MAKE_TAG('t','i','b','t'),
378 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
379 {{Script_Phags_pa
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
380 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
381 MS_MAKE_TAG('p','h','a','g'),
382 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
383 {{Script_Thai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
384 {LANG_THAI
, 0, 1, 1, 1, THAI_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 1},
385 MS_MAKE_TAG('t','h','a','i'),
386 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
387 {{Script_Thai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
388 {LANG_THAI
, 1, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
389 MS_MAKE_TAG('t','h','a','i'),
390 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
391 {{Script_Lao
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
392 {LANG_LAO
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
393 MS_MAKE_TAG('l','a','o',' '),
394 {'D','o','k','C','h','a','m','p','a',0}},
395 {{Script_Lao_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
396 {LANG_LAO
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
397 MS_MAKE_TAG('l','a','o',' '),
398 {'D','o','k','C','h','a','m','p','a',0}},
399 {{Script_Devanagari
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
400 {LANG_HINDI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
401 MS_MAKE_TAG('d','e','v','a'),
402 {'M','a','n','g','a','l',0}},
403 {{Script_Devanagari_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
404 {LANG_HINDI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
405 MS_MAKE_TAG('d','e','v','a'),
406 {'M','a','n','g','a','l',0}},
407 {{Script_Bengali
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
408 {LANG_BENGALI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
409 MS_MAKE_TAG('b','e','n','g'),
410 {'V','r','i','n','d','a',0}},
411 {{Script_Bengali_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
412 {LANG_BENGALI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
413 MS_MAKE_TAG('b','e','n','g'),
414 {'V','r','i','n','d','a',0}},
415 {{Script_Bengali_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
416 {LANG_BENGALI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
417 MS_MAKE_TAG('b','e','n','g'),
418 {'V','r','i','n','d','a',0}},
419 {{Script_Gurmukhi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
420 {LANG_PUNJABI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
421 MS_MAKE_TAG('g','u','r','u'),
422 {'R','a','a','v','i',0}},
423 {{Script_Gurmukhi_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
424 {LANG_PUNJABI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
425 MS_MAKE_TAG('g','u','r','u'),
426 {'R','a','a','v','i',0}},
427 {{Script_Gujarati
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
428 {LANG_GUJARATI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
429 MS_MAKE_TAG('g','u','j','r'),
430 {'S','h','r','u','t','i',0}},
431 {{Script_Gujarati_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
432 {LANG_GUJARATI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
433 MS_MAKE_TAG('g','u','j','r'),
434 {'S','h','r','u','t','i',0}},
435 {{Script_Gujarati_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
436 {LANG_GUJARATI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
437 MS_MAKE_TAG('g','u','j','r'),
438 {'S','h','r','u','t','i',0}},
439 {{Script_Oriya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
440 {LANG_ORIYA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
441 MS_MAKE_TAG('o','r','y','a'),
442 {'K','a','l','i','n','g','a',0}},
443 {{Script_Oriya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
444 {LANG_ORIYA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
445 MS_MAKE_TAG('o','r','y','a'),
446 {'K','a','l','i','n','g','a',0}},
447 {{Script_Tamil
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
448 {LANG_TAMIL
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
449 MS_MAKE_TAG('t','a','m','l'),
450 {'L','a','t','h','a',0}},
451 {{Script_Tamil_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
452 {LANG_TAMIL
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
453 MS_MAKE_TAG('t','a','m','l'),
454 {'L','a','t','h','a',0}},
455 {{Script_Telugu
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
456 {LANG_TELUGU
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
457 MS_MAKE_TAG('t','e','l','u'),
458 {'G','a','u','t','a','m','i',0}},
459 {{Script_Telugu_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
460 {LANG_TELUGU
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
461 MS_MAKE_TAG('t','e','l','u'),
462 {'G','a','u','t','a','m','i',0}},
463 {{Script_Kannada
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
464 {LANG_KANNADA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
465 MS_MAKE_TAG('k','n','d','a'),
466 {'T','u','n','g','a',0}},
467 {{Script_Kannada_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
468 {LANG_KANNADA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
469 MS_MAKE_TAG('k','n','d','a'),
470 {'T','u','n','g','a',0}},
471 {{Script_Malayalam
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
472 {LANG_MALAYALAM
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
473 MS_MAKE_TAG('m','l','y','m'),
474 {'K','a','r','t','i','k','a',0}},
475 {{Script_Malayalam_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
476 {LANG_MALAYALAM
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
477 MS_MAKE_TAG('m','l','y','m'),
478 {'K','a','r','t','i','k','a',0}},
479 {{Script_Diacritical
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
480 {LANG_ENGLISH
, 0, 1, 0, 1, ANSI_CHARSET
, 0, 0, 0, 0, 0, 1, 1, 0, 0},
483 {{Script_Punctuation2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
484 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
485 MS_MAKE_TAG('l','a','t','n'),
486 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
487 {{Script_Numeric2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
488 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
491 {{Script_Myanmar
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
492 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
493 MS_MAKE_TAG('m','y','m','r'),
494 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
495 {{Script_Myanmar_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
496 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
497 MS_MAKE_TAG('m','y','m','r'),
499 {{Script_Tai_Le
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
500 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
501 MS_MAKE_TAG('t','a','l','e'),
502 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
503 {{Script_New_Tai_Lue
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
504 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
505 MS_MAKE_TAG('t','a','l','u'),
506 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
507 {{Script_New_Tai_Lue_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
508 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
509 MS_MAKE_TAG('t','a','l','u'),
510 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
511 {{Script_Khmer
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
512 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
513 MS_MAKE_TAG('k','h','m','r'),
514 {'D','a','u','n','P','e','n','h',0}},
515 {{Script_Khmer_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
516 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
517 MS_MAKE_TAG('k','h','m','r'),
518 {'D','a','u','n','P','e','n','h',0}},
519 {{Script_CJK_Han
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
520 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
521 MS_MAKE_TAG('h','a','n','i'),
523 {{Script_Ideograph
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
524 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
525 MS_MAKE_TAG('h','a','n','i'),
527 {{Script_Bopomofo
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
528 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
529 MS_MAKE_TAG('b','o','p','o'),
531 {{Script_Kana
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
532 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
533 MS_MAKE_TAG('k','a','n','a'),
535 {{Script_Hangul
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
536 {LANG_KOREAN
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
537 MS_MAKE_TAG('h','a','n','g'),
539 {{Script_Yi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
540 {LANG_ENGLISH
, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
541 MS_MAKE_TAG('y','i',' ',' '),
542 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
543 {{Script_Ethiopic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
544 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
545 MS_MAKE_TAG('e','t','h','i'),
546 {'N','y','a','l','a',0}},
547 {{Script_Ethiopic_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
548 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
549 MS_MAKE_TAG('e','t','h','i'),
550 {'N','y','a','l','a',0}},
551 {{Script_Mongolian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
552 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
553 MS_MAKE_TAG('m','o','n','g'),
554 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
555 {{Script_Mongolian_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
556 {LANG_MONGOLIAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
557 MS_MAKE_TAG('m','o','n','g'),
558 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
559 {{Script_Tifinagh
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
560 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
561 MS_MAKE_TAG('t','f','n','g'),
562 {'E','b','r','i','m','a',0}},
563 {{Script_NKo
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
564 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
565 MS_MAKE_TAG('n','k','o',' '),
566 {'E','b','r','i','m','a',0}},
567 {{Script_Vai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
568 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
569 MS_MAKE_TAG('v','a','i',' '),
570 {'E','b','r','i','m','a',0}},
571 {{Script_Vai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
572 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
573 MS_MAKE_TAG('v','a','i',' '),
574 {'E','b','r','i','m','a',0}},
575 {{Script_Cherokee
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
576 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
577 MS_MAKE_TAG('c','h','e','r'),
578 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
579 {{Script_Canadian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
580 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
581 MS_MAKE_TAG('c','a','n','s'),
582 {'E','u','p','h','e','m','i','a',0}},
583 {{Script_Ogham
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
584 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
585 MS_MAKE_TAG('o','g','a','m'),
586 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
587 {{Script_Runic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
588 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
589 MS_MAKE_TAG('r','u','n','r'),
590 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
591 {{Script_Braille
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
592 {LANG_ENGLISH
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
593 MS_MAKE_TAG('b','r','a','i'),
594 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
595 {{Script_Surrogates
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
596 {LANG_ENGLISH
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
599 {{Script_Private
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
600 {0, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 1, 0, 0, 0, 0, 1, 0, 0},
603 {{Script_Deseret
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
604 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
605 MS_MAKE_TAG('d','s','r','t'),
606 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
607 {{Script_Osmanya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
608 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
609 MS_MAKE_TAG('o','s','m','a'),
610 {'E','b','r','i','m','a',0}},
611 {{Script_Osmanya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
612 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
613 MS_MAKE_TAG('o','s','m','a'),
614 {'E','b','r','i','m','a',0}},
615 {{Script_MathAlpha
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
616 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
617 MS_MAKE_TAG('m','a','t','h'),
618 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
619 {{Script_Hebrew_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
620 {LANG_HEBREW
, 0, 1, 0, 0, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
621 MS_MAKE_TAG('h','e','b','r'),
622 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
623 {{Script_Vietnamese_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
624 {LANG_VIETNAMESE
, 0, 0, 0, 0, VIETNAMESE_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
625 MS_MAKE_TAG('l','a','t','n'),
626 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
627 {{Script_Thai_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
628 {LANG_THAI
, 0, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
629 MS_MAKE_TAG('t','h','a','i'),
630 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
633 static const SCRIPT_PROPERTIES
*script_props
[] =
635 &scriptInformation
[0].props
, &scriptInformation
[1].props
,
636 &scriptInformation
[2].props
, &scriptInformation
[3].props
,
637 &scriptInformation
[4].props
, &scriptInformation
[5].props
,
638 &scriptInformation
[6].props
, &scriptInformation
[7].props
,
639 &scriptInformation
[8].props
, &scriptInformation
[9].props
,
640 &scriptInformation
[10].props
, &scriptInformation
[11].props
,
641 &scriptInformation
[12].props
, &scriptInformation
[13].props
,
642 &scriptInformation
[14].props
, &scriptInformation
[15].props
,
643 &scriptInformation
[16].props
, &scriptInformation
[17].props
,
644 &scriptInformation
[18].props
, &scriptInformation
[19].props
,
645 &scriptInformation
[20].props
, &scriptInformation
[21].props
,
646 &scriptInformation
[22].props
, &scriptInformation
[23].props
,
647 &scriptInformation
[24].props
, &scriptInformation
[25].props
,
648 &scriptInformation
[26].props
, &scriptInformation
[27].props
,
649 &scriptInformation
[28].props
, &scriptInformation
[29].props
,
650 &scriptInformation
[30].props
, &scriptInformation
[31].props
,
651 &scriptInformation
[32].props
, &scriptInformation
[33].props
,
652 &scriptInformation
[34].props
, &scriptInformation
[35].props
,
653 &scriptInformation
[36].props
, &scriptInformation
[37].props
,
654 &scriptInformation
[38].props
, &scriptInformation
[39].props
,
655 &scriptInformation
[40].props
, &scriptInformation
[41].props
,
656 &scriptInformation
[42].props
, &scriptInformation
[43].props
,
657 &scriptInformation
[44].props
, &scriptInformation
[45].props
,
658 &scriptInformation
[46].props
, &scriptInformation
[47].props
,
659 &scriptInformation
[48].props
, &scriptInformation
[49].props
,
660 &scriptInformation
[50].props
, &scriptInformation
[51].props
,
661 &scriptInformation
[52].props
, &scriptInformation
[53].props
,
662 &scriptInformation
[54].props
, &scriptInformation
[55].props
,
663 &scriptInformation
[56].props
, &scriptInformation
[57].props
,
664 &scriptInformation
[58].props
, &scriptInformation
[59].props
,
665 &scriptInformation
[60].props
, &scriptInformation
[61].props
,
666 &scriptInformation
[62].props
, &scriptInformation
[63].props
,
667 &scriptInformation
[64].props
, &scriptInformation
[65].props
,
668 &scriptInformation
[66].props
, &scriptInformation
[67].props
,
669 &scriptInformation
[68].props
, &scriptInformation
[69].props
,
670 &scriptInformation
[70].props
, &scriptInformation
[71].props
,
671 &scriptInformation
[72].props
, &scriptInformation
[73].props
,
672 &scriptInformation
[74].props
, &scriptInformation
[75].props
,
673 &scriptInformation
[76].props
, &scriptInformation
[77].props
,
674 &scriptInformation
[78].props
, &scriptInformation
[79].props
,
675 &scriptInformation
[80].props
, &scriptInformation
[81].props
684 SCRIPT_VISATTR
* psva
;
700 StringGlyphs
* glyphs
;
701 SCRIPT_LOGATTR
* logattrs
;
711 BOOL
usp10_array_reserve(void **elements
, SIZE_T
*capacity
, SIZE_T count
, SIZE_T size
)
713 SIZE_T max_capacity
, new_capacity
;
716 if (count
<= *capacity
)
719 max_capacity
= ~(SIZE_T
)0 / size
;
720 if (count
> max_capacity
)
723 new_capacity
= max(1, *capacity
);
724 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
726 if (new_capacity
< count
)
727 new_capacity
= count
;
730 new_elements
= heap_alloc_zero(new_capacity
* size
);
732 new_elements
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *elements
, new_capacity
* size
);
736 *elements
= new_elements
;
737 *capacity
= new_capacity
;
741 /* TODO Fix font properties on Arabic locale */
742 static inline BOOL
set_cache_font_properties(const HDC hdc
, ScriptCache
*sc
)
746 sc
->sfp
.wgBlank
= sc
->tm
.tmBreakChar
;
747 sc
->sfp
.wgDefault
= sc
->tm
.tmDefaultChar
;
748 sc
->sfp
.wgInvalid
= sc
->sfp
.wgBlank
;
749 sc
->sfp
.wgKashida
= 0xFFFF;
750 sc
->sfp
.iKashidaWidth
= 0;
754 static const WCHAR chars
[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
755 /* U+0020: numeric space
756 U+200B: zero width space
757 U+F71B: unknown char found by black box testing
761 if (GetGlyphIndicesW(hdc
, chars
, 4, gi
, GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
763 if(gi
[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
764 sc
->sfp
.wgBlank
= gi
[0];
768 sc
->sfp
.wgDefault
= 0;
771 sc
->sfp
.wgInvalid
= gi
[2];
772 else if (gi
[1] != 0xFFFF)
773 sc
->sfp
.wgInvalid
= gi
[1];
774 else if (gi
[0] != 0xFFFF)
775 sc
->sfp
.wgInvalid
= gi
[0];
777 sc
->sfp
.wgInvalid
= 0;
779 sc
->sfp
.wgKashida
= gi
[3];
781 sc
->sfp
.iKashidaWidth
= 0; /* TODO */
789 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES
*sfp
, ScriptCache
*sc
)
791 sfp
->wgBlank
= sc
->sfp
.wgBlank
;
792 sfp
->wgDefault
= sc
->sfp
.wgDefault
;
793 sfp
->wgInvalid
= sc
->sfp
.wgInvalid
;
794 sfp
->wgKashida
= sc
->sfp
.wgKashida
;
795 sfp
->iKashidaWidth
= sc
->sfp
.iKashidaWidth
;
798 static inline LONG
get_cache_height(SCRIPT_CACHE
*psc
)
800 return ((ScriptCache
*)*psc
)->tm
.tmHeight
;
803 static inline BYTE
get_cache_pitch_family(SCRIPT_CACHE
*psc
)
805 return ((ScriptCache
*)*psc
)->tm
.tmPitchAndFamily
;
808 static inline WORD
get_cache_glyph(SCRIPT_CACHE
*psc
, DWORD c
)
810 CacheGlyphPage
*page
= ((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
814 block
= page
->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
815 if (!block
) return 0;
816 return block
[(c
% 0x10000) & GLYPH_BLOCK_MASK
];
819 static inline WORD
set_cache_glyph(SCRIPT_CACHE
*psc
, WCHAR c
, WORD glyph
)
821 CacheGlyphPage
**page
= &((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
823 if (!*page
&& !(*page
= heap_alloc_zero(sizeof(CacheGlyphPage
)))) return 0;
825 block
= &(*page
)->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
826 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(WORD
) * GLYPH_BLOCK_SIZE
))) return 0;
827 return ((*block
)[(c
% 0x10000) & GLYPH_BLOCK_MASK
] = glyph
);
830 static inline BOOL
get_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
832 static const ABC nil
;
833 ABC
*block
= ((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
835 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(ABC
))) return FALSE
;
836 memcpy(abc
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(ABC
));
840 static inline BOOL
set_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
842 ABC
**block
= &((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
844 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(ABC
) * GLYPH_BLOCK_SIZE
))) return FALSE
;
845 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], abc
, sizeof(ABC
));
849 static HRESULT
init_script_cache(const HDC hdc
, SCRIPT_CACHE
*psc
)
854 if (!psc
) return E_INVALIDARG
;
855 if (*psc
) return S_OK
;
856 if (!hdc
) return E_PENDING
;
858 if (!(sc
= heap_alloc_zero(sizeof(ScriptCache
)))) return E_OUTOFMEMORY
;
859 if (!GetTextMetricsW(hdc
, &sc
->tm
))
864 size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
867 sc
->otm
= heap_alloc(size
);
868 sc
->otm
->otmSize
= size
;
869 GetOutlineTextMetricsW(hdc
, size
, sc
->otm
);
871 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(LOGFONTW
), &sc
->lf
))
876 sc
->sfnt
= (GetFontData(hdc
, MS_MAKE_TAG('h','e','a','d'), 0, NULL
, 0)!=GDI_ERROR
);
877 if (!set_cache_font_properties(hdc
, sc
))
883 TRACE("<- %p\n", sc
);
887 static WCHAR
mirror_char( WCHAR ch
)
889 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
890 return ch
+ wine_mirror_map
[wine_mirror_map
[ch
>> 8] + (ch
& 0xff)];
893 static DWORD
decode_surrogate_pair(const WCHAR
*str
, unsigned int index
, unsigned int end
)
895 if (index
< end
-1 && IS_SURROGATE_PAIR(str
[index
],str
[index
+1]))
897 DWORD ch
= 0x10000 + ((str
[index
] - 0xd800) << 10) + (str
[index
+1] - 0xdc00);
898 TRACE("Surrogate Pair %x %x => %x\n",str
[index
], str
[index
+1], ch
);
904 static int usp10_compare_script_range(const void *key
, const void *value
)
906 const struct usp10_script_range
*range
= value
;
907 const DWORD
*ch
= key
;
909 if (*ch
< range
->rangeFirst
)
911 if (*ch
> range
->rangeLast
)
916 static enum usp10_script
get_char_script(const WCHAR
*str
, unsigned int index
,
917 unsigned int end
, unsigned int *consumed
)
919 static const WCHAR latin_punc
[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
920 struct usp10_script_range
*range
;
921 WORD type
= 0, type2
= 0;
926 if (str
[index
] == 0xc || str
[index
] == 0x20 || str
[index
] == 0x202f)
929 /* These punctuation characters are separated out as Latin punctuation */
930 if (strchrW(latin_punc
,str
[index
]))
931 return Script_Punctuation2
;
933 /* These chars are itemized as Punctuation by Windows */
934 if (str
[index
] == 0x2212 || str
[index
] == 0x2044)
935 return Script_Punctuation
;
937 /* Currency Symbols by Unicode point */
941 case 0x09f3: return Script_Bengali_Currency
;
942 case 0x0af1: return Script_Gujarati_Currency
;
943 case 0x0e3f: return Script_Thai_Currency
;
944 case 0x20aa: return Script_Hebrew_Currency
;
945 case 0x20ab: return Script_Vietnamese_Currency
;
946 case 0xfb29: return Script_Hebrew_Currency
;
949 GetStringTypeW(CT_CTYPE1
, &str
[index
], 1, &type
);
950 GetStringTypeW(CT_CTYPE2
, &str
[index
], 1, &type2
);
953 return SCRIPT_UNDEFINED
;
956 return Script_Control
;
958 ch
= decode_surrogate_pair(str
, index
, end
);
964 if (!(range
= bsearch(&ch
, script_ranges
, ARRAY_SIZE(script_ranges
),
965 sizeof(*script_ranges
), usp10_compare_script_range
)))
966 return Script_Undefined
;
968 if (range
->numericScript
&& (type
& C1_DIGIT
|| type2
== C2_ARABICNUMBER
))
969 return range
->numericScript
;
970 if (range
->punctScript
&& type
& C1_PUNCT
)
971 return range
->punctScript
;
972 return range
->script
;
975 static int compare_FindGlyph(const void *a
, const void* b
)
977 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
978 const WORD
*idx
= (WORD
*)b
;
981 if ( find
->target
> *idx
)
983 else if (find
->target
< *idx
)
986 if (!find
->ascending
)
991 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
993 FindGlyph_struct fgs
;
997 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
998 fgs
.ascending
= TRUE
;
1000 fgs
.ascending
= FALSE
;
1002 fgs
.target
= target
;
1003 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
1008 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
1015 /***********************************************************************
1016 * ScriptFreeCache (USP10.@)
1018 * Free a script cache.
1021 * psc [I/O] Script cache.
1025 * Failure: Non-zero HRESULT value.
1027 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1035 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1037 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1039 for (i
= 0; i
< NUM_PAGES
; i
++)
1042 if (((ScriptCache
*)*psc
)->page
[i
])
1043 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1044 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1045 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1047 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1048 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1049 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1050 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1051 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1054 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1057 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1058 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1059 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1061 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1062 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1063 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1064 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1066 heap_free(((ScriptCache
*)*psc
)->scripts
);
1067 heap_free(((ScriptCache
*)*psc
)->otm
);
1074 /***********************************************************************
1075 * ScriptGetProperties (USP10.@)
1077 * Retrieve a list of script properties.
1080 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1081 * num [I] Pointer to the number of scripts.
1085 * Failure: Non-zero HRESULT value.
1088 * Behaviour matches WinXP.
1090 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1092 TRACE("(%p,%p)\n", props
, num
);
1094 if (!props
&& !num
) return E_INVALIDARG
;
1096 if (num
) *num
= sizeof(script_props
)/sizeof(script_props
[0]);
1097 if (props
) *props
= script_props
;
1102 /***********************************************************************
1103 * ScriptGetFontProperties (USP10.@)
1105 * Get information on special glyphs.
1108 * hdc [I] Device context.
1109 * psc [I/O] Opaque pointer to a script cache.
1110 * sfp [O] Font properties structure.
1112 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1116 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1118 if (!sfp
) return E_INVALIDARG
;
1119 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1121 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1122 return E_INVALIDARG
;
1124 get_cache_font_properties(sfp
, *psc
);
1129 /***********************************************************************
1130 * ScriptRecordDigitSubstitution (USP10.@)
1132 * Record digit substitution settings for a given locale.
1135 * locale [I] Locale identifier.
1136 * sds [I] Structure to record substitution settings.
1140 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1143 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1145 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1149 TRACE("0x%x, %p\n", locale
, sds
);
1151 /* This implementation appears to be correct for all languages, but it's
1152 * not clear if sds->DigitSubstitute is ever set to anything except
1153 * CONTEXT or NONE in reality */
1155 if (!sds
) return E_POINTER
;
1157 locale
= ConvertDefaultLocale(locale
);
1159 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1160 return E_INVALIDARG
;
1162 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1163 sds
->TraditionalDigitLanguage
= plgid
;
1165 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1166 sds
->NationalDigitLanguage
= plgid
;
1168 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1170 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1171 (WCHAR
*)&sub
, sizeof(sub
) / sizeof(WCHAR
)))
1172 return E_INVALIDARG
;
1177 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1178 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1180 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1183 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1186 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1189 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1193 sds
->dwReserved
= 0;
1197 /***********************************************************************
1198 * ScriptApplyDigitSubstitution (USP10.@)
1200 * Apply digit substitution settings.
1203 * sds [I] Structure with recorded substitution settings.
1204 * sc [I] Script control structure.
1205 * ss [I] Script state structure.
1209 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1211 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1212 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1214 SCRIPT_DIGITSUBSTITUTE psds
;
1216 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1218 if (!sc
|| !ss
) return E_POINTER
;
1222 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1223 return E_INVALIDARG
;
1226 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1227 sc
->fContextDigits
= 0;
1228 ss
->fDigitSubstitute
= 0;
1230 switch (sds
->DigitSubstitute
) {
1231 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1232 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1233 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1234 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1237 return E_INVALIDARG
;
1241 static inline BOOL
is_indic(enum usp10_script script
)
1243 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1246 static inline enum usp10_script
base_indic(enum usp10_script script
)
1250 case Script_Devanagari
:
1251 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1252 case Script_Bengali
:
1253 case Script_Bengali_Numeric
:
1254 case Script_Bengali_Currency
: return Script_Bengali
;
1255 case Script_Gurmukhi
:
1256 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1257 case Script_Gujarati
:
1258 case Script_Gujarati_Numeric
:
1259 case Script_Gujarati_Currency
: return Script_Gujarati
;
1261 case Script_Oriya_Numeric
: return Script_Oriya
;
1263 case Script_Tamil_Numeric
: return Script_Tamil
;
1265 case Script_Telugu_Numeric
: return Script_Telugu
;
1266 case Script_Kannada
:
1267 case Script_Kannada_Numeric
: return Script_Kannada
;
1268 case Script_Malayalam
:
1269 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1271 return Script_Undefined
;
1275 static BOOL
script_is_numeric(enum usp10_script script
)
1277 return scriptInformation
[script
].props
.fNumeric
;
1280 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1281 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1282 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1283 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1286 #define Numeric_space 0x0020
1291 enum usp10_script last_indic
= Script_Undefined
;
1292 int cnt
= 0, index
= 0, str
= 0;
1293 enum usp10_script New_Script
= -1;
1295 WORD
*levels
= NULL
;
1296 WORD
*layout_levels
= NULL
;
1297 WORD
*overrides
= NULL
;
1298 WORD
*strength
= NULL
;
1299 enum usp10_script
*scripts
;
1301 WORD baselayout
= 0;
1304 BOOL forceLevels
= FALSE
;
1305 unsigned int consumed
= 0;
1306 HRESULT res
= E_OUTOFMEMORY
;
1308 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1309 psControl
, psState
, pItems
, pcItems
);
1311 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1312 return E_INVALIDARG
;
1314 if (!(scripts
= heap_alloc(cInChars
* sizeof(*scripts
))))
1315 return E_OUTOFMEMORY
;
1317 for (i
= 0; i
< cInChars
; i
++)
1321 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1326 scripts
[i
] = scripts
[i
-1];
1329 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1330 all Indic scripts */
1331 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
!= Script_Undefined
)
1332 scripts
[i
] = last_indic
;
1333 else if (is_indic(scripts
[i
]))
1334 last_indic
= base_indic(scripts
[i
]);
1336 /* Some unicode points :
1337 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1338 (Left Right Embed U+202A - Left Right Override U+202D)
1339 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1340 will force us into bidi mode */
1341 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1342 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1343 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1347 /* Diacritical marks merge with other scripts */
1348 if (scripts
[i
] == Script_Diacritical
)
1353 scripts
[i
] = scripts
[i
-1];
1358 enum usp10_script first_script
= scripts
[i
-1];
1359 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1361 enum usp10_script original
= scripts
[j
];
1362 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1367 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1369 scripts
[j
] = scripts
[i
];
1370 if (original
== Script_Punctuation2
)
1373 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1374 scripts
[i
] = scripts
[j
];
1380 for (i
= 0; i
< cInChars
; i
++)
1382 /* Joiners get merged preferencially right */
1383 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1386 if (i
+1 == cInChars
)
1387 scripts
[i
] = scripts
[i
-1];
1390 for (j
= i
+1; j
< cInChars
; j
++)
1392 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1393 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1395 scripts
[i
] = scripts
[j
];
1403 if (psState
&& psControl
)
1405 levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1409 overrides
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1413 layout_levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1417 if (psState
->fOverrideDirection
)
1421 SCRIPT_STATE s
= *psState
;
1422 s
.fOverrideDirection
= FALSE
;
1423 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1424 if (odd(layout_levels
[0]))
1426 else for (i
= 0; i
< cInChars
; i
++)
1427 if (layout_levels
[i
]!=layout_levels
[0])
1434 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1438 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1439 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1441 baselevel
= levels
[0];
1442 baselayout
= layout_levels
[0];
1443 for (i
= 0; i
< cInChars
; i
++)
1444 if (levels
[i
]!=levels
[0])
1446 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1449 heap_free(overrides
);
1450 heap_free(layout_levels
);
1453 layout_levels
= NULL
;
1457 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1458 static const WCHAR repeatable_math_punc
[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1460 strength
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1463 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1465 /* We currently mis-level leading Diacriticals */
1466 if (scripts
[0] == Script_Diacritical
)
1467 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1469 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1470 strength
[i
] = BIDI_STRONG
;
1473 /* Math punctuation bordered on both sides by numbers can be
1474 merged into the number */
1475 for (i
= 0; i
< cInChars
; i
++)
1477 if (i
> 0 && i
< cInChars
-1 &&
1478 script_is_numeric(scripts
[i
-1]) &&
1479 strchrW(math_punc
, pwcInChars
[i
]))
1481 if (script_is_numeric(scripts
[i
+1]))
1483 scripts
[i
] = scripts
[i
+1];
1484 levels
[i
] = levels
[i
-1];
1485 strength
[i
] = strength
[i
-1];
1488 else if (strchrW(repeatable_math_punc
, pwcInChars
[i
]))
1491 for (j
= i
+1; j
< cInChars
; j
++)
1493 if (script_is_numeric(scripts
[j
]))
1497 scripts
[i
] = scripts
[j
];
1498 levels
[i
] = levels
[i
-1];
1499 strength
[i
] = strength
[i
-1];
1502 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1508 for (i
= 0; i
< cInChars
; i
++)
1510 /* Numerics at level 0 get bumped to level 2 */
1511 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
)
1512 && levels
[i
] == psState
->uBidiLevel
+ 1)) && script_is_numeric(scripts
[i
]))
1517 /* Joiners get merged preferencially right */
1518 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1521 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1522 strength
[i
] = strength
[i
-1];
1524 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1525 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1526 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1528 strength
[i
] = strength
[j
];
1533 if (psControl
->fMergeNeutralItems
)
1535 /* Merge the neutrals */
1536 for (i
= 0; i
< cInChars
; i
++)
1538 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1541 for (j
= i
; j
> 0; j
--)
1543 if (levels
[i
] != levels
[j
])
1545 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1547 scripts
[i
] = scripts
[j
];
1548 strength
[i
] = strength
[j
];
1553 /* Try going the other way */
1554 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1557 for (j
= i
; j
< cInChars
; j
++)
1559 if (levels
[i
] != levels
[j
])
1561 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1563 scripts
[i
] = scripts
[j
];
1564 strength
[i
] = strength
[j
];
1574 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1575 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1578 if (cnt
== cInChars
) /* All Spaces */
1581 New_Script
= scripts
[cnt
];
1584 pItems
[index
].iCharPos
= 0;
1585 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1587 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1589 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1590 str
= strength
[cnt
];
1598 if (strength
[cnt
] == BIDI_STRONG
)
1599 layoutRTL
= odd(layout_levels
[cnt
]);
1601 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1603 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1604 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1605 if (script_is_numeric(pItems
[index
].a
.eScript
))
1606 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1608 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1609 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1611 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1613 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1614 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1615 layoutRTL
= odd(baselayout
);
1616 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1617 pItems
[index
].a
.fRTL
= odd(baselevel
);
1618 if (script_is_numeric(pItems
[index
].a
.eScript
))
1619 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1621 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1624 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1625 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1626 pItems
[index
].iCharPos
);
1628 for (cnt
=1; cnt
< cInChars
; cnt
++)
1630 if(pwcInChars
[cnt
] != Numeric_space
)
1631 New_Script
= scripts
[cnt
];
1635 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1637 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1638 New_Script
= scripts
[cnt
+j
];
1640 New_Script
= scripts
[cnt
];
1644 /* merge space strengths*/
1645 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1648 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1651 /* changes in level */
1652 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1654 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1657 /* changes in strength */
1658 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1660 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1663 /* changes in script */
1664 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1666 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1670 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1672 layoutRTL
= odd(layout_levels
[cnt
]);
1673 if (script_is_numeric(pItems
[index
].a
.eScript
))
1674 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1679 TRACE("New_Level = %i, New_Strength = %i, New_Script=%d, eScript=%d\n", levels
?levels
[cnt
]:-1, strength
?strength
[cnt
]:str
, New_Script
, pItems
[index
].a
.eScript
);
1682 if (index
+1 > cMaxItems
)
1686 str
= strength
[cnt
];
1688 pItems
[index
].iCharPos
= cnt
;
1689 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1691 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1693 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1697 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1698 if (layout_levels
[cnt
] == 0)
1701 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1702 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1703 if (script_is_numeric(pItems
[index
].a
.eScript
))
1704 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1706 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1707 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1709 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1711 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1712 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1713 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1714 pItems
[index
].a
.fRTL
= odd(baselevel
);
1715 if (script_is_numeric(pItems
[index
].a
.eScript
))
1716 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1718 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1721 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1725 /* While not strictly necessary according to the spec, make sure the n+1
1726 * item is set up to prevent random behaviour if the caller erroneously
1727 * checks the n+1 structure */
1729 if (index
+ 1 > cMaxItems
) goto nomemory
;
1730 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1732 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1734 /* Set one SCRIPT_STATE item being returned */
1735 if (pcItems
) *pcItems
= index
;
1737 /* Set SCRIPT_ITEM */
1738 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1742 heap_free(overrides
);
1743 heap_free(layout_levels
);
1744 heap_free(strength
);
1749 /***********************************************************************
1750 * ScriptItemizeOpenType (USP10.@)
1752 * Split a Unicode string into shapeable parts.
1755 * pwcInChars [I] String to split.
1756 * cInChars [I] Number of characters in pwcInChars.
1757 * cMaxItems [I] Maximum number of items to return.
1758 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1759 * psState [I] Pointer to a SCRIPT_STATE structure.
1760 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1761 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1762 * pcItems [O] Number of script items returned.
1766 * Failure: Non-zero HRESULT value.
1768 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1769 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1770 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1772 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1775 /***********************************************************************
1776 * ScriptItemize (USP10.@)
1778 * Split a Unicode string into shapeable parts.
1781 * pwcInChars [I] String to split.
1782 * cInChars [I] Number of characters in pwcInChars.
1783 * cMaxItems [I] Maximum number of items to return.
1784 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1785 * psState [I] Pointer to a SCRIPT_STATE structure.
1786 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1787 * pcItems [O] Number of script items returned.
1791 * Failure: Non-zero HRESULT value.
1793 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1794 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1795 SCRIPT_ITEM
*pItems
, int *pcItems
)
1797 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1800 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1804 INT
*lpTabPos
= NULL
;
1809 lpTabPos
= pTabdef
->pTabStops
;
1811 if (pTabdef
&& pTabdef
->iTabOrigin
)
1813 if (pTabdef
->iScale
)
1814 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1816 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1820 cTabStops
= pTabdef
->cTabStops
;
1824 if (pTabdef
->iScale
)
1825 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1827 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1831 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1833 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1835 int position
= *lpTabPos
;
1837 position
= -1 * position
;
1838 if (pTabdef
->iScale
)
1839 position
= (position
* pTabdef
->iScale
) / 4;
1841 position
= position
* psc
->tm
.tmAveCharWidth
;
1843 if( nTabOrg
+ position
> current_x
)
1847 /* a left aligned tab */
1848 x
= (nTabOrg
+ *lpTabPos
) - current_x
;
1853 FIXME("Negative tabstop\n");
1858 if ((!cTabStops
) && (defWidth
> 0))
1859 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1860 else if ((!cTabStops
) && (defWidth
< 0))
1861 FIXME("TODO: Negative defWidth\n");
1866 /***********************************************************************
1867 * Helper function for ScriptStringAnalyse
1869 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1870 const WCHAR
*pwcInChars
, int cChars
)
1872 /* FIXME: When to properly fallback is still a bit of a mystery */
1875 if (psa
->fNoGlyphIndex
)
1878 if (init_script_cache(hdc
, psc
) != S_OK
)
1881 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1884 glyphs
= heap_alloc(sizeof(WORD
) * cChars
);
1887 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1897 static void find_fallback_font(enum usp10_script scriptid
, WCHAR
*FaceName
)
1901 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1903 static const WCHAR szFmt
[] = {'%','x',0};
1905 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1908 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1909 if (RegQueryValueExW(hkey
, value
, 0, &type
, (BYTE
*)FaceName
, &count
))
1910 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1914 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1917 /***********************************************************************
1918 * ScriptStringAnalyse (USP10.@)
1921 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1922 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1923 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1924 SCRIPT_STATE
*psState
, const int *piDx
,
1925 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1926 SCRIPT_STRING_ANALYSIS
*pssa
)
1928 HRESULT hr
= E_OUTOFMEMORY
;
1929 StringAnalysis
*analysis
= NULL
;
1930 SCRIPT_CONTROL sControl
;
1931 SCRIPT_STATE sState
;
1932 int i
, num_items
= 255;
1934 WCHAR
*iString
= NULL
;
1936 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1937 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1938 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
1942 FIXME("Only Unicode strings are supported\n");
1943 return E_INVALIDARG
;
1945 if (cString
< 1 || !pString
) return E_INVALIDARG
;
1946 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
1948 if (!(analysis
= heap_alloc_zero(sizeof(StringAnalysis
)))) return E_OUTOFMEMORY
;
1949 if (!(analysis
->pItem
= heap_alloc_zero(num_items
* sizeof(SCRIPT_ITEM
) + 1))) goto error
;
1951 /* FIXME: handle clipping */
1952 analysis
->clip_len
= cString
;
1953 analysis
->hdc
= hdc
;
1954 analysis
->dwFlags
= dwFlags
;
1959 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
1962 sControl
= *psControl
;
1964 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
1966 if (dwFlags
& SSA_PASSWORD
)
1968 iString
= heap_alloc(sizeof(WCHAR
)*cString
);
1974 for (i
= 0; i
< cString
; i
++)
1975 iString
[i
] = *((const WCHAR
*)pString
);
1979 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
1980 &analysis
->numItems
);
1984 if (hr
== E_OUTOFMEMORY
)
1989 /* set back to out of memory for default goto error behaviour */
1992 if (dwFlags
& SSA_BREAK
)
1994 if ((analysis
->logattrs
= heap_alloc(sizeof(SCRIPT_LOGATTR
) * cString
)))
1996 for (i
= 0; i
< analysis
->numItems
; i
++)
1997 ScriptBreak(&((WCHAR
*)pString
)[analysis
->pItem
[i
].iCharPos
],
1998 analysis
->pItem
[i
+ 1].iCharPos
- analysis
->pItem
[i
].iCharPos
,
1999 &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
2005 if (!(analysis
->logical2visual
= heap_alloc_zero(sizeof(int) * analysis
->numItems
)))
2007 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
2010 if (dwFlags
& SSA_GLYPHS
)
2013 if (!(analysis
->glyphs
= heap_alloc_zero(sizeof(StringGlyphs
) * analysis
->numItems
)))
2015 heap_free(BidiLevel
);
2019 for (i
= 0; i
< analysis
->numItems
; i
++)
2021 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
2022 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2023 int numGlyphs
= 1.5 * cChar
+ 16;
2024 WORD
*glyphs
= heap_alloc_zero(sizeof(WORD
) * numGlyphs
);
2025 WORD
*pwLogClust
= heap_alloc_zero(sizeof(WORD
) * cChar
);
2026 int *piAdvance
= heap_alloc_zero(sizeof(int) * numGlyphs
);
2027 SCRIPT_VISATTR
*psva
= heap_alloc_zero(sizeof(SCRIPT_VISATTR
) * numGlyphs
);
2028 GOFFSET
*pGoffset
= heap_alloc_zero(sizeof(GOFFSET
) * numGlyphs
);
2029 ABC
*abc
= heap_alloc_zero(sizeof(ABC
));
2030 int numGlyphsReturned
;
2031 HFONT originalFont
= 0x0;
2033 /* FIXME: non unicode strings */
2034 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2035 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2037 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
|| !abc
)
2039 heap_free (BidiLevel
);
2041 heap_free (pwLogClust
);
2042 heap_free (piAdvance
);
2044 heap_free (pGoffset
);
2050 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2053 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2054 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2055 lf
.lfFaceName
[0] = 0;
2056 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2057 if (lf
.lfFaceName
[0])
2059 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2060 if (analysis
->glyphs
[i
].fallbackFont
)
2062 ScriptFreeCache(sc
);
2063 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2068 /* FIXME: When we properly shape Hangul remove this check */
2069 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2070 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2072 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2073 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2075 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2076 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2077 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2078 piAdvance
, pGoffset
, abc
);
2080 SelectObject(hdc
,originalFont
);
2082 if (dwFlags
& SSA_TAB
)
2085 for (tabi
= 0; tabi
< cChar
; tabi
++)
2087 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2088 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2089 tab_x
+=piAdvance
[tabi
];
2093 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2094 analysis
->glyphs
[i
].glyphs
= glyphs
;
2095 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2096 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2097 analysis
->glyphs
[i
].psva
= psva
;
2098 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2099 analysis
->glyphs
[i
].abc
= abc
;
2100 analysis
->glyphs
[i
].iMaxPosX
= -1;
2102 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2107 for (i
= 0; i
< analysis
->numItems
; i
++)
2108 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2111 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2112 heap_free(BidiLevel
);
2120 heap_free(analysis
->glyphs
);
2121 heap_free(analysis
->logattrs
);
2122 heap_free(analysis
->pItem
);
2123 heap_free(analysis
->logical2visual
);
2124 heap_free(analysis
);
2128 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2130 if (pva
[glyph
].fClusterStart
)
2132 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2139 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2150 StringAnalysis
*analysis
;
2153 COLORREF BkColor
= 0x0;
2154 COLORREF TextColor
= 0x0;
2156 INT runStart
, runEnd
;
2157 INT iGlyph
, cGlyphs
;
2158 HFONT oldFont
= 0x0;
2162 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2163 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2165 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2167 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2168 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2174 BkMode
= GetBkMode(analysis
->hdc
);
2175 SetBkMode( analysis
->hdc
, OPAQUE
);
2176 BkColor
= GetBkColor(analysis
->hdc
);
2177 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2180 TextColor
= GetTextColor(analysis
->hdc
);
2181 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2184 if (analysis
->glyphs
[iItem
].fallbackFont
)
2185 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2187 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2188 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2191 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2192 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2194 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2196 if (analysis
->pItem
[iItem
].a
.fRTL
)
2198 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2199 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2201 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2202 crc
.left
= iX
+ off_x
;
2206 if (cStart
>=0 && runStart
)
2207 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2209 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2210 crc
.left
= iX
+ off_x
;
2213 if (analysis
->pItem
[iItem
].a
.fRTL
)
2214 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2216 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2218 if (analysis
->pItem
[iItem
].a
.fRTL
)
2219 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2221 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2225 /* adjust for cluster glyphs when starting */
2226 if (analysis
->pItem
[iItem
].a
.fRTL
)
2227 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2229 i
= analysis
->pItem
[iItem
].iCharPos
;
2231 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2233 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2235 if (analysis
->pItem
[iItem
].a
.fRTL
)
2236 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2238 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2243 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2248 clust_glyph
= iGlyph
+ cGlyphs
;
2249 if (analysis
->pItem
[iItem
].a
.fRTL
)
2254 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2255 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2262 hr
= ScriptTextOut(analysis
->hdc
,
2263 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2264 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2265 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2266 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2267 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2269 TRACE("ScriptTextOut hr=%08x\n", hr
);
2273 SetBkColor(analysis
->hdc
, BkColor
);
2274 SetBkMode( analysis
->hdc
, BkMode
);
2276 SetTextColor(analysis
->hdc
, TextColor
);
2278 if (analysis
->glyphs
[iItem
].fallbackFont
)
2279 SelectObject(analysis
->hdc
, oldFont
);
2284 /***********************************************************************
2285 * ScriptStringOut (USP10.@)
2287 * This function takes the output of ScriptStringAnalyse and joins the segments
2288 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2289 * only processes glyphs.
2292 * ssa [I] buffer to hold the analysed string components
2293 * iX [I] X axis displacement for output
2294 * iY [I] Y axis displacement for output
2295 * uOptions [I] flags controlling output processing
2296 * prc [I] rectangle coordinates
2297 * iMinSel [I] starting pos for substringing output string
2298 * iMaxSel [I] ending pos for substringing output string
2299 * fDisabled [I] controls text highlighting
2303 * Failure: is the value returned by ScriptTextOut
2305 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2314 StringAnalysis
*analysis
;
2318 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2319 ssa
, iX
, iY
, uOptions
, wine_dbgstr_rect(prc
), iMinSel
, iMaxSel
, fDisabled
);
2321 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2322 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2324 for (item
= 0; item
< analysis
->numItems
; item
++)
2326 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2331 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2333 if (iMaxSel
> 0 && iMinSel
< 0)
2335 for (item
= 0; item
< analysis
->numItems
; item
++)
2337 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2346 /***********************************************************************
2347 * ScriptStringCPtoX (USP10.@)
2350 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2354 StringAnalysis
* analysis
= ssa
;
2356 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2358 if (!ssa
|| !pX
) return S_FALSE
;
2359 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2361 /* icp out of range */
2364 analysis
->invalid
= TRUE
;
2365 return E_INVALIDARG
;
2368 for(item
=0; item
<analysis
->numItems
; item
++)
2373 i
= analysis
->logical2visual
[item
];
2374 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2375 /* initialize max extents for uninitialized runs */
2376 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2378 if (analysis
->pItem
[i
].a
.fRTL
)
2379 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2380 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2381 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2383 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2384 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2385 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2388 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2390 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2394 icp
-= analysis
->pItem
[i
].iCharPos
;
2395 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2396 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2397 &analysis
->pItem
[i
].a
, &offset
);
2404 /* icp out of range */
2405 analysis
->invalid
= TRUE
;
2406 return E_INVALIDARG
;
2409 /***********************************************************************
2410 * ScriptStringXtoCP (USP10.@)
2413 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2415 StringAnalysis
* analysis
= ssa
;
2418 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2420 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2421 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2426 if (analysis
->pItem
[0].a
.fRTL
)
2429 *piTrailing
= FALSE
;
2439 for(item
=0; item
<analysis
->numItems
; item
++)
2444 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2447 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2448 /* initialize max extents for uninitialized runs */
2449 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2451 if (analysis
->pItem
[i
].a
.fRTL
)
2452 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2453 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2454 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2456 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2457 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2458 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2461 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2463 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2467 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2468 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2469 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2470 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2476 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2477 *piTrailing
= FALSE
;
2483 /***********************************************************************
2484 * ScriptStringFree (USP10.@)
2486 * Free a string analysis.
2489 * pssa [I] string analysis.
2493 * Failure: Non-zero HRESULT value.
2495 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2497 StringAnalysis
* analysis
;
2501 TRACE("(%p)\n", pssa
);
2503 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2505 invalid
= analysis
->invalid
;
2507 if (analysis
->glyphs
)
2509 for (i
= 0; i
< analysis
->numItems
; i
++)
2511 heap_free(analysis
->glyphs
[i
].glyphs
);
2512 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2513 heap_free(analysis
->glyphs
[i
].piAdvance
);
2514 heap_free(analysis
->glyphs
[i
].psva
);
2515 heap_free(analysis
->glyphs
[i
].pGoffset
);
2516 heap_free(analysis
->glyphs
[i
].abc
);
2517 if (analysis
->glyphs
[i
].fallbackFont
)
2518 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2519 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2520 heap_free(analysis
->glyphs
[i
].sc
);
2522 heap_free(analysis
->glyphs
);
2525 heap_free(analysis
->pItem
);
2526 heap_free(analysis
->logattrs
);
2527 heap_free(analysis
->sz
);
2528 heap_free(analysis
->logical2visual
);
2529 heap_free(analysis
);
2531 if (invalid
) return E_INVALIDARG
;
2535 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2536 int direction
, int* iCluster
, int *check_out
)
2540 WORD clust
= pwLogClust
[item
];
2542 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2544 if (pwLogClust
[check
] == clust
)
2547 if (iCluster
&& *iCluster
== -1)
2559 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
)
2564 advance
= piAdvance
[glyph
];
2566 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2567 log_clust_max
= pwLogClust
[0];
2569 log_clust_max
= pwLogClust
[cChars
-1];
2571 if (glyph
> log_clust_max
)
2574 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2577 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2579 if (glyph
> log_clust_max
)
2581 advance
+= piAdvance
[glyph
];
2587 /***********************************************************************
2588 * ScriptCPtoX (USP10.@)
2591 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2595 const WORD
*pwLogClust
,
2596 const SCRIPT_VISATTR
*psva
,
2597 const int *piAdvance
,
2598 const SCRIPT_ANALYSIS
*psa
,
2606 float special_size
= 0.0;
2611 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2612 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2615 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2623 int max_clust
= pwLogClust
[0];
2625 for (item
=0; item
< cGlyphs
; item
++)
2626 if (pwLogClust
[item
] > max_clust
)
2628 ERR("We do not handle non reversed clusters properly\n");
2633 for (item
= max_clust
; item
>=0; item
--)
2634 iMaxPos
+= piAdvance
[item
];
2638 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2640 if (iSpecial
== -1 && (iCluster
== -1 || (iCluster
!= -1 && iCluster
+clust_size
<= item
)))
2643 int clust
= pwLogClust
[item
];
2646 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2649 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2651 if (check
>= cChars
&& !iMaxPos
)
2654 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2655 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2657 special_size
/= (cChars
- item
);
2658 iPosX
+= special_size
;
2662 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2665 if (clust_size
== 0)
2669 iPosX
+= advance
/ (float)clust_size
;
2672 else if (iSpecial
!= -1)
2673 iPosX
+= special_size
;
2674 else /* (iCluster != -1) */
2676 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2677 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2680 if (clust_size
== 0)
2684 iPosX
+= adv
/ (float)clust_size
;
2690 iPosX
= iMaxPos
- iPosX
;
2696 TRACE("*piX=%d\n", *piX
);
2700 /* Count the number of characters in a cluster and its starting index*/
2701 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2706 for (i
= 0; i
< cChars
; i
++)
2708 if (pwLogClust
[i
] == cluster_index
)
2710 if (!size
&& start_index
)
2718 else if (size
) break;
2721 *cluster_size
= size
;
2727 To handle multi-glyph clusters we need to find all the glyphs that are
2728 represented in the cluster. This involves finding the glyph whose
2729 index is the cluster index as well as whose glyph indices are greater than
2730 our cluster index but not part of a new cluster.
2732 Then we sum all those glyphs' advances.
2734 static inline int get_cluster_advance(const int* piAdvance
,
2735 const SCRIPT_VISATTR
*psva
,
2736 const WORD
*pwLogClust
, int cGlyphs
,
2737 int cChars
, int cluster
, int direction
)
2748 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2750 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2751 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2752 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2757 glyph_end
= cGlyphs
;
2760 /* Don't fully understand multi-glyph reversed clusters yet,
2761 * do they occur for real or just in our test? */
2762 FIXME("multi-glyph reversed clusters found\n");
2763 glyph_end
= glyph_start
+ 1;
2767 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2768 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2770 if (psva
[i
].fClusterStart
)
2777 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2778 advance
+= piAdvance
[i
];
2784 /***********************************************************************
2785 * ScriptXtoCP (USP10.@)
2788 * Use piAdvance to find the cluster we are looking at.
2789 * Find the character that is the first character of the cluster.
2790 * That is our base piCP.
2791 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2792 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2793 * determine how far through the cluster to advance the cursor.
2795 HRESULT WINAPI
ScriptXtoCP(int iX
,
2798 const WORD
*pwLogClust
,
2799 const SCRIPT_VISATTR
*psva
,
2800 const int *piAdvance
,
2801 const SCRIPT_ANALYSIS
*psa
,
2808 int glyph_index
, cluster_index
;
2811 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2812 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2813 psa
, piCP
, piTrailing
);
2815 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2818 /* Handle an iX < 0 */
2834 /* Looking for non-reversed clusters in a reversed string */
2837 int max_clust
= pwLogClust
[0];
2838 for (i
=0; i
< cChars
; i
++)
2839 if (pwLogClust
[i
] > max_clust
)
2841 FIXME("We do not handle non reversed clusters properly\n");
2846 /* find the glyph_index based in iX */
2849 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2854 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2858 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2861 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2863 /* find the cluster */
2865 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2868 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2871 TRACE("cluster_index %i\n", cluster_index
);
2873 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2875 /* We are off the end of the string */
2881 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2883 TRACE("first char index %i\n",i
);
2884 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2886 /* Check trailing */
2887 if (glyph_index
!= cluster_index
||
2888 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2889 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2890 *piTrailing
= cluster_size
;
2894 if (cluster_size
> 1)
2896 /* Be part way through the glyph cluster based on size and position */
2897 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2898 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2902 /* back up to the beginning of the cluster */
2903 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2904 adv
+= piAdvance
[part_index
];
2905 if (adv
> iX
) adv
= iX
;
2907 TRACE("Multi-char cluster, no snap\n");
2908 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2909 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2912 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2914 if (part_index
) part_index
--;
2918 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2920 if (part_index
> cluster_size
)
2922 adv
+= cluster_part_width
;
2923 part_index
=cluster_size
;
2927 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2932 i
+= (cluster_size
- part_index
);
2934 /* Check trailing */
2935 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2936 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2941 /* Check trailing */
2942 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2943 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2950 TRACE("Point falls outside of string\n");
2951 if (glyph_index
< 0)
2953 else /* (glyph_index >= cGlyphs) */
2956 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2957 point flow to the next character */
2960 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
2969 TRACE("*piCP=%d\n", *piCP
);
2970 TRACE("*piTrailing=%d\n", *piTrailing
);
2974 /***********************************************************************
2975 * ScriptBreak (USP10.@)
2977 * Retrieve line break information.
2980 * chars [I] Array of characters.
2981 * sa [I] Script analysis.
2982 * la [I] Array of logical attribute structures.
2988 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
2990 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
2992 if (count
< 0 || !la
) return E_INVALIDARG
;
2993 if (count
== 0) return E_FAIL
;
2995 BREAK_line(chars
, count
, sa
, la
);
3000 /***********************************************************************
3001 * ScriptIsComplex (USP10.@)
3003 * Determine if a string is complex.
3006 * chars [I] Array of characters to test.
3007 * len [I] Length in characters.
3015 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
3017 enum usp10_script script
;
3018 unsigned int i
, consumed
;
3020 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
3022 if (!chars
|| len
< 0)
3023 return E_INVALIDARG
;
3025 for (i
= 0; i
< len
; i
+=consumed
)
3030 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3033 script
= get_char_script(chars
,i
,len
, &consumed
);
3034 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3035 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3041 /***********************************************************************
3042 * ScriptShapeOpenType (USP10.@)
3044 * Produce glyphs and visual attributes for a run.
3047 * hdc [I] Device context.
3048 * psc [I/O] Opaque pointer to a script cache.
3049 * psa [I/O] Script analysis.
3050 * tagScript [I] The OpenType tag for the Script
3051 * tagLangSys [I] The OpenType tag for the Language
3052 * rcRangeChars[I] Array of Character counts in each range
3053 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3054 * cRanges [I] Count of ranges
3055 * pwcChars [I] Array of characters specifying the run.
3056 * cChars [I] Number of characters in pwcChars.
3057 * cMaxGlyphs [I] Length of pwOutGlyphs.
3058 * pwLogClust [O] Array of logical cluster info.
3059 * pCharProps [O] Array of character property values
3060 * pwOutGlyphs [O] Array of glyphs.
3061 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3062 * pcGlyphs [O] Number of glyphs returned.
3066 * Failure: Non-zero HRESULT value.
3068 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3069 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3070 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3071 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3072 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3073 int cMaxGlyphs
, WORD
*pwLogClust
,
3074 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3075 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3082 static int once
= 0;
3084 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3086 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3087 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3088 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3090 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3091 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3093 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3094 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3097 if(!once
++) FIXME("Ranges not supported yet\n");
3099 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3102 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3103 if (!pwLogClust
) return E_FAIL
;
3105 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3106 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3108 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3109 for (i
= 0; i
< cChars
; i
++)
3112 if (rtl
) idx
= cChars
- 1 - i
;
3113 /* FIXME: set to better values */
3114 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3115 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3116 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3117 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3118 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3119 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3121 /* FIXME: have the shaping engine set this */
3122 pCharProps
[i
].fCanGlyphAlone
= 0;
3124 pwLogClust
[i
] = idx
;
3127 if (psa
&& !psa
->fNoGlyphIndex
&& ((ScriptCache
*)*psc
)->sfnt
)
3130 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3132 rChars
= heap_alloc(sizeof(WCHAR
) * cChars
);
3133 if (!rChars
) return E_OUTOFMEMORY
;
3134 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3139 if (rtl
) idx
= cChars
- 1 - i
;
3142 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3146 chInput
= mirror_char(pwcChars
[idx
]);
3148 chInput
= pwcChars
[idx
];
3149 rChars
[i
] = chInput
;
3153 rChars
[i
] = pwcChars
[idx
];
3154 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3157 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3165 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3170 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3178 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3179 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3185 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3186 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3187 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3189 for (i
= 0; i
< cChars
; ++i
)
3191 /* Special case for tabs and joiners. As control characters, ZWNJ
3192 * and ZWJ would in principle get handled by the corresponding
3193 * shaping functions. However, since ZWNJ and ZWJ can get merged
3194 * into adjoining runs during itemisation, these don't generally
3195 * get classified as Script_Control. */
3196 if (pwcChars
[i
] == 0x0009 || pwcChars
[i
] == ZWSP
|| pwcChars
[i
] == ZWNJ
|| pwcChars
[i
] == ZWJ
)
3198 pwOutGlyphs
[pwLogClust
[i
]] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3199 pOutGlyphProps
[pwLogClust
[i
]].sva
.fZeroWidth
= 1;
3206 TRACE("no glyph translation\n");
3207 for (i
= 0; i
< cChars
; i
++)
3210 /* No mirroring done here */
3211 if (rtl
) idx
= cChars
- 1 - i
;
3212 pwOutGlyphs
[i
] = pwcChars
[idx
];
3217 /* overwrite some basic control glyphs to blank */
3218 if (psa
->fNoGlyphIndex
)
3220 if (pwcChars
[idx
] == ZWSP
|| pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3222 pwOutGlyphs
[i
] = 0x20;
3223 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3226 else if (psa
->eScript
== Script_Control
|| pwcChars
[idx
] == ZWSP
3227 || pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3229 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3230 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3232 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3233 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3243 /***********************************************************************
3244 * ScriptShape (USP10.@)
3246 * Produce glyphs and visual attributes for a run.
3249 * hdc [I] Device context.
3250 * psc [I/O] Opaque pointer to a script cache.
3251 * pwcChars [I] Array of characters specifying the run.
3252 * cChars [I] Number of characters in pwcChars.
3253 * cMaxGlyphs [I] Length of pwOutGlyphs.
3254 * psa [I/O] Script analysis.
3255 * pwOutGlyphs [O] Array of glyphs.
3256 * pwLogClust [O] Array of logical cluster info.
3257 * psva [O] Array of visual attributes.
3258 * pcGlyphs [O] Number of glyphs returned.
3262 * Failure: Non-zero HRESULT value.
3264 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3265 int cChars
, int cMaxGlyphs
,
3266 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3267 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3271 SCRIPT_CHARPROP
*charProps
;
3272 SCRIPT_GLYPHPROP
*glyphProps
;
3274 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3275 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3277 charProps
= heap_alloc_zero(sizeof(SCRIPT_CHARPROP
)*cChars
);
3278 if (!charProps
) return E_OUTOFMEMORY
;
3279 glyphProps
= heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP
)*cMaxGlyphs
);
3282 heap_free(charProps
);
3283 return E_OUTOFMEMORY
;
3286 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3290 for (i
= 0; i
< *pcGlyphs
; i
++)
3291 psva
[i
] = glyphProps
[i
].sva
;
3294 heap_free(charProps
);
3295 heap_free(glyphProps
);
3300 /***********************************************************************
3301 * ScriptPlaceOpenType (USP10.@)
3303 * Produce advance widths for a run.
3306 * hdc [I] Device context.
3307 * psc [I/O] Opaque pointer to a script cache.
3308 * psa [I/O] Script analysis.
3309 * tagScript [I] The OpenType tag for the Script
3310 * tagLangSys [I] The OpenType tag for the Language
3311 * rcRangeChars[I] Array of Character counts in each range
3312 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3313 * cRanges [I] Count of ranges
3314 * pwcChars [I] Array of characters specifying the run.
3315 * pwLogClust [I] Array of logical cluster info
3316 * pCharProps [I] Array of character property values
3317 * cChars [I] Number of characters in pwcChars.
3318 * pwGlyphs [I] Array of glyphs.
3319 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3320 * cGlyphs [I] Count of Glyphs
3321 * piAdvance [O] Array of advance widths.
3322 * pGoffset [O] Glyph offsets.
3323 * pABC [O] Combined ABC width.
3327 * Failure: Non-zero HRESULT value.
3330 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3331 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3332 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3333 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3334 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3335 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3336 int cGlyphs
, int *piAdvance
,
3337 GOFFSET
*pGoffset
, ABC
*pABC
3342 static int once
= 0;
3344 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3346 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3347 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3348 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3351 if (!pGlyphProps
) return E_INVALIDARG
;
3352 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3353 if (!pGoffset
) return E_FAIL
;
3356 if (!once
++) FIXME("Ranges not supported yet\n");
3358 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3359 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3361 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3362 for (i
= 0; i
< cGlyphs
; i
++)
3365 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3367 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3369 else if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3372 if (!hdc
) return E_PENDING
;
3373 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3375 if (psa
->fNoGlyphIndex
)
3376 ret
= GetCharABCWidthsW(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &abc
);
3378 ret
= GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
);
3379 if (!ret
) return S_FALSE
;
3384 if (psa
->fNoGlyphIndex
)
3385 ret
= GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
);
3387 ret
= GetCharWidthI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &width
);
3388 if (!ret
) return S_FALSE
;
3390 abc
.abcA
= abc
.abcC
= 0;
3392 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3396 pABC
->abcA
+= abc
.abcA
;
3397 pABC
->abcB
+= abc
.abcB
;
3398 pABC
->abcC
+= abc
.abcC
;
3400 /* FIXME: set to more reasonable values */
3401 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3402 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3405 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3407 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3411 /***********************************************************************
3412 * ScriptPlace (USP10.@)
3414 * Produce advance widths for a run.
3417 * hdc [I] Device context.
3418 * psc [I/O] Opaque pointer to a script cache.
3419 * pwGlyphs [I] Array of glyphs.
3420 * cGlyphs [I] Number of glyphs in pwGlyphs.
3421 * psva [I] Array of visual attributes.
3422 * psa [I/O] String analysis.
3423 * piAdvance [O] Array of advance widths.
3424 * pGoffset [O] Glyph offsets.
3425 * pABC [O] Combined ABC width.
3429 * Failure: Non-zero HRESULT value.
3431 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3432 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3433 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3436 SCRIPT_GLYPHPROP
*glyphProps
;
3439 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3440 piAdvance
, pGoffset
, pABC
);
3442 if (!psva
) return E_INVALIDARG
;
3443 if (!pGoffset
) return E_FAIL
;
3445 glyphProps
= heap_alloc(sizeof(SCRIPT_GLYPHPROP
)*cGlyphs
);
3446 if (!glyphProps
) return E_OUTOFMEMORY
;
3448 for (i
= 0; i
< cGlyphs
; i
++)
3449 glyphProps
[i
].sva
= psva
[i
];
3451 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3453 heap_free(glyphProps
);
3458 /***********************************************************************
3459 * ScriptGetCMap (USP10.@)
3461 * Retrieve glyph indices.
3464 * hdc [I] Device context.
3465 * psc [I/O] Opaque pointer to a script cache.
3466 * pwcInChars [I] Array of Unicode characters.
3467 * cChars [I] Number of characters in pwcInChars.
3468 * dwFlags [I] Flags.
3469 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3473 * Failure: Non-zero HRESULT value.
3475 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3476 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3481 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3482 cChars
, dwFlags
, pwOutGlyphs
);
3484 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3488 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3490 for (i
= 0; i
< cChars
; i
++)
3493 if (dwFlags
== SGCM_RTL
)
3494 inChar
= mirror_char(pwcInChars
[i
]);
3496 inChar
= pwcInChars
[i
];
3497 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3500 if (!hdc
) return E_PENDING
;
3501 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3502 if (glyph
== 0xffff)
3507 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3513 TRACE("no glyph translation\n");
3514 for (i
= 0; i
< cChars
; i
++)
3517 if (dwFlags
== SGCM_RTL
)
3518 inChar
= mirror_char(pwcInChars
[i
]);
3520 inChar
= pwcInChars
[i
];
3521 pwOutGlyphs
[i
] = inChar
;
3527 /***********************************************************************
3528 * ScriptTextOut (USP10.@)
3531 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3532 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3533 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3534 const int *piJustify
, const GOFFSET
*pGoffset
)
3539 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3541 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3542 hdc
, psc
, x
, y
, fuOptions
, wine_dbgstr_rect(lprc
), psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3543 piAdvance
, piJustify
, pGoffset
);
3545 if (!hdc
|| !psc
) return E_INVALIDARG
;
3546 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3548 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3549 fuOptions
|= ETO_IGNORELANGUAGE
;
3550 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3551 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3553 lpDx
= heap_alloc(cGlyphs
* sizeof(INT
) * 2);
3554 if (!lpDx
) return E_OUTOFMEMORY
;
3555 fuOptions
|= ETO_PDY
;
3557 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3559 reordered_glyphs
= heap_alloc( cGlyphs
* sizeof(WORD
) );
3560 if (!reordered_glyphs
)
3563 return E_OUTOFMEMORY
;
3566 for (i
= 0; i
< cGlyphs
; i
++)
3567 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3571 for (i
= 0; i
< cGlyphs
; i
++)
3573 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3574 lpDx
[i
* 2] = piAdvance
[orig_index
];
3575 lpDx
[i
* 2 + 1] = 0;
3581 x
+= pGoffset
[orig_index
].du
* dir
;
3582 y
+= pGoffset
[orig_index
].dv
;
3586 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3587 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3589 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3590 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3594 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3597 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3603 /***********************************************************************
3604 * ScriptCacheGetHeight (USP10.@)
3606 * Retrieve the height of the font in the cache.
3609 * hdc [I] Device context.
3610 * psc [I/O] Opaque pointer to a script cache.
3611 * height [O] Receives font height.
3615 * Failure: Non-zero HRESULT value.
3617 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3621 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3623 if (!height
) return E_INVALIDARG
;
3624 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3626 *height
= get_cache_height(psc
);
3630 /***********************************************************************
3631 * ScriptGetGlyphABCWidth (USP10.@)
3633 * Retrieve the width of a glyph.
3636 * hdc [I] Device context.
3637 * psc [I/O] Opaque pointer to a script cache.
3638 * glyph [I] Glyph to retrieve the width for.
3639 * abc [O] ABC widths of the glyph.
3643 * Failure: Non-zero HRESULT value.
3645 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3649 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3651 if (!abc
) return E_INVALIDARG
;
3652 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3654 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3656 if (!hdc
) return E_PENDING
;
3657 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3659 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3664 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3666 abc
->abcA
= abc
->abcC
= 0;
3668 set_cache_glyph_widths(psc
, glyph
, abc
);
3673 /***********************************************************************
3674 * ScriptLayout (USP10.@)
3676 * Map embedding levels to visual and/or logical order.
3679 * runs [I] Size of level array.
3680 * level [I] Array of embedding levels.
3681 * vistolog [O] Map of embedding levels from visual to logical order.
3682 * logtovis [O] Map of embedding levels from logical to visual order.
3686 * Failure: Non-zero HRESULT value.
3689 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3694 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3696 if (!level
|| (!vistolog
&& !logtovis
))
3697 return E_INVALIDARG
;
3699 indexs
= heap_alloc(sizeof(int) * runs
);
3701 return E_OUTOFMEMORY
;
3705 for( ich
= 0; ich
< runs
; ich
++)
3710 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3711 memcpy(vistolog
, indexs
, runs
* sizeof(*vistolog
));
3716 for( ich
= 0; ich
< runs
; ich
++)
3721 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3722 memcpy(logtovis
, indexs
, runs
* sizeof(*logtovis
));
3729 /***********************************************************************
3730 * ScriptStringGetLogicalWidths (USP10.@)
3732 * Returns logical widths from a string analysis.
3735 * ssa [I] string analysis.
3736 * piDx [O] logical widths returned.
3740 * Failure: a non-zero HRESULT.
3742 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3745 StringAnalysis
*analysis
= ssa
;
3747 TRACE("%p, %p\n", ssa
, piDx
);
3749 if (!analysis
) return S_FALSE
;
3750 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3752 for (i
= 0; i
< analysis
->numItems
; i
++)
3754 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3757 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3760 for (j
= 0; j
< cChar
; j
++)
3763 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3764 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3765 cChar
, j
, direction
, NULL
, NULL
);
3766 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
);
3768 for (k
= 0; k
< clust_size
; k
++)
3770 piDx
[next
] = advance
/ clust_size
;
3779 /***********************************************************************
3780 * ScriptStringValidate (USP10.@)
3782 * Validate a string analysis.
3785 * ssa [I] string analysis.
3789 * Failure: S_FALSE if invalid sequences are found
3790 * or a non-zero HRESULT if it fails.
3792 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3794 StringAnalysis
*analysis
= ssa
;
3796 TRACE("(%p)\n", ssa
);
3798 if (!analysis
) return E_INVALIDARG
;
3799 return (analysis
->invalid
) ? S_FALSE
: S_OK
;
3802 /***********************************************************************
3803 * ScriptString_pSize (USP10.@)
3805 * Retrieve width and height of an analysed string.
3808 * ssa [I] string analysis.
3811 * Success: Pointer to a SIZE structure.
3814 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3817 StringAnalysis
*analysis
= ssa
;
3819 TRACE("(%p)\n", ssa
);
3821 if (!analysis
) return NULL
;
3822 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return NULL
;
3826 if (!(analysis
->sz
= heap_alloc(sizeof(SIZE
)))) return NULL
;
3827 analysis
->sz
->cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3829 analysis
->sz
->cx
= 0;
3830 for (i
= 0; i
< analysis
->numItems
; i
++)
3832 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
->cy
)
3833 analysis
->sz
->cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3834 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3835 analysis
->sz
->cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3838 return analysis
->sz
;
3841 /***********************************************************************
3842 * ScriptString_pLogAttr (USP10.@)
3844 * Retrieve logical attributes of an analysed string.
3847 * ssa [I] string analysis.
3850 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3853 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3855 StringAnalysis
*analysis
= ssa
;
3857 TRACE("(%p)\n", ssa
);
3859 if (!analysis
) return NULL
;
3860 if (!(analysis
->dwFlags
& SSA_BREAK
)) return NULL
;
3861 return analysis
->logattrs
;
3864 /***********************************************************************
3865 * ScriptString_pcOutChars (USP10.@)
3867 * Retrieve the length of a string after clipping.
3870 * ssa [I] String analysis.
3873 * Success: Pointer to the length.
3876 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3878 StringAnalysis
*analysis
= ssa
;
3880 TRACE("(%p)\n", ssa
);
3882 if (!analysis
) return NULL
;
3883 return &analysis
->clip_len
;
3886 /***********************************************************************
3887 * ScriptStringGetOrder (USP10.@)
3889 * Retrieve a glyph order map.
3892 * ssa [I] String analysis.
3893 * order [I/O] Array of glyph positions.
3897 * Failure: a non-zero HRESULT.
3899 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3903 StringAnalysis
*analysis
= ssa
;
3905 TRACE("(%p)\n", ssa
);
3907 if (!analysis
) return S_FALSE
;
3908 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3910 /* FIXME: handle RTL scripts */
3911 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3912 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3918 /***********************************************************************
3919 * ScriptGetLogicalWidths (USP10.@)
3921 * Convert advance widths to logical widths.
3924 * sa [I] Script analysis.
3925 * nbchars [I] Number of characters.
3926 * nbglyphs [I] Number of glyphs.
3927 * glyph_width [I] Array of glyph widths.
3928 * log_clust [I] Array of logical clusters.
3929 * sva [I] Visual attributes.
3930 * widths [O] Array of logical widths.
3934 * Failure: a non-zero HRESULT.
3936 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3937 const int *advances
, const WORD
*log_clust
,
3938 const SCRIPT_VISATTR
*sva
, int *widths
)
3940 int i
, next
= 0, direction
;
3942 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3943 sa
, nbchars
, nbglyphs
, advances
, log_clust
, sva
, widths
);
3945 if (sa
->fRTL
&& !sa
->fLogicalOrder
)
3950 for (i
= 0; i
< nbchars
; i
++)
3952 int clust_size
= get_cluster_size(log_clust
, nbchars
, i
, direction
, NULL
, NULL
);
3953 int advance
= get_glyph_cluster_advance(advances
, sva
, log_clust
, nbglyphs
, nbchars
, log_clust
[i
], direction
);
3956 for (j
= 0; j
< clust_size
; j
++)
3958 widths
[next
] = advance
/ clust_size
;
3967 /***********************************************************************
3968 * ScriptApplyLogicalWidth (USP10.@)
3970 * Generate glyph advance widths.
3973 * dx [I] Array of logical advance widths.
3974 * num_chars [I] Number of characters.
3975 * num_glyphs [I] Number of glyphs.
3976 * log_clust [I] Array of logical clusters.
3977 * sva [I] Visual attributes.
3978 * advance [I] Array of glyph advance widths.
3979 * sa [I] Script analysis.
3980 * abc [I/O] Summed ABC widths.
3981 * justify [O] Array of glyph advance widths.
3985 * Failure: a non-zero HRESULT.
3987 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
3988 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
3989 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
3990 ABC
*abc
, int *justify
)
3994 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3995 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
3997 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
4001 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
4002 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
4006 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
4008 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
4012 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
4015 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4016 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4018 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
4021 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
4024 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4025 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4027 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
4030 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
4033 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4034 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4036 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);