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
;
691 enum stringanalysis_flags
693 SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
= 0x1,
694 SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
= 0x2,
706 StringGlyphs
* glyphs
;
707 SCRIPT_LOGATTR
* logattrs
;
717 BOOL
usp10_array_reserve(void **elements
, SIZE_T
*capacity
, SIZE_T count
, SIZE_T size
)
719 SIZE_T max_capacity
, new_capacity
;
722 if (count
<= *capacity
)
725 max_capacity
= ~(SIZE_T
)0 / size
;
726 if (count
> max_capacity
)
729 new_capacity
= max(1, *capacity
);
730 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
732 if (new_capacity
< count
)
733 new_capacity
= count
;
736 new_elements
= heap_alloc_zero(new_capacity
* size
);
738 new_elements
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *elements
, new_capacity
* size
);
742 *elements
= new_elements
;
743 *capacity
= new_capacity
;
747 /* TODO Fix font properties on Arabic locale */
748 static inline BOOL
set_cache_font_properties(const HDC hdc
, ScriptCache
*sc
)
750 sc
->sfp
.cBytes
= sizeof(sc
->sfp
);
754 sc
->sfp
.wgBlank
= sc
->tm
.tmBreakChar
;
755 sc
->sfp
.wgDefault
= sc
->tm
.tmDefaultChar
;
756 sc
->sfp
.wgInvalid
= sc
->sfp
.wgBlank
;
757 sc
->sfp
.wgKashida
= 0xFFFF;
758 sc
->sfp
.iKashidaWidth
= 0;
762 static const WCHAR chars
[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
763 /* U+0020: numeric space
764 U+200B: zero width space
765 U+F71B: unknown char found by black box testing
769 if (GetGlyphIndicesW(hdc
, chars
, 4, gi
, GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
771 if(gi
[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
772 sc
->sfp
.wgBlank
= gi
[0];
776 sc
->sfp
.wgDefault
= 0;
779 sc
->sfp
.wgInvalid
= gi
[2];
780 else if (gi
[1] != 0xFFFF)
781 sc
->sfp
.wgInvalid
= gi
[1];
782 else if (gi
[0] != 0xFFFF)
783 sc
->sfp
.wgInvalid
= gi
[0];
785 sc
->sfp
.wgInvalid
= 0;
787 sc
->sfp
.wgKashida
= gi
[3];
789 sc
->sfp
.iKashidaWidth
= 0; /* TODO */
797 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES
*sfp
, ScriptCache
*sc
)
802 static inline LONG
get_cache_height(SCRIPT_CACHE
*psc
)
804 return ((ScriptCache
*)*psc
)->tm
.tmHeight
;
807 static inline BYTE
get_cache_pitch_family(SCRIPT_CACHE
*psc
)
809 return ((ScriptCache
*)*psc
)->tm
.tmPitchAndFamily
;
812 static inline WORD
get_cache_glyph(SCRIPT_CACHE
*psc
, DWORD c
)
814 CacheGlyphPage
*page
= ((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
818 block
= page
->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
819 if (!block
) return 0;
820 return block
[(c
% 0x10000) & GLYPH_BLOCK_MASK
];
823 static inline WORD
set_cache_glyph(SCRIPT_CACHE
*psc
, WCHAR c
, WORD glyph
)
825 CacheGlyphPage
**page
= &((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
827 if (!*page
&& !(*page
= heap_alloc_zero(sizeof(CacheGlyphPage
)))) return 0;
829 block
= &(*page
)->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
830 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(WORD
) * GLYPH_BLOCK_SIZE
))) return 0;
831 return ((*block
)[(c
% 0x10000) & GLYPH_BLOCK_MASK
] = glyph
);
834 static inline BOOL
get_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
836 static const ABC nil
;
837 ABC
*block
= ((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
839 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(ABC
))) return FALSE
;
840 memcpy(abc
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(ABC
));
844 static inline BOOL
set_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
846 ABC
**block
= &((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
848 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(ABC
) * GLYPH_BLOCK_SIZE
))) return FALSE
;
849 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], abc
, sizeof(ABC
));
853 static HRESULT
init_script_cache(const HDC hdc
, SCRIPT_CACHE
*psc
)
858 if (!psc
) return E_INVALIDARG
;
859 if (*psc
) return S_OK
;
860 if (!hdc
) return E_PENDING
;
862 if (!(sc
= heap_alloc_zero(sizeof(ScriptCache
)))) return E_OUTOFMEMORY
;
863 if (!GetTextMetricsW(hdc
, &sc
->tm
))
868 size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
871 sc
->otm
= heap_alloc(size
);
872 sc
->otm
->otmSize
= size
;
873 GetOutlineTextMetricsW(hdc
, size
, sc
->otm
);
875 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(LOGFONTW
), &sc
->lf
))
880 sc
->sfnt
= (GetFontData(hdc
, MS_MAKE_TAG('h','e','a','d'), 0, NULL
, 0)!=GDI_ERROR
);
881 if (!set_cache_font_properties(hdc
, sc
))
887 TRACE("<- %p\n", sc
);
891 static WCHAR
mirror_char( WCHAR ch
)
893 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
894 return ch
+ wine_mirror_map
[wine_mirror_map
[ch
>> 8] + (ch
& 0xff)];
897 static DWORD
decode_surrogate_pair(const WCHAR
*str
, unsigned int index
, unsigned int end
)
899 if (index
< end
-1 && IS_SURROGATE_PAIR(str
[index
],str
[index
+1]))
901 DWORD ch
= 0x10000 + ((str
[index
] - 0xd800) << 10) + (str
[index
+1] - 0xdc00);
902 TRACE("Surrogate Pair %x %x => %x\n",str
[index
], str
[index
+1], ch
);
908 static int usp10_compare_script_range(const void *key
, const void *value
)
910 const struct usp10_script_range
*range
= value
;
911 const DWORD
*ch
= key
;
913 if (*ch
< range
->rangeFirst
)
915 if (*ch
> range
->rangeLast
)
920 static enum usp10_script
get_char_script(const WCHAR
*str
, unsigned int index
,
921 unsigned int end
, unsigned int *consumed
)
923 static const WCHAR latin_punc
[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
924 struct usp10_script_range
*range
;
925 WORD type
= 0, type2
= 0;
930 if (str
[index
] == 0xc || str
[index
] == 0x20 || str
[index
] == 0x202f)
933 /* These punctuation characters are separated out as Latin punctuation */
934 if (strchrW(latin_punc
,str
[index
]))
935 return Script_Punctuation2
;
937 /* These chars are itemized as Punctuation by Windows */
938 if (str
[index
] == 0x2212 || str
[index
] == 0x2044)
939 return Script_Punctuation
;
941 /* Currency Symbols by Unicode point */
945 case 0x09f3: return Script_Bengali_Currency
;
946 case 0x0af1: return Script_Gujarati_Currency
;
947 case 0x0e3f: return Script_Thai_Currency
;
948 case 0x20aa: return Script_Hebrew_Currency
;
949 case 0x20ab: return Script_Vietnamese_Currency
;
950 case 0xfb29: return Script_Hebrew_Currency
;
953 GetStringTypeW(CT_CTYPE1
, &str
[index
], 1, &type
);
954 GetStringTypeW(CT_CTYPE2
, &str
[index
], 1, &type2
);
957 return SCRIPT_UNDEFINED
;
960 return Script_Control
;
962 ch
= decode_surrogate_pair(str
, index
, end
);
968 if (!(range
= bsearch(&ch
, script_ranges
, ARRAY_SIZE(script_ranges
),
969 sizeof(*script_ranges
), usp10_compare_script_range
)))
970 return (*consumed
== 2) ? Script_Surrogates
: Script_Undefined
;
972 if (range
->numericScript
&& (type
& C1_DIGIT
|| type2
== C2_ARABICNUMBER
))
973 return range
->numericScript
;
974 if (range
->punctScript
&& type
& C1_PUNCT
)
975 return range
->punctScript
;
976 return range
->script
;
979 static int compare_FindGlyph(const void *a
, const void* b
)
981 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
982 const WORD
*idx
= (WORD
*)b
;
985 if ( find
->target
> *idx
)
987 else if (find
->target
< *idx
)
990 if (!find
->ascending
)
995 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
997 FindGlyph_struct fgs
;
1001 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
1002 fgs
.ascending
= TRUE
;
1004 fgs
.ascending
= FALSE
;
1006 fgs
.target
= target
;
1007 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
1012 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
1019 /***********************************************************************
1020 * ScriptFreeCache (USP10.@)
1022 * Free a script cache.
1025 * psc [I/O] Script cache.
1029 * Failure: Non-zero HRESULT value.
1031 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1039 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1041 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1043 for (i
= 0; i
< NUM_PAGES
; i
++)
1046 if (((ScriptCache
*)*psc
)->page
[i
])
1047 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1048 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1049 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1051 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1052 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1053 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1054 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1055 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1058 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1061 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1062 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1063 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1065 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1066 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1067 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1068 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1070 heap_free(((ScriptCache
*)*psc
)->scripts
);
1071 heap_free(((ScriptCache
*)*psc
)->otm
);
1078 /***********************************************************************
1079 * ScriptGetProperties (USP10.@)
1081 * Retrieve a list of script properties.
1084 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1085 * num [I] Pointer to the number of scripts.
1089 * Failure: Non-zero HRESULT value.
1092 * Behaviour matches WinXP.
1094 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1096 TRACE("(%p,%p)\n", props
, num
);
1098 if (!props
&& !num
) return E_INVALIDARG
;
1100 if (num
) *num
= sizeof(script_props
)/sizeof(script_props
[0]);
1101 if (props
) *props
= script_props
;
1106 /***********************************************************************
1107 * ScriptGetFontProperties (USP10.@)
1109 * Get information on special glyphs.
1112 * hdc [I] Device context.
1113 * psc [I/O] Opaque pointer to a script cache.
1114 * sfp [O] Font properties structure.
1116 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1120 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1122 if (!sfp
) return E_INVALIDARG
;
1123 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1125 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1126 return E_INVALIDARG
;
1128 get_cache_font_properties(sfp
, *psc
);
1133 /***********************************************************************
1134 * ScriptRecordDigitSubstitution (USP10.@)
1136 * Record digit substitution settings for a given locale.
1139 * locale [I] Locale identifier.
1140 * sds [I] Structure to record substitution settings.
1144 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1147 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1149 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1153 TRACE("0x%x, %p\n", locale
, sds
);
1155 /* This implementation appears to be correct for all languages, but it's
1156 * not clear if sds->DigitSubstitute is ever set to anything except
1157 * CONTEXT or NONE in reality */
1159 if (!sds
) return E_POINTER
;
1161 locale
= ConvertDefaultLocale(locale
);
1163 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1164 return E_INVALIDARG
;
1166 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1167 sds
->TraditionalDigitLanguage
= plgid
;
1169 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1170 sds
->NationalDigitLanguage
= plgid
;
1172 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1174 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1175 (WCHAR
*)&sub
, sizeof(sub
) / sizeof(WCHAR
)))
1176 return E_INVALIDARG
;
1181 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1182 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1184 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1187 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1190 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1193 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1197 sds
->dwReserved
= 0;
1201 /***********************************************************************
1202 * ScriptApplyDigitSubstitution (USP10.@)
1204 * Apply digit substitution settings.
1207 * sds [I] Structure with recorded substitution settings.
1208 * sc [I] Script control structure.
1209 * ss [I] Script state structure.
1213 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1215 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1216 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1218 SCRIPT_DIGITSUBSTITUTE psds
;
1220 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1222 if (!sc
|| !ss
) return E_POINTER
;
1226 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1227 return E_INVALIDARG
;
1230 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1231 sc
->fContextDigits
= 0;
1232 ss
->fDigitSubstitute
= 0;
1234 switch (sds
->DigitSubstitute
) {
1235 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1236 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1237 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1238 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1241 return E_INVALIDARG
;
1245 static inline BOOL
is_indic(enum usp10_script script
)
1247 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1250 static inline enum usp10_script
base_indic(enum usp10_script script
)
1254 case Script_Devanagari
:
1255 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1256 case Script_Bengali
:
1257 case Script_Bengali_Numeric
:
1258 case Script_Bengali_Currency
: return Script_Bengali
;
1259 case Script_Gurmukhi
:
1260 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1261 case Script_Gujarati
:
1262 case Script_Gujarati_Numeric
:
1263 case Script_Gujarati_Currency
: return Script_Gujarati
;
1265 case Script_Oriya_Numeric
: return Script_Oriya
;
1267 case Script_Tamil_Numeric
: return Script_Tamil
;
1269 case Script_Telugu_Numeric
: return Script_Telugu
;
1270 case Script_Kannada
:
1271 case Script_Kannada_Numeric
: return Script_Kannada
;
1272 case Script_Malayalam
:
1273 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1275 return Script_Undefined
;
1279 static BOOL
script_is_numeric(enum usp10_script script
)
1281 return scriptInformation
[script
].props
.fNumeric
;
1284 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1285 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1286 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1287 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1290 #define Numeric_space 0x0020
1295 enum usp10_script last_indic
= Script_Undefined
;
1296 int cnt
= 0, index
= 0, str
= 0;
1297 enum usp10_script New_Script
= -1;
1299 WORD
*levels
= NULL
;
1300 WORD
*layout_levels
= NULL
;
1301 WORD
*overrides
= NULL
;
1302 WORD
*strength
= NULL
;
1303 enum usp10_script
*scripts
;
1305 WORD baselayout
= 0;
1308 BOOL forceLevels
= FALSE
;
1309 unsigned int consumed
= 0;
1310 HRESULT res
= E_OUTOFMEMORY
;
1312 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1313 psControl
, psState
, pItems
, pcItems
);
1315 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1316 return E_INVALIDARG
;
1318 if (!(scripts
= heap_alloc(cInChars
* sizeof(*scripts
))))
1319 return E_OUTOFMEMORY
;
1321 for (i
= 0; i
< cInChars
; i
++)
1325 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1330 scripts
[i
] = scripts
[i
-1];
1333 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1334 all Indic scripts */
1335 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
!= Script_Undefined
)
1336 scripts
[i
] = last_indic
;
1337 else if (is_indic(scripts
[i
]))
1338 last_indic
= base_indic(scripts
[i
]);
1340 /* Some unicode points :
1341 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1342 (Left Right Embed U+202A - Left Right Override U+202D)
1343 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1344 will force us into bidi mode */
1345 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1346 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1347 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1351 /* Diacritical marks merge with other scripts */
1352 if (scripts
[i
] == Script_Diacritical
)
1357 scripts
[i
] = scripts
[i
-1];
1362 enum usp10_script first_script
= scripts
[i
-1];
1363 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1365 enum usp10_script original
= scripts
[j
];
1366 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1371 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1373 scripts
[j
] = scripts
[i
];
1374 if (original
== Script_Punctuation2
)
1377 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1378 scripts
[i
] = scripts
[j
];
1384 for (i
= 0; i
< cInChars
; i
++)
1386 /* Joiners get merged preferencially right */
1387 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1390 if (i
+1 == cInChars
)
1391 scripts
[i
] = scripts
[i
-1];
1394 for (j
= i
+1; j
< cInChars
; j
++)
1396 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1397 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1399 scripts
[i
] = scripts
[j
];
1407 if (psState
&& psControl
)
1409 levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1413 overrides
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1417 layout_levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1421 if (psState
->fOverrideDirection
)
1425 SCRIPT_STATE s
= *psState
;
1426 s
.fOverrideDirection
= FALSE
;
1427 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1428 if (odd(layout_levels
[0]))
1430 else for (i
= 0; i
< cInChars
; i
++)
1431 if (layout_levels
[i
]!=layout_levels
[0])
1438 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1442 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1443 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1445 baselevel
= levels
[0];
1446 baselayout
= layout_levels
[0];
1447 for (i
= 0; i
< cInChars
; i
++)
1448 if (levels
[i
]!=levels
[0])
1450 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1453 heap_free(overrides
);
1454 heap_free(layout_levels
);
1457 layout_levels
= NULL
;
1461 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1462 static const WCHAR repeatable_math_punc
[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1464 strength
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1467 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1469 /* We currently mis-level leading Diacriticals */
1470 if (scripts
[0] == Script_Diacritical
)
1471 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1473 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1474 strength
[i
] = BIDI_STRONG
;
1477 /* Math punctuation bordered on both sides by numbers can be
1478 merged into the number */
1479 for (i
= 0; i
< cInChars
; i
++)
1481 if (i
> 0 && i
< cInChars
-1 &&
1482 script_is_numeric(scripts
[i
-1]) &&
1483 strchrW(math_punc
, pwcInChars
[i
]))
1485 if (script_is_numeric(scripts
[i
+1]))
1487 scripts
[i
] = scripts
[i
+1];
1488 levels
[i
] = levels
[i
-1];
1489 strength
[i
] = strength
[i
-1];
1492 else if (strchrW(repeatable_math_punc
, pwcInChars
[i
]))
1495 for (j
= i
+1; j
< cInChars
; j
++)
1497 if (script_is_numeric(scripts
[j
]))
1501 scripts
[i
] = scripts
[j
];
1502 levels
[i
] = levels
[i
-1];
1503 strength
[i
] = strength
[i
-1];
1506 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1512 for (i
= 0; i
< cInChars
; i
++)
1514 /* Numerics at level 0 get bumped to level 2 */
1515 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
)
1516 && levels
[i
] == psState
->uBidiLevel
+ 1)) && script_is_numeric(scripts
[i
]))
1521 /* Joiners get merged preferencially right */
1522 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1525 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1526 strength
[i
] = strength
[i
-1];
1528 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1529 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1530 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1532 strength
[i
] = strength
[j
];
1537 if (psControl
->fMergeNeutralItems
)
1539 /* Merge the neutrals */
1540 for (i
= 0; i
< cInChars
; i
++)
1542 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1545 for (j
= i
; j
> 0; j
--)
1547 if (levels
[i
] != levels
[j
])
1549 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1551 scripts
[i
] = scripts
[j
];
1552 strength
[i
] = strength
[j
];
1557 /* Try going the other way */
1558 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1561 for (j
= i
; j
< cInChars
; j
++)
1563 if (levels
[i
] != levels
[j
])
1565 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1567 scripts
[i
] = scripts
[j
];
1568 strength
[i
] = strength
[j
];
1578 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1579 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1582 if (cnt
== cInChars
) /* All Spaces */
1585 New_Script
= scripts
[cnt
];
1588 pItems
[index
].iCharPos
= 0;
1589 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1591 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1593 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1594 str
= strength
[cnt
];
1602 if (strength
[cnt
] == BIDI_STRONG
)
1603 layoutRTL
= odd(layout_levels
[cnt
]);
1605 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1607 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1608 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1609 if (script_is_numeric(pItems
[index
].a
.eScript
))
1610 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1612 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1613 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1615 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1617 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1618 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1619 layoutRTL
= odd(baselayout
);
1620 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1621 pItems
[index
].a
.fRTL
= odd(baselevel
);
1622 if (script_is_numeric(pItems
[index
].a
.eScript
))
1623 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1625 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1628 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1629 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1630 pItems
[index
].iCharPos
);
1632 for (cnt
=1; cnt
< cInChars
; cnt
++)
1634 if(pwcInChars
[cnt
] != Numeric_space
)
1635 New_Script
= scripts
[cnt
];
1639 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1641 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1642 New_Script
= scripts
[cnt
+j
];
1644 New_Script
= scripts
[cnt
];
1648 /* merge space strengths*/
1649 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1652 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1655 /* changes in level */
1656 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1658 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1661 /* changes in strength */
1662 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1664 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1667 /* changes in script */
1668 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1670 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1674 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1676 layoutRTL
= odd(layout_levels
[cnt
]);
1677 if (script_is_numeric(pItems
[index
].a
.eScript
))
1678 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1683 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
);
1686 if (index
+1 > cMaxItems
)
1690 str
= strength
[cnt
];
1692 pItems
[index
].iCharPos
= cnt
;
1693 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1695 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1697 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1701 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1702 if (layout_levels
[cnt
] == 0)
1705 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1706 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1707 if (script_is_numeric(pItems
[index
].a
.eScript
))
1708 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1710 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1711 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1713 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1715 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1716 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1717 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1718 pItems
[index
].a
.fRTL
= odd(baselevel
);
1719 if (script_is_numeric(pItems
[index
].a
.eScript
))
1720 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1722 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1725 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1729 /* While not strictly necessary according to the spec, make sure the n+1
1730 * item is set up to prevent random behaviour if the caller erroneously
1731 * checks the n+1 structure */
1733 if (index
+ 1 > cMaxItems
) goto nomemory
;
1734 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1736 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1738 /* Set one SCRIPT_STATE item being returned */
1739 if (pcItems
) *pcItems
= index
;
1741 /* Set SCRIPT_ITEM */
1742 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1746 heap_free(overrides
);
1747 heap_free(layout_levels
);
1748 heap_free(strength
);
1753 /***********************************************************************
1754 * ScriptItemizeOpenType (USP10.@)
1756 * Split a Unicode string into shapeable parts.
1759 * pwcInChars [I] String to split.
1760 * cInChars [I] Number of characters in pwcInChars.
1761 * cMaxItems [I] Maximum number of items to return.
1762 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1763 * psState [I] Pointer to a SCRIPT_STATE structure.
1764 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1765 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1766 * pcItems [O] Number of script items returned.
1770 * Failure: Non-zero HRESULT value.
1772 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1773 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1774 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1776 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1779 /***********************************************************************
1780 * ScriptItemize (USP10.@)
1782 * Split a Unicode string into shapeable parts.
1785 * pwcInChars [I] String to split.
1786 * cInChars [I] Number of characters in pwcInChars.
1787 * cMaxItems [I] Maximum number of items to return.
1788 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1789 * psState [I] Pointer to a SCRIPT_STATE structure.
1790 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1791 * pcItems [O] Number of script items returned.
1795 * Failure: Non-zero HRESULT value.
1797 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1798 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1799 SCRIPT_ITEM
*pItems
, int *pcItems
)
1801 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1804 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1808 INT
*lpTabPos
= NULL
;
1813 lpTabPos
= pTabdef
->pTabStops
;
1815 if (pTabdef
&& pTabdef
->iTabOrigin
)
1817 if (pTabdef
->iScale
)
1818 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1820 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1824 cTabStops
= pTabdef
->cTabStops
;
1828 if (pTabdef
->iScale
)
1829 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1831 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1836 if (pTabdef
->iScale
)
1837 defWidth
= (32 * pTabdef
->iScale
) / 4;
1839 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1842 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1844 int position
= *lpTabPos
;
1846 position
= -1 * position
;
1847 if (pTabdef
->iScale
)
1848 position
= (position
* pTabdef
->iScale
) / 4;
1850 position
= position
* psc
->tm
.tmAveCharWidth
;
1852 if( nTabOrg
+ position
> current_x
)
1856 /* a left aligned tab */
1857 x
= (nTabOrg
+ position
) - current_x
;
1862 FIXME("Negative tabstop\n");
1867 if ((!cTabStops
) && (defWidth
> 0))
1868 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1869 else if ((!cTabStops
) && (defWidth
< 0))
1870 FIXME("TODO: Negative defWidth\n");
1875 /***********************************************************************
1876 * Helper function for ScriptStringAnalyse
1878 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1879 const WCHAR
*pwcInChars
, int cChars
)
1881 /* FIXME: When to properly fallback is still a bit of a mystery */
1884 if (psa
->fNoGlyphIndex
)
1887 if (init_script_cache(hdc
, psc
) != S_OK
)
1890 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1893 glyphs
= heap_alloc(sizeof(WORD
) * cChars
);
1896 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1906 static void find_fallback_font(enum usp10_script scriptid
, WCHAR
*FaceName
)
1910 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1912 static const WCHAR szFmt
[] = {'%','x',0};
1914 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1917 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1918 if (RegQueryValueExW(hkey
, value
, 0, &type
, (BYTE
*)FaceName
, &count
))
1919 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1923 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1926 /***********************************************************************
1927 * ScriptStringAnalyse (USP10.@)
1930 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1931 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1932 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1933 SCRIPT_STATE
*psState
, const int *piDx
,
1934 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1935 SCRIPT_STRING_ANALYSIS
*pssa
)
1937 HRESULT hr
= E_OUTOFMEMORY
;
1938 StringAnalysis
*analysis
= NULL
;
1939 SCRIPT_CONTROL sControl
;
1940 SCRIPT_STATE sState
;
1941 int i
, num_items
= 255;
1943 WCHAR
*iString
= NULL
;
1945 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1946 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1947 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
1951 FIXME("Only Unicode strings are supported\n");
1952 return E_INVALIDARG
;
1954 if (cString
< 1 || !pString
) return E_INVALIDARG
;
1955 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
1957 if (!(analysis
= heap_alloc_zero(sizeof(StringAnalysis
)))) return E_OUTOFMEMORY
;
1958 if (!(analysis
->pItem
= heap_alloc_zero(num_items
* sizeof(SCRIPT_ITEM
) + 1))) goto error
;
1960 /* FIXME: handle clipping */
1961 analysis
->clip_len
= cString
;
1962 analysis
->hdc
= hdc
;
1963 analysis
->ssa_flags
= dwFlags
;
1968 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
1971 sControl
= *psControl
;
1973 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
1975 if (dwFlags
& SSA_PASSWORD
)
1977 iString
= heap_alloc(sizeof(WCHAR
)*cString
);
1983 for (i
= 0; i
< cString
; i
++)
1984 iString
[i
] = *((const WCHAR
*)pString
);
1988 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
1989 &analysis
->numItems
);
1993 if (hr
== E_OUTOFMEMORY
)
1998 /* set back to out of memory for default goto error behaviour */
2001 if (dwFlags
& SSA_BREAK
)
2003 if ((analysis
->logattrs
= heap_alloc(sizeof(SCRIPT_LOGATTR
) * cString
)))
2005 for (i
= 0; i
< analysis
->numItems
; i
++)
2006 ScriptBreak(&((WCHAR
*)pString
)[analysis
->pItem
[i
].iCharPos
],
2007 analysis
->pItem
[i
+ 1].iCharPos
- analysis
->pItem
[i
].iCharPos
,
2008 &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
2014 if (!(analysis
->logical2visual
= heap_alloc_zero(sizeof(int) * analysis
->numItems
)))
2016 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
2019 if (dwFlags
& SSA_GLYPHS
)
2022 if (!(analysis
->glyphs
= heap_alloc_zero(sizeof(StringGlyphs
) * analysis
->numItems
)))
2024 heap_free(BidiLevel
);
2028 for (i
= 0; i
< analysis
->numItems
; i
++)
2030 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
2031 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2032 int numGlyphs
= 1.5 * cChar
+ 16;
2033 WORD
*glyphs
= heap_alloc_zero(sizeof(WORD
) * numGlyphs
);
2034 WORD
*pwLogClust
= heap_alloc_zero(sizeof(WORD
) * cChar
);
2035 int *piAdvance
= heap_alloc_zero(sizeof(int) * numGlyphs
);
2036 SCRIPT_VISATTR
*psva
= heap_alloc_zero(sizeof(SCRIPT_VISATTR
) * numGlyphs
);
2037 GOFFSET
*pGoffset
= heap_alloc_zero(sizeof(GOFFSET
) * numGlyphs
);
2038 int numGlyphsReturned
;
2039 HFONT originalFont
= 0x0;
2041 /* FIXME: non unicode strings */
2042 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2043 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2045 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
)
2047 heap_free (BidiLevel
);
2049 heap_free (pwLogClust
);
2050 heap_free (piAdvance
);
2052 heap_free (pGoffset
);
2057 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2060 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2061 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2062 lf
.lfFaceName
[0] = 0;
2063 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2064 if (lf
.lfFaceName
[0])
2066 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2067 if (analysis
->glyphs
[i
].fallbackFont
)
2069 ScriptFreeCache(sc
);
2070 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2075 /* FIXME: When we properly shape Hangul remove this check */
2076 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2077 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2079 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2080 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2082 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2083 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2084 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2085 piAdvance
, pGoffset
, &analysis
->glyphs
[i
].abc
);
2087 SelectObject(hdc
,originalFont
);
2089 if (dwFlags
& SSA_TAB
)
2092 for (tabi
= 0; tabi
< cChar
; tabi
++)
2094 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2095 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2096 tab_x
+=piAdvance
[tabi
];
2100 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2101 analysis
->glyphs
[i
].glyphs
= glyphs
;
2102 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2103 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2104 analysis
->glyphs
[i
].psva
= psva
;
2105 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2106 analysis
->glyphs
[i
].iMaxPosX
= -1;
2108 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2113 for (i
= 0; i
< analysis
->numItems
; i
++)
2114 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2117 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2118 heap_free(BidiLevel
);
2126 heap_free(analysis
->glyphs
);
2127 heap_free(analysis
->logattrs
);
2128 heap_free(analysis
->pItem
);
2129 heap_free(analysis
->logical2visual
);
2130 heap_free(analysis
);
2134 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2136 if (pva
[glyph
].fClusterStart
)
2138 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2145 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2156 StringAnalysis
*analysis
;
2159 COLORREF BkColor
= 0x0;
2160 COLORREF TextColor
= 0x0;
2162 INT runStart
, runEnd
;
2163 INT iGlyph
, cGlyphs
;
2164 HFONT oldFont
= 0x0;
2168 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2169 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2171 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2173 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2174 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2180 BkMode
= GetBkMode(analysis
->hdc
);
2181 SetBkMode( analysis
->hdc
, OPAQUE
);
2182 BkColor
= GetBkColor(analysis
->hdc
);
2183 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2186 TextColor
= GetTextColor(analysis
->hdc
);
2187 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2190 if (analysis
->glyphs
[iItem
].fallbackFont
)
2191 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2193 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2194 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2197 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2198 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2200 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2202 if (analysis
->pItem
[iItem
].a
.fRTL
)
2204 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2205 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2207 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2208 crc
.left
= iX
+ off_x
;
2212 if (cStart
>=0 && runStart
)
2213 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2215 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2216 crc
.left
= iX
+ off_x
;
2219 if (analysis
->pItem
[iItem
].a
.fRTL
)
2220 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2222 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2224 if (analysis
->pItem
[iItem
].a
.fRTL
)
2225 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2227 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2231 /* adjust for cluster glyphs when starting */
2232 if (analysis
->pItem
[iItem
].a
.fRTL
)
2233 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2235 i
= analysis
->pItem
[iItem
].iCharPos
;
2237 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2239 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2241 if (analysis
->pItem
[iItem
].a
.fRTL
)
2242 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2244 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2249 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2254 clust_glyph
= iGlyph
+ cGlyphs
;
2255 if (analysis
->pItem
[iItem
].a
.fRTL
)
2260 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2261 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2268 hr
= ScriptTextOut(analysis
->hdc
,
2269 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2270 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2271 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2272 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2273 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2275 TRACE("ScriptTextOut hr=%08x\n", hr
);
2279 SetBkColor(analysis
->hdc
, BkColor
);
2280 SetBkMode( analysis
->hdc
, BkMode
);
2282 SetTextColor(analysis
->hdc
, TextColor
);
2284 if (analysis
->glyphs
[iItem
].fallbackFont
)
2285 SelectObject(analysis
->hdc
, oldFont
);
2290 /***********************************************************************
2291 * ScriptStringOut (USP10.@)
2293 * This function takes the output of ScriptStringAnalyse and joins the segments
2294 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2295 * only processes glyphs.
2298 * ssa [I] buffer to hold the analysed string components
2299 * iX [I] X axis displacement for output
2300 * iY [I] Y axis displacement for output
2301 * uOptions [I] flags controlling output processing
2302 * prc [I] rectangle coordinates
2303 * iMinSel [I] starting pos for substringing output string
2304 * iMaxSel [I] ending pos for substringing output string
2305 * fDisabled [I] controls text highlighting
2309 * Failure: is the value returned by ScriptTextOut
2311 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2320 StringAnalysis
*analysis
;
2324 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2325 ssa
, iX
, iY
, uOptions
, wine_dbgstr_rect(prc
), iMinSel
, iMaxSel
, fDisabled
);
2327 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2328 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2330 for (item
= 0; item
< analysis
->numItems
; item
++)
2332 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2337 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2339 if (iMaxSel
> 0 && iMinSel
< 0)
2341 for (item
= 0; item
< analysis
->numItems
; item
++)
2343 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2352 /***********************************************************************
2353 * ScriptStringCPtoX (USP10.@)
2356 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2360 StringAnalysis
* analysis
= ssa
;
2362 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2364 if (!ssa
|| !pX
) return S_FALSE
;
2365 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2367 /* icp out of range */
2370 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2371 return E_INVALIDARG
;
2374 for(item
=0; item
<analysis
->numItems
; item
++)
2379 i
= analysis
->logical2visual
[item
];
2380 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2381 /* initialize max extents for uninitialized runs */
2382 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2384 if (analysis
->pItem
[i
].a
.fRTL
)
2385 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2386 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2387 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2389 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2390 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2391 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2394 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2396 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2400 icp
-= analysis
->pItem
[i
].iCharPos
;
2401 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2402 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2403 &analysis
->pItem
[i
].a
, &offset
);
2410 /* icp out of range */
2411 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2412 return E_INVALIDARG
;
2415 /***********************************************************************
2416 * ScriptStringXtoCP (USP10.@)
2419 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2421 StringAnalysis
* analysis
= ssa
;
2424 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2426 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2427 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2432 if (analysis
->pItem
[0].a
.fRTL
)
2435 *piTrailing
= FALSE
;
2445 for(item
=0; item
<analysis
->numItems
; item
++)
2450 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2453 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2454 /* initialize max extents for uninitialized runs */
2455 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2457 if (analysis
->pItem
[i
].a
.fRTL
)
2458 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2459 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2460 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2462 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2463 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2464 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2467 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2469 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2473 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2474 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2475 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2476 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2482 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2483 *piTrailing
= FALSE
;
2489 /***********************************************************************
2490 * ScriptStringFree (USP10.@)
2492 * Free a string analysis.
2495 * pssa [I] string analysis.
2499 * Failure: Non-zero HRESULT value.
2501 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2503 StringAnalysis
* analysis
;
2507 TRACE("(%p)\n", pssa
);
2509 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2511 invalid
= analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2513 if (analysis
->glyphs
)
2515 for (i
= 0; i
< analysis
->numItems
; i
++)
2517 heap_free(analysis
->glyphs
[i
].glyphs
);
2518 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2519 heap_free(analysis
->glyphs
[i
].piAdvance
);
2520 heap_free(analysis
->glyphs
[i
].psva
);
2521 heap_free(analysis
->glyphs
[i
].pGoffset
);
2522 if (analysis
->glyphs
[i
].fallbackFont
)
2523 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2524 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2525 heap_free(analysis
->glyphs
[i
].sc
);
2527 heap_free(analysis
->glyphs
);
2530 heap_free(analysis
->pItem
);
2531 heap_free(analysis
->logattrs
);
2532 heap_free(analysis
->logical2visual
);
2533 heap_free(analysis
);
2535 if (invalid
) return E_INVALIDARG
;
2539 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2540 int direction
, int* iCluster
, int *check_out
)
2544 WORD clust
= pwLogClust
[item
];
2546 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2548 if (pwLogClust
[check
] == clust
)
2551 if (iCluster
&& *iCluster
== -1)
2563 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
)
2568 advance
= piAdvance
[glyph
];
2570 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2571 log_clust_max
= pwLogClust
[0];
2573 log_clust_max
= pwLogClust
[cChars
-1];
2575 if (glyph
> log_clust_max
)
2578 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2581 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2583 if (glyph
> log_clust_max
)
2585 advance
+= piAdvance
[glyph
];
2591 /***********************************************************************
2592 * ScriptCPtoX (USP10.@)
2595 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2599 const WORD
*pwLogClust
,
2600 const SCRIPT_VISATTR
*psva
,
2601 const int *piAdvance
,
2602 const SCRIPT_ANALYSIS
*psa
,
2610 float special_size
= 0.0;
2615 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2616 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2619 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2627 int max_clust
= pwLogClust
[0];
2629 for (item
=0; item
< cGlyphs
; item
++)
2630 if (pwLogClust
[item
] > max_clust
)
2632 ERR("We do not handle non reversed clusters properly\n");
2637 for (item
= max_clust
; item
>=0; item
--)
2638 iMaxPos
+= piAdvance
[item
];
2642 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2644 if (iSpecial
== -1 && (iCluster
== -1 || iCluster
+clust_size
<= item
))
2647 int clust
= pwLogClust
[item
];
2650 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2653 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2655 if (check
>= cChars
&& !iMaxPos
)
2658 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2659 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2661 special_size
/= (cChars
- item
);
2662 iPosX
+= special_size
;
2666 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2669 if (clust_size
== 0)
2673 iPosX
+= advance
/ (float)clust_size
;
2676 else if (iSpecial
!= -1)
2677 iPosX
+= special_size
;
2678 else /* (iCluster != -1) */
2680 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2681 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2684 if (clust_size
== 0)
2688 iPosX
+= adv
/ (float)clust_size
;
2694 iPosX
= iMaxPos
- iPosX
;
2700 TRACE("*piX=%d\n", *piX
);
2704 /* Count the number of characters in a cluster and its starting index*/
2705 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2710 for (i
= 0; i
< cChars
; i
++)
2712 if (pwLogClust
[i
] == cluster_index
)
2714 if (!size
&& start_index
)
2722 else if (size
) break;
2725 *cluster_size
= size
;
2731 To handle multi-glyph clusters we need to find all the glyphs that are
2732 represented in the cluster. This involves finding the glyph whose
2733 index is the cluster index as well as whose glyph indices are greater than
2734 our cluster index but not part of a new cluster.
2736 Then we sum all those glyphs' advances.
2738 static inline int get_cluster_advance(const int* piAdvance
,
2739 const SCRIPT_VISATTR
*psva
,
2740 const WORD
*pwLogClust
, int cGlyphs
,
2741 int cChars
, int cluster
, int direction
)
2752 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2754 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2755 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2756 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2761 glyph_end
= cGlyphs
;
2764 /* Don't fully understand multi-glyph reversed clusters yet,
2765 * do they occur for real or just in our test? */
2766 FIXME("multi-glyph reversed clusters found\n");
2767 glyph_end
= glyph_start
+ 1;
2771 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2772 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2774 if (psva
[i
].fClusterStart
)
2781 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2782 advance
+= piAdvance
[i
];
2788 /***********************************************************************
2789 * ScriptXtoCP (USP10.@)
2792 * Use piAdvance to find the cluster we are looking at.
2793 * Find the character that is the first character of the cluster.
2794 * That is our base piCP.
2795 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2796 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2797 * determine how far through the cluster to advance the cursor.
2799 HRESULT WINAPI
ScriptXtoCP(int iX
,
2802 const WORD
*pwLogClust
,
2803 const SCRIPT_VISATTR
*psva
,
2804 const int *piAdvance
,
2805 const SCRIPT_ANALYSIS
*psa
,
2812 int glyph_index
, cluster_index
;
2815 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2816 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2817 psa
, piCP
, piTrailing
);
2819 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2822 /* Handle an iX < 0 */
2838 /* Looking for non-reversed clusters in a reversed string */
2841 int max_clust
= pwLogClust
[0];
2842 for (i
=0; i
< cChars
; i
++)
2843 if (pwLogClust
[i
] > max_clust
)
2845 FIXME("We do not handle non reversed clusters properly\n");
2850 /* find the glyph_index based in iX */
2853 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2858 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2862 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2865 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2867 /* find the cluster */
2869 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2872 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2875 TRACE("cluster_index %i\n", cluster_index
);
2877 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2879 /* We are off the end of the string */
2885 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2887 TRACE("first char index %i\n",i
);
2888 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2890 /* Check trailing */
2891 if (glyph_index
!= cluster_index
||
2892 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2893 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2894 *piTrailing
= cluster_size
;
2898 if (cluster_size
> 1)
2900 /* Be part way through the glyph cluster based on size and position */
2901 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2902 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2906 /* back up to the beginning of the cluster */
2907 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2908 adv
+= piAdvance
[part_index
];
2909 if (adv
> iX
) adv
= iX
;
2911 TRACE("Multi-char cluster, no snap\n");
2912 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2913 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2916 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2918 if (part_index
) part_index
--;
2922 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2924 if (part_index
> cluster_size
)
2926 adv
+= cluster_part_width
;
2927 part_index
=cluster_size
;
2931 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2936 i
+= (cluster_size
- part_index
);
2938 /* Check trailing */
2939 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2940 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2945 /* Check trailing */
2946 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2947 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2954 TRACE("Point falls outside of string\n");
2955 if (glyph_index
< 0)
2957 else /* (glyph_index >= cGlyphs) */
2960 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2961 point flow to the next character */
2964 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
2973 TRACE("*piCP=%d\n", *piCP
);
2974 TRACE("*piTrailing=%d\n", *piTrailing
);
2978 /***********************************************************************
2979 * ScriptBreak (USP10.@)
2981 * Retrieve line break information.
2984 * chars [I] Array of characters.
2985 * sa [I] Script analysis.
2986 * la [I] Array of logical attribute structures.
2992 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
2994 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
2996 if (count
< 0 || !la
) return E_INVALIDARG
;
2997 if (count
== 0) return E_FAIL
;
2999 BREAK_line(chars
, count
, sa
, la
);
3004 /***********************************************************************
3005 * ScriptIsComplex (USP10.@)
3007 * Determine if a string is complex.
3010 * chars [I] Array of characters to test.
3011 * len [I] Length in characters.
3019 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
3021 enum usp10_script script
;
3022 unsigned int i
, consumed
;
3024 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
3026 if (!chars
|| len
< 0)
3027 return E_INVALIDARG
;
3029 for (i
= 0; i
< len
; i
+=consumed
)
3034 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3037 script
= get_char_script(chars
,i
,len
, &consumed
);
3038 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3039 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3045 /***********************************************************************
3046 * ScriptShapeOpenType (USP10.@)
3048 * Produce glyphs and visual attributes for a run.
3051 * hdc [I] Device context.
3052 * psc [I/O] Opaque pointer to a script cache.
3053 * psa [I/O] Script analysis.
3054 * tagScript [I] The OpenType tag for the Script
3055 * tagLangSys [I] The OpenType tag for the Language
3056 * rcRangeChars[I] Array of Character counts in each range
3057 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3058 * cRanges [I] Count of ranges
3059 * pwcChars [I] Array of characters specifying the run.
3060 * cChars [I] Number of characters in pwcChars.
3061 * cMaxGlyphs [I] Length of pwOutGlyphs.
3062 * pwLogClust [O] Array of logical cluster info.
3063 * pCharProps [O] Array of character property values
3064 * pwOutGlyphs [O] Array of glyphs.
3065 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3066 * pcGlyphs [O] Number of glyphs returned.
3070 * Failure: Non-zero HRESULT value.
3072 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3073 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3074 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3075 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3076 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3077 int cMaxGlyphs
, WORD
*pwLogClust
,
3078 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3079 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3086 static int once
= 0;
3088 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3090 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3091 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3092 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3094 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3095 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3097 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3098 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3101 if(!once
++) FIXME("Ranges not supported yet\n");
3103 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3106 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3107 if (!pwLogClust
) return E_FAIL
;
3109 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3110 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3112 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3113 for (i
= 0; i
< cChars
; i
++)
3116 if (rtl
) idx
= cChars
- 1 - i
;
3117 /* FIXME: set to better values */
3118 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3119 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3120 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3121 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3122 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3123 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3125 /* FIXME: have the shaping engine set this */
3126 pCharProps
[i
].fCanGlyphAlone
= 0;
3128 pwLogClust
[i
] = idx
;
3131 if (psa
&& !psa
->fNoGlyphIndex
&& ((ScriptCache
*)*psc
)->sfnt
)
3134 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3136 rChars
= heap_alloc(sizeof(WCHAR
) * cChars
);
3137 if (!rChars
) return E_OUTOFMEMORY
;
3138 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3143 if (rtl
) idx
= cChars
- 1 - i
;
3146 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3150 chInput
= mirror_char(pwcChars
[idx
]);
3152 chInput
= pwcChars
[idx
];
3153 rChars
[i
] = chInput
;
3157 rChars
[i
] = pwcChars
[idx
];
3158 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3161 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3169 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3174 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3182 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3183 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3189 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3190 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3191 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3193 for (i
= 0; i
< cChars
; ++i
)
3195 /* Special case for tabs and joiners. As control characters, ZWNJ
3196 * and ZWJ would in principle get handled by the corresponding
3197 * shaping functions. However, since ZWNJ and ZWJ can get merged
3198 * into adjoining runs during itemisation, these don't generally
3199 * get classified as Script_Control. */
3200 if (pwcChars
[i
] == 0x0009 || pwcChars
[i
] == ZWSP
|| pwcChars
[i
] == ZWNJ
|| pwcChars
[i
] == ZWJ
)
3202 pwOutGlyphs
[pwLogClust
[i
]] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3203 pOutGlyphProps
[pwLogClust
[i
]].sva
.fZeroWidth
= 1;
3210 TRACE("no glyph translation\n");
3211 for (i
= 0; i
< cChars
; i
++)
3214 /* No mirroring done here */
3215 if (rtl
) idx
= cChars
- 1 - i
;
3216 pwOutGlyphs
[i
] = pwcChars
[idx
];
3221 /* overwrite some basic control glyphs to blank */
3222 if (psa
->fNoGlyphIndex
)
3224 if (pwcChars
[idx
] == ZWSP
|| pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3226 pwOutGlyphs
[i
] = 0x20;
3227 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3230 else if (psa
->eScript
== Script_Control
|| pwcChars
[idx
] == ZWSP
3231 || pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3233 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3234 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3236 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3237 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3247 /***********************************************************************
3248 * ScriptShape (USP10.@)
3250 * Produce glyphs and visual attributes for a run.
3253 * hdc [I] Device context.
3254 * psc [I/O] Opaque pointer to a script cache.
3255 * pwcChars [I] Array of characters specifying the run.
3256 * cChars [I] Number of characters in pwcChars.
3257 * cMaxGlyphs [I] Length of pwOutGlyphs.
3258 * psa [I/O] Script analysis.
3259 * pwOutGlyphs [O] Array of glyphs.
3260 * pwLogClust [O] Array of logical cluster info.
3261 * psva [O] Array of visual attributes.
3262 * pcGlyphs [O] Number of glyphs returned.
3266 * Failure: Non-zero HRESULT value.
3268 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3269 int cChars
, int cMaxGlyphs
,
3270 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3271 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3275 SCRIPT_CHARPROP
*charProps
;
3276 SCRIPT_GLYPHPROP
*glyphProps
;
3278 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3279 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3281 charProps
= heap_alloc_zero(sizeof(SCRIPT_CHARPROP
)*cChars
);
3282 if (!charProps
) return E_OUTOFMEMORY
;
3283 glyphProps
= heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP
)*cMaxGlyphs
);
3286 heap_free(charProps
);
3287 return E_OUTOFMEMORY
;
3290 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3294 for (i
= 0; i
< *pcGlyphs
; i
++)
3295 psva
[i
] = glyphProps
[i
].sva
;
3298 heap_free(charProps
);
3299 heap_free(glyphProps
);
3304 /***********************************************************************
3305 * ScriptPlaceOpenType (USP10.@)
3307 * Produce advance widths for a run.
3310 * hdc [I] Device context.
3311 * psc [I/O] Opaque pointer to a script cache.
3312 * psa [I/O] Script analysis.
3313 * tagScript [I] The OpenType tag for the Script
3314 * tagLangSys [I] The OpenType tag for the Language
3315 * rcRangeChars[I] Array of Character counts in each range
3316 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3317 * cRanges [I] Count of ranges
3318 * pwcChars [I] Array of characters specifying the run.
3319 * pwLogClust [I] Array of logical cluster info
3320 * pCharProps [I] Array of character property values
3321 * cChars [I] Number of characters in pwcChars.
3322 * pwGlyphs [I] Array of glyphs.
3323 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3324 * cGlyphs [I] Count of Glyphs
3325 * piAdvance [O] Array of advance widths.
3326 * pGoffset [O] Glyph offsets.
3327 * pABC [O] Combined ABC width.
3331 * Failure: Non-zero HRESULT value.
3334 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3335 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3336 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3337 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3338 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3339 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3340 int cGlyphs
, int *piAdvance
,
3341 GOFFSET
*pGoffset
, ABC
*pABC
3346 static int once
= 0;
3348 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3350 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3351 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3352 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3355 if (!pGlyphProps
) return E_INVALIDARG
;
3356 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3357 if (!pGoffset
) return E_FAIL
;
3360 if (!once
++) FIXME("Ranges not supported yet\n");
3362 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3363 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3365 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3366 for (i
= 0; i
< cGlyphs
; i
++)
3369 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3371 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3373 else if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3376 if (!hdc
) return E_PENDING
;
3377 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3379 if (psa
->fNoGlyphIndex
)
3380 ret
= GetCharABCWidthsW(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &abc
);
3382 ret
= GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
);
3383 if (!ret
) return S_FALSE
;
3388 if (psa
->fNoGlyphIndex
)
3389 ret
= GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
);
3391 ret
= GetCharWidthI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &width
);
3392 if (!ret
) return S_FALSE
;
3394 abc
.abcA
= abc
.abcC
= 0;
3396 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3400 pABC
->abcA
+= abc
.abcA
;
3401 pABC
->abcB
+= abc
.abcB
;
3402 pABC
->abcC
+= abc
.abcC
;
3404 /* FIXME: set to more reasonable values */
3405 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3406 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3409 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3411 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3415 /***********************************************************************
3416 * ScriptPlace (USP10.@)
3418 * Produce advance widths for a run.
3421 * hdc [I] Device context.
3422 * psc [I/O] Opaque pointer to a script cache.
3423 * pwGlyphs [I] Array of glyphs.
3424 * cGlyphs [I] Number of glyphs in pwGlyphs.
3425 * psva [I] Array of visual attributes.
3426 * psa [I/O] String analysis.
3427 * piAdvance [O] Array of advance widths.
3428 * pGoffset [O] Glyph offsets.
3429 * pABC [O] Combined ABC width.
3433 * Failure: Non-zero HRESULT value.
3435 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3436 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3437 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3440 SCRIPT_GLYPHPROP
*glyphProps
;
3443 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3444 piAdvance
, pGoffset
, pABC
);
3446 if (!psva
) return E_INVALIDARG
;
3447 if (!pGoffset
) return E_FAIL
;
3449 glyphProps
= heap_alloc(sizeof(SCRIPT_GLYPHPROP
)*cGlyphs
);
3450 if (!glyphProps
) return E_OUTOFMEMORY
;
3452 for (i
= 0; i
< cGlyphs
; i
++)
3453 glyphProps
[i
].sva
= psva
[i
];
3455 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3457 heap_free(glyphProps
);
3462 /***********************************************************************
3463 * ScriptGetCMap (USP10.@)
3465 * Retrieve glyph indices.
3468 * hdc [I] Device context.
3469 * psc [I/O] Opaque pointer to a script cache.
3470 * pwcInChars [I] Array of Unicode characters.
3471 * cChars [I] Number of characters in pwcInChars.
3472 * dwFlags [I] Flags.
3473 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3477 * Failure: Non-zero HRESULT value.
3479 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3480 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3485 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3486 cChars
, dwFlags
, pwOutGlyphs
);
3488 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3492 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3494 for (i
= 0; i
< cChars
; i
++)
3497 if (dwFlags
== SGCM_RTL
)
3498 inChar
= mirror_char(pwcInChars
[i
]);
3500 inChar
= pwcInChars
[i
];
3501 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3504 if (!hdc
) return E_PENDING
;
3505 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3506 if (glyph
== 0xffff)
3511 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3517 TRACE("no glyph translation\n");
3518 for (i
= 0; i
< cChars
; i
++)
3521 if (dwFlags
== SGCM_RTL
)
3522 inChar
= mirror_char(pwcInChars
[i
]);
3524 inChar
= pwcInChars
[i
];
3525 pwOutGlyphs
[i
] = inChar
;
3531 /***********************************************************************
3532 * ScriptTextOut (USP10.@)
3535 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3536 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3537 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3538 const int *piJustify
, const GOFFSET
*pGoffset
)
3543 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3545 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3546 hdc
, psc
, x
, y
, fuOptions
, wine_dbgstr_rect(lprc
), psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3547 piAdvance
, piJustify
, pGoffset
);
3549 if (!hdc
|| !psc
) return E_INVALIDARG
;
3550 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3552 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3553 fuOptions
|= ETO_IGNORELANGUAGE
;
3554 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3555 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3557 lpDx
= heap_alloc(cGlyphs
* sizeof(INT
) * 2);
3558 if (!lpDx
) return E_OUTOFMEMORY
;
3559 fuOptions
|= ETO_PDY
;
3561 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3563 reordered_glyphs
= heap_alloc( cGlyphs
* sizeof(WORD
) );
3564 if (!reordered_glyphs
)
3567 return E_OUTOFMEMORY
;
3570 for (i
= 0; i
< cGlyphs
; i
++)
3571 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3575 for (i
= 0; i
< cGlyphs
; i
++)
3577 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3578 lpDx
[i
* 2] = piAdvance
[orig_index
];
3579 lpDx
[i
* 2 + 1] = 0;
3585 x
+= pGoffset
[orig_index
].du
* dir
;
3586 y
+= pGoffset
[orig_index
].dv
;
3590 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3591 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3593 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3594 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3598 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3601 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3607 /***********************************************************************
3608 * ScriptCacheGetHeight (USP10.@)
3610 * Retrieve the height of the font in the cache.
3613 * hdc [I] Device context.
3614 * psc [I/O] Opaque pointer to a script cache.
3615 * height [O] Receives font height.
3619 * Failure: Non-zero HRESULT value.
3621 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3625 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3627 if (!height
) return E_INVALIDARG
;
3628 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3630 *height
= get_cache_height(psc
);
3634 /***********************************************************************
3635 * ScriptGetGlyphABCWidth (USP10.@)
3637 * Retrieve the width of a glyph.
3640 * hdc [I] Device context.
3641 * psc [I/O] Opaque pointer to a script cache.
3642 * glyph [I] Glyph to retrieve the width for.
3643 * abc [O] ABC widths of the glyph.
3647 * Failure: Non-zero HRESULT value.
3649 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3653 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3655 if (!abc
) return E_INVALIDARG
;
3656 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3658 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3660 if (!hdc
) return E_PENDING
;
3661 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3663 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3668 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3670 abc
->abcA
= abc
->abcC
= 0;
3672 set_cache_glyph_widths(psc
, glyph
, abc
);
3677 /***********************************************************************
3678 * ScriptLayout (USP10.@)
3680 * Map embedding levels to visual and/or logical order.
3683 * runs [I] Size of level array.
3684 * level [I] Array of embedding levels.
3685 * vistolog [O] Map of embedding levels from visual to logical order.
3686 * logtovis [O] Map of embedding levels from logical to visual order.
3690 * Failure: Non-zero HRESULT value.
3693 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3698 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3700 if (!level
|| (!vistolog
&& !logtovis
))
3701 return E_INVALIDARG
;
3703 indexs
= heap_alloc(sizeof(int) * runs
);
3705 return E_OUTOFMEMORY
;
3709 for( ich
= 0; ich
< runs
; ich
++)
3714 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3715 memcpy(vistolog
, indexs
, runs
* sizeof(*vistolog
));
3720 for( ich
= 0; ich
< runs
; ich
++)
3725 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3726 memcpy(logtovis
, indexs
, runs
* sizeof(*logtovis
));
3733 /***********************************************************************
3734 * ScriptStringGetLogicalWidths (USP10.@)
3736 * Returns logical widths from a string analysis.
3739 * ssa [I] string analysis.
3740 * piDx [O] logical widths returned.
3744 * Failure: a non-zero HRESULT.
3746 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3749 StringAnalysis
*analysis
= ssa
;
3751 TRACE("%p, %p\n", ssa
, piDx
);
3753 if (!analysis
) return S_FALSE
;
3754 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3756 for (i
= 0; i
< analysis
->numItems
; i
++)
3758 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3761 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3764 for (j
= 0; j
< cChar
; j
++)
3767 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3768 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3769 cChar
, j
, direction
, NULL
, NULL
);
3770 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
);
3772 for (k
= 0; k
< clust_size
; k
++)
3774 piDx
[next
] = advance
/ clust_size
;
3783 /***********************************************************************
3784 * ScriptStringValidate (USP10.@)
3786 * Validate a string analysis.
3789 * ssa [I] string analysis.
3793 * Failure: S_FALSE if invalid sequences are found
3794 * or a non-zero HRESULT if it fails.
3796 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3798 StringAnalysis
*analysis
= ssa
;
3800 TRACE("(%p)\n", ssa
);
3802 if (!analysis
) return E_INVALIDARG
;
3803 return analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
? S_FALSE
: S_OK
;
3806 /***********************************************************************
3807 * ScriptString_pSize (USP10.@)
3809 * Retrieve width and height of an analysed string.
3812 * ssa [I] string analysis.
3815 * Success: Pointer to a SIZE structure.
3818 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3821 StringAnalysis
*analysis
= ssa
;
3823 TRACE("(%p)\n", ssa
);
3825 if (!analysis
) return NULL
;
3826 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return NULL
;
3828 if (!(analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
))
3830 analysis
->sz
.cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3832 analysis
->sz
.cx
= 0;
3833 for (i
= 0; i
< analysis
->numItems
; i
++)
3835 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
.cy
)
3836 analysis
->sz
.cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3837 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3838 analysis
->sz
.cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3841 return &analysis
->sz
;
3844 /***********************************************************************
3845 * ScriptString_pLogAttr (USP10.@)
3847 * Retrieve logical attributes of an analysed string.
3850 * ssa [I] string analysis.
3853 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3856 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3858 StringAnalysis
*analysis
= ssa
;
3860 TRACE("(%p)\n", ssa
);
3862 if (!analysis
) return NULL
;
3863 if (!(analysis
->ssa_flags
& SSA_BREAK
)) return NULL
;
3864 return analysis
->logattrs
;
3867 /***********************************************************************
3868 * ScriptString_pcOutChars (USP10.@)
3870 * Retrieve the length of a string after clipping.
3873 * ssa [I] String analysis.
3876 * Success: Pointer to the length.
3879 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3881 StringAnalysis
*analysis
= ssa
;
3883 TRACE("(%p)\n", ssa
);
3885 if (!analysis
) return NULL
;
3886 return &analysis
->clip_len
;
3889 /***********************************************************************
3890 * ScriptStringGetOrder (USP10.@)
3892 * Retrieve a glyph order map.
3895 * ssa [I] String analysis.
3896 * order [I/O] Array of glyph positions.
3900 * Failure: a non-zero HRESULT.
3902 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3906 StringAnalysis
*analysis
= ssa
;
3908 TRACE("(%p)\n", ssa
);
3910 if (!analysis
) return S_FALSE
;
3911 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3913 /* FIXME: handle RTL scripts */
3914 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3915 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3921 /***********************************************************************
3922 * ScriptGetLogicalWidths (USP10.@)
3924 * Convert advance widths to logical widths.
3927 * sa [I] Script analysis.
3928 * nbchars [I] Number of characters.
3929 * nbglyphs [I] Number of glyphs.
3930 * glyph_width [I] Array of glyph widths.
3931 * log_clust [I] Array of logical clusters.
3932 * sva [I] Visual attributes.
3933 * widths [O] Array of logical widths.
3937 * Failure: a non-zero HRESULT.
3939 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3940 const int *advances
, const WORD
*log_clust
,
3941 const SCRIPT_VISATTR
*sva
, int *widths
)
3943 int i
, next
= 0, direction
;
3945 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3946 sa
, nbchars
, nbglyphs
, advances
, log_clust
, sva
, widths
);
3948 if (sa
->fRTL
&& !sa
->fLogicalOrder
)
3953 for (i
= 0; i
< nbchars
; i
++)
3955 int clust_size
= get_cluster_size(log_clust
, nbchars
, i
, direction
, NULL
, NULL
);
3956 int advance
= get_glyph_cluster_advance(advances
, sva
, log_clust
, nbglyphs
, nbchars
, log_clust
[i
], direction
);
3959 for (j
= 0; j
< clust_size
; j
++)
3961 widths
[next
] = advance
/ clust_size
;
3970 /***********************************************************************
3971 * ScriptApplyLogicalWidth (USP10.@)
3973 * Generate glyph advance widths.
3976 * dx [I] Array of logical advance widths.
3977 * num_chars [I] Number of characters.
3978 * num_glyphs [I] Number of glyphs.
3979 * log_clust [I] Array of logical clusters.
3980 * sva [I] Visual attributes.
3981 * advance [I] Array of glyph advance widths.
3982 * sa [I] Script analysis.
3983 * abc [I/O] Summed ABC widths.
3984 * justify [O] Array of glyph advance widths.
3988 * Failure: a non-zero HRESULT.
3990 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
3991 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
3992 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
3993 ABC
*abc
, int *justify
)
3997 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3998 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
4000 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
4004 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
4005 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
4009 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
4011 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
4015 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
4018 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4019 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4021 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
4024 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
4027 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4028 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4030 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
4033 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
4036 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4037 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4039 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);