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 (Zero Width Space U+200B -
1311 Right-to-Left Mark U+200F) will force us into bidi mode */
1312 if (!forceLevels
&& pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F)
1315 /* Diacritical marks merge with other scripts */
1316 if (scripts
[i
] == Script_Diacritical
)
1321 scripts
[i
] = scripts
[i
-1];
1326 WORD first_script
= scripts
[i
-1];
1327 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1329 WORD original
= scripts
[j
];
1330 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1335 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1337 scripts
[j
] = scripts
[i
];
1338 if (original
== Script_Punctuation2
)
1341 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1342 scripts
[i
] = scripts
[j
];
1348 for (i
= 0; i
< cInChars
; i
++)
1350 /* Joiners get merged preferencially right */
1351 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1354 if (i
+1 == cInChars
)
1355 scripts
[i
] = scripts
[i
-1];
1358 for (j
= i
+1; j
< cInChars
; j
++)
1360 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1362 scripts
[i
] = scripts
[j
];
1370 if (psState
&& psControl
)
1372 levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1376 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
);
1377 baselevel
= levels
[0];
1378 for (i
= 0; i
< cInChars
; i
++)
1379 if (levels
[i
]!=levels
[0])
1381 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1388 BOOL inNumber
= FALSE
;
1389 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1391 strength
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1394 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1396 /* We currently mis-level leading Diacriticals */
1397 if (scripts
[0] == Script_Diacritical
)
1398 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1400 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1401 strength
[i
] = BIDI_STRONG
;
1404 for (i
= 0; i
< cInChars
; i
++)
1406 /* Script_Numeric and select puncuation at level 0 get bumped to level 2 */
1407 if ((levels
[i
] == 0 || (odd(psState
->uBidiLevel
) && levels
[i
] == psState
->uBidiLevel
+1)) && inNumber
&& strchrW(math_punc
,pwcInChars
[i
]))
1409 scripts
[i
] = Script_Numeric
;
1412 else if ((levels
[i
] == 0 || (odd(psState
->uBidiLevel
) && levels
[i
] == psState
->uBidiLevel
+1)) && scripts
[i
] == Script_Numeric
)
1420 /* Joiners get merged preferencially right */
1421 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1424 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1425 strength
[i
] = strength
[i
-1];
1427 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1428 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1430 strength
[i
] = strength
[j
];
1435 if (psControl
->fMergeNeutralItems
)
1437 /* Merge the neutrals */
1438 for (i
= 0; i
< cInChars
; i
++)
1440 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1443 for (j
= i
; j
> 0; j
--)
1445 if (levels
[i
] != levels
[j
])
1447 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1449 scripts
[i
] = scripts
[j
];
1450 strength
[i
] = strength
[j
];
1455 /* Try going the other way */
1456 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1459 for (j
= i
; j
< cInChars
; j
++)
1461 if (levels
[i
] != levels
[j
])
1463 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1465 scripts
[i
] = scripts
[j
];
1466 strength
[i
] = strength
[j
];
1476 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1477 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1480 if (cnt
== cInChars
) /* All Spaces */
1483 New_Script
= scripts
[cnt
];
1486 pItems
[index
].iCharPos
= 0;
1487 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1489 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1491 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1492 str
= strength
[cnt
];
1500 if (strength
[cnt
] == BIDI_STRONG
)
1501 layoutRTL
= (odd(levels
[cnt
]))?1:0;
1503 layoutRTL
= (psState
->uBidiLevel
|| odd(levels
[cnt
]))?1:0;
1504 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1505 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1506 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1508 else if (!pItems
[index
].a
.s
.uBidiLevel
)
1510 layoutRTL
= (odd(baselevel
))?1:0;
1511 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1512 pItems
[index
].a
.fLayoutRTL
= odd(baselevel
);
1513 pItems
[index
].a
.fRTL
= odd(baselevel
);
1516 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1517 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1518 pItems
[index
].iCharPos
);
1520 for (cnt
=1; cnt
< cInChars
; cnt
++)
1522 if(pwcInChars
[cnt
] != Numeric_space
)
1523 New_Script
= scripts
[cnt
];
1527 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1529 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1530 New_Script
= scripts
[cnt
+j
];
1532 New_Script
= scripts
[cnt
];
1536 /* merge space strengths*/
1537 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1540 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1543 /* changes in level */
1544 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1546 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1549 /* changes in strength */
1550 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1552 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1555 /* changes in script */
1556 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1558 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1562 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1564 layoutRTL
= odd(levels
[cnt
])?1:0;
1565 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1570 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
);
1573 if (index
+1 > cMaxItems
)
1577 str
= strength
[cnt
];
1579 pItems
[index
].iCharPos
= cnt
;
1580 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1582 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1584 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1587 if (levels
[cnt
] == 0)
1590 layoutRTL
= (layoutRTL
|| odd(levels
[cnt
]))?1:0;
1591 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1592 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1593 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1595 else if (!pItems
[index
].a
.s
.uBidiLevel
)
1597 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1598 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1599 pItems
[index
].a
.fRTL
= odd(baselevel
);
1602 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1606 /* While not strictly necessary according to the spec, make sure the n+1
1607 * item is set up to prevent random behaviour if the caller erroneously
1608 * checks the n+1 structure */
1610 if (index
+ 1 > cMaxItems
) goto nomemory
;
1611 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1613 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1615 /* Set one SCRIPT_STATE item being returned */
1616 if (pcItems
) *pcItems
= index
;
1618 /* Set SCRIPT_ITEM */
1619 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1623 heap_free(strength
);
1628 /***********************************************************************
1629 * ScriptItemizeOpenType (USP10.@)
1631 * Split a Unicode string into shapeable parts.
1634 * pwcInChars [I] String to split.
1635 * cInChars [I] Number of characters in pwcInChars.
1636 * cMaxItems [I] Maximum number of items to return.
1637 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1638 * psState [I] Pointer to a SCRIPT_STATE structure.
1639 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1640 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1641 * pcItems [O] Number of script items returned.
1645 * Failure: Non-zero HRESULT value.
1647 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1648 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1649 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1651 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1654 /***********************************************************************
1655 * ScriptItemize (USP10.@)
1657 * Split a Unicode string into shapeable parts.
1660 * pwcInChars [I] String to split.
1661 * cInChars [I] Number of characters in pwcInChars.
1662 * cMaxItems [I] Maximum number of items to return.
1663 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1664 * psState [I] Pointer to a SCRIPT_STATE structure.
1665 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1666 * pcItems [O] Number of script items returned.
1670 * Failure: Non-zero HRESULT value.
1672 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1673 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1674 SCRIPT_ITEM
*pItems
, int *pcItems
)
1676 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1679 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1683 INT
*lpTabPos
= NULL
;
1688 lpTabPos
= pTabdef
->pTabStops
;
1690 if (pTabdef
&& pTabdef
->iTabOrigin
)
1692 if (pTabdef
->iScale
)
1693 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1695 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1699 cTabStops
= pTabdef
->cTabStops
;
1703 if (pTabdef
->iScale
)
1704 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1706 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1710 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1712 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1714 int position
= *lpTabPos
;
1716 position
= -1 * position
;
1717 if (pTabdef
->iScale
)
1718 position
= (position
* pTabdef
->iScale
) / 4;
1720 position
= position
* psc
->tm
.tmAveCharWidth
;
1722 if( nTabOrg
+ position
> current_x
)
1726 /* a left aligned tab */
1727 x
= (nTabOrg
+ *lpTabPos
) - current_x
;
1732 FIXME("Negative tabstop\n");
1737 if ((!cTabStops
) && (defWidth
> 0))
1738 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1739 else if ((!cTabStops
) && (defWidth
< 0))
1740 FIXME("TODO: Negative defWidth\n");
1745 /***********************************************************************
1746 * Helper function for ScriptStringAnalyse
1748 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1749 const WCHAR
*pwcInChars
, int cChars
)
1751 /* FIXME: When to properly fallback is still a bit of a mystery */
1754 if (psa
->fNoGlyphIndex
)
1757 if (init_script_cache(hdc
, psc
) != S_OK
)
1760 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1763 glyphs
= heap_alloc(sizeof(WORD
) * cChars
);
1766 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1776 static void find_fallback_font(DWORD scriptid
, LPWSTR FaceName
)
1780 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1782 static const WCHAR szFmt
[] = {'%','x',0};
1784 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1787 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1788 if (RegQueryValueExW(hkey
, value
, 0, &type
, (LPBYTE
)FaceName
, &count
))
1789 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1793 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1796 /***********************************************************************
1797 * ScriptStringAnalyse (USP10.@)
1800 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1801 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1802 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1803 SCRIPT_STATE
*psState
, const int *piDx
,
1804 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1805 SCRIPT_STRING_ANALYSIS
*pssa
)
1807 HRESULT hr
= E_OUTOFMEMORY
;
1808 StringAnalysis
*analysis
= NULL
;
1809 SCRIPT_CONTROL sControl
;
1810 SCRIPT_STATE sState
;
1811 int i
, num_items
= 255;
1813 WCHAR
*iString
= NULL
;
1815 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1816 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1817 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
1821 FIXME("Only Unicode strings are supported\n");
1822 return E_INVALIDARG
;
1824 if (cString
< 1 || !pString
) return E_INVALIDARG
;
1825 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
1827 if (!(analysis
= heap_alloc_zero(sizeof(StringAnalysis
)))) return E_OUTOFMEMORY
;
1828 if (!(analysis
->pItem
= heap_alloc_zero(num_items
* sizeof(SCRIPT_ITEM
) + 1))) goto error
;
1830 /* FIXME: handle clipping */
1831 analysis
->clip_len
= cString
;
1832 analysis
->hdc
= hdc
;
1833 analysis
->dwFlags
= dwFlags
;
1838 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
1841 sControl
= *psControl
;
1843 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
1845 if (dwFlags
& SSA_PASSWORD
)
1847 iString
= heap_alloc(sizeof(WCHAR
)*cString
);
1853 for (i
= 0; i
< cString
; i
++)
1854 iString
[i
] = *((const WCHAR
*)pString
);
1858 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
1859 &analysis
->numItems
);
1863 if (hr
== E_OUTOFMEMORY
)
1868 /* set back to out of memory for default goto error behaviour */
1871 if (dwFlags
& SSA_BREAK
)
1873 if ((analysis
->logattrs
= heap_alloc(sizeof(SCRIPT_LOGATTR
) * cString
)))
1875 for (i
= 0; i
< analysis
->numItems
; i
++)
1876 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
]);
1882 if (!(analysis
->logical2visual
= heap_alloc_zero(sizeof(int) * analysis
->numItems
)))
1884 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
1887 if (dwFlags
& SSA_GLYPHS
)
1890 if (!(analysis
->glyphs
= heap_alloc_zero(sizeof(StringGlyphs
) * analysis
->numItems
)))
1892 heap_free(BidiLevel
);
1896 for (i
= 0; i
< analysis
->numItems
; i
++)
1898 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
1899 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
1900 int numGlyphs
= 1.5 * cChar
+ 16;
1901 WORD
*glyphs
= heap_alloc_zero(sizeof(WORD
) * numGlyphs
);
1902 WORD
*pwLogClust
= heap_alloc_zero(sizeof(WORD
) * cChar
);
1903 int *piAdvance
= heap_alloc_zero(sizeof(int) * numGlyphs
);
1904 SCRIPT_VISATTR
*psva
= heap_alloc_zero(sizeof(SCRIPT_VISATTR
) * numGlyphs
);
1905 GOFFSET
*pGoffset
= heap_alloc_zero(sizeof(GOFFSET
) * numGlyphs
);
1906 ABC
*abc
= heap_alloc_zero(sizeof(ABC
));
1907 int numGlyphsReturned
;
1908 HFONT originalFont
= 0x0;
1910 /* FIXME: non unicode strings */
1911 const WCHAR
* pStr
= (const WCHAR
*)pString
;
1912 analysis
->glyphs
[i
].fallbackFont
= NULL
;
1914 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
|| !abc
)
1916 heap_free (BidiLevel
);
1918 heap_free (pwLogClust
);
1919 heap_free (piAdvance
);
1921 heap_free (pGoffset
);
1927 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
1930 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
1931 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
1932 lf
.lfFaceName
[0] = 0;
1933 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
1934 if (lf
.lfFaceName
[0])
1936 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
1937 if (analysis
->glyphs
[i
].fallbackFont
)
1939 ScriptFreeCache(sc
);
1940 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
1945 /* FIXME: When we properly shape Hangul remove this check */
1946 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
1947 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
1949 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
1950 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
1952 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
1953 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
1954 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
1955 piAdvance
, pGoffset
, abc
);
1957 SelectObject(hdc
,originalFont
);
1959 if (dwFlags
& SSA_TAB
)
1962 for (tabi
= 0; tabi
< cChar
; tabi
++)
1964 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
1965 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
1966 tab_x
+=piAdvance
[tabi
];
1970 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
1971 analysis
->glyphs
[i
].glyphs
= glyphs
;
1972 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
1973 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
1974 analysis
->glyphs
[i
].psva
= psva
;
1975 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
1976 analysis
->glyphs
[i
].abc
= abc
;
1977 analysis
->glyphs
[i
].iMaxPosX
= -1;
1979 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
1984 for (i
= 0; i
< analysis
->numItems
; i
++)
1985 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
1988 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
1989 heap_free(BidiLevel
);
1997 heap_free(analysis
->glyphs
);
1998 heap_free(analysis
->logattrs
);
1999 heap_free(analysis
->pItem
);
2000 heap_free(analysis
->logical2visual
);
2001 heap_free(analysis
);
2005 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2007 if (pva
[glyph
].fClusterStart
)
2009 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2016 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2027 StringAnalysis
*analysis
;
2030 COLORREF BkColor
= 0x0;
2031 COLORREF TextColor
= 0x0;
2033 INT runStart
, runEnd
;
2034 INT iGlyph
, cGlyphs
;
2035 HFONT oldFont
= 0x0;
2039 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2040 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2042 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2044 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2045 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2051 BkMode
= GetBkMode(analysis
->hdc
);
2052 SetBkMode( analysis
->hdc
, OPAQUE
);
2053 BkColor
= GetBkColor(analysis
->hdc
);
2054 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2057 TextColor
= GetTextColor(analysis
->hdc
);
2058 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2061 if (analysis
->glyphs
[iItem
].fallbackFont
)
2062 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2064 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2065 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2068 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2069 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2071 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2073 if (analysis
->pItem
[iItem
].a
.fRTL
)
2075 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2076 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2078 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2079 crc
.left
= iX
+ off_x
;
2083 if (cStart
>=0 && runStart
)
2084 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2086 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2087 crc
.left
= iX
+ off_x
;
2090 if (analysis
->pItem
[iItem
].a
.fRTL
)
2091 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2093 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2095 if (analysis
->pItem
[iItem
].a
.fRTL
)
2096 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2098 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2102 /* adjust for cluster glyphs when starting */
2103 if (analysis
->pItem
[iItem
].a
.fRTL
)
2104 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2106 i
= analysis
->pItem
[iItem
].iCharPos
;
2108 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2110 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2112 if (analysis
->pItem
[iItem
].a
.fRTL
)
2113 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2115 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2120 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2125 clust_glyph
= iGlyph
+ cGlyphs
;
2126 if (analysis
->pItem
[iItem
].a
.fRTL
)
2131 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2132 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2139 hr
= ScriptTextOut(analysis
->hdc
,
2140 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2141 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2142 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2143 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2144 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2146 TRACE("ScriptTextOut hr=%08x\n", hr
);
2150 SetBkColor(analysis
->hdc
, BkColor
);
2151 SetBkMode( analysis
->hdc
, BkMode
);
2153 SetTextColor(analysis
->hdc
, TextColor
);
2155 if (analysis
->glyphs
[iItem
].fallbackFont
)
2156 SelectObject(analysis
->hdc
, oldFont
);
2161 /***********************************************************************
2162 * ScriptStringOut (USP10.@)
2164 * This function takes the output of ScriptStringAnalyse and joins the segments
2165 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2166 * only processes glyphs.
2169 * ssa [I] buffer to hold the analysed string components
2170 * iX [I] X axis displacement for output
2171 * iY [I] Y axis displacement for output
2172 * uOptions [I] flags controlling output processing
2173 * prc [I] rectangle coordinates
2174 * iMinSel [I] starting pos for substringing output string
2175 * iMaxSel [I] ending pos for substringing output string
2176 * fDisabled [I] controls text highlighting
2180 * Failure: is the value returned by ScriptTextOut
2182 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2191 StringAnalysis
*analysis
;
2195 TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
2196 ssa
, iX
, iY
, uOptions
, prc
, iMinSel
, iMaxSel
, fDisabled
);
2198 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2199 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2201 for (item
= 0; item
< analysis
->numItems
; item
++)
2203 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2208 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2210 if (iMaxSel
> 0 && iMinSel
< 0)
2212 for (item
= 0; item
< analysis
->numItems
; item
++)
2214 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2223 /***********************************************************************
2224 * ScriptStringCPtoX (USP10.@)
2227 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2231 StringAnalysis
* analysis
= ssa
;
2233 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2235 if (!ssa
|| !pX
) return S_FALSE
;
2236 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2238 /* icp out of range */
2241 analysis
->invalid
= TRUE
;
2242 return E_INVALIDARG
;
2245 for(item
=0; item
<analysis
->numItems
; item
++)
2250 i
= analysis
->logical2visual
[item
];
2251 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2252 /* initialize max extents for uninitialized runs */
2253 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2255 if (analysis
->pItem
[i
].a
.fRTL
)
2256 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2257 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2258 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2260 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2261 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2262 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2265 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2267 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2271 icp
-= analysis
->pItem
[i
].iCharPos
;
2272 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2273 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2274 &analysis
->pItem
[i
].a
, &offset
);
2281 /* icp out of range */
2282 analysis
->invalid
= TRUE
;
2283 return E_INVALIDARG
;
2286 /***********************************************************************
2287 * ScriptStringXtoCP (USP10.@)
2290 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2292 StringAnalysis
* analysis
= ssa
;
2295 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2297 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2298 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2303 if (analysis
->pItem
[0].a
.fRTL
)
2306 *piTrailing
= FALSE
;
2316 for(item
=0; item
<analysis
->numItems
; item
++)
2321 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2324 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2325 /* initialize max extents for uninitialized runs */
2326 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2328 if (analysis
->pItem
[i
].a
.fRTL
)
2329 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2330 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2331 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2333 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2334 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2335 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2338 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2340 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2344 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2345 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2346 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2347 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2353 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2354 *piTrailing
= FALSE
;
2360 /***********************************************************************
2361 * ScriptStringFree (USP10.@)
2363 * Free a string analysis.
2366 * pssa [I] string analysis.
2370 * Failure: Non-zero HRESULT value.
2372 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2374 StringAnalysis
* analysis
;
2378 TRACE("(%p)\n", pssa
);
2380 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2382 invalid
= analysis
->invalid
;
2384 if (analysis
->glyphs
)
2386 for (i
= 0; i
< analysis
->numItems
; i
++)
2388 heap_free(analysis
->glyphs
[i
].glyphs
);
2389 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2390 heap_free(analysis
->glyphs
[i
].piAdvance
);
2391 heap_free(analysis
->glyphs
[i
].psva
);
2392 heap_free(analysis
->glyphs
[i
].pGoffset
);
2393 heap_free(analysis
->glyphs
[i
].abc
);
2394 if (analysis
->glyphs
[i
].fallbackFont
)
2395 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2396 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2397 heap_free(analysis
->glyphs
[i
].sc
);
2399 heap_free(analysis
->glyphs
);
2402 heap_free(analysis
->pItem
);
2403 heap_free(analysis
->logattrs
);
2404 heap_free(analysis
->sz
);
2405 heap_free(analysis
->logical2visual
);
2406 heap_free(analysis
);
2408 if (invalid
) return E_INVALIDARG
;
2412 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2413 int direction
, int* iCluster
, int *check_out
)
2417 WORD clust
= pwLogClust
[item
];
2419 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2421 if (pwLogClust
[check
] == clust
)
2424 if (iCluster
&& *iCluster
== -1)
2436 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
)
2441 advance
= piAdvance
[glyph
];
2443 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2444 log_clust_max
= pwLogClust
[0];
2446 log_clust_max
= pwLogClust
[cChars
-1];
2448 if (glyph
> log_clust_max
)
2451 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2454 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2456 if (glyph
> log_clust_max
)
2458 advance
+= piAdvance
[glyph
];
2464 /***********************************************************************
2465 * ScriptCPtoX (USP10.@)
2468 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2472 const WORD
*pwLogClust
,
2473 const SCRIPT_VISATTR
*psva
,
2474 const int *piAdvance
,
2475 const SCRIPT_ANALYSIS
*psa
,
2483 float special_size
= 0.0;
2488 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2489 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2492 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2500 int max_clust
= pwLogClust
[0];
2502 for (item
=0; item
< cGlyphs
; item
++)
2503 if (pwLogClust
[item
] > max_clust
)
2505 ERR("We do not handle non reversed clusters properly\n");
2510 for (item
= max_clust
; item
>=0; item
--)
2511 iMaxPos
+= piAdvance
[item
];
2515 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2517 if (iSpecial
== -1 && (iCluster
== -1 || (iCluster
!= -1 && iCluster
+clust_size
<= item
)))
2520 int clust
= pwLogClust
[item
];
2523 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2526 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2528 if (check
>= cChars
&& !iMaxPos
)
2531 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2532 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2534 special_size
/= (cChars
- item
);
2535 iPosX
+= special_size
;
2539 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2542 if (clust_size
== 0)
2546 iPosX
+= advance
/ (float)clust_size
;
2549 else if (iSpecial
!= -1)
2550 iPosX
+= special_size
;
2551 else /* (iCluster != -1) */
2553 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2554 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2557 if (clust_size
== 0)
2561 iPosX
+= adv
/ (float)clust_size
;
2567 iPosX
= iMaxPos
- iPosX
;
2573 TRACE("*piX=%d\n", *piX
);
2577 /* Count the number of characters in a cluster and its starting index*/
2578 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2583 for (i
= 0; i
< cChars
; i
++)
2585 if (pwLogClust
[i
] == cluster_index
)
2587 if (!size
&& start_index
)
2595 else if (size
) break;
2598 *cluster_size
= size
;
2604 To handle multi-glyph clusters we need to find all the glyphs that are
2605 represented in the cluster. This involves finding the glyph whose
2606 index is the cluster index as well as whose glyph indices are greater than
2607 our cluster index but not part of a new cluster.
2609 Then we sum all those glyphs' advances.
2611 static inline int get_cluster_advance(const int* piAdvance
,
2612 const SCRIPT_VISATTR
*psva
,
2613 const WORD
*pwLogClust
, int cGlyphs
,
2614 int cChars
, int cluster
, int direction
)
2625 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2627 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2628 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2629 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2634 glyph_end
= cGlyphs
;
2637 /* Don't fully understand multi-glyph reversed clusters yet,
2638 * do they occur for real or just in our test? */
2639 FIXME("multi-glyph reversed clusters found\n");
2640 glyph_end
= glyph_start
+ 1;
2644 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2645 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2647 if (psva
[i
].fClusterStart
)
2654 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2655 advance
+= piAdvance
[i
];
2661 /***********************************************************************
2662 * ScriptXtoCP (USP10.@)
2665 * use piAdvance to find the cluster we are looking at
2666 * Find the character that is the first character of the cluster
2667 * That is our base piCP
2668 * If the script snaps to cluster boundries (Hebrew, Indic, Thai) then we
2669 * are good Otherwise if the cluster is larger than 1 glyph we need to
2670 * determine how far through the cluster to advance the cursor.
2672 HRESULT WINAPI
ScriptXtoCP(int iX
,
2675 const WORD
*pwLogClust
,
2676 const SCRIPT_VISATTR
*psva
,
2677 const int *piAdvance
,
2678 const SCRIPT_ANALYSIS
*psa
,
2685 int glyph_index
, cluster_index
;
2688 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2689 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2690 psa
, piCP
, piTrailing
);
2692 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2695 /* Handle an iX < 0 */
2711 /* Looking for non-reversed clusters in a reversed string */
2714 int max_clust
= pwLogClust
[0];
2715 for (i
=0; i
< cChars
; i
++)
2716 if (pwLogClust
[i
] > max_clust
)
2718 FIXME("We do not handle non reversed clusters properly\n");
2723 /* find the glyph_index based in iX */
2726 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2731 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2735 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2738 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2740 /* find the cluster */
2742 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2745 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2748 TRACE("cluster_index %i\n", cluster_index
);
2750 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2752 /* We are off the end of the string */
2758 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2760 TRACE("first char index %i\n",i
);
2761 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2763 /* Check trailing */
2764 if (glyph_index
!= cluster_index
||
2765 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2766 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2767 *piTrailing
= cluster_size
;
2771 if (cluster_size
> 1)
2773 /* Be part way through the glyph cluster based on size and position */
2774 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2775 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2779 /* back up to the beginning of the cluster */
2780 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2781 adv
+= piAdvance
[part_index
];
2782 if (adv
> iX
) adv
= iX
;
2784 TRACE("Multi-char cluster, no snap\n");
2785 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2786 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2789 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2791 if (part_index
) part_index
--;
2795 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2797 if (part_index
> cluster_size
)
2799 adv
+= cluster_part_width
;
2800 part_index
=cluster_size
;
2804 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2809 i
+= (cluster_size
- part_index
);
2811 /* Check trailing */
2812 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2813 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2818 /* Check trailing */
2819 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2820 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2827 TRACE("Point falls outside of string\n");
2828 if (glyph_index
< 0)
2830 else /* (glyph_index >= cGlyphs) */
2833 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2834 point flow to the next character */
2837 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
2846 TRACE("*piCP=%d\n", *piCP
);
2847 TRACE("*piTrailing=%d\n", *piTrailing
);
2851 /***********************************************************************
2852 * ScriptBreak (USP10.@)
2854 * Retrieve line break information.
2857 * chars [I] Array of characters.
2858 * sa [I] String analysis.
2859 * la [I] Array of logical attribute structures.
2865 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
2867 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
2869 if (count
< 0 || !la
) return E_INVALIDARG
;
2870 if (count
== 0) return E_FAIL
;
2872 BREAK_line(chars
, count
, sa
, la
);
2877 /***********************************************************************
2878 * ScriptIsComplex (USP10.@)
2880 * Determine if a string is complex.
2883 * chars [I] Array of characters to test.
2884 * len [I] Length in characters.
2892 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
2897 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
2899 for (i
= 0; i
< len
; i
+=consumed
)
2905 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
2908 script
= get_char_script(chars
,i
,len
, &consumed
);
2909 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
2910 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
2916 /***********************************************************************
2917 * ScriptShapeOpenType (USP10.@)
2919 * Produce glyphs and visual attributes for a run.
2922 * hdc [I] Device context.
2923 * psc [I/O] Opaque pointer to a script cache.
2924 * psa [I/O] Script analysis.
2925 * tagScript [I] The OpenType tag for the Script
2926 * tagLangSys [I] The OpenType tag for the Language
2927 * rcRangeChars[I] Array of Character counts in each range
2928 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2929 * cRanges [I] Count of ranges
2930 * pwcChars [I] Array of characters specifying the run.
2931 * cChars [I] Number of characters in pwcChars.
2932 * cMaxGlyphs [I] Length of pwOutGlyphs.
2933 * pwLogClust [O] Array of logical cluster info.
2934 * pCharProps [O] Array of character property values
2935 * pwOutGlyphs [O] Array of glyphs.
2936 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
2937 * pcGlyphs [O] Number of glyphs returned.
2941 * Failure: Non-zero HRESULT value.
2943 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
2944 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
2945 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
2946 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
2947 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
2948 int cMaxGlyphs
, WORD
*pwLogClust
,
2949 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
2950 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
2957 static int once
= 0;
2959 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
2961 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
2962 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
2963 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
2965 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
2966 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
2968 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
2969 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
2972 if(!once
++) FIXME("Ranges not supported yet\n");
2974 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
2977 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
2978 if (!pwLogClust
) return E_FAIL
;
2980 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
2981 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
2983 /* set fNoGlyphIndex non truetype/opentype fonts */
2984 if (psa
&& !psa
->fNoGlyphIndex
&& !((ScriptCache
*)*psc
)->sfnt
)
2985 psa
->fNoGlyphIndex
= TRUE
;
2987 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
2988 for (i
= 0; i
< cChars
; i
++)
2991 if (rtl
) idx
= cChars
- 1 - i
;
2992 /* FIXME: set to better values */
2993 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
2994 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
2995 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
2996 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
2997 pOutGlyphProps
[i
].sva
.fReserved
= 0;
2998 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3000 /* FIXME: have the shaping engine set this */
3001 pCharProps
[i
].fCanGlyphAlone
= 0;
3003 pwLogClust
[i
] = idx
;
3006 if (psa
&& !psa
->fNoGlyphIndex
)
3009 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3011 rChars
= heap_alloc(sizeof(WCHAR
) * cChars
);
3012 if (!rChars
) return E_OUTOFMEMORY
;
3013 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3018 if (rtl
) idx
= cChars
- 1 - i
;
3021 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3025 chInput
= mirror_char(pwcChars
[idx
]);
3027 chInput
= pwcChars
[idx
];
3028 /* special case for tabs */
3029 if (chInput
== 0x0009)
3031 rChars
[i
] = chInput
;
3035 rChars
[i
] = pwcChars
[idx
];
3036 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3039 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3047 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3052 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3060 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3061 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3067 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3068 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3069 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3074 TRACE("no glyph translation\n");
3075 for (i
= 0; i
< cChars
; i
++)
3078 /* No mirroring done here */
3079 if (rtl
) idx
= cChars
- 1 - i
;
3080 pwOutGlyphs
[i
] = pwcChars
[idx
];
3082 /* overwrite some basic control glyphs to blank */
3083 if (psa
&& psa
->eScript
== Script_Control
&&
3084 pwcChars
[idx
] < ((ScriptCache
*)*psc
)->tm
.tmFirstChar
)
3086 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3087 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3088 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3097 /***********************************************************************
3098 * ScriptShape (USP10.@)
3100 * Produce glyphs and visual attributes for a run.
3103 * hdc [I] Device context.
3104 * psc [I/O] Opaque pointer to a script cache.
3105 * pwcChars [I] Array of characters specifying the run.
3106 * cChars [I] Number of characters in pwcChars.
3107 * cMaxGlyphs [I] Length of pwOutGlyphs.
3108 * psa [I/O] Script analysis.
3109 * pwOutGlyphs [O] Array of glyphs.
3110 * pwLogClust [O] Array of logical cluster info.
3111 * psva [O] Array of visual attributes.
3112 * pcGlyphs [O] Number of glyphs returned.
3116 * Failure: Non-zero HRESULT value.
3118 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3119 int cChars
, int cMaxGlyphs
,
3120 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3121 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3125 SCRIPT_CHARPROP
*charProps
;
3126 SCRIPT_GLYPHPROP
*glyphProps
;
3128 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3129 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3131 charProps
= heap_alloc_zero(sizeof(SCRIPT_CHARPROP
)*cChars
);
3132 if (!charProps
) return E_OUTOFMEMORY
;
3133 glyphProps
= heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP
)*cMaxGlyphs
);
3136 heap_free(charProps
);
3137 return E_OUTOFMEMORY
;
3140 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3144 for (i
= 0; i
< *pcGlyphs
; i
++)
3145 psva
[i
] = glyphProps
[i
].sva
;
3148 heap_free(charProps
);
3149 heap_free(glyphProps
);
3154 /***********************************************************************
3155 * ScriptPlaceOpenType (USP10.@)
3157 * Produce advance widths for a run.
3160 * hdc [I] Device context.
3161 * psc [I/O] Opaque pointer to a script cache.
3162 * psa [I/O] String analysis.
3163 * tagScript [I] The OpenType tag for the Script
3164 * tagLangSys [I] The OpenType tag for the Language
3165 * rcRangeChars[I] Array of Character counts in each range
3166 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3167 * cRanges [I] Count of ranges
3168 * pwcChars [I] Array of characters specifying the run.
3169 * pwLogClust [I] Array of logical cluster info
3170 * pCharProps [I] Array of character property values
3171 * cChars [I] Number of characters in pwcChars.
3172 * pwGlyphs [I] Array of glyphs.
3173 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3174 * cGlyphs [I] Count of Glyphs
3175 * piAdvance [O] Array of advance widths.
3176 * pGoffset [O] Glyph offsets.
3177 * pABC [O] Combined ABC width.
3181 * Failure: Non-zero HRESULT value.
3184 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3185 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3186 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3187 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3188 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3189 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3190 int cGlyphs
, int *piAdvance
,
3191 GOFFSET
*pGoffset
, ABC
*pABC
3196 static int once
= 0;
3198 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3200 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3201 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3202 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3205 if (!pGlyphProps
) return E_INVALIDARG
;
3206 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3207 if (!pGoffset
) return E_FAIL
;
3210 if (!once
++) FIXME("Ranges not supported yet\n");
3212 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3213 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3215 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3216 for (i
= 0; i
< cGlyphs
; i
++)
3219 if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3221 if (!hdc
) return E_PENDING
;
3222 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
) && !psa
->fNoGlyphIndex
)
3224 if (!GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
)) return S_FALSE
;
3229 if (!GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
)) return S_FALSE
;
3231 abc
.abcA
= abc
.abcC
= 0;
3233 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3237 pABC
->abcA
+= abc
.abcA
;
3238 pABC
->abcB
+= abc
.abcB
;
3239 pABC
->abcC
+= abc
.abcC
;
3241 /* FIXME: set to more reasonable values */
3242 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3243 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3246 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3248 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3252 /***********************************************************************
3253 * ScriptPlace (USP10.@)
3255 * Produce advance widths for a run.
3258 * hdc [I] Device context.
3259 * psc [I/O] Opaque pointer to a script cache.
3260 * pwGlyphs [I] Array of glyphs.
3261 * cGlyphs [I] Number of glyphs in pwGlyphs.
3262 * psva [I] Array of visual attributes.
3263 * psa [I/O] String analysis.
3264 * piAdvance [O] Array of advance widths.
3265 * pGoffset [O] Glyph offsets.
3266 * pABC [O] Combined ABC width.
3270 * Failure: Non-zero HRESULT value.
3272 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3273 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3274 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3277 SCRIPT_GLYPHPROP
*glyphProps
;
3280 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3281 piAdvance
, pGoffset
, pABC
);
3283 if (!psva
) return E_INVALIDARG
;
3284 if (!pGoffset
) return E_FAIL
;
3286 glyphProps
= heap_alloc(sizeof(SCRIPT_GLYPHPROP
)*cGlyphs
);
3287 if (!glyphProps
) return E_OUTOFMEMORY
;
3289 for (i
= 0; i
< cGlyphs
; i
++)
3290 glyphProps
[i
].sva
= psva
[i
];
3292 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3294 heap_free(glyphProps
);
3299 /***********************************************************************
3300 * ScriptGetCMap (USP10.@)
3302 * Retrieve glyph indices.
3305 * hdc [I] Device context.
3306 * psc [I/O] Opaque pointer to a script cache.
3307 * pwcInChars [I] Array of Unicode characters.
3308 * cChars [I] Number of characters in pwcInChars.
3309 * dwFlags [I] Flags.
3310 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3314 * Failure: Non-zero HRESULT value.
3316 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3317 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3322 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3323 cChars
, dwFlags
, pwOutGlyphs
);
3325 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3329 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3331 for (i
= 0; i
< cChars
; i
++)
3334 if (dwFlags
== SGCM_RTL
)
3335 inChar
= mirror_char(pwcInChars
[i
]);
3337 inChar
= pwcInChars
[i
];
3338 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3341 if (!hdc
) return E_PENDING
;
3342 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3343 if (glyph
== 0xffff)
3348 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3354 TRACE("no glyph translation\n");
3355 for (i
= 0; i
< cChars
; i
++)
3358 if (dwFlags
== SGCM_RTL
)
3359 inChar
= mirror_char(pwcInChars
[i
]);
3361 inChar
= pwcInChars
[i
];
3362 pwOutGlyphs
[i
] = inChar
;
3368 /***********************************************************************
3369 * ScriptTextOut (USP10.@)
3372 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3373 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3374 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3375 const int *piJustify
, const GOFFSET
*pGoffset
)
3380 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3382 TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3383 hdc
, psc
, x
, y
, fuOptions
, lprc
, psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3384 piAdvance
, piJustify
, pGoffset
);
3386 if (!hdc
|| !psc
) return E_INVALIDARG
;
3387 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3389 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3390 fuOptions
|= ETO_IGNORELANGUAGE
;
3391 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3392 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3394 lpDx
= heap_alloc(cGlyphs
* sizeof(INT
) * 2);
3395 if (!lpDx
) return E_OUTOFMEMORY
;
3396 fuOptions
|= ETO_PDY
;
3398 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3400 reordered_glyphs
= heap_alloc( cGlyphs
* sizeof(WORD
) );
3401 if (!reordered_glyphs
)
3404 return E_OUTOFMEMORY
;
3407 for (i
= 0; i
< cGlyphs
; i
++)
3408 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3412 for (i
= 0; i
< cGlyphs
; i
++)
3414 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3415 lpDx
[i
* 2] = piAdvance
[orig_index
];
3416 lpDx
[i
* 2 + 1] = 0;
3422 x
+= pGoffset
[orig_index
].du
* dir
;
3423 y
+= pGoffset
[orig_index
].dv
;
3427 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3428 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3430 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3431 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3435 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3438 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3444 /***********************************************************************
3445 * ScriptCacheGetHeight (USP10.@)
3447 * Retrieve the height of the font in the cache.
3450 * hdc [I] Device context.
3451 * psc [I/O] Opaque pointer to a script cache.
3452 * height [O] Receives font height.
3456 * Failure: Non-zero HRESULT value.
3458 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3462 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3464 if (!height
) return E_INVALIDARG
;
3465 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3467 *height
= get_cache_height(psc
);
3471 /***********************************************************************
3472 * ScriptGetGlyphABCWidth (USP10.@)
3474 * Retrieve the width of a glyph.
3477 * hdc [I] Device context.
3478 * psc [I/O] Opaque pointer to a script cache.
3479 * glyph [I] Glyph to retrieve the width for.
3480 * abc [O] ABC widths of the glyph.
3484 * Failure: Non-zero HRESULT value.
3486 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3490 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3492 if (!abc
) return E_INVALIDARG
;
3493 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3495 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3497 if (!hdc
) return E_PENDING
;
3498 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3500 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3505 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3507 abc
->abcA
= abc
->abcC
= 0;
3509 set_cache_glyph_widths(psc
, glyph
, abc
);
3514 /***********************************************************************
3515 * ScriptLayout (USP10.@)
3517 * Map embedding levels to visual and/or logical order.
3520 * runs [I] Size of level array.
3521 * level [I] Array of embedding levels.
3522 * vistolog [O] Map of embedding levels from visual to logical order.
3523 * logtovis [O] Map of embedding levels from logical to visual order.
3527 * Failure: Non-zero HRESULT value.
3530 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3535 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3537 if (!level
|| (!vistolog
&& !logtovis
))
3538 return E_INVALIDARG
;
3540 indexs
= heap_alloc(sizeof(int) * runs
);
3542 return E_OUTOFMEMORY
;
3547 for( ich
= 0; ich
< runs
; ich
++)
3552 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3553 for (ich
= 0; ich
< runs
; ich
++)
3554 vistolog
[ich
] = indexs
[ich
];
3560 for( ich
= 0; ich
< runs
; ich
++)
3565 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3566 for (ich
= 0; ich
< runs
; ich
++)
3567 logtovis
[ich
] = indexs
[ich
];
3574 /***********************************************************************
3575 * ScriptStringGetLogicalWidths (USP10.@)
3577 * Returns logical widths from a string analysis.
3580 * ssa [I] string analysis.
3581 * piDx [O] logical widths returned.
3585 * Failure: a non-zero HRESULT.
3587 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3590 StringAnalysis
*analysis
= ssa
;
3592 TRACE("%p, %p\n", ssa
, piDx
);
3594 if (!analysis
) return S_FALSE
;
3595 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3597 for (i
= 0; i
< analysis
->numItems
; i
++)
3599 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3602 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3605 for (j
= 0; j
< cChar
; j
++)
3608 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3609 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3610 cChar
, j
, direction
, NULL
, NULL
);
3611 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
);
3613 for (k
= 0; k
< clust_size
; k
++)
3615 piDx
[next
] = advance
/ clust_size
;
3624 /***********************************************************************
3625 * ScriptStringValidate (USP10.@)
3627 * Validate a string analysis.
3630 * ssa [I] string analysis.
3634 * Failure: S_FALSE if invalid sequences are found
3635 * or a non-zero HRESULT if it fails.
3637 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3639 StringAnalysis
*analysis
= ssa
;
3641 TRACE("(%p)\n", ssa
);
3643 if (!analysis
) return E_INVALIDARG
;
3644 return (analysis
->invalid
) ? S_FALSE
: S_OK
;
3647 /***********************************************************************
3648 * ScriptString_pSize (USP10.@)
3650 * Retrieve width and height of an analysed string.
3653 * ssa [I] string analysis.
3656 * Success: Pointer to a SIZE structure.
3659 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3662 StringAnalysis
*analysis
= ssa
;
3664 TRACE("(%p)\n", ssa
);
3666 if (!analysis
) return NULL
;
3667 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return NULL
;
3671 if (!(analysis
->sz
= heap_alloc(sizeof(SIZE
)))) return NULL
;
3672 analysis
->sz
->cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3674 analysis
->sz
->cx
= 0;
3675 for (i
= 0; i
< analysis
->numItems
; i
++)
3677 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
->cy
)
3678 analysis
->sz
->cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3679 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3680 analysis
->sz
->cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3683 return analysis
->sz
;
3686 /***********************************************************************
3687 * ScriptString_pLogAttr (USP10.@)
3689 * Retrieve logical attributes of an analysed string.
3692 * ssa [I] string analysis.
3695 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3698 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3700 StringAnalysis
*analysis
= ssa
;
3702 TRACE("(%p)\n", ssa
);
3704 if (!analysis
) return NULL
;
3705 if (!(analysis
->dwFlags
& SSA_BREAK
)) return NULL
;
3706 return analysis
->logattrs
;
3709 /***********************************************************************
3710 * ScriptString_pcOutChars (USP10.@)
3712 * Retrieve the length of a string after clipping.
3715 * ssa [I] String analysis.
3718 * Success: Pointer to the length.
3721 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3723 StringAnalysis
*analysis
= ssa
;
3725 TRACE("(%p)\n", ssa
);
3727 if (!analysis
) return NULL
;
3728 return &analysis
->clip_len
;
3731 /***********************************************************************
3732 * ScriptStringGetOrder (USP10.@)
3734 * Retrieve a glyph order map.
3737 * ssa [I] String analysis.
3738 * order [I/O] Array of glyph positions.
3742 * Failure: a non-zero HRESULT.
3744 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3748 StringAnalysis
*analysis
= ssa
;
3750 TRACE("(%p)\n", ssa
);
3752 if (!analysis
) return S_FALSE
;
3753 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3755 /* FIXME: handle RTL scripts */
3756 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3757 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3763 /***********************************************************************
3764 * ScriptGetLogicalWidths (USP10.@)
3766 * Convert advance widths to logical widths.
3769 * sa [I] Script analysis.
3770 * nbchars [I] Number of characters.
3771 * nbglyphs [I] Number of glyphs.
3772 * glyph_width [I] Array of glyph widths.
3773 * log_clust [I] Array of logical clusters.
3774 * sva [I] Visual attributes.
3775 * widths [O] Array of logical widths.
3779 * Failure: a non-zero HRESULT.
3781 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3782 const int *glyph_width
, const WORD
*log_clust
,
3783 const SCRIPT_VISATTR
*sva
, int *widths
)
3787 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3788 sa
, nbchars
, nbglyphs
, glyph_width
, log_clust
, sva
, widths
);
3791 for (i
= 0; i
< nbchars
; i
++) widths
[i
] = glyph_width
[i
];
3795 /***********************************************************************
3796 * ScriptApplyLogicalWidth (USP10.@)
3798 * Generate glyph advance widths.
3801 * dx [I] Array of logical advance widths.
3802 * num_chars [I] Number of characters.
3803 * num_glyphs [I] Number of glyphs.
3804 * log_clust [I] Array of logical clusters.
3805 * sva [I] Visual attributes.
3806 * advance [I] Array of glyph advance widths.
3807 * sa [I] Script analysis.
3808 * abc [I/O] Summed ABC widths.
3809 * justify [O] Array of glyph advance widths.
3813 * Failure: a non-zero HRESULT.
3815 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
3816 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
3817 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
3818 ABC
*abc
, int *justify
)
3822 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3823 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
3825 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
3829 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
3830 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
3834 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
3836 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
3840 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
3843 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3844 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3846 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
3849 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
3852 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3853 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3855 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
3858 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
3861 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3862 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3864 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);