2 * Implementation of Uniscribe Script Processor (usp10.dll)
4 * Copyright 2005 Steven Edwards for CodeWeavers
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * Uniscribe allows for processing of complex scripts such as joining
24 * and filtering characters and bi-directional text with custom line breaks.
39 #include "usp10_internal.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe
);
46 typedef struct _scriptRange
55 static const scriptRange scriptRanges
[] = {
56 /* Basic Latin: U+0000–U+007A */
57 { Script_Latin
, 0x00, 0x07a , Script_Numeric
, Script_Punctuation
},
58 /* Latin-1 Supplement: U+0080–U+00FF */
59 /* Latin Extended-A: U+0100–U+017F */
60 /* Latin Extended-B: U+0180–U+024F */
61 /* IPA Extensions: U+0250–U+02AF */
62 /* Spacing Modifier Letters:U+02B0–U+02FF */
63 { Script_Latin
, 0x80, 0x2ff , Script_Numeric2
, Script_Punctuation
},
64 /* Combining Diacritical Marks : U+0300–U+036F */
65 { Script_Diacritical
,0x300, 0x36f, 0, 0},
66 /* Greek: U+0370–U+03FF */
67 { Script_Greek
, 0x370, 0x3ff, 0, 0},
68 /* Cyrillic: U+0400–U+04FF */
69 /* Cyrillic Supplement: U+0500–U+052F */
70 { Script_Cyrillic
, 0x400, 0x52f, 0, 0},
71 /* Armenian: U+0530–U+058F */
72 { Script_Armenian
, 0x530, 0x58f, 0, 0},
73 /* Hebrew: U+0590–U+05FF */
74 { Script_Hebrew
, 0x590, 0x5ff, 0, 0},
75 /* Arabic: U+0600–U+06FF */
76 { Script_Arabic
, 0x600, 0x6ef, Script_Arabic_Numeric
, 0},
77 /* Defined by Windows */
78 { Script_Persian
, 0x6f0, 0x6f9, 0, 0},
79 /* Continue Arabic: U+0600–U+06FF */
80 { Script_Arabic
, 0x6fa, 0x6ff, 0, 0},
81 /* Syriac: U+0700–U+074F*/
82 { Script_Syriac
, 0x700, 0x74f, 0, 0},
83 /* Arabic Supplement: U+0750–U+077F */
84 { Script_Arabic
, 0x750, 0x77f, 0, 0},
85 /* Thaana: U+0780–U+07BF */
86 { Script_Thaana
, 0x780, 0x7bf, 0, 0},
87 /* N’Ko: U+07C0–U+07FF */
88 { Script_NKo
, 0x7c0, 0x7ff, 0, 0},
89 /* Devanagari: U+0900–U+097F */
90 { Script_Devanagari
, 0x900, 0x97f, Script_Devanagari_Numeric
, 0},
91 /* Bengali: U+0980–U+09FF */
92 { Script_Bengali
, 0x980, 0x9ff, Script_Bengali_Numeric
, 0},
93 /* Gurmukhi: U+0A00–U+0A7F*/
94 { Script_Gurmukhi
, 0xa00, 0xa7f, Script_Gurmukhi_Numeric
, 0},
95 /* Gujarati: U+0A80–U+0AFF*/
96 { Script_Gujarati
, 0xa80, 0xaff, Script_Gujarati_Numeric
, 0},
97 /* Oriya: U+0B00–U+0B7F */
98 { Script_Oriya
, 0xb00, 0xb7f, Script_Oriya_Numeric
, 0},
99 /* Tamil: U+0B80–U+0BFF */
100 { Script_Tamil
, 0xb80, 0xbff, Script_Tamil_Numeric
, 0},
101 /* Telugu: U+0C00–U+0C7F */
102 { Script_Telugu
, 0xc00, 0xc7f, Script_Telugu_Numeric
, 0},
103 /* Kannada: U+0C80–U+0CFF */
104 { Script_Kannada
, 0xc80, 0xcff, Script_Kannada_Numeric
, 0},
105 /* Malayalam: U+0D00–U+0D7F */
106 { Script_Malayalam
, 0xd00, 0xd7f, Script_Malayalam_Numeric
, 0},
107 /* Sinhala: U+0D80–U+0DFF */
108 { Script_Sinhala
, 0xd80, 0xdff, 0, 0},
109 /* Thai: U+0E00–U+0E7F */
110 { Script_Thai
, 0xe00, 0xe7f, Script_Thai_Numeric
, 0},
111 /* Lao: U+0E80–U+0EFF */
112 { Script_Lao
, 0xe80, 0xeff, Script_Lao_Numeric
, 0},
113 /* Tibetan: U+0F00–U+0FFF */
114 { Script_Tibetan
, 0xf00, 0xfff, 0, 0},
115 /* Myanmar: U+1000–U+109F */
116 { Script_Myanmar
, 0x1000, 0x109f, Script_Myanmar_Numeric
, 0},
117 /* Georgian: U+10A0–U+10FF */
118 { Script_Georgian
, 0x10a0, 0x10ff, 0, 0},
119 /* Hangul Jamo: U+1100–U+11FF */
120 { Script_Hangul
, 0x1100, 0x11ff, 0, 0},
121 /* Ethiopic: U+1200–U+137F */
122 /* Ethiopic Extensions: U+1380–U+139F */
123 { Script_Ethiopic
, 0x1200, 0x139f, 0, 0},
124 /* Cherokee: U+13A0–U+13FF */
125 { Script_Cherokee
, 0x13a0, 0x13ff, 0, 0},
126 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
127 { Script_Canadian
, 0x1400, 0x167f, 0, 0},
128 /* Ogham: U+1680–U+169F */
129 { Script_Ogham
, 0x1680, 0x169f, 0, 0},
130 /* Runic: U+16A0–U+16F0 */
131 { Script_Runic
, 0x16a0, 0x16f0, 0, 0},
132 /* Khmer: U+1780–U+17FF */
133 { Script_Khmer
, 0x1780, 0x17ff, Script_Khmer_Numeric
, 0},
134 /* Mongolian: U+1800–U+18AF */
135 { Script_Mongolian
, 0x1800, 0x18af, Script_Mongolian_Numeric
, 0},
136 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
137 { Script_Canadian
, 0x18b0, 0x18ff, 0, 0},
138 /* Tai Le: U+1950–U+197F */
139 { Script_Tai_Le
, 0x1950, 0x197f, 0, 0},
140 /* New Tai Lue: U+1980–U+19DF */
141 { Script_New_Tai_Lue
,0x1980, 0x19df, Script_New_Tai_Lue_Numeric
, 0},
142 /* Khmer Symbols: U+19E0–U+19FF */
143 { Script_Khmer
, 0x19e0, 0x19ff, Script_Khmer_Numeric
, 0},
144 /* Vedic Extensions: U+1CD0-U+1CFF */
145 { Script_Devanagari
, 0x1cd0, 0x1cff, Script_Devanagari_Numeric
, 0},
146 /* Phonetic Extensions: U+1D00–U+1DBF */
147 { Script_Latin
, 0x1d00, 0x1dbf, 0, 0},
148 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
149 { Script_Diacritical
,0x1dc0, 0x1dff, 0, 0},
150 /* Latin Extended Additional: U+1E00–U+1EFF */
151 { Script_Latin
, 0x1e00, 0x1eff, 0, 0},
152 /* Greek Extended: U+1F00–U+1FFF */
153 { Script_Greek
, 0x1f00, 0x1fff, 0, 0},
154 /* General Punctuation: U+2000 –U+206f */
155 { Script_Latin
, 0x2000, 0x206f, 0, 0},
156 /* Superscripts and Subscripts : U+2070 –U+209f */
157 /* Currency Symbols : U+20a0 –U+20cf */
158 { Script_Numeric2
, 0x2070, 0x2070, 0, 0},
159 { Script_Latin
, 0x2071, 0x2073, 0, 0},
160 { Script_Numeric2
, 0x2074, 0x2079, 0, 0},
161 { Script_Latin
, 0x207a, 0x207f, 0, 0},
162 { Script_Numeric2
, 0x2080, 0x2089, 0, 0},
163 { Script_Latin
, 0x208a, 0x20cf, 0, 0},
164 /* Letterlike Symbols : U+2100 –U+214f */
165 /* Number Forms : U+2150 –U+218f */
166 /* Arrows : U+2190 –U+21ff */
167 /* Mathematical Operators : U+2200 –U+22ff */
168 /* Miscellaneous Technical : U+2300 –U+23ff */
169 /* Control Pictures : U+2400 –U+243f */
170 /* Optical Character Recognition : U+2440 –U+245f */
171 /* Enclosed Alphanumerics : U+2460 –U+24ff */
172 /* Box Drawing : U+2500 –U+25ff */
173 /* Block Elements : U+2580 –U+259f */
174 /* Geometric Shapes : U+25a0 –U+25ff */
175 /* Miscellaneous Symbols : U+2600 –U+26ff */
176 /* Dingbats : U+2700 –U+27bf */
177 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
178 /* Supplemental Arrows-A : U+27f0 –U+27ff */
179 { Script_Latin
, 0x2100, 0x27ff, 0, 0},
180 /* Braille Patterns: U+2800–U+28FF */
181 { Script_Braille
, 0x2800, 0x28ff, 0, 0},
182 /* Supplemental Arrows-B : U+2900 –U+297f */
183 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
184 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
185 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
186 { Script_Latin
, 0x2900, 0x2bff, 0, 0},
187 /* Latin Extended-C: U+2C60–U+2C7F */
188 { Script_Latin
, 0x2c60, 0x2c7f, 0, 0},
189 /* Georgian: U+2D00–U+2D2F */
190 { Script_Georgian
, 0x2d00, 0x2d2f, 0, 0},
191 /* Tifinagh: U+2D30–U+2D7F */
192 { Script_Tifinagh
, 0x2d30, 0x2d7f, 0, 0},
193 /* Ethiopic Extensions: U+2D80–U+2DDF */
194 { Script_Ethiopic
, 0x2d80, 0x2ddf, 0, 0},
195 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
196 { Script_Cyrillic
, 0x2de0, 0x2dff, 0, 0},
197 /* CJK Radicals Supplement: U+2E80–U+2EFF */
198 /* Kangxi Radicals: U+2F00–U+2FDF */
199 { Script_CJK_Han
, 0x2e80, 0x2fdf, 0, 0},
200 /* Ideographic Description Characters: U+2FF0–U+2FFF */
201 { Script_Ideograph
,0x2ff0, 0x2fff, 0, 0},
202 /* CJK Symbols and Punctuation: U+3000–U+303F */
203 { Script_Ideograph
,0x3000, 0x3004, 0, 0},
204 { Script_CJK_Han
,0x3005, 0x3005, 0, 0},
205 { Script_Ideograph
,0x3006, 0x3006, 0, 0},
206 { Script_CJK_Han
,0x3007, 0x3007, 0, 0},
207 { Script_Ideograph
,0x3008, 0x3020, 0, 0},
208 { Script_CJK_Han
,0x3021, 0x3029, 0, 0},
209 { Script_Ideograph
,0x302a, 0x3030, 0, 0},
211 { Script_Kana
,0x3031, 0x3035, 0, 0},
212 { Script_Ideograph
,0x3036, 0x3037, 0, 0},
213 { Script_CJK_Han
,0x3038, 0x303b, 0, 0},
214 { Script_Ideograph
,0x303c, 0x303f, 0, 0},
215 /* Hiragana: U+3040–U+309F */
216 /* Katakana: U+30A0–U+30FF */
217 { Script_Kana
,0x3040, 0x30ff, 0, 0},
218 /* Bopomofo: U+3100–U+312F */
219 { Script_Bopomofo
,0x3100, 0x312f, 0, 0},
220 /* Hangul Compatibility Jamo: U+3130–U+318F */
221 { Script_Hangul
,0x3130, 0x318f, 0, 0},
222 /* Kanbun: U+3190–U+319F */
223 { Script_Ideograph
,0x3190, 0x319f, 0, 0},
224 /* Bopomofo Extended: U+31A0–U+31BF */
225 { Script_Bopomofo
,0x31a0, 0x31bf, 0, 0},
226 /* CJK Strokes: U+31C0–U+31EF */
227 { Script_Ideograph
,0x31c0, 0x31ef, 0, 0},
228 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
229 { Script_Kana
,0x31f0, 0x31ff, 0, 0},
230 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
231 { Script_Hangul
,0x3200, 0x321f, 0, 0},
232 { Script_Ideograph
,0x3220, 0x325f, 0, 0},
233 { Script_Hangul
,0x3260, 0x327f, 0, 0},
234 { Script_Ideograph
,0x3280, 0x32ef, 0, 0},
235 { Script_Kana
,0x32d0, 0x31ff, 0, 0},
236 /* CJK Compatibility: U+3300–U+33FF*/
237 { Script_Kana
,0x3300, 0x3357, 0, 0},
238 { Script_Ideograph
,0x3358, 0x33ff, 0, 0},
239 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
240 { Script_CJK_Han
,0x3400, 0x4dbf, 0, 0},
241 /* CJK Unified Ideographs: U+4E00–U+9FFF */
242 { Script_CJK_Han
,0x4e00, 0x9fff, 0, 0},
243 /* Yi: U+A000–U+A4CF */
244 { Script_Yi
,0xa000, 0xa4cf, 0, 0},
245 /* Vai: U+A500–U+A63F */
246 { Script_Vai
,0xa500, 0xa63f, Script_Vai_Numeric
, 0},
247 /* Cyrillic Extended-B: U+A640–U+A69F */
248 { Script_Cyrillic
, 0xa640, 0xa69f, 0, 0},
249 /* Modifier Tone Letters: U+A700–U+A71F */
250 /* Latin Extended-D: U+A720–U+A7FF */
251 { Script_Latin
, 0xa700, 0xa7ff, 0, 0},
252 /* Phags-pa: U+A840–U+A87F */
253 { Script_Phags_pa
, 0xa840, 0xa87f, 0, 0},
254 /* Devanagari Extended: U+A8E0-U+A8FF */
255 { Script_Devanagari
, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric
, 0},
256 /* Myanmar Extended-A: U+AA60–U+AA7F */
257 { Script_Myanmar
, 0xaa60, 0xaa7f, Script_Myanmar_Numeric
, 0},
258 /* Hangul Jamo Extended-A: U+A960–U+A97F */
259 { Script_Hangul
, 0xa960, 0xa97f, 0, 0},
260 /* Hangul Syllables: U+AC00–U+D7A3 */
261 { Script_Hangul
, 0xac00, 0xd7a3, 0, 0},
262 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
263 { Script_Hangul
, 0xd7b0, 0xd7ff, 0, 0},
264 /* Surrogates Area: U+D800–U+DFFF */
265 { Script_Surrogates
, 0xd800, 0xdbfe, 0, 0},
266 { Script_Private
, 0xdbff, 0xdc00, 0, 0},
267 { Script_Surrogates
, 0xdc01, 0xdfff, 0, 0},
268 /* Private Use Area: U+E000–U+F8FF */
269 { Script_Private
, 0xe000, 0xf8ff, 0, 0},
270 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
271 { Script_CJK_Han
,0xf900, 0xfaff, 0, 0},
272 /* Latin Ligatures: U+FB00–U+FB06 */
273 { Script_Latin
, 0xfb00, 0xfb06, 0, 0},
274 /* Armenian ligatures U+FB13..U+FB17 */
275 { Script_Armenian
, 0xfb13, 0xfb17, 0, 0},
276 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
277 { Script_Hebrew
, 0xfb1d, 0xfb4f, 0, 0},
278 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
279 { Script_Arabic
, 0xfb50, 0xfdff, 0, 0},
280 /* Vertical Forms: U+FE10–U+FE1F */
281 /* Combining Half Marks: U+FE20–U+FE2F */
282 /* CJK Compatibility Forms: U+FE30–U+FE4F */
283 /* Small Form Variants: U+FE50–U+FE6F */
284 { Script_Ideograph
,0xfe10, 0xfe6f, 0, 0},
285 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
286 { Script_Arabic
, 0xfe70, 0xfeff, 0, 0},
287 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
288 { Script_Ideograph
,0xff00, 0xff64, Script_Numeric2
, 0},
289 { Script_Kana
,0xff65, 0xff9f, 0, 0},
290 { Script_Hangul
,0xffa0, 0xffdf, 0, 0},
291 { Script_Ideograph
,0xffe0, 0xffef, 0, 0},
293 /* Deseret: U+10400–U+1044F */
294 { Script_Deseret
, 0x10400, 0x1044F, 0, 0},
295 /* Osmanya: U+10480–U+104AF */
296 { Script_Osmanya
, 0x10480, 0x104AF, Script_Osmanya_Numeric
, 0},
297 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
298 { Script_MathAlpha
, 0x1D400, 0x1D7FF, 0, 0},
300 { SCRIPT_UNDEFINED
, 0, 0, 0}
303 /* the must be in order so that the index matches the Script value */
304 const scriptData scriptInformation
[] = {
305 {{SCRIPT_UNDEFINED
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
306 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
309 {{Script_Latin
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
310 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
311 MS_MAKE_TAG('l','a','t','n'),
312 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
313 {{Script_CR
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
314 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
317 {{Script_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
318 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
320 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
321 {{Script_Control
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
322 {LANG_ENGLISH
, 0, 1, 0, 0, ANSI_CHARSET
, 1, 0, 0, 0, 0, 0, 1, 0, 0},
325 {{Script_Punctuation
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
326 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
328 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
329 {{Script_Arabic
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
330 {LANG_ARABIC
, 0, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 1, 0},
331 MS_MAKE_TAG('a','r','a','b'),
332 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
333 {{Script_Arabic_Numeric
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
334 {LANG_ARABIC
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
335 MS_MAKE_TAG('a','r','a','b'),
336 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
337 {{Script_Hebrew
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
338 {LANG_HEBREW
, 0, 1, 0, 1, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
339 MS_MAKE_TAG('h','e','b','r'),
340 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
341 {{Script_Syriac
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
342 {LANG_SYRIAC
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 1, 0},
343 MS_MAKE_TAG('s','y','r','c'),
344 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
345 {{Script_Persian
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
346 {LANG_PERSIAN
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
347 MS_MAKE_TAG('s','y','r','c'),
348 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
349 {{Script_Thaana
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
350 {LANG_DIVEHI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
351 MS_MAKE_TAG('t','h','a','a'),
352 {'M','V',' ','B','o','l','i',0}},
353 {{Script_Greek
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
354 {LANG_GREEK
, 0, 0, 0, 0, GREEK_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
355 MS_MAKE_TAG('g','r','e','k'),
356 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
357 {{Script_Cyrillic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
358 {LANG_RUSSIAN
, 0, 0, 0, 0, RUSSIAN_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
359 MS_MAKE_TAG('c','y','r','l'),
360 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
361 {{Script_Armenian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
362 {LANG_ARMENIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
363 MS_MAKE_TAG('a','r','m','n'),
364 {'S','y','l','f','a','e','n',0}},
365 {{Script_Georgian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
366 {LANG_GEORGIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
367 MS_MAKE_TAG('g','e','o','r'),
368 {'S','y','l','f','a','e','n',0}},
369 {{Script_Sinhala
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
370 {LANG_SINHALESE
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
371 MS_MAKE_TAG('s','i','n','h'),
372 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
373 {{Script_Tibetan
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
374 {LANG_TIBETAN
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
375 MS_MAKE_TAG('t','i','b','t'),
376 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
377 {{Script_Tibetan_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
378 {LANG_TIBETAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
379 MS_MAKE_TAG('t','i','b','t'),
380 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
381 {{Script_Phags_pa
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
382 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
383 MS_MAKE_TAG('p','h','a','g'),
384 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
385 {{Script_Thai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
386 {LANG_THAI
, 0, 1, 1, 1, THAI_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 1},
387 MS_MAKE_TAG('t','h','a','i'),
388 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
389 {{Script_Thai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
390 {LANG_THAI
, 1, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
391 MS_MAKE_TAG('t','h','a','i'),
392 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
393 {{Script_Lao
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
394 {LANG_LAO
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
395 MS_MAKE_TAG('l','a','o',' '),
396 {'D','o','k','C','h','a','m','p','a',0}},
397 {{Script_Lao_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
398 {LANG_LAO
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
399 MS_MAKE_TAG('l','a','o',' '),
400 {'D','o','k','C','h','a','m','p','a',0}},
401 {{Script_Devanagari
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
402 {LANG_HINDI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
403 MS_MAKE_TAG('d','e','v','a'),
404 {'M','a','n','g','a','l',0}},
405 {{Script_Devanagari_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
406 {LANG_HINDI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
407 MS_MAKE_TAG('d','e','v','a'),
408 {'M','a','n','g','a','l',0}},
409 {{Script_Bengali
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
410 {LANG_BENGALI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
411 MS_MAKE_TAG('b','e','n','g'),
412 {'V','r','i','n','d','a',0}},
413 {{Script_Bengali_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
414 {LANG_BENGALI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
415 MS_MAKE_TAG('b','e','n','g'),
416 {'V','r','i','n','d','a',0}},
417 {{Script_Bengali_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
418 {LANG_BENGALI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
419 MS_MAKE_TAG('b','e','n','g'),
420 {'V','r','i','n','d','a',0}},
421 {{Script_Gurmukhi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
422 {LANG_PUNJABI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
423 MS_MAKE_TAG('g','u','r','u'),
424 {'R','a','a','v','i',0}},
425 {{Script_Gurmukhi_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
426 {LANG_PUNJABI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
427 MS_MAKE_TAG('g','u','r','u'),
428 {'R','a','a','v','i',0}},
429 {{Script_Gujarati
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
430 {LANG_GUJARATI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
431 MS_MAKE_TAG('g','u','j','r'),
432 {'S','h','r','u','t','i',0}},
433 {{Script_Gujarati_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
434 {LANG_GUJARATI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
435 MS_MAKE_TAG('g','u','j','r'),
436 {'S','h','r','u','t','i',0}},
437 {{Script_Gujarati_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
438 {LANG_GUJARATI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
439 MS_MAKE_TAG('g','u','j','r'),
440 {'S','h','r','u','t','i',0}},
441 {{Script_Oriya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
442 {LANG_ORIYA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
443 MS_MAKE_TAG('o','r','y','a'),
444 {'K','a','l','i','n','g','a',0}},
445 {{Script_Oriya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
446 {LANG_ORIYA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
447 MS_MAKE_TAG('o','r','y','a'),
448 {'K','a','l','i','n','g','a',0}},
449 {{Script_Tamil
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
450 {LANG_TAMIL
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
451 MS_MAKE_TAG('t','a','m','l'),
452 {'L','a','t','h','a',0}},
453 {{Script_Tamil_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
454 {LANG_TAMIL
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
455 MS_MAKE_TAG('t','a','m','l'),
456 {'L','a','t','h','a',0}},
457 {{Script_Telugu
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
458 {LANG_TELUGU
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
459 MS_MAKE_TAG('t','e','l','u'),
460 {'G','a','u','t','a','m','i',0}},
461 {{Script_Telugu_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
462 {LANG_TELUGU
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
463 MS_MAKE_TAG('t','e','l','u'),
464 {'G','a','u','t','a','m','i',0}},
465 {{Script_Kannada
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
466 {LANG_KANNADA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
467 MS_MAKE_TAG('k','n','d','a'),
468 {'T','u','n','g','a',0}},
469 {{Script_Kannada_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
470 {LANG_KANNADA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
471 MS_MAKE_TAG('k','n','d','a'),
472 {'T','u','n','g','a',0}},
473 {{Script_Malayalam
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
474 {LANG_MALAYALAM
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
475 MS_MAKE_TAG('m','l','y','m'),
476 {'K','a','r','t','i','k','a',0}},
477 {{Script_Malayalam_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
478 {LANG_MALAYALAM
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
479 MS_MAKE_TAG('m','l','y','m'),
480 {'K','a','r','t','i','k','a',0}},
481 {{Script_Diacritical
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
482 {LANG_ENGLISH
, 0, 1, 0, 1, ANSI_CHARSET
, 0, 0, 0, 0, 0, 1, 1, 0, 0},
485 {{Script_Punctuation2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
486 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
487 MS_MAKE_TAG('l','a','t','n'),
488 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
489 {{Script_Numeric2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
490 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
493 {{Script_Myanmar
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
494 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
495 MS_MAKE_TAG('m','y','m','r'),
496 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
497 {{Script_Myanmar_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
498 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
499 MS_MAKE_TAG('m','y','m','r'),
501 {{Script_Tai_Le
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
502 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
503 MS_MAKE_TAG('t','a','l','e'),
504 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
505 {{Script_New_Tai_Lue
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
506 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
507 MS_MAKE_TAG('t','a','l','u'),
508 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
509 {{Script_New_Tai_Lue_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
510 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
511 MS_MAKE_TAG('t','a','l','u'),
512 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
513 {{Script_Khmer
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
514 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
515 MS_MAKE_TAG('k','h','m','r'),
516 {'D','a','u','n','P','e','n','h',0}},
517 {{Script_Khmer_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
518 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
519 MS_MAKE_TAG('k','h','m','r'),
520 {'D','a','u','n','P','e','n','h',0}},
521 {{Script_CJK_Han
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
522 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
523 MS_MAKE_TAG('h','a','n','i'),
525 {{Script_Ideograph
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
526 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
527 MS_MAKE_TAG('h','a','n','i'),
529 {{Script_Bopomofo
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
530 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
531 MS_MAKE_TAG('b','o','p','o'),
533 {{Script_Kana
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
534 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
535 MS_MAKE_TAG('k','a','n','a'),
537 {{Script_Hangul
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
538 {LANG_KOREAN
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
539 MS_MAKE_TAG('h','a','n','g'),
541 {{Script_Yi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
542 {LANG_ENGLISH
, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
543 MS_MAKE_TAG('y','i',' ',' '),
544 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
545 {{Script_Ethiopic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
546 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
547 MS_MAKE_TAG('e','t','h','i'),
548 {'N','y','a','l','a',0}},
549 {{Script_Ethiopic_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
550 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
551 MS_MAKE_TAG('e','t','h','i'),
552 {'N','y','a','l','a',0}},
553 {{Script_Mongolian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
554 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
555 MS_MAKE_TAG('m','o','n','g'),
556 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
557 {{Script_Mongolian_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
558 {LANG_MONGOLIAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
559 MS_MAKE_TAG('m','o','n','g'),
560 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
561 {{Script_Tifinagh
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
562 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
563 MS_MAKE_TAG('t','f','n','g'),
564 {'E','b','r','i','m','a',0}},
565 {{Script_NKo
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
566 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
567 MS_MAKE_TAG('n','k','o',' '),
568 {'E','b','r','i','m','a',0}},
569 {{Script_Vai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
570 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
571 MS_MAKE_TAG('v','a','i',' '),
572 {'E','b','r','i','m','a',0}},
573 {{Script_Vai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
574 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
575 MS_MAKE_TAG('v','a','i',' '),
576 {'E','b','r','i','m','a',0}},
577 {{Script_Cherokee
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
578 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
579 MS_MAKE_TAG('c','h','e','r'),
580 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
581 {{Script_Canadian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
582 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
583 MS_MAKE_TAG('c','a','n','s'),
584 {'E','u','p','h','e','m','i','a',0}},
585 {{Script_Ogham
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
586 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
587 MS_MAKE_TAG('o','g','a','m'),
588 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
589 {{Script_Runic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
590 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
591 MS_MAKE_TAG('r','u','n','r'),
592 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
593 {{Script_Braille
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
594 {LANG_ENGLISH
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
595 MS_MAKE_TAG('b','r','a','i'),
596 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
597 {{Script_Surrogates
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
598 {LANG_ENGLISH
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
601 {{Script_Private
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
602 {0, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 1, 0, 0, 0, 0, 1, 0, 0},
605 {{Script_Deseret
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
606 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
607 MS_MAKE_TAG('d','s','r','t'),
608 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
609 {{Script_Osmanya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
610 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
611 MS_MAKE_TAG('o','s','m','a'),
612 {'E','b','r','i','m','a',0}},
613 {{Script_Osmanya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
614 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
615 MS_MAKE_TAG('o','s','m','a'),
616 {'E','b','r','i','m','a',0}},
617 {{Script_MathAlpha
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
618 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
619 MS_MAKE_TAG('m','a','t','h'),
620 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
621 {{Script_Hebrew_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
622 {LANG_HEBREW
, 0, 1, 0, 0, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
623 MS_MAKE_TAG('h','e','b','r'),
624 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
625 {{Script_Vietnamese_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
626 {LANG_VIETNAMESE
, 0, 0, 0, 0, VIETNAMESE_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
627 MS_MAKE_TAG('l','a','t','n'),
628 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
629 {{Script_Thai_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
630 {LANG_THAI
, 0, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
631 MS_MAKE_TAG('t','h','a','i'),
632 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
635 static const SCRIPT_PROPERTIES
*script_props
[] =
637 &scriptInformation
[0].props
, &scriptInformation
[1].props
,
638 &scriptInformation
[2].props
, &scriptInformation
[3].props
,
639 &scriptInformation
[4].props
, &scriptInformation
[5].props
,
640 &scriptInformation
[6].props
, &scriptInformation
[7].props
,
641 &scriptInformation
[8].props
, &scriptInformation
[9].props
,
642 &scriptInformation
[10].props
, &scriptInformation
[11].props
,
643 &scriptInformation
[12].props
, &scriptInformation
[13].props
,
644 &scriptInformation
[14].props
, &scriptInformation
[15].props
,
645 &scriptInformation
[16].props
, &scriptInformation
[17].props
,
646 &scriptInformation
[18].props
, &scriptInformation
[19].props
,
647 &scriptInformation
[20].props
, &scriptInformation
[21].props
,
648 &scriptInformation
[22].props
, &scriptInformation
[23].props
,
649 &scriptInformation
[24].props
, &scriptInformation
[25].props
,
650 &scriptInformation
[26].props
, &scriptInformation
[27].props
,
651 &scriptInformation
[28].props
, &scriptInformation
[29].props
,
652 &scriptInformation
[30].props
, &scriptInformation
[31].props
,
653 &scriptInformation
[32].props
, &scriptInformation
[33].props
,
654 &scriptInformation
[34].props
, &scriptInformation
[35].props
,
655 &scriptInformation
[36].props
, &scriptInformation
[37].props
,
656 &scriptInformation
[38].props
, &scriptInformation
[39].props
,
657 &scriptInformation
[40].props
, &scriptInformation
[41].props
,
658 &scriptInformation
[42].props
, &scriptInformation
[43].props
,
659 &scriptInformation
[44].props
, &scriptInformation
[45].props
,
660 &scriptInformation
[46].props
, &scriptInformation
[47].props
,
661 &scriptInformation
[48].props
, &scriptInformation
[49].props
,
662 &scriptInformation
[50].props
, &scriptInformation
[51].props
,
663 &scriptInformation
[52].props
, &scriptInformation
[53].props
,
664 &scriptInformation
[54].props
, &scriptInformation
[55].props
,
665 &scriptInformation
[56].props
, &scriptInformation
[57].props
,
666 &scriptInformation
[58].props
, &scriptInformation
[59].props
,
667 &scriptInformation
[60].props
, &scriptInformation
[61].props
,
668 &scriptInformation
[62].props
, &scriptInformation
[63].props
,
669 &scriptInformation
[64].props
, &scriptInformation
[65].props
,
670 &scriptInformation
[66].props
, &scriptInformation
[67].props
,
671 &scriptInformation
[68].props
, &scriptInformation
[69].props
,
672 &scriptInformation
[70].props
, &scriptInformation
[71].props
,
673 &scriptInformation
[72].props
, &scriptInformation
[73].props
,
674 &scriptInformation
[74].props
, &scriptInformation
[75].props
,
675 &scriptInformation
[76].props
, &scriptInformation
[77].props
,
676 &scriptInformation
[78].props
, &scriptInformation
[79].props
,
677 &scriptInformation
[80].props
, &scriptInformation
[81].props
686 SCRIPT_VISATTR
* psva
;
702 StringGlyphs
* glyphs
;
703 SCRIPT_LOGATTR
* logattrs
;
713 static inline void *heap_alloc(SIZE_T size
)
715 return HeapAlloc(GetProcessHeap(), 0, size
);
718 static inline void *heap_alloc_zero(SIZE_T size
)
720 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
723 static inline BOOL
heap_free(LPVOID mem
)
725 return HeapFree(GetProcessHeap(), 0, mem
);
728 /* TODO Fix font properties on Arabic locale */
729 static inline BOOL
set_cache_font_properties(const HDC hdc
, ScriptCache
*sc
)
733 sc
->sfp
.wgBlank
= sc
->tm
.tmBreakChar
;
734 sc
->sfp
.wgDefault
= sc
->tm
.tmDefaultChar
;
735 sc
->sfp
.wgInvalid
= sc
->sfp
.wgBlank
;
736 sc
->sfp
.wgKashida
= 0xFFFF;
737 sc
->sfp
.iKashidaWidth
= 0;
741 static const WCHAR chars
[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
742 /* U+0020: numeric space
743 U+200B: zero width space
744 U+F71B: unknow char found by black box testing
748 if (GetGlyphIndicesW(hdc
, chars
, 4, gi
, GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
750 if(gi
[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
751 sc
->sfp
.wgBlank
= gi
[0];
755 sc
->sfp
.wgDefault
= 0;
758 sc
->sfp
.wgInvalid
= gi
[2];
759 else if (gi
[1] != 0xFFFF)
760 sc
->sfp
.wgInvalid
= gi
[1];
761 else if (gi
[0] != 0xFFFF)
762 sc
->sfp
.wgInvalid
= gi
[0];
764 sc
->sfp
.wgInvalid
= 0;
766 sc
->sfp
.wgKashida
= gi
[3];
768 sc
->sfp
.iKashidaWidth
= 0; /* TODO */
776 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES
*sfp
, ScriptCache
*sc
)
778 sfp
->wgBlank
= sc
->sfp
.wgBlank
;
779 sfp
->wgDefault
= sc
->sfp
.wgDefault
;
780 sfp
->wgInvalid
= sc
->sfp
.wgInvalid
;
781 sfp
->wgKashida
= sc
->sfp
.wgKashida
;
782 sfp
->iKashidaWidth
= sc
->sfp
.iKashidaWidth
;
785 static inline LONG
get_cache_height(SCRIPT_CACHE
*psc
)
787 return ((ScriptCache
*)*psc
)->tm
.tmHeight
;
790 static inline BYTE
get_cache_pitch_family(SCRIPT_CACHE
*psc
)
792 return ((ScriptCache
*)*psc
)->tm
.tmPitchAndFamily
;
795 static inline WORD
get_cache_glyph(SCRIPT_CACHE
*psc
, DWORD c
)
797 CacheGlyphPage
*page
= ((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
801 block
= page
->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
802 if (!block
) return 0;
803 return block
[(c
% 0x10000) & GLYPH_BLOCK_MASK
];
806 static inline WORD
set_cache_glyph(SCRIPT_CACHE
*psc
, WCHAR c
, WORD glyph
)
808 CacheGlyphPage
**page
= &((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
810 if (!*page
&& !(*page
= heap_alloc_zero(sizeof(CacheGlyphPage
)))) return 0;
812 block
= &(*page
)->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
813 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(WORD
) * GLYPH_BLOCK_SIZE
))) return 0;
814 return ((*block
)[(c
% 0x10000) & GLYPH_BLOCK_MASK
] = glyph
);
817 static inline BOOL
get_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
819 static const ABC nil
;
820 ABC
*block
= ((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
822 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(ABC
))) return FALSE
;
823 memcpy(abc
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(ABC
));
827 static inline BOOL
set_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
829 ABC
**block
= &((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
831 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(ABC
) * GLYPH_BLOCK_SIZE
))) return FALSE
;
832 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], abc
, sizeof(ABC
));
836 static HRESULT
init_script_cache(const HDC hdc
, SCRIPT_CACHE
*psc
)
841 if (!psc
) return E_INVALIDARG
;
842 if (*psc
) return S_OK
;
843 if (!hdc
) return E_PENDING
;
845 if (!(sc
= heap_alloc_zero(sizeof(ScriptCache
)))) return E_OUTOFMEMORY
;
846 if (!GetTextMetricsW(hdc
, &sc
->tm
))
851 size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
854 sc
->otm
= heap_alloc(size
);
855 sc
->otm
->otmSize
= size
;
856 GetOutlineTextMetricsW(hdc
, size
, sc
->otm
);
858 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(LOGFONTW
), &sc
->lf
))
863 sc
->sfnt
= (GetFontData(hdc
, MS_MAKE_TAG('h','e','a','d'), 0, NULL
, 0)!=GDI_ERROR
);
864 if (!set_cache_font_properties(hdc
, sc
))
870 TRACE("<- %p\n", sc
);
874 static WCHAR
mirror_char( WCHAR ch
)
876 extern const WCHAR wine_mirror_map
[];
877 return ch
+ wine_mirror_map
[wine_mirror_map
[ch
>> 8] + (ch
& 0xff)];
880 static inline DWORD
decode_surrogate_pair(LPCWSTR str
, INT index
, INT end
)
882 if (index
< end
-1 && IS_SURROGATE_PAIR(str
[index
],str
[index
+1]))
884 DWORD ch
= 0x10000 + ((str
[index
] - 0xd800) << 10) + (str
[index
+1] - 0xdc00);
885 TRACE("Surrogate Pair %x %x => %x\n",str
[index
], str
[index
+1], ch
);
891 static WORD
get_char_script( LPCWSTR str
, INT index
, INT end
, INT
*consumed
)
893 static const WCHAR latin_punc
[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
900 if (str
[index
] == 0xc || str
[index
] == 0x20 || str
[index
] == 0x202f)
903 /* These punctuation characters are separated out as Latin punctuation */
904 if (strchrW(latin_punc
,str
[index
]))
905 return Script_Punctuation2
;
907 /* These chars are itemized as Punctuation by Windows */
908 if (str
[index
] == 0x2212 || str
[index
] == 0x2044)
909 return Script_Punctuation
;
911 /* Currency Symboles by Unicode point */
915 case 0x09f3: return Script_Bengali_Currency
;
916 case 0x0af1: return Script_Gujarati_Currency
;
917 case 0x0e3f: return Script_Thai_Currency
;
918 case 0x20aa: return Script_Hebrew_Currency
;
919 case 0x20ab: return Script_Vietnamese_Currency
;
920 case 0xfb29: return Script_Hebrew_Currency
;
923 GetStringTypeW(CT_CTYPE1
, &str
[index
], 1, &type
);
926 return SCRIPT_UNDEFINED
;
929 return Script_Control
;
931 ch
= decode_surrogate_pair(str
, index
, end
);
940 if (ch
< scriptRanges
[i
].rangeFirst
|| scriptRanges
[i
].script
== SCRIPT_UNDEFINED
)
943 if (ch
>= scriptRanges
[i
].rangeFirst
&& ch
<= scriptRanges
[i
].rangeLast
)
945 if (scriptRanges
[i
].numericScript
&& type
& C1_DIGIT
)
946 return scriptRanges
[i
].numericScript
;
947 if (scriptRanges
[i
].punctScript
&& type
& C1_PUNCT
)
948 return scriptRanges
[i
].punctScript
;
949 return scriptRanges
[i
].script
;
954 return SCRIPT_UNDEFINED
;
957 static int compare_FindGlyph(const void *a
, const void* b
)
959 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
960 const WORD
*idx
= (WORD
*)b
;
963 if ( find
->target
> *idx
)
965 else if (find
->target
< *idx
)
968 if (!find
->ascending
)
973 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
975 FindGlyph_struct fgs
;
979 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
980 fgs
.ascending
= TRUE
;
982 fgs
.ascending
= FALSE
;
985 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
990 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
997 /***********************************************************************
998 * ScriptFreeCache (USP10.@)
1000 * Free a script cache.
1003 * psc [I/O] Script cache.
1007 * Failure: Non-zero HRESULT value.
1009 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1017 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1019 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1021 for (i
= 0; i
< 0x10; i
++)
1024 if (((ScriptCache
*)*psc
)->page
[i
])
1025 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1026 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1027 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1029 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1030 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1031 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1032 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1033 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1036 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1039 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1040 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1041 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1043 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1044 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1045 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1046 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1048 heap_free(((ScriptCache
*)*psc
)->scripts
);
1049 heap_free(((ScriptCache
*)*psc
)->otm
);
1056 /***********************************************************************
1057 * ScriptGetProperties (USP10.@)
1059 * Retrieve a list of script properties.
1062 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1063 * num [I] Pointer to the number of scripts.
1067 * Failure: Non-zero HRESULT value.
1070 * Behaviour matches WinXP.
1072 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1074 TRACE("(%p,%p)\n", props
, num
);
1076 if (!props
&& !num
) return E_INVALIDARG
;
1078 if (num
) *num
= sizeof(script_props
)/sizeof(script_props
[0]);
1079 if (props
) *props
= script_props
;
1084 /***********************************************************************
1085 * ScriptGetFontProperties (USP10.@)
1087 * Get information on special glyphs.
1090 * hdc [I] Device context.
1091 * psc [I/O] Opaque pointer to a script cache.
1092 * sfp [O] Font properties structure.
1094 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1098 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1100 if (!sfp
) return E_INVALIDARG
;
1101 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1103 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1104 return E_INVALIDARG
;
1106 get_cache_font_properties(sfp
, *psc
);
1111 /***********************************************************************
1112 * ScriptRecordDigitSubstitution (USP10.@)
1114 * Record digit substitution settings for a given locale.
1117 * locale [I] Locale identifier.
1118 * sds [I] Structure to record substitution settings.
1122 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1125 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1127 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1131 TRACE("0x%x, %p\n", locale
, sds
);
1133 /* This implementation appears to be correct for all languages, but it's
1134 * not clear if sds->DigitSubstitute is ever set to anything except
1135 * CONTEXT or NONE in reality */
1137 if (!sds
) return E_POINTER
;
1139 locale
= ConvertDefaultLocale(locale
);
1141 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1142 return E_INVALIDARG
;
1144 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1145 sds
->TraditionalDigitLanguage
= plgid
;
1147 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1148 sds
->NationalDigitLanguage
= plgid
;
1150 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1152 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1153 (LPWSTR
)&sub
, sizeof(sub
)/sizeof(WCHAR
))) return E_INVALIDARG
;
1158 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1159 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1161 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1164 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1167 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1170 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1174 sds
->dwReserved
= 0;
1178 /***********************************************************************
1179 * ScriptApplyDigitSubstitution (USP10.@)
1181 * Apply digit substitution settings.
1184 * sds [I] Structure with recorded substitution settings.
1185 * sc [I] Script control structure.
1186 * ss [I] Script state structure.
1190 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1192 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1193 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1195 SCRIPT_DIGITSUBSTITUTE psds
;
1197 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1199 if (!sc
|| !ss
) return E_POINTER
;
1203 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1204 return E_INVALIDARG
;
1207 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1208 sc
->fContextDigits
= 0;
1209 ss
->fDigitSubstitute
= 0;
1211 switch (sds
->DigitSubstitute
) {
1212 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1213 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1214 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1215 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1218 return E_INVALIDARG
;
1222 static inline BOOL
is_indic(WORD script
)
1224 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1227 static inline WORD
base_indic(WORD script
)
1231 case Script_Devanagari
:
1232 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1233 case Script_Bengali
:
1234 case Script_Bengali_Numeric
:
1235 case Script_Bengali_Currency
: return Script_Bengali
;
1236 case Script_Gurmukhi
:
1237 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1238 case Script_Gujarati
:
1239 case Script_Gujarati_Numeric
:
1240 case Script_Gujarati_Currency
: return Script_Gujarati
;
1242 case Script_Oriya_Numeric
: return Script_Oriya
;
1244 case Script_Tamil_Numeric
: return Script_Tamil
;
1246 case Script_Telugu_Numeric
: return Script_Telugu
;
1247 case Script_Kannada
:
1248 case Script_Kannada_Numeric
: return Script_Kannada
;
1249 case Script_Malayalam
:
1250 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1257 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1258 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1259 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1260 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1263 #define Numeric_space 0x0020
1267 int cnt
= 0, index
= 0, str
= 0;
1268 int New_Script
= -1;
1270 WORD
*levels
= NULL
;
1271 WORD
*strength
= NULL
;
1272 WORD
*scripts
= NULL
;
1275 WORD last_indic
= -1;
1277 BOOL forceLevels
= FALSE
;
1279 HRESULT res
= E_OUTOFMEMORY
;
1281 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1282 psControl
, psState
, pItems
, pcItems
);
1284 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1285 return E_INVALIDARG
;
1287 scripts
= heap_alloc(cInChars
* sizeof(WORD
));
1289 return E_OUTOFMEMORY
;
1291 for (i
= 0; i
< cInChars
; i
++)
1295 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1300 scripts
[i
] = scripts
[i
-1];
1303 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1304 all Indic scripts */
1305 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
> 0)
1306 scripts
[i
] = last_indic
;
1307 else if (is_indic(scripts
[i
]))
1308 last_indic
= base_indic(scripts
[i
]);
1310 /* Some unicode points :
1311 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1312 (Left Right Embed U+202A - Left Right Override U+202D)
1313 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1314 will force us into bidi mode */
1315 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1316 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1317 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1321 /* Diacritical marks merge with other scripts */
1322 if (scripts
[i
] == Script_Diacritical
)
1327 scripts
[i
] = scripts
[i
-1];
1332 WORD first_script
= scripts
[i
-1];
1333 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1335 WORD original
= scripts
[j
];
1336 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1341 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1343 scripts
[j
] = scripts
[i
];
1344 if (original
== Script_Punctuation2
)
1347 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1348 scripts
[i
] = scripts
[j
];
1354 for (i
= 0; i
< cInChars
; i
++)
1356 /* Joiners get merged preferencially right */
1357 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1360 if (i
+1 == cInChars
)
1361 scripts
[i
] = scripts
[i
-1];
1364 for (j
= i
+1; j
< cInChars
; j
++)
1366 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1368 scripts
[i
] = scripts
[j
];
1376 if (psState
&& psControl
)
1378 levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1382 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
);
1383 baselevel
= levels
[0];
1384 for (i
= 0; i
< cInChars
; i
++)
1385 if (levels
[i
]!=levels
[0])
1387 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1394 BOOL inNumber
= FALSE
;
1395 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1397 strength
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1400 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1402 /* We currently mis-level leading Diacriticals */
1403 if (scripts
[0] == Script_Diacritical
)
1404 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1406 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1407 strength
[i
] = BIDI_STRONG
;
1410 for (i
= 0; i
< cInChars
; i
++)
1412 /* Script_Numeric and select puncuation at level 0 get bumped to level 2 */
1413 if ((levels
[i
] == 0 || (odd(psState
->uBidiLevel
) && levels
[i
] == psState
->uBidiLevel
+1)) && inNumber
&& strchrW(math_punc
,pwcInChars
[i
]))
1415 scripts
[i
] = Script_Numeric
;
1418 else if ((levels
[i
] == 0 || (odd(psState
->uBidiLevel
) && levels
[i
] == psState
->uBidiLevel
+1)) && scripts
[i
] == Script_Numeric
)
1426 /* Joiners get merged preferencially right */
1427 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1430 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1431 strength
[i
] = strength
[i
-1];
1433 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1434 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1436 strength
[i
] = strength
[j
];
1441 if (psControl
->fMergeNeutralItems
)
1443 /* Merge the neutrals */
1444 for (i
= 0; i
< cInChars
; i
++)
1446 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1449 for (j
= i
; j
> 0; j
--)
1451 if (levels
[i
] != levels
[j
])
1453 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1455 scripts
[i
] = scripts
[j
];
1456 strength
[i
] = strength
[j
];
1461 /* Try going the other way */
1462 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1465 for (j
= i
; j
< cInChars
; j
++)
1467 if (levels
[i
] != levels
[j
])
1469 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1471 scripts
[i
] = scripts
[j
];
1472 strength
[i
] = strength
[j
];
1482 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1483 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1486 if (cnt
== cInChars
) /* All Spaces */
1489 New_Script
= scripts
[cnt
];
1492 pItems
[index
].iCharPos
= 0;
1493 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1495 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1497 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1498 str
= strength
[cnt
];
1506 if (strength
[cnt
] == BIDI_STRONG
)
1507 layoutRTL
= (odd(levels
[cnt
]))?1:0;
1509 layoutRTL
= (psState
->uBidiLevel
|| odd(levels
[cnt
]))?1:0;
1510 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1511 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1512 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1514 else if (!pItems
[index
].a
.s
.uBidiLevel
)
1516 layoutRTL
= (odd(baselevel
))?1:0;
1517 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1518 pItems
[index
].a
.fLayoutRTL
= odd(baselevel
);
1519 pItems
[index
].a
.fRTL
= odd(baselevel
);
1522 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1523 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1524 pItems
[index
].iCharPos
);
1526 for (cnt
=1; cnt
< cInChars
; cnt
++)
1528 if(pwcInChars
[cnt
] != Numeric_space
)
1529 New_Script
= scripts
[cnt
];
1533 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1535 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1536 New_Script
= scripts
[cnt
+j
];
1538 New_Script
= scripts
[cnt
];
1542 /* merge space strengths*/
1543 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1546 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1549 /* changes in level */
1550 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1552 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1555 /* changes in strength */
1556 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1558 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1561 /* changes in script */
1562 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1564 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1568 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1570 layoutRTL
= odd(levels
[cnt
])?1:0;
1571 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1576 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
);
1579 if (index
+1 > cMaxItems
)
1583 str
= strength
[cnt
];
1585 pItems
[index
].iCharPos
= cnt
;
1586 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1588 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1590 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1593 if (levels
[cnt
] == 0)
1596 layoutRTL
= (layoutRTL
|| odd(levels
[cnt
]))?1:0;
1597 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1598 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1599 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1601 else if (!pItems
[index
].a
.s
.uBidiLevel
)
1603 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1604 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1605 pItems
[index
].a
.fRTL
= odd(baselevel
);
1608 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1612 /* While not strictly necessary according to the spec, make sure the n+1
1613 * item is set up to prevent random behaviour if the caller erroneously
1614 * checks the n+1 structure */
1616 if (index
+ 1 > cMaxItems
) goto nomemory
;
1617 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1619 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1621 /* Set one SCRIPT_STATE item being returned */
1622 if (pcItems
) *pcItems
= index
;
1624 /* Set SCRIPT_ITEM */
1625 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1629 heap_free(strength
);
1634 /***********************************************************************
1635 * ScriptItemizeOpenType (USP10.@)
1637 * Split a Unicode string into shapeable parts.
1640 * pwcInChars [I] String to split.
1641 * cInChars [I] Number of characters in pwcInChars.
1642 * cMaxItems [I] Maximum number of items to return.
1643 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1644 * psState [I] Pointer to a SCRIPT_STATE structure.
1645 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1646 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1647 * pcItems [O] Number of script items returned.
1651 * Failure: Non-zero HRESULT value.
1653 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1654 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1655 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1657 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1660 /***********************************************************************
1661 * ScriptItemize (USP10.@)
1663 * Split a Unicode string into shapeable parts.
1666 * pwcInChars [I] String to split.
1667 * cInChars [I] Number of characters in pwcInChars.
1668 * cMaxItems [I] Maximum number of items to return.
1669 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1670 * psState [I] Pointer to a SCRIPT_STATE structure.
1671 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1672 * pcItems [O] Number of script items returned.
1676 * Failure: Non-zero HRESULT value.
1678 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1679 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1680 SCRIPT_ITEM
*pItems
, int *pcItems
)
1682 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1685 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1689 INT
*lpTabPos
= NULL
;
1694 lpTabPos
= pTabdef
->pTabStops
;
1696 if (pTabdef
&& pTabdef
->iTabOrigin
)
1698 if (pTabdef
->iScale
)
1699 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1701 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1705 cTabStops
= pTabdef
->cTabStops
;
1709 if (pTabdef
->iScale
)
1710 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1712 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1716 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1718 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1720 int position
= *lpTabPos
;
1722 position
= -1 * position
;
1723 if (pTabdef
->iScale
)
1724 position
= (position
* pTabdef
->iScale
) / 4;
1726 position
= position
* psc
->tm
.tmAveCharWidth
;
1728 if( nTabOrg
+ position
> current_x
)
1732 /* a left aligned tab */
1733 x
= (nTabOrg
+ *lpTabPos
) - current_x
;
1738 FIXME("Negative tabstop\n");
1743 if ((!cTabStops
) && (defWidth
> 0))
1744 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1745 else if ((!cTabStops
) && (defWidth
< 0))
1746 FIXME("TODO: Negative defWidth\n");
1751 /***********************************************************************
1752 * Helper function for ScriptStringAnalyse
1754 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1755 const WCHAR
*pwcInChars
, int cChars
)
1757 /* FIXME: When to properly fallback is still a bit of a mystery */
1760 if (psa
->fNoGlyphIndex
)
1763 if (init_script_cache(hdc
, psc
) != S_OK
)
1766 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1769 glyphs
= heap_alloc(sizeof(WORD
) * cChars
);
1772 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1782 static void find_fallback_font(DWORD scriptid
, LPWSTR FaceName
)
1786 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1788 static const WCHAR szFmt
[] = {'%','x',0};
1790 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1793 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1794 if (RegQueryValueExW(hkey
, value
, 0, &type
, (LPBYTE
)FaceName
, &count
))
1795 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1799 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1802 /***********************************************************************
1803 * ScriptStringAnalyse (USP10.@)
1806 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1807 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1808 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1809 SCRIPT_STATE
*psState
, const int *piDx
,
1810 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1811 SCRIPT_STRING_ANALYSIS
*pssa
)
1813 HRESULT hr
= E_OUTOFMEMORY
;
1814 StringAnalysis
*analysis
= NULL
;
1815 SCRIPT_CONTROL sControl
;
1816 SCRIPT_STATE sState
;
1817 int i
, num_items
= 255;
1819 WCHAR
*iString
= NULL
;
1821 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1822 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1823 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
1827 FIXME("Only Unicode strings are supported\n");
1828 return E_INVALIDARG
;
1830 if (cString
< 1 || !pString
) return E_INVALIDARG
;
1831 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
1833 if (!(analysis
= heap_alloc_zero(sizeof(StringAnalysis
)))) return E_OUTOFMEMORY
;
1834 if (!(analysis
->pItem
= heap_alloc_zero(num_items
* sizeof(SCRIPT_ITEM
) + 1))) goto error
;
1836 /* FIXME: handle clipping */
1837 analysis
->clip_len
= cString
;
1838 analysis
->hdc
= hdc
;
1839 analysis
->dwFlags
= dwFlags
;
1844 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
1847 sControl
= *psControl
;
1849 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
1851 if (dwFlags
& SSA_PASSWORD
)
1853 iString
= heap_alloc(sizeof(WCHAR
)*cString
);
1859 for (i
= 0; i
< cString
; i
++)
1860 iString
[i
] = *((const WCHAR
*)pString
);
1864 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
1865 &analysis
->numItems
);
1869 if (hr
== E_OUTOFMEMORY
)
1874 /* set back to out of memory for default goto error behaviour */
1877 if (dwFlags
& SSA_BREAK
)
1879 if ((analysis
->logattrs
= heap_alloc(sizeof(SCRIPT_LOGATTR
) * cString
)))
1881 for (i
= 0; i
< analysis
->numItems
; i
++)
1882 ScriptBreak(&((LPWSTR
)pString
)[analysis
->pItem
[i
].iCharPos
], analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
, &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
1888 if (!(analysis
->logical2visual
= heap_alloc_zero(sizeof(int) * analysis
->numItems
)))
1890 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
1893 if (dwFlags
& SSA_GLYPHS
)
1896 if (!(analysis
->glyphs
= heap_alloc_zero(sizeof(StringGlyphs
) * analysis
->numItems
)))
1898 heap_free(BidiLevel
);
1902 for (i
= 0; i
< analysis
->numItems
; i
++)
1904 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
1905 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
1906 int numGlyphs
= 1.5 * cChar
+ 16;
1907 WORD
*glyphs
= heap_alloc_zero(sizeof(WORD
) * numGlyphs
);
1908 WORD
*pwLogClust
= heap_alloc_zero(sizeof(WORD
) * cChar
);
1909 int *piAdvance
= heap_alloc_zero(sizeof(int) * numGlyphs
);
1910 SCRIPT_VISATTR
*psva
= heap_alloc_zero(sizeof(SCRIPT_VISATTR
) * numGlyphs
);
1911 GOFFSET
*pGoffset
= heap_alloc_zero(sizeof(GOFFSET
) * numGlyphs
);
1912 ABC
*abc
= heap_alloc_zero(sizeof(ABC
));
1913 int numGlyphsReturned
;
1914 HFONT originalFont
= 0x0;
1916 /* FIXME: non unicode strings */
1917 const WCHAR
* pStr
= (const WCHAR
*)pString
;
1918 analysis
->glyphs
[i
].fallbackFont
= NULL
;
1920 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
|| !abc
)
1922 heap_free (BidiLevel
);
1924 heap_free (pwLogClust
);
1925 heap_free (piAdvance
);
1927 heap_free (pGoffset
);
1933 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
1936 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
1937 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
1938 lf
.lfFaceName
[0] = 0;
1939 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
1940 if (lf
.lfFaceName
[0])
1942 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
1943 if (analysis
->glyphs
[i
].fallbackFont
)
1945 ScriptFreeCache(sc
);
1946 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
1951 /* FIXME: When we properly shape Hangul remove this check */
1952 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
1953 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
1955 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
1956 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
1958 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
1959 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
1960 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
1961 piAdvance
, pGoffset
, abc
);
1963 SelectObject(hdc
,originalFont
);
1965 if (dwFlags
& SSA_TAB
)
1968 for (tabi
= 0; tabi
< cChar
; tabi
++)
1970 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
1971 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
1972 tab_x
+=piAdvance
[tabi
];
1976 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
1977 analysis
->glyphs
[i
].glyphs
= glyphs
;
1978 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
1979 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
1980 analysis
->glyphs
[i
].psva
= psva
;
1981 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
1982 analysis
->glyphs
[i
].abc
= abc
;
1983 analysis
->glyphs
[i
].iMaxPosX
= -1;
1985 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
1990 for (i
= 0; i
< analysis
->numItems
; i
++)
1991 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
1994 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
1995 heap_free(BidiLevel
);
2003 heap_free(analysis
->glyphs
);
2004 heap_free(analysis
->logattrs
);
2005 heap_free(analysis
->pItem
);
2006 heap_free(analysis
->logical2visual
);
2007 heap_free(analysis
);
2011 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2013 if (pva
[glyph
].fClusterStart
)
2015 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2022 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2033 StringAnalysis
*analysis
;
2036 COLORREF BkColor
= 0x0;
2037 COLORREF TextColor
= 0x0;
2039 INT runStart
, runEnd
;
2040 INT iGlyph
, cGlyphs
;
2041 HFONT oldFont
= 0x0;
2045 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2046 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2048 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2050 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2051 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2057 BkMode
= GetBkMode(analysis
->hdc
);
2058 SetBkMode( analysis
->hdc
, OPAQUE
);
2059 BkColor
= GetBkColor(analysis
->hdc
);
2060 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2063 TextColor
= GetTextColor(analysis
->hdc
);
2064 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2067 if (analysis
->glyphs
[iItem
].fallbackFont
)
2068 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2070 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2071 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2074 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2075 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2077 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2079 if (analysis
->pItem
[iItem
].a
.fRTL
)
2081 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2082 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2084 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2085 crc
.left
= iX
+ off_x
;
2089 if (cStart
>=0 && runStart
)
2090 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2092 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2093 crc
.left
= iX
+ off_x
;
2096 if (analysis
->pItem
[iItem
].a
.fRTL
)
2097 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2099 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2101 if (analysis
->pItem
[iItem
].a
.fRTL
)
2102 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2104 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2108 /* adjust for cluster glyphs when starting */
2109 if (analysis
->pItem
[iItem
].a
.fRTL
)
2110 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2112 i
= analysis
->pItem
[iItem
].iCharPos
;
2114 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2116 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2118 if (analysis
->pItem
[iItem
].a
.fRTL
)
2119 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2121 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2126 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2131 clust_glyph
= iGlyph
+ cGlyphs
;
2132 if (analysis
->pItem
[iItem
].a
.fRTL
)
2137 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2138 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2145 hr
= ScriptTextOut(analysis
->hdc
,
2146 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2147 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2148 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2149 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2150 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2152 TRACE("ScriptTextOut hr=%08x\n", hr
);
2156 SetBkColor(analysis
->hdc
, BkColor
);
2157 SetBkMode( analysis
->hdc
, BkMode
);
2159 SetTextColor(analysis
->hdc
, TextColor
);
2161 if (analysis
->glyphs
[iItem
].fallbackFont
)
2162 SelectObject(analysis
->hdc
, oldFont
);
2167 /***********************************************************************
2168 * ScriptStringOut (USP10.@)
2170 * This function takes the output of ScriptStringAnalyse and joins the segments
2171 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2172 * only processes glyphs.
2175 * ssa [I] buffer to hold the analysed string components
2176 * iX [I] X axis displacement for output
2177 * iY [I] Y axis displacement for output
2178 * uOptions [I] flags controlling output processing
2179 * prc [I] rectangle coordinates
2180 * iMinSel [I] starting pos for substringing output string
2181 * iMaxSel [I] ending pos for substringing output string
2182 * fDisabled [I] controls text highlighting
2186 * Failure: is the value returned by ScriptTextOut
2188 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2197 StringAnalysis
*analysis
;
2201 TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
2202 ssa
, iX
, iY
, uOptions
, prc
, iMinSel
, iMaxSel
, fDisabled
);
2204 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2205 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2207 for (item
= 0; item
< analysis
->numItems
; item
++)
2209 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2214 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2216 if (iMaxSel
> 0 && iMinSel
< 0)
2218 for (item
= 0; item
< analysis
->numItems
; item
++)
2220 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2229 /***********************************************************************
2230 * ScriptStringCPtoX (USP10.@)
2233 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2237 StringAnalysis
* analysis
= ssa
;
2239 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2241 if (!ssa
|| !pX
) return S_FALSE
;
2242 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2244 /* icp out of range */
2247 analysis
->invalid
= TRUE
;
2248 return E_INVALIDARG
;
2251 for(item
=0; item
<analysis
->numItems
; item
++)
2256 i
= analysis
->logical2visual
[item
];
2257 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2258 /* initialize max extents for uninitialized runs */
2259 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2261 if (analysis
->pItem
[i
].a
.fRTL
)
2262 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2263 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2264 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2266 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2267 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2268 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2271 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2273 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2277 icp
-= analysis
->pItem
[i
].iCharPos
;
2278 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2279 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2280 &analysis
->pItem
[i
].a
, &offset
);
2287 /* icp out of range */
2288 analysis
->invalid
= TRUE
;
2289 return E_INVALIDARG
;
2292 /***********************************************************************
2293 * ScriptStringXtoCP (USP10.@)
2296 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2298 StringAnalysis
* analysis
= ssa
;
2301 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2303 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2304 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2309 if (analysis
->pItem
[0].a
.fRTL
)
2312 *piTrailing
= FALSE
;
2322 for(item
=0; item
<analysis
->numItems
; item
++)
2327 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2330 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2331 /* initialize max extents for uninitialized runs */
2332 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2334 if (analysis
->pItem
[i
].a
.fRTL
)
2335 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2336 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2337 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2339 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2340 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2341 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2344 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2346 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2350 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2351 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2352 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2353 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2359 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2360 *piTrailing
= FALSE
;
2366 /***********************************************************************
2367 * ScriptStringFree (USP10.@)
2369 * Free a string analysis.
2372 * pssa [I] string analysis.
2376 * Failure: Non-zero HRESULT value.
2378 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2380 StringAnalysis
* analysis
;
2384 TRACE("(%p)\n", pssa
);
2386 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2388 invalid
= analysis
->invalid
;
2390 if (analysis
->glyphs
)
2392 for (i
= 0; i
< analysis
->numItems
; i
++)
2394 heap_free(analysis
->glyphs
[i
].glyphs
);
2395 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2396 heap_free(analysis
->glyphs
[i
].piAdvance
);
2397 heap_free(analysis
->glyphs
[i
].psva
);
2398 heap_free(analysis
->glyphs
[i
].pGoffset
);
2399 heap_free(analysis
->glyphs
[i
].abc
);
2400 if (analysis
->glyphs
[i
].fallbackFont
)
2401 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2402 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2403 heap_free(analysis
->glyphs
[i
].sc
);
2405 heap_free(analysis
->glyphs
);
2408 heap_free(analysis
->pItem
);
2409 heap_free(analysis
->logattrs
);
2410 heap_free(analysis
->sz
);
2411 heap_free(analysis
->logical2visual
);
2412 heap_free(analysis
);
2414 if (invalid
) return E_INVALIDARG
;
2418 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2419 int direction
, int* iCluster
, int *check_out
)
2423 WORD clust
= pwLogClust
[item
];
2425 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2427 if (pwLogClust
[check
] == clust
)
2430 if (iCluster
&& *iCluster
== -1)
2442 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
)
2447 advance
= piAdvance
[glyph
];
2449 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2450 log_clust_max
= pwLogClust
[0];
2452 log_clust_max
= pwLogClust
[cChars
-1];
2454 if (glyph
> log_clust_max
)
2457 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2460 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2462 if (glyph
> log_clust_max
)
2464 advance
+= piAdvance
[glyph
];
2470 /***********************************************************************
2471 * ScriptCPtoX (USP10.@)
2474 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2478 const WORD
*pwLogClust
,
2479 const SCRIPT_VISATTR
*psva
,
2480 const int *piAdvance
,
2481 const SCRIPT_ANALYSIS
*psa
,
2489 float special_size
= 0.0;
2494 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2495 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2498 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2506 int max_clust
= pwLogClust
[0];
2508 for (item
=0; item
< cGlyphs
; item
++)
2509 if (pwLogClust
[item
] > max_clust
)
2511 ERR("We do not handle non reversed clusters properly\n");
2516 for (item
= max_clust
; item
>=0; item
--)
2517 iMaxPos
+= piAdvance
[item
];
2521 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2523 if (iSpecial
== -1 && (iCluster
== -1 || (iCluster
!= -1 && iCluster
+clust_size
<= item
)))
2526 int clust
= pwLogClust
[item
];
2529 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2532 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2534 if (check
>= cChars
&& !iMaxPos
)
2537 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2538 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2540 special_size
/= (cChars
- item
);
2541 iPosX
+= special_size
;
2545 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2548 if (clust_size
== 0)
2552 iPosX
+= advance
/ (float)clust_size
;
2555 else if (iSpecial
!= -1)
2556 iPosX
+= special_size
;
2557 else /* (iCluster != -1) */
2559 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2560 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2563 if (clust_size
== 0)
2567 iPosX
+= adv
/ (float)clust_size
;
2573 iPosX
= iMaxPos
- iPosX
;
2579 TRACE("*piX=%d\n", *piX
);
2583 /* Count the number of characters in a cluster and its starting index*/
2584 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2589 for (i
= 0; i
< cChars
; i
++)
2591 if (pwLogClust
[i
] == cluster_index
)
2593 if (!size
&& start_index
)
2601 else if (size
) break;
2604 *cluster_size
= size
;
2610 To handle multi-glyph clusters we need to find all the glyphs that are
2611 represented in the cluster. This involves finding the glyph whose
2612 index is the cluster index as well as whose glyph indices are greater than
2613 our cluster index but not part of a new cluster.
2615 Then we sum all those glyphs' advances.
2617 static inline int get_cluster_advance(const int* piAdvance
,
2618 const SCRIPT_VISATTR
*psva
,
2619 const WORD
*pwLogClust
, int cGlyphs
,
2620 int cChars
, int cluster
, int direction
)
2631 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2633 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2634 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2635 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2640 glyph_end
= cGlyphs
;
2643 /* Don't fully understand multi-glyph reversed clusters yet,
2644 * do they occur for real or just in our test? */
2645 FIXME("multi-glyph reversed clusters found\n");
2646 glyph_end
= glyph_start
+ 1;
2650 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2651 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2653 if (psva
[i
].fClusterStart
)
2660 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2661 advance
+= piAdvance
[i
];
2667 /***********************************************************************
2668 * ScriptXtoCP (USP10.@)
2671 * use piAdvance to find the cluster we are looking at
2672 * Find the character that is the first character of the cluster
2673 * That is our base piCP
2674 * If the script snaps to cluster boundries (Hebrew, Indic, Thai) then we
2675 * are good Otherwise if the cluster is larger than 1 glyph we need to
2676 * determine how far through the cluster to advance the cursor.
2678 HRESULT WINAPI
ScriptXtoCP(int iX
,
2681 const WORD
*pwLogClust
,
2682 const SCRIPT_VISATTR
*psva
,
2683 const int *piAdvance
,
2684 const SCRIPT_ANALYSIS
*psa
,
2691 int glyph_index
, cluster_index
;
2694 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2695 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2696 psa
, piCP
, piTrailing
);
2698 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2701 /* Handle an iX < 0 */
2717 /* Looking for non-reversed clusters in a reversed string */
2720 int max_clust
= pwLogClust
[0];
2721 for (i
=0; i
< cChars
; i
++)
2722 if (pwLogClust
[i
] > max_clust
)
2724 FIXME("We do not handle non reversed clusters properly\n");
2729 /* find the glyph_index based in iX */
2732 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2737 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2741 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2744 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2746 /* find the cluster */
2748 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2751 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2754 TRACE("cluster_index %i\n", cluster_index
);
2756 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2758 /* We are off the end of the string */
2764 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2766 TRACE("first char index %i\n",i
);
2767 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2769 /* Check trailing */
2770 if (glyph_index
!= cluster_index
||
2771 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2772 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2773 *piTrailing
= cluster_size
;
2777 if (cluster_size
> 1)
2779 /* Be part way through the glyph cluster based on size and position */
2780 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2781 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2785 /* back up to the beginning of the cluster */
2786 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2787 adv
+= piAdvance
[part_index
];
2788 if (adv
> iX
) adv
= iX
;
2790 TRACE("Multi-char cluster, no snap\n");
2791 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2792 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2795 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2797 if (part_index
) part_index
--;
2801 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2803 if (part_index
> cluster_size
)
2805 adv
+= cluster_part_width
;
2806 part_index
=cluster_size
;
2810 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2815 i
+= (cluster_size
- part_index
);
2817 /* Check trailing */
2818 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2819 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2824 /* Check trailing */
2825 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2826 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2833 TRACE("Point falls outside of string\n");
2834 if (glyph_index
< 0)
2836 else /* (glyph_index >= cGlyphs) */
2839 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2840 point flow to the next character */
2843 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
2852 TRACE("*piCP=%d\n", *piCP
);
2853 TRACE("*piTrailing=%d\n", *piTrailing
);
2857 /***********************************************************************
2858 * ScriptBreak (USP10.@)
2860 * Retrieve line break information.
2863 * chars [I] Array of characters.
2864 * sa [I] String analysis.
2865 * la [I] Array of logical attribute structures.
2871 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
2873 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
2875 if (count
< 0 || !la
) return E_INVALIDARG
;
2876 if (count
== 0) return E_FAIL
;
2878 BREAK_line(chars
, count
, sa
, la
);
2883 /***********************************************************************
2884 * ScriptIsComplex (USP10.@)
2886 * Determine if a string is complex.
2889 * chars [I] Array of characters to test.
2890 * len [I] Length in characters.
2898 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
2903 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
2905 for (i
= 0; i
< len
; i
+=consumed
)
2911 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
2914 script
= get_char_script(chars
,i
,len
, &consumed
);
2915 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
2916 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
2922 /***********************************************************************
2923 * ScriptShapeOpenType (USP10.@)
2925 * Produce glyphs and visual attributes for a run.
2928 * hdc [I] Device context.
2929 * psc [I/O] Opaque pointer to a script cache.
2930 * psa [I/O] Script analysis.
2931 * tagScript [I] The OpenType tag for the Script
2932 * tagLangSys [I] The OpenType tag for the Language
2933 * rcRangeChars[I] Array of Character counts in each range
2934 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2935 * cRanges [I] Count of ranges
2936 * pwcChars [I] Array of characters specifying the run.
2937 * cChars [I] Number of characters in pwcChars.
2938 * cMaxGlyphs [I] Length of pwOutGlyphs.
2939 * pwLogClust [O] Array of logical cluster info.
2940 * pCharProps [O] Array of character property values
2941 * pwOutGlyphs [O] Array of glyphs.
2942 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
2943 * pcGlyphs [O] Number of glyphs returned.
2947 * Failure: Non-zero HRESULT value.
2949 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
2950 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
2951 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
2952 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
2953 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
2954 int cMaxGlyphs
, WORD
*pwLogClust
,
2955 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
2956 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
2963 static int once
= 0;
2965 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
2967 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
2968 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
2969 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
2971 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
2972 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
2974 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
2975 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
2978 if(!once
++) FIXME("Ranges not supported yet\n");
2980 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
2983 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
2984 if (!pwLogClust
) return E_FAIL
;
2986 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
2987 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
2989 /* set fNoGlyphIndex non truetype/opentype fonts */
2990 if (psa
&& !psa
->fNoGlyphIndex
&& !((ScriptCache
*)*psc
)->sfnt
)
2991 psa
->fNoGlyphIndex
= TRUE
;
2993 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
2994 for (i
= 0; i
< cChars
; i
++)
2997 if (rtl
) idx
= cChars
- 1 - i
;
2998 /* FIXME: set to better values */
2999 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3000 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3001 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3002 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3003 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3004 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3006 /* FIXME: have the shaping engine set this */
3007 pCharProps
[i
].fCanGlyphAlone
= 0;
3009 pwLogClust
[i
] = idx
;
3012 if (psa
&& !psa
->fNoGlyphIndex
)
3015 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3017 rChars
= heap_alloc(sizeof(WCHAR
) * cChars
);
3018 if (!rChars
) return E_OUTOFMEMORY
;
3019 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3024 if (rtl
) idx
= cChars
- 1 - i
;
3027 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3031 chInput
= mirror_char(pwcChars
[idx
]);
3033 chInput
= pwcChars
[idx
];
3034 /* special case for tabs */
3035 if (chInput
== 0x0009)
3037 rChars
[i
] = chInput
;
3041 rChars
[i
] = pwcChars
[idx
];
3042 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3045 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3053 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3058 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3066 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3067 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3073 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3074 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3075 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3080 TRACE("no glyph translation\n");
3081 for (i
= 0; i
< cChars
; i
++)
3084 /* No mirroring done here */
3085 if (rtl
) idx
= cChars
- 1 - i
;
3086 pwOutGlyphs
[i
] = pwcChars
[idx
];
3088 /* overwrite some basic control glyphs to blank */
3089 if (psa
&& psa
->eScript
== Script_Control
&&
3090 pwcChars
[idx
] < ((ScriptCache
*)*psc
)->tm
.tmFirstChar
)
3092 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3093 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3094 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3103 /***********************************************************************
3104 * ScriptShape (USP10.@)
3106 * Produce glyphs and visual attributes for a run.
3109 * hdc [I] Device context.
3110 * psc [I/O] Opaque pointer to a script cache.
3111 * pwcChars [I] Array of characters specifying the run.
3112 * cChars [I] Number of characters in pwcChars.
3113 * cMaxGlyphs [I] Length of pwOutGlyphs.
3114 * psa [I/O] Script analysis.
3115 * pwOutGlyphs [O] Array of glyphs.
3116 * pwLogClust [O] Array of logical cluster info.
3117 * psva [O] Array of visual attributes.
3118 * pcGlyphs [O] Number of glyphs returned.
3122 * Failure: Non-zero HRESULT value.
3124 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3125 int cChars
, int cMaxGlyphs
,
3126 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3127 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3131 SCRIPT_CHARPROP
*charProps
;
3132 SCRIPT_GLYPHPROP
*glyphProps
;
3134 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3135 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3137 charProps
= heap_alloc_zero(sizeof(SCRIPT_CHARPROP
)*cChars
);
3138 if (!charProps
) return E_OUTOFMEMORY
;
3139 glyphProps
= heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP
)*cMaxGlyphs
);
3142 heap_free(charProps
);
3143 return E_OUTOFMEMORY
;
3146 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3150 for (i
= 0; i
< *pcGlyphs
; i
++)
3151 psva
[i
] = glyphProps
[i
].sva
;
3154 heap_free(charProps
);
3155 heap_free(glyphProps
);
3160 /***********************************************************************
3161 * ScriptPlaceOpenType (USP10.@)
3163 * Produce advance widths for a run.
3166 * hdc [I] Device context.
3167 * psc [I/O] Opaque pointer to a script cache.
3168 * psa [I/O] String analysis.
3169 * tagScript [I] The OpenType tag for the Script
3170 * tagLangSys [I] The OpenType tag for the Language
3171 * rcRangeChars[I] Array of Character counts in each range
3172 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3173 * cRanges [I] Count of ranges
3174 * pwcChars [I] Array of characters specifying the run.
3175 * pwLogClust [I] Array of logical cluster info
3176 * pCharProps [I] Array of character property values
3177 * cChars [I] Number of characters in pwcChars.
3178 * pwGlyphs [I] Array of glyphs.
3179 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3180 * cGlyphs [I] Count of Glyphs
3181 * piAdvance [O] Array of advance widths.
3182 * pGoffset [O] Glyph offsets.
3183 * pABC [O] Combined ABC width.
3187 * Failure: Non-zero HRESULT value.
3190 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3191 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3192 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3193 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3194 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3195 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3196 int cGlyphs
, int *piAdvance
,
3197 GOFFSET
*pGoffset
, ABC
*pABC
3202 static int once
= 0;
3204 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3206 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3207 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3208 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3211 if (!pGlyphProps
) return E_INVALIDARG
;
3212 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3213 if (!pGoffset
) return E_FAIL
;
3216 if (!once
++) FIXME("Ranges not supported yet\n");
3218 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3219 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3221 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3222 for (i
= 0; i
< cGlyphs
; i
++)
3225 if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3227 if (!hdc
) return E_PENDING
;
3228 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
) && !psa
->fNoGlyphIndex
)
3230 if (!GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
)) return S_FALSE
;
3235 if (!GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
)) return S_FALSE
;
3237 abc
.abcA
= abc
.abcC
= 0;
3239 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3243 pABC
->abcA
+= abc
.abcA
;
3244 pABC
->abcB
+= abc
.abcB
;
3245 pABC
->abcC
+= abc
.abcC
;
3247 /* FIXME: set to more reasonable values */
3248 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3249 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3252 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3254 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3258 /***********************************************************************
3259 * ScriptPlace (USP10.@)
3261 * Produce advance widths for a run.
3264 * hdc [I] Device context.
3265 * psc [I/O] Opaque pointer to a script cache.
3266 * pwGlyphs [I] Array of glyphs.
3267 * cGlyphs [I] Number of glyphs in pwGlyphs.
3268 * psva [I] Array of visual attributes.
3269 * psa [I/O] String analysis.
3270 * piAdvance [O] Array of advance widths.
3271 * pGoffset [O] Glyph offsets.
3272 * pABC [O] Combined ABC width.
3276 * Failure: Non-zero HRESULT value.
3278 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3279 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3280 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3283 SCRIPT_GLYPHPROP
*glyphProps
;
3286 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3287 piAdvance
, pGoffset
, pABC
);
3289 if (!psva
) return E_INVALIDARG
;
3290 if (!pGoffset
) return E_FAIL
;
3292 glyphProps
= heap_alloc(sizeof(SCRIPT_GLYPHPROP
)*cGlyphs
);
3293 if (!glyphProps
) return E_OUTOFMEMORY
;
3295 for (i
= 0; i
< cGlyphs
; i
++)
3296 glyphProps
[i
].sva
= psva
[i
];
3298 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3300 heap_free(glyphProps
);
3305 /***********************************************************************
3306 * ScriptGetCMap (USP10.@)
3308 * Retrieve glyph indices.
3311 * hdc [I] Device context.
3312 * psc [I/O] Opaque pointer to a script cache.
3313 * pwcInChars [I] Array of Unicode characters.
3314 * cChars [I] Number of characters in pwcInChars.
3315 * dwFlags [I] Flags.
3316 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3320 * Failure: Non-zero HRESULT value.
3322 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3323 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3328 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3329 cChars
, dwFlags
, pwOutGlyphs
);
3331 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3335 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3337 for (i
= 0; i
< cChars
; i
++)
3340 if (dwFlags
== SGCM_RTL
)
3341 inChar
= mirror_char(pwcInChars
[i
]);
3343 inChar
= pwcInChars
[i
];
3344 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3347 if (!hdc
) return E_PENDING
;
3348 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3349 if (glyph
== 0xffff)
3354 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3360 TRACE("no glyph translation\n");
3361 for (i
= 0; i
< cChars
; i
++)
3364 if (dwFlags
== SGCM_RTL
)
3365 inChar
= mirror_char(pwcInChars
[i
]);
3367 inChar
= pwcInChars
[i
];
3368 pwOutGlyphs
[i
] = inChar
;
3374 /***********************************************************************
3375 * ScriptTextOut (USP10.@)
3378 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3379 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3380 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3381 const int *piJustify
, const GOFFSET
*pGoffset
)
3386 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3388 TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3389 hdc
, psc
, x
, y
, fuOptions
, lprc
, psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3390 piAdvance
, piJustify
, pGoffset
);
3392 if (!hdc
|| !psc
) return E_INVALIDARG
;
3393 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3395 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3396 fuOptions
|= ETO_IGNORELANGUAGE
;
3397 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3398 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3400 lpDx
= heap_alloc(cGlyphs
* sizeof(INT
) * 2);
3401 if (!lpDx
) return E_OUTOFMEMORY
;
3402 fuOptions
|= ETO_PDY
;
3404 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3406 reordered_glyphs
= heap_alloc( cGlyphs
* sizeof(WORD
) );
3407 if (!reordered_glyphs
)
3410 return E_OUTOFMEMORY
;
3413 for (i
= 0; i
< cGlyphs
; i
++)
3414 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3418 for (i
= 0; i
< cGlyphs
; i
++)
3420 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3421 lpDx
[i
* 2] = piAdvance
[orig_index
];
3422 lpDx
[i
* 2 + 1] = 0;
3428 x
+= pGoffset
[orig_index
].du
* dir
;
3429 y
+= pGoffset
[orig_index
].dv
;
3433 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3434 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3436 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3437 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3441 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3444 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3450 /***********************************************************************
3451 * ScriptCacheGetHeight (USP10.@)
3453 * Retrieve the height of the font in the cache.
3456 * hdc [I] Device context.
3457 * psc [I/O] Opaque pointer to a script cache.
3458 * height [O] Receives font height.
3462 * Failure: Non-zero HRESULT value.
3464 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3468 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3470 if (!height
) return E_INVALIDARG
;
3471 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3473 *height
= get_cache_height(psc
);
3477 /***********************************************************************
3478 * ScriptGetGlyphABCWidth (USP10.@)
3480 * Retrieve the width of a glyph.
3483 * hdc [I] Device context.
3484 * psc [I/O] Opaque pointer to a script cache.
3485 * glyph [I] Glyph to retrieve the width for.
3486 * abc [O] ABC widths of the glyph.
3490 * Failure: Non-zero HRESULT value.
3492 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3496 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3498 if (!abc
) return E_INVALIDARG
;
3499 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3501 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3503 if (!hdc
) return E_PENDING
;
3504 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3506 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3511 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3513 abc
->abcA
= abc
->abcC
= 0;
3515 set_cache_glyph_widths(psc
, glyph
, abc
);
3520 /***********************************************************************
3521 * ScriptLayout (USP10.@)
3523 * Map embedding levels to visual and/or logical order.
3526 * runs [I] Size of level array.
3527 * level [I] Array of embedding levels.
3528 * vistolog [O] Map of embedding levels from visual to logical order.
3529 * logtovis [O] Map of embedding levels from logical to visual order.
3533 * Failure: Non-zero HRESULT value.
3536 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3541 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3543 if (!level
|| (!vistolog
&& !logtovis
))
3544 return E_INVALIDARG
;
3546 indexs
= heap_alloc(sizeof(int) * runs
);
3548 return E_OUTOFMEMORY
;
3553 for( ich
= 0; ich
< runs
; ich
++)
3558 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3559 for (ich
= 0; ich
< runs
; ich
++)
3560 vistolog
[ich
] = indexs
[ich
];
3566 for( ich
= 0; ich
< runs
; ich
++)
3571 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3572 for (ich
= 0; ich
< runs
; ich
++)
3573 logtovis
[ich
] = indexs
[ich
];
3580 /***********************************************************************
3581 * ScriptStringGetLogicalWidths (USP10.@)
3583 * Returns logical widths from a string analysis.
3586 * ssa [I] string analysis.
3587 * piDx [O] logical widths returned.
3591 * Failure: a non-zero HRESULT.
3593 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3596 StringAnalysis
*analysis
= ssa
;
3598 TRACE("%p, %p\n", ssa
, piDx
);
3600 if (!analysis
) return S_FALSE
;
3601 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3603 for (i
= 0; i
< analysis
->numItems
; i
++)
3605 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3608 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3611 for (j
= 0; j
< cChar
; j
++)
3614 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3615 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3616 cChar
, j
, direction
, NULL
, NULL
);
3617 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
);
3619 for (k
= 0; k
< clust_size
; k
++)
3621 piDx
[next
] = advance
/ clust_size
;
3630 /***********************************************************************
3631 * ScriptStringValidate (USP10.@)
3633 * Validate a string analysis.
3636 * ssa [I] string analysis.
3640 * Failure: S_FALSE if invalid sequences are found
3641 * or a non-zero HRESULT if it fails.
3643 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3645 StringAnalysis
*analysis
= ssa
;
3647 TRACE("(%p)\n", ssa
);
3649 if (!analysis
) return E_INVALIDARG
;
3650 return (analysis
->invalid
) ? S_FALSE
: S_OK
;
3653 /***********************************************************************
3654 * ScriptString_pSize (USP10.@)
3656 * Retrieve width and height of an analysed string.
3659 * ssa [I] string analysis.
3662 * Success: Pointer to a SIZE structure.
3665 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3668 StringAnalysis
*analysis
= ssa
;
3670 TRACE("(%p)\n", ssa
);
3672 if (!analysis
) return NULL
;
3673 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return NULL
;
3677 if (!(analysis
->sz
= heap_alloc(sizeof(SIZE
)))) return NULL
;
3678 analysis
->sz
->cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3680 analysis
->sz
->cx
= 0;
3681 for (i
= 0; i
< analysis
->numItems
; i
++)
3683 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
->cy
)
3684 analysis
->sz
->cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3685 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3686 analysis
->sz
->cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3689 return analysis
->sz
;
3692 /***********************************************************************
3693 * ScriptString_pLogAttr (USP10.@)
3695 * Retrieve logical attributes of an analysed string.
3698 * ssa [I] string analysis.
3701 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3704 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3706 StringAnalysis
*analysis
= ssa
;
3708 TRACE("(%p)\n", ssa
);
3710 if (!analysis
) return NULL
;
3711 if (!(analysis
->dwFlags
& SSA_BREAK
)) return NULL
;
3712 return analysis
->logattrs
;
3715 /***********************************************************************
3716 * ScriptString_pcOutChars (USP10.@)
3718 * Retrieve the length of a string after clipping.
3721 * ssa [I] String analysis.
3724 * Success: Pointer to the length.
3727 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3729 StringAnalysis
*analysis
= ssa
;
3731 TRACE("(%p)\n", ssa
);
3733 if (!analysis
) return NULL
;
3734 return &analysis
->clip_len
;
3737 /***********************************************************************
3738 * ScriptStringGetOrder (USP10.@)
3740 * Retrieve a glyph order map.
3743 * ssa [I] String analysis.
3744 * order [I/O] Array of glyph positions.
3748 * Failure: a non-zero HRESULT.
3750 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3754 StringAnalysis
*analysis
= ssa
;
3756 TRACE("(%p)\n", ssa
);
3758 if (!analysis
) return S_FALSE
;
3759 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3761 /* FIXME: handle RTL scripts */
3762 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3763 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3769 /***********************************************************************
3770 * ScriptGetLogicalWidths (USP10.@)
3772 * Convert advance widths to logical widths.
3775 * sa [I] Script analysis.
3776 * nbchars [I] Number of characters.
3777 * nbglyphs [I] Number of glyphs.
3778 * glyph_width [I] Array of glyph widths.
3779 * log_clust [I] Array of logical clusters.
3780 * sva [I] Visual attributes.
3781 * widths [O] Array of logical widths.
3785 * Failure: a non-zero HRESULT.
3787 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3788 const int *glyph_width
, const WORD
*log_clust
,
3789 const SCRIPT_VISATTR
*sva
, int *widths
)
3793 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3794 sa
, nbchars
, nbglyphs
, glyph_width
, log_clust
, sva
, widths
);
3797 for (i
= 0; i
< nbchars
; i
++) widths
[i
] = glyph_width
[i
];
3801 /***********************************************************************
3802 * ScriptApplyLogicalWidth (USP10.@)
3804 * Generate glyph advance widths.
3807 * dx [I] Array of logical advance widths.
3808 * num_chars [I] Number of characters.
3809 * num_glyphs [I] Number of glyphs.
3810 * log_clust [I] Array of logical clusters.
3811 * sva [I] Visual attributes.
3812 * advance [I] Array of glyph advance widths.
3813 * sa [I] Script analysis.
3814 * abc [I/O] Summed ABC widths.
3815 * justify [O] Array of glyph advance widths.
3819 * Failure: a non-zero HRESULT.
3821 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
3822 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
3823 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
3824 ABC
*abc
, int *justify
)
3828 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3829 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
3831 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
3835 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
3836 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
3840 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
3842 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
3846 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
3849 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3850 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3852 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
3855 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
3858 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3859 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3861 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
3864 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
3867 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3868 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3870 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);