2 * Implementation of Uniscribe Script Processor (usp10.dll)
4 * Copyright 2005 Steven Edwards for CodeWeavers
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * Uniscribe allows for processing of complex scripts such as joining
24 * and filtering characters and bi-directional text with custom line breaks.
39 #include "usp10_internal.h"
41 #include "wine/debug.h"
42 #include "wine/heap.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe
);
46 static const struct usp10_script_range
48 enum usp10_script script
;
51 enum usp10_script numericScript
;
52 enum usp10_script punctScript
;
56 /* Basic Latin: U+0000–U+007A */
57 { Script_Latin
, 0x00, 0x07a , Script_Numeric
, Script_Punctuation
},
58 /* Latin-1 Supplement: U+0080–U+00FF */
59 /* Latin Extended-A: U+0100–U+017F */
60 /* Latin Extended-B: U+0180–U+024F */
61 /* IPA Extensions: U+0250–U+02AF */
62 /* Spacing Modifier Letters:U+02B0–U+02FF */
63 { Script_Latin
, 0x80, 0x2ff , Script_Numeric2
, Script_Punctuation
},
64 /* Combining Diacritical Marks : U+0300–U+036F */
65 { Script_Diacritical
,0x300, 0x36f, 0, 0},
66 /* Greek: U+0370–U+03FF */
67 { Script_Greek
, 0x370, 0x3ff, 0, 0},
68 /* Cyrillic: U+0400–U+04FF */
69 /* Cyrillic Supplement: U+0500–U+052F */
70 { Script_Cyrillic
, 0x400, 0x52f, 0, 0},
71 /* Armenian: U+0530–U+058F */
72 { Script_Armenian
, 0x530, 0x58f, 0, 0},
73 /* Hebrew: U+0590–U+05FF */
74 { Script_Hebrew
, 0x590, 0x5ff, 0, 0},
75 /* Arabic: U+0600–U+06FF */
76 { Script_Arabic
, 0x600, 0x6ef, Script_Arabic_Numeric
, 0},
77 /* Defined by Windows */
78 { Script_Persian
, 0x6f0, 0x6f9, 0, 0},
79 /* Continue Arabic: U+0600–U+06FF */
80 { Script_Arabic
, 0x6fa, 0x6ff, 0, 0},
81 /* Syriac: U+0700–U+074F*/
82 { Script_Syriac
, 0x700, 0x74f, 0, 0},
83 /* Arabic Supplement: U+0750–U+077F */
84 { Script_Arabic
, 0x750, 0x77f, 0, 0},
85 /* Thaana: U+0780–U+07BF */
86 { Script_Thaana
, 0x780, 0x7bf, 0, 0},
87 /* N’Ko: U+07C0–U+07FF */
88 { Script_NKo
, 0x7c0, 0x7ff, 0, 0},
89 /* Devanagari: U+0900–U+097F */
90 { Script_Devanagari
, 0x900, 0x97f, Script_Devanagari_Numeric
, 0},
91 /* Bengali: U+0980–U+09FF */
92 { Script_Bengali
, 0x980, 0x9ff, Script_Bengali_Numeric
, 0},
93 /* Gurmukhi: U+0A00–U+0A7F*/
94 { Script_Gurmukhi
, 0xa00, 0xa7f, Script_Gurmukhi_Numeric
, 0},
95 /* Gujarati: U+0A80–U+0AFF*/
96 { Script_Gujarati
, 0xa80, 0xaff, Script_Gujarati_Numeric
, 0},
97 /* Oriya: U+0B00–U+0B7F */
98 { Script_Oriya
, 0xb00, 0xb7f, Script_Oriya_Numeric
, 0},
99 /* Tamil: U+0B80–U+0BFF */
100 { Script_Tamil
, 0xb80, 0xbff, Script_Tamil_Numeric
, 0},
101 /* Telugu: U+0C00–U+0C7F */
102 { Script_Telugu
, 0xc00, 0xc7f, Script_Telugu_Numeric
, 0},
103 /* Kannada: U+0C80–U+0CFF */
104 { Script_Kannada
, 0xc80, 0xcff, Script_Kannada_Numeric
, 0},
105 /* Malayalam: U+0D00–U+0D7F */
106 { Script_Malayalam
, 0xd00, 0xd7f, Script_Malayalam_Numeric
, 0},
107 /* Sinhala: U+0D80–U+0DFF */
108 { Script_Sinhala
, 0xd80, 0xdff, 0, 0},
109 /* Thai: U+0E00–U+0E7F */
110 { Script_Thai
, 0xe00, 0xe7f, Script_Thai_Numeric
, 0},
111 /* Lao: U+0E80–U+0EFF */
112 { Script_Lao
, 0xe80, 0xeff, Script_Lao_Numeric
, 0},
113 /* Tibetan: U+0F00–U+0FFF */
114 { Script_Tibetan
, 0xf00, 0xfff, 0, 0},
115 /* Myanmar: U+1000–U+109F */
116 { Script_Myanmar
, 0x1000, 0x109f, Script_Myanmar_Numeric
, 0},
117 /* Georgian: U+10A0–U+10FF */
118 { Script_Georgian
, 0x10a0, 0x10ff, 0, 0},
119 /* Hangul Jamo: U+1100–U+11FF */
120 { Script_Hangul
, 0x1100, 0x11ff, 0, 0},
121 /* Ethiopic: U+1200–U+137F */
122 /* Ethiopic Extensions: U+1380–U+139F */
123 { Script_Ethiopic
, 0x1200, 0x139f, 0, 0},
124 /* Cherokee: U+13A0–U+13FF */
125 { Script_Cherokee
, 0x13a0, 0x13ff, 0, 0},
126 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
127 { Script_Canadian
, 0x1400, 0x167f, 0, 0},
128 /* Ogham: U+1680–U+169F */
129 { Script_Ogham
, 0x1680, 0x169f, 0, 0},
130 /* Runic: U+16A0–U+16F0 */
131 { Script_Runic
, 0x16a0, 0x16f0, 0, 0},
132 /* Khmer: U+1780–U+17FF */
133 { Script_Khmer
, 0x1780, 0x17ff, Script_Khmer_Numeric
, 0},
134 /* Mongolian: U+1800–U+18AF */
135 { Script_Mongolian
, 0x1800, 0x18af, Script_Mongolian_Numeric
, 0},
136 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
137 { Script_Canadian
, 0x18b0, 0x18ff, 0, 0},
138 /* Tai Le: U+1950–U+197F */
139 { Script_Tai_Le
, 0x1950, 0x197f, 0, 0},
140 /* New Tai Lue: U+1980–U+19DF */
141 { Script_New_Tai_Lue
,0x1980, 0x19df, Script_New_Tai_Lue_Numeric
, 0},
142 /* Khmer Symbols: U+19E0–U+19FF */
143 { Script_Khmer
, 0x19e0, 0x19ff, Script_Khmer_Numeric
, 0},
144 /* Vedic Extensions: U+1CD0-U+1CFF */
145 { Script_Devanagari
, 0x1cd0, 0x1cff, Script_Devanagari_Numeric
, 0},
146 /* Phonetic Extensions: U+1D00–U+1DBF */
147 { Script_Latin
, 0x1d00, 0x1dbf, 0, 0},
148 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
149 { Script_Diacritical
,0x1dc0, 0x1dff, 0, 0},
150 /* Latin Extended Additional: U+1E00–U+1EFF */
151 { Script_Latin
, 0x1e00, 0x1eff, 0, 0},
152 /* Greek Extended: U+1F00–U+1FFF */
153 { Script_Greek
, 0x1f00, 0x1fff, 0, 0},
154 /* General Punctuation: U+2000 –U+206f */
155 { Script_Latin
, 0x2000, 0x206f, 0, 0},
156 /* Superscripts and Subscripts : U+2070 –U+209f */
157 /* Currency Symbols : U+20a0 –U+20cf */
158 { Script_Numeric2
, 0x2070, 0x2070, 0, 0},
159 { Script_Latin
, 0x2071, 0x2073, 0, 0},
160 { Script_Numeric2
, 0x2074, 0x2079, 0, 0},
161 { Script_Latin
, 0x207a, 0x207f, 0, 0},
162 { Script_Numeric2
, 0x2080, 0x2089, 0, 0},
163 { Script_Latin
, 0x208a, 0x20cf, 0, 0},
164 /* Letterlike Symbols : U+2100 –U+214f */
165 /* Number Forms : U+2150 –U+218f */
166 /* Arrows : U+2190 –U+21ff */
167 /* Mathematical Operators : U+2200 –U+22ff */
168 /* Miscellaneous Technical : U+2300 –U+23ff */
169 /* Control Pictures : U+2400 –U+243f */
170 /* Optical Character Recognition : U+2440 –U+245f */
171 /* Enclosed Alphanumerics : U+2460 –U+24ff */
172 /* Box Drawing : U+2500 –U+25ff */
173 /* Block Elements : U+2580 –U+259f */
174 /* Geometric Shapes : U+25a0 –U+25ff */
175 /* Miscellaneous Symbols : U+2600 –U+26ff */
176 /* Dingbats : U+2700 –U+27bf */
177 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
178 /* Supplemental Arrows-A : U+27f0 –U+27ff */
179 { Script_Latin
, 0x2100, 0x27ff, 0, 0},
180 /* Braille Patterns: U+2800–U+28FF */
181 { Script_Braille
, 0x2800, 0x28ff, 0, 0},
182 /* Supplemental Arrows-B : U+2900 –U+297f */
183 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
184 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
185 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
186 { Script_Latin
, 0x2900, 0x2bff, 0, 0},
187 /* Latin Extended-C: U+2C60–U+2C7F */
188 { Script_Latin
, 0x2c60, 0x2c7f, 0, 0},
189 /* Georgian: U+2D00–U+2D2F */
190 { Script_Georgian
, 0x2d00, 0x2d2f, 0, 0},
191 /* Tifinagh: U+2D30–U+2D7F */
192 { Script_Tifinagh
, 0x2d30, 0x2d7f, 0, 0},
193 /* Ethiopic Extensions: U+2D80–U+2DDF */
194 { Script_Ethiopic
, 0x2d80, 0x2ddf, 0, 0},
195 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
196 { Script_Cyrillic
, 0x2de0, 0x2dff, 0, 0},
197 /* CJK Radicals Supplement: U+2E80–U+2EFF */
198 /* Kangxi Radicals: U+2F00–U+2FDF */
199 { Script_CJK_Han
, 0x2e80, 0x2fdf, 0, 0},
200 /* Ideographic Description Characters: U+2FF0–U+2FFF */
201 { Script_Ideograph
,0x2ff0, 0x2fff, 0, 0},
202 /* CJK Symbols and Punctuation: U+3000–U+303F */
203 { Script_Ideograph
,0x3000, 0x3004, 0, 0},
204 { Script_CJK_Han
,0x3005, 0x3005, 0, 0},
205 { Script_Ideograph
,0x3006, 0x3006, 0, 0},
206 { Script_CJK_Han
,0x3007, 0x3007, 0, 0},
207 { Script_Ideograph
,0x3008, 0x3020, 0, 0},
208 { Script_CJK_Han
,0x3021, 0x3029, 0, 0},
209 { Script_Ideograph
,0x302a, 0x3030, 0, 0},
211 { Script_Kana
,0x3031, 0x3035, 0, 0},
212 { Script_Ideograph
,0x3036, 0x3037, 0, 0},
213 { Script_CJK_Han
,0x3038, 0x303b, 0, 0},
214 { Script_Ideograph
,0x303c, 0x303f, 0, 0},
215 /* Hiragana: U+3040–U+309F */
216 /* Katakana: U+30A0–U+30FF */
217 { Script_Kana
,0x3040, 0x30ff, 0, 0},
218 /* Bopomofo: U+3100–U+312F */
219 { Script_Bopomofo
,0x3100, 0x312f, 0, 0},
220 /* Hangul Compatibility Jamo: U+3130–U+318F */
221 { Script_Hangul
,0x3130, 0x318f, 0, 0},
222 /* Kanbun: U+3190–U+319F */
223 { Script_Ideograph
,0x3190, 0x319f, 0, 0},
224 /* Bopomofo Extended: U+31A0–U+31BF */
225 { Script_Bopomofo
,0x31a0, 0x31bf, 0, 0},
226 /* CJK Strokes: U+31C0–U+31EF */
227 { Script_Ideograph
,0x31c0, 0x31ef, 0, 0},
228 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
229 { Script_Kana
,0x31f0, 0x31ff, 0, 0},
230 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
231 { Script_Hangul
,0x3200, 0x321f, 0, 0},
232 { Script_Ideograph
,0x3220, 0x325f, 0, 0},
233 { Script_Hangul
,0x3260, 0x327f, 0, 0},
234 { Script_Ideograph
,0x3280, 0x32ef, 0, 0},
235 { Script_Kana
,0x32d0, 0x31ff, 0, 0},
236 /* CJK Compatibility: U+3300–U+33FF*/
237 { Script_Kana
,0x3300, 0x3357, 0, 0},
238 { Script_Ideograph
,0x3358, 0x33ff, 0, 0},
239 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
240 { Script_CJK_Han
,0x3400, 0x4dbf, 0, 0},
241 /* CJK Unified Ideographs: U+4E00–U+9FFF */
242 { Script_CJK_Han
,0x4e00, 0x9fff, 0, 0},
243 /* Yi: U+A000–U+A4CF */
244 { Script_Yi
,0xa000, 0xa4cf, 0, 0},
245 /* Vai: U+A500–U+A63F */
246 { Script_Vai
,0xa500, 0xa63f, Script_Vai_Numeric
, 0},
247 /* Cyrillic Extended-B: U+A640–U+A69F */
248 { Script_Cyrillic
, 0xa640, 0xa69f, 0, 0},
249 /* Modifier Tone Letters: U+A700–U+A71F */
250 /* Latin Extended-D: U+A720–U+A7FF */
251 { Script_Latin
, 0xa700, 0xa7ff, 0, 0},
252 /* Phags-pa: U+A840–U+A87F */
253 { Script_Phags_pa
, 0xa840, 0xa87f, 0, 0},
254 /* Devanagari Extended: U+A8E0-U+A8FF */
255 { Script_Devanagari
, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric
, 0},
256 /* Myanmar Extended-A: U+AA60–U+AA7F */
257 { Script_Myanmar
, 0xaa60, 0xaa7f, Script_Myanmar_Numeric
, 0},
258 /* Hangul Jamo Extended-A: U+A960–U+A97F */
259 { Script_Hangul
, 0xa960, 0xa97f, 0, 0},
260 /* Hangul Syllables: U+AC00–U+D7A3 */
261 { Script_Hangul
, 0xac00, 0xd7a3, 0, 0},
262 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
263 { Script_Hangul
, 0xd7b0, 0xd7ff, 0, 0},
264 /* Surrogates Area: U+D800–U+DFFF */
265 { Script_Surrogates
, 0xd800, 0xdbfe, 0, 0},
266 { Script_Private
, 0xdbff, 0xdc00, 0, 0},
267 { Script_Surrogates
, 0xdc01, 0xdfff, 0, 0},
268 /* Private Use Area: U+E000–U+F8FF */
269 { Script_Private
, 0xe000, 0xf8ff, 0, 0},
270 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
271 { Script_CJK_Han
,0xf900, 0xfaff, 0, 0},
272 /* Latin Ligatures: U+FB00–U+FB06 */
273 { Script_Latin
, 0xfb00, 0xfb06, 0, 0},
274 /* Armenian ligatures U+FB13..U+FB17 */
275 { Script_Armenian
, 0xfb13, 0xfb17, 0, 0},
276 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
277 { Script_Hebrew
, 0xfb1d, 0xfb4f, 0, 0},
278 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
279 { Script_Arabic
, 0xfb50, 0xfdff, 0, 0},
280 /* Vertical Forms: U+FE10–U+FE1F */
281 /* Combining Half Marks: U+FE20–U+FE2F */
282 /* CJK Compatibility Forms: U+FE30–U+FE4F */
283 /* Small Form Variants: U+FE50–U+FE6F */
284 { Script_Ideograph
,0xfe10, 0xfe6f, 0, 0},
285 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
286 { Script_Arabic
, 0xfe70, 0xfeff, 0, 0},
287 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
288 { Script_Ideograph
,0xff00, 0xff64, Script_Numeric2
, 0},
289 { Script_Kana
,0xff65, 0xff9f, 0, 0},
290 { Script_Hangul
,0xffa0, 0xffdf, 0, 0},
291 { Script_Ideograph
,0xffe0, 0xffef, 0, 0},
293 /* Deseret: U+10400–U+1044F */
294 { Script_Deseret
, 0x10400, 0x1044F, 0, 0},
295 /* Osmanya: U+10480–U+104AF */
296 { Script_Osmanya
, 0x10480, 0x104AF, Script_Osmanya_Numeric
, 0},
297 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
298 { Script_MathAlpha
, 0x1D400, 0x1D7FF, 0, 0},
301 /* this must be in order so that the index matches the Script value */
302 const scriptData scriptInformation
[] = {
303 {{SCRIPT_UNDEFINED
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
304 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
307 {{Script_Latin
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
308 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
309 MS_MAKE_TAG('l','a','t','n'),
310 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
311 {{Script_CR
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
312 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
315 {{Script_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
316 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
318 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
319 {{Script_Control
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
320 {LANG_ENGLISH
, 0, 1, 0, 0, ANSI_CHARSET
, 1, 0, 0, 0, 0, 0, 1, 0, 0},
323 {{Script_Punctuation
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
324 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
326 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
327 {{Script_Arabic
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
328 {LANG_ARABIC
, 0, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 1, 0},
329 MS_MAKE_TAG('a','r','a','b'),
330 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
331 {{Script_Arabic_Numeric
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
332 {LANG_ARABIC
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
333 MS_MAKE_TAG('a','r','a','b'),
334 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
335 {{Script_Hebrew
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
336 {LANG_HEBREW
, 0, 1, 0, 1, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
337 MS_MAKE_TAG('h','e','b','r'),
338 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
339 {{Script_Syriac
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
340 {LANG_SYRIAC
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 1, 0},
341 MS_MAKE_TAG('s','y','r','c'),
342 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
343 {{Script_Persian
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
344 {LANG_PERSIAN
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
345 MS_MAKE_TAG('a','r','a','b'),
346 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
347 {{Script_Thaana
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
348 {LANG_DIVEHI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
349 MS_MAKE_TAG('t','h','a','a'),
350 {'M','V',' ','B','o','l','i',0}},
351 {{Script_Greek
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
352 {LANG_GREEK
, 0, 0, 0, 0, GREEK_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
353 MS_MAKE_TAG('g','r','e','k'),
354 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
355 {{Script_Cyrillic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
356 {LANG_RUSSIAN
, 0, 0, 0, 0, RUSSIAN_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
357 MS_MAKE_TAG('c','y','r','l'),
358 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
359 {{Script_Armenian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
360 {LANG_ARMENIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
361 MS_MAKE_TAG('a','r','m','n'),
362 {'S','y','l','f','a','e','n',0}},
363 {{Script_Georgian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
364 {LANG_GEORGIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
365 MS_MAKE_TAG('g','e','o','r'),
366 {'S','y','l','f','a','e','n',0}},
367 {{Script_Sinhala
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
368 {LANG_SINHALESE
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
369 MS_MAKE_TAG('s','i','n','h'),
370 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
371 {{Script_Tibetan
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
372 {LANG_TIBETAN
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
373 MS_MAKE_TAG('t','i','b','t'),
374 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
375 {{Script_Tibetan_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
376 {LANG_TIBETAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
377 MS_MAKE_TAG('t','i','b','t'),
378 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
379 {{Script_Phags_pa
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
380 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
381 MS_MAKE_TAG('p','h','a','g'),
382 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
383 {{Script_Thai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
384 {LANG_THAI
, 0, 1, 1, 1, THAI_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 1},
385 MS_MAKE_TAG('t','h','a','i'),
386 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
387 {{Script_Thai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
388 {LANG_THAI
, 1, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
389 MS_MAKE_TAG('t','h','a','i'),
390 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
391 {{Script_Lao
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
392 {LANG_LAO
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
393 MS_MAKE_TAG('l','a','o',' '),
394 {'D','o','k','C','h','a','m','p','a',0}},
395 {{Script_Lao_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
396 {LANG_LAO
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
397 MS_MAKE_TAG('l','a','o',' '),
398 {'D','o','k','C','h','a','m','p','a',0}},
399 {{Script_Devanagari
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
400 {LANG_HINDI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
401 MS_MAKE_TAG('d','e','v','a'),
402 {'M','a','n','g','a','l',0}},
403 {{Script_Devanagari_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
404 {LANG_HINDI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
405 MS_MAKE_TAG('d','e','v','a'),
406 {'M','a','n','g','a','l',0}},
407 {{Script_Bengali
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
408 {LANG_BENGALI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
409 MS_MAKE_TAG('b','e','n','g'),
410 {'V','r','i','n','d','a',0}},
411 {{Script_Bengali_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
412 {LANG_BENGALI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
413 MS_MAKE_TAG('b','e','n','g'),
414 {'V','r','i','n','d','a',0}},
415 {{Script_Bengali_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
416 {LANG_BENGALI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
417 MS_MAKE_TAG('b','e','n','g'),
418 {'V','r','i','n','d','a',0}},
419 {{Script_Gurmukhi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
420 {LANG_PUNJABI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
421 MS_MAKE_TAG('g','u','r','u'),
422 {'R','a','a','v','i',0}},
423 {{Script_Gurmukhi_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
424 {LANG_PUNJABI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
425 MS_MAKE_TAG('g','u','r','u'),
426 {'R','a','a','v','i',0}},
427 {{Script_Gujarati
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
428 {LANG_GUJARATI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
429 MS_MAKE_TAG('g','u','j','r'),
430 {'S','h','r','u','t','i',0}},
431 {{Script_Gujarati_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
432 {LANG_GUJARATI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
433 MS_MAKE_TAG('g','u','j','r'),
434 {'S','h','r','u','t','i',0}},
435 {{Script_Gujarati_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
436 {LANG_GUJARATI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
437 MS_MAKE_TAG('g','u','j','r'),
438 {'S','h','r','u','t','i',0}},
439 {{Script_Oriya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
440 {LANG_ORIYA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
441 MS_MAKE_TAG('o','r','y','a'),
442 {'K','a','l','i','n','g','a',0}},
443 {{Script_Oriya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
444 {LANG_ORIYA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
445 MS_MAKE_TAG('o','r','y','a'),
446 {'K','a','l','i','n','g','a',0}},
447 {{Script_Tamil
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
448 {LANG_TAMIL
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
449 MS_MAKE_TAG('t','a','m','l'),
450 {'L','a','t','h','a',0}},
451 {{Script_Tamil_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
452 {LANG_TAMIL
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
453 MS_MAKE_TAG('t','a','m','l'),
454 {'L','a','t','h','a',0}},
455 {{Script_Telugu
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
456 {LANG_TELUGU
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
457 MS_MAKE_TAG('t','e','l','u'),
458 {'G','a','u','t','a','m','i',0}},
459 {{Script_Telugu_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
460 {LANG_TELUGU
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
461 MS_MAKE_TAG('t','e','l','u'),
462 {'G','a','u','t','a','m','i',0}},
463 {{Script_Kannada
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
464 {LANG_KANNADA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
465 MS_MAKE_TAG('k','n','d','a'),
466 {'T','u','n','g','a',0}},
467 {{Script_Kannada_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
468 {LANG_KANNADA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
469 MS_MAKE_TAG('k','n','d','a'),
470 {'T','u','n','g','a',0}},
471 {{Script_Malayalam
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
472 {LANG_MALAYALAM
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
473 MS_MAKE_TAG('m','l','y','m'),
474 {'K','a','r','t','i','k','a',0}},
475 {{Script_Malayalam_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
476 {LANG_MALAYALAM
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
477 MS_MAKE_TAG('m','l','y','m'),
478 {'K','a','r','t','i','k','a',0}},
479 {{Script_Diacritical
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
480 {LANG_ENGLISH
, 0, 1, 0, 1, ANSI_CHARSET
, 0, 0, 0, 0, 0, 1, 1, 0, 0},
483 {{Script_Punctuation2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
484 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
485 MS_MAKE_TAG('l','a','t','n'),
486 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
487 {{Script_Numeric2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
488 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
491 {{Script_Myanmar
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
492 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
493 MS_MAKE_TAG('m','y','m','r'),
494 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
495 {{Script_Myanmar_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
496 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
497 MS_MAKE_TAG('m','y','m','r'),
499 {{Script_Tai_Le
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
500 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
501 MS_MAKE_TAG('t','a','l','e'),
502 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
503 {{Script_New_Tai_Lue
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
504 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
505 MS_MAKE_TAG('t','a','l','u'),
506 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
507 {{Script_New_Tai_Lue_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
508 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
509 MS_MAKE_TAG('t','a','l','u'),
510 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
511 {{Script_Khmer
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
512 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
513 MS_MAKE_TAG('k','h','m','r'),
514 {'D','a','u','n','P','e','n','h',0}},
515 {{Script_Khmer_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
516 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
517 MS_MAKE_TAG('k','h','m','r'),
518 {'D','a','u','n','P','e','n','h',0}},
519 {{Script_CJK_Han
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
520 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
521 MS_MAKE_TAG('h','a','n','i'),
523 {{Script_Ideograph
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
524 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
525 MS_MAKE_TAG('h','a','n','i'),
527 {{Script_Bopomofo
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
528 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
529 MS_MAKE_TAG('b','o','p','o'),
531 {{Script_Kana
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
532 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
533 MS_MAKE_TAG('k','a','n','a'),
535 {{Script_Hangul
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
536 {LANG_KOREAN
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
537 MS_MAKE_TAG('h','a','n','g'),
539 {{Script_Yi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
540 {LANG_ENGLISH
, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
541 MS_MAKE_TAG('y','i',' ',' '),
542 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
543 {{Script_Ethiopic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
544 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
545 MS_MAKE_TAG('e','t','h','i'),
546 {'N','y','a','l','a',0}},
547 {{Script_Ethiopic_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
548 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
549 MS_MAKE_TAG('e','t','h','i'),
550 {'N','y','a','l','a',0}},
551 {{Script_Mongolian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
552 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
553 MS_MAKE_TAG('m','o','n','g'),
554 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
555 {{Script_Mongolian_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
556 {LANG_MONGOLIAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
557 MS_MAKE_TAG('m','o','n','g'),
558 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
559 {{Script_Tifinagh
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
560 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
561 MS_MAKE_TAG('t','f','n','g'),
562 {'E','b','r','i','m','a',0}},
563 {{Script_NKo
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
564 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
565 MS_MAKE_TAG('n','k','o',' '),
566 {'E','b','r','i','m','a',0}},
567 {{Script_Vai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
568 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
569 MS_MAKE_TAG('v','a','i',' '),
570 {'E','b','r','i','m','a',0}},
571 {{Script_Vai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
572 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
573 MS_MAKE_TAG('v','a','i',' '),
574 {'E','b','r','i','m','a',0}},
575 {{Script_Cherokee
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
576 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
577 MS_MAKE_TAG('c','h','e','r'),
578 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
579 {{Script_Canadian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
580 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
581 MS_MAKE_TAG('c','a','n','s'),
582 {'E','u','p','h','e','m','i','a',0}},
583 {{Script_Ogham
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
584 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
585 MS_MAKE_TAG('o','g','a','m'),
586 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
587 {{Script_Runic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
588 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
589 MS_MAKE_TAG('r','u','n','r'),
590 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
591 {{Script_Braille
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
592 {LANG_ENGLISH
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
593 MS_MAKE_TAG('b','r','a','i'),
594 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
595 {{Script_Surrogates
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
596 {LANG_ENGLISH
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
599 {{Script_Private
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
600 {0, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 1, 0, 0, 0, 0, 1, 0, 0},
603 {{Script_Deseret
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
604 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
605 MS_MAKE_TAG('d','s','r','t'),
606 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
607 {{Script_Osmanya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
608 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
609 MS_MAKE_TAG('o','s','m','a'),
610 {'E','b','r','i','m','a',0}},
611 {{Script_Osmanya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
612 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
613 MS_MAKE_TAG('o','s','m','a'),
614 {'E','b','r','i','m','a',0}},
615 {{Script_MathAlpha
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
616 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
617 MS_MAKE_TAG('m','a','t','h'),
618 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
619 {{Script_Hebrew_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
620 {LANG_HEBREW
, 0, 1, 0, 0, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
621 MS_MAKE_TAG('h','e','b','r'),
622 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
623 {{Script_Vietnamese_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
624 {LANG_VIETNAMESE
, 0, 0, 0, 0, VIETNAMESE_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
625 MS_MAKE_TAG('l','a','t','n'),
626 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
627 {{Script_Thai_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
628 {LANG_THAI
, 0, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
629 MS_MAKE_TAG('t','h','a','i'),
630 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
633 static const SCRIPT_PROPERTIES
*script_props
[] =
635 &scriptInformation
[0].props
, &scriptInformation
[1].props
,
636 &scriptInformation
[2].props
, &scriptInformation
[3].props
,
637 &scriptInformation
[4].props
, &scriptInformation
[5].props
,
638 &scriptInformation
[6].props
, &scriptInformation
[7].props
,
639 &scriptInformation
[8].props
, &scriptInformation
[9].props
,
640 &scriptInformation
[10].props
, &scriptInformation
[11].props
,
641 &scriptInformation
[12].props
, &scriptInformation
[13].props
,
642 &scriptInformation
[14].props
, &scriptInformation
[15].props
,
643 &scriptInformation
[16].props
, &scriptInformation
[17].props
,
644 &scriptInformation
[18].props
, &scriptInformation
[19].props
,
645 &scriptInformation
[20].props
, &scriptInformation
[21].props
,
646 &scriptInformation
[22].props
, &scriptInformation
[23].props
,
647 &scriptInformation
[24].props
, &scriptInformation
[25].props
,
648 &scriptInformation
[26].props
, &scriptInformation
[27].props
,
649 &scriptInformation
[28].props
, &scriptInformation
[29].props
,
650 &scriptInformation
[30].props
, &scriptInformation
[31].props
,
651 &scriptInformation
[32].props
, &scriptInformation
[33].props
,
652 &scriptInformation
[34].props
, &scriptInformation
[35].props
,
653 &scriptInformation
[36].props
, &scriptInformation
[37].props
,
654 &scriptInformation
[38].props
, &scriptInformation
[39].props
,
655 &scriptInformation
[40].props
, &scriptInformation
[41].props
,
656 &scriptInformation
[42].props
, &scriptInformation
[43].props
,
657 &scriptInformation
[44].props
, &scriptInformation
[45].props
,
658 &scriptInformation
[46].props
, &scriptInformation
[47].props
,
659 &scriptInformation
[48].props
, &scriptInformation
[49].props
,
660 &scriptInformation
[50].props
, &scriptInformation
[51].props
,
661 &scriptInformation
[52].props
, &scriptInformation
[53].props
,
662 &scriptInformation
[54].props
, &scriptInformation
[55].props
,
663 &scriptInformation
[56].props
, &scriptInformation
[57].props
,
664 &scriptInformation
[58].props
, &scriptInformation
[59].props
,
665 &scriptInformation
[60].props
, &scriptInformation
[61].props
,
666 &scriptInformation
[62].props
, &scriptInformation
[63].props
,
667 &scriptInformation
[64].props
, &scriptInformation
[65].props
,
668 &scriptInformation
[66].props
, &scriptInformation
[67].props
,
669 &scriptInformation
[68].props
, &scriptInformation
[69].props
,
670 &scriptInformation
[70].props
, &scriptInformation
[71].props
,
671 &scriptInformation
[72].props
, &scriptInformation
[73].props
,
672 &scriptInformation
[74].props
, &scriptInformation
[75].props
,
673 &scriptInformation
[76].props
, &scriptInformation
[77].props
,
674 &scriptInformation
[78].props
, &scriptInformation
[79].props
,
675 &scriptInformation
[80].props
, &scriptInformation
[81].props
678 static CRITICAL_SECTION cs_script_cache
;
679 static CRITICAL_SECTION_DEBUG cs_script_cache_dbg
=
681 0, 0, &cs_script_cache
,
682 { &cs_script_cache_dbg
.ProcessLocksList
, &cs_script_cache_dbg
.ProcessLocksList
},
683 0, 0, { (DWORD_PTR
)(__FILE__
": script_cache") }
685 static CRITICAL_SECTION cs_script_cache
= { &cs_script_cache_dbg
, -1, 0, 0, 0, 0 };
686 static struct list script_cache_list
= LIST_INIT(script_cache_list
);
694 SCRIPT_VISATTR
* psva
;
701 enum stringanalysis_flags
703 SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
= 0x1,
704 SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
= 0x2,
716 StringGlyphs
* glyphs
;
717 SCRIPT_LOGATTR
* logattrs
;
727 BOOL
usp10_array_reserve(void **elements
, SIZE_T
*capacity
, SIZE_T count
, SIZE_T size
)
729 SIZE_T max_capacity
, new_capacity
;
732 if (count
<= *capacity
)
735 max_capacity
= ~(SIZE_T
)0 / size
;
736 if (count
> max_capacity
)
739 new_capacity
= max(1, *capacity
);
740 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
742 if (new_capacity
< count
)
743 new_capacity
= count
;
746 new_elements
= heap_alloc_zero(new_capacity
* size
);
748 new_elements
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *elements
, new_capacity
* size
);
752 *elements
= new_elements
;
753 *capacity
= new_capacity
;
757 /* TODO Fix font properties on Arabic locale */
758 static inline BOOL
set_cache_font_properties(const HDC hdc
, ScriptCache
*sc
)
760 sc
->sfp
.cBytes
= sizeof(sc
->sfp
);
764 sc
->sfp
.wgBlank
= sc
->tm
.tmBreakChar
;
765 sc
->sfp
.wgDefault
= sc
->tm
.tmDefaultChar
;
766 sc
->sfp
.wgInvalid
= sc
->sfp
.wgBlank
;
767 sc
->sfp
.wgKashida
= 0xFFFF;
768 sc
->sfp
.iKashidaWidth
= 0;
772 static const WCHAR chars
[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
773 /* U+0020: numeric space
774 U+200B: zero width space
775 U+F71B: unknown char found by black box testing
779 if (GetGlyphIndicesW(hdc
, chars
, 4, gi
, GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
781 if(gi
[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
782 sc
->sfp
.wgBlank
= gi
[0];
786 sc
->sfp
.wgDefault
= 0;
789 sc
->sfp
.wgInvalid
= gi
[2];
790 else if (gi
[1] != 0xFFFF)
791 sc
->sfp
.wgInvalid
= gi
[1];
792 else if (gi
[0] != 0xFFFF)
793 sc
->sfp
.wgInvalid
= gi
[0];
795 sc
->sfp
.wgInvalid
= 0;
797 sc
->sfp
.wgKashida
= gi
[3];
799 sc
->sfp
.iKashidaWidth
= 0; /* TODO */
807 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES
*sfp
, ScriptCache
*sc
)
812 static inline LONG
get_cache_height(SCRIPT_CACHE
*psc
)
814 return ((ScriptCache
*)*psc
)->tm
.tmHeight
;
817 static inline BYTE
get_cache_pitch_family(SCRIPT_CACHE
*psc
)
819 return ((ScriptCache
*)*psc
)->tm
.tmPitchAndFamily
;
822 static inline WORD
get_cache_glyph(SCRIPT_CACHE
*psc
, DWORD c
)
824 CacheGlyphPage
*page
= ((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
828 block
= page
->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
829 if (!block
) return 0;
830 return block
[(c
% 0x10000) & GLYPH_BLOCK_MASK
];
833 static inline WORD
set_cache_glyph(SCRIPT_CACHE
*psc
, WCHAR c
, WORD glyph
)
835 CacheGlyphPage
**page
= &((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
837 if (!*page
&& !(*page
= heap_alloc_zero(sizeof(CacheGlyphPage
)))) return 0;
839 block
= &(*page
)->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
840 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(WORD
) * GLYPH_BLOCK_SIZE
))) return 0;
841 return ((*block
)[(c
% 0x10000) & GLYPH_BLOCK_MASK
] = glyph
);
844 static inline BOOL
get_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
846 static const ABC nil
;
847 ABC
*block
= ((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
849 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(ABC
))) return FALSE
;
850 memcpy(abc
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(ABC
));
854 static inline BOOL
set_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
856 ABC
**block
= &((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
858 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(ABC
) * GLYPH_BLOCK_SIZE
))) return FALSE
;
859 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], abc
, sizeof(ABC
));
863 static HRESULT
init_script_cache(const HDC hdc
, SCRIPT_CACHE
*psc
)
869 if (!psc
) return E_INVALIDARG
;
870 if (*psc
) return S_OK
;
871 if (!hdc
) return E_PENDING
;
873 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), &lf
))
877 /* Ensure canonical result by zeroing extra space in lfFaceName */
878 size
= lstrlenW(lf
.lfFaceName
);
879 memset(lf
.lfFaceName
+ size
, 0, sizeof(lf
.lfFaceName
) - size
* sizeof(WCHAR
));
881 EnterCriticalSection(&cs_script_cache
);
882 LIST_FOR_EACH_ENTRY(sc
, &script_cache_list
, ScriptCache
, entry
)
884 if (!memcmp(&sc
->lf
, &lf
, sizeof(lf
)))
887 LeaveCriticalSection(&cs_script_cache
);
892 LeaveCriticalSection(&cs_script_cache
);
894 if (!(sc
= heap_alloc_zero(sizeof(ScriptCache
)))) return E_OUTOFMEMORY
;
895 if (!GetTextMetricsW(hdc
, &sc
->tm
))
900 size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
903 sc
->otm
= heap_alloc(size
);
904 sc
->otm
->otmSize
= size
;
905 GetOutlineTextMetricsW(hdc
, size
, sc
->otm
);
907 sc
->sfnt
= (GetFontData(hdc
, MS_MAKE_TAG('h','e','a','d'), 0, NULL
, 0)!=GDI_ERROR
);
908 if (!set_cache_font_properties(hdc
, sc
))
917 EnterCriticalSection(&cs_script_cache
);
918 list_add_head(&script_cache_list
, &sc
->entry
);
919 LIST_FOR_EACH_ENTRY(sc
, &script_cache_list
, ScriptCache
, entry
)
921 if (sc
!= *psc
&& !memcmp(&sc
->lf
, &lf
, sizeof(lf
)))
923 /* Another thread won the race. Use their cache instead of ours */
924 list_remove(&sc
->entry
);
926 LeaveCriticalSection(&cs_script_cache
);
932 LeaveCriticalSection(&cs_script_cache
);
933 TRACE("<- %p\n", sc
);
937 static WCHAR
mirror_char( WCHAR ch
)
939 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
940 return ch
+ wine_mirror_map
[wine_mirror_map
[ch
>> 8] + (ch
& 0xff)];
943 static DWORD
decode_surrogate_pair(const WCHAR
*str
, unsigned int index
, unsigned int end
)
945 if (index
< end
-1 && IS_SURROGATE_PAIR(str
[index
],str
[index
+1]))
947 DWORD ch
= 0x10000 + ((str
[index
] - 0xd800) << 10) + (str
[index
+1] - 0xdc00);
948 TRACE("Surrogate Pair %x %x => %x\n",str
[index
], str
[index
+1], ch
);
954 static int __cdecl
usp10_compare_script_range(const void *key
, const void *value
)
956 const struct usp10_script_range
*range
= value
;
957 const DWORD
*ch
= key
;
959 if (*ch
< range
->rangeFirst
)
961 if (*ch
> range
->rangeLast
)
966 static enum usp10_script
get_char_script(const WCHAR
*str
, unsigned int index
,
967 unsigned int end
, unsigned int *consumed
)
969 static const WCHAR latin_punc
[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
970 struct usp10_script_range
*range
;
971 WORD type
= 0, type2
= 0;
976 if (str
[index
] == 0xc || str
[index
] == 0x20 || str
[index
] == 0x202f)
979 /* These punctuation characters are separated out as Latin punctuation */
980 if (wcschr(latin_punc
,str
[index
]))
981 return Script_Punctuation2
;
983 /* These chars are itemized as Punctuation by Windows */
984 if (str
[index
] == 0x2212 || str
[index
] == 0x2044)
985 return Script_Punctuation
;
987 /* Currency Symbols by Unicode point */
991 case 0x09f3: return Script_Bengali_Currency
;
992 case 0x0af1: return Script_Gujarati_Currency
;
993 case 0x0e3f: return Script_Thai_Currency
;
994 case 0x20aa: return Script_Hebrew_Currency
;
995 case 0x20ab: return Script_Vietnamese_Currency
;
996 case 0xfb29: return Script_Hebrew_Currency
;
999 GetStringTypeW(CT_CTYPE1
, &str
[index
], 1, &type
);
1000 GetStringTypeW(CT_CTYPE2
, &str
[index
], 1, &type2
);
1003 return SCRIPT_UNDEFINED
;
1005 if (type
& C1_CNTRL
)
1006 return Script_Control
;
1008 ch
= decode_surrogate_pair(str
, index
, end
);
1014 if (!(range
= bsearch(&ch
, script_ranges
, ARRAY_SIZE(script_ranges
),
1015 sizeof(*script_ranges
), usp10_compare_script_range
)))
1016 return (*consumed
== 2) ? Script_Surrogates
: Script_Undefined
;
1018 if (range
->numericScript
&& (type
& C1_DIGIT
|| type2
== C2_ARABICNUMBER
))
1019 return range
->numericScript
;
1020 if (range
->punctScript
&& type
& C1_PUNCT
)
1021 return range
->punctScript
;
1022 return range
->script
;
1025 static int __cdecl
compare_FindGlyph(const void *a
, const void* b
)
1027 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
1028 const WORD
*idx
= (WORD
*)b
;
1031 if ( find
->target
> *idx
)
1033 else if (find
->target
< *idx
)
1036 if (!find
->ascending
)
1041 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
1043 FindGlyph_struct fgs
;
1047 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
1048 fgs
.ascending
= TRUE
;
1050 fgs
.ascending
= FALSE
;
1052 fgs
.target
= target
;
1053 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
1058 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
1065 /***********************************************************************
1066 * ScriptFreeCache (USP10.@)
1068 * Free a script cache.
1071 * psc [I/O] Script cache.
1075 * Failure: Non-zero HRESULT value.
1077 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1086 EnterCriticalSection(&cs_script_cache
);
1087 if (--((ScriptCache
*)*psc
)->refcount
> 0)
1089 LeaveCriticalSection(&cs_script_cache
);
1093 list_remove(&((ScriptCache
*)*psc
)->entry
);
1094 LeaveCriticalSection(&cs_script_cache
);
1096 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1098 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1100 for (i
= 0; i
< NUM_PAGES
; i
++)
1103 if (((ScriptCache
*)*psc
)->page
[i
])
1104 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1105 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1106 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1108 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1109 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1110 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1111 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1112 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1115 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1118 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1119 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1120 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1122 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1123 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1124 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1125 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1127 heap_free(((ScriptCache
*)*psc
)->scripts
);
1128 heap_free(((ScriptCache
*)*psc
)->otm
);
1135 /***********************************************************************
1136 * ScriptGetProperties (USP10.@)
1138 * Retrieve a list of script properties.
1141 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1142 * num [I] Pointer to the number of scripts.
1146 * Failure: Non-zero HRESULT value.
1149 * Behaviour matches WinXP.
1151 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1153 TRACE("(%p,%p)\n", props
, num
);
1155 if (!props
&& !num
) return E_INVALIDARG
;
1157 if (num
) *num
= ARRAY_SIZE(script_props
);
1158 if (props
) *props
= script_props
;
1163 /***********************************************************************
1164 * ScriptGetFontProperties (USP10.@)
1166 * Get information on special glyphs.
1169 * hdc [I] Device context.
1170 * psc [I/O] Opaque pointer to a script cache.
1171 * sfp [O] Font properties structure.
1173 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1177 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1179 if (!sfp
) return E_INVALIDARG
;
1180 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1182 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1183 return E_INVALIDARG
;
1185 get_cache_font_properties(sfp
, *psc
);
1190 /***********************************************************************
1191 * ScriptRecordDigitSubstitution (USP10.@)
1193 * Record digit substitution settings for a given locale.
1196 * locale [I] Locale identifier.
1197 * sds [I] Structure to record substitution settings.
1201 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1204 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1206 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1210 TRACE("0x%x, %p\n", locale
, sds
);
1212 /* This implementation appears to be correct for all languages, but it's
1213 * not clear if sds->DigitSubstitute is ever set to anything except
1214 * CONTEXT or NONE in reality */
1216 if (!sds
) return E_POINTER
;
1218 locale
= ConvertDefaultLocale(locale
);
1220 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1221 return E_INVALIDARG
;
1223 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1224 sds
->TraditionalDigitLanguage
= plgid
;
1226 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1227 sds
->NationalDigitLanguage
= plgid
;
1229 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1231 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1232 (WCHAR
*)&sub
, sizeof(sub
) / sizeof(WCHAR
)))
1233 return E_INVALIDARG
;
1238 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1239 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1241 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1244 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1247 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1250 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1254 sds
->dwReserved
= 0;
1258 /***********************************************************************
1259 * ScriptApplyDigitSubstitution (USP10.@)
1261 * Apply digit substitution settings.
1264 * sds [I] Structure with recorded substitution settings.
1265 * sc [I] Script control structure.
1266 * ss [I] Script state structure.
1270 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1272 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1273 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1275 SCRIPT_DIGITSUBSTITUTE psds
;
1277 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1279 if (!sc
|| !ss
) return E_POINTER
;
1283 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1284 return E_INVALIDARG
;
1287 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1288 sc
->fContextDigits
= 0;
1289 ss
->fDigitSubstitute
= 0;
1291 switch (sds
->DigitSubstitute
) {
1292 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1293 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1294 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1295 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1298 return E_INVALIDARG
;
1302 static inline BOOL
is_indic(enum usp10_script script
)
1304 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1307 static inline enum usp10_script
base_indic(enum usp10_script script
)
1311 case Script_Devanagari
:
1312 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1313 case Script_Bengali
:
1314 case Script_Bengali_Numeric
:
1315 case Script_Bengali_Currency
: return Script_Bengali
;
1316 case Script_Gurmukhi
:
1317 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1318 case Script_Gujarati
:
1319 case Script_Gujarati_Numeric
:
1320 case Script_Gujarati_Currency
: return Script_Gujarati
;
1322 case Script_Oriya_Numeric
: return Script_Oriya
;
1324 case Script_Tamil_Numeric
: return Script_Tamil
;
1326 case Script_Telugu_Numeric
: return Script_Telugu
;
1327 case Script_Kannada
:
1328 case Script_Kannada_Numeric
: return Script_Kannada
;
1329 case Script_Malayalam
:
1330 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1332 return Script_Undefined
;
1336 static BOOL
script_is_numeric(enum usp10_script script
)
1338 return scriptInformation
[script
].props
.fNumeric
;
1341 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1342 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1343 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1344 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1347 #define Numeric_space 0x0020
1352 enum usp10_script last_indic
= Script_Undefined
;
1353 int cnt
= 0, index
= 0, str
= 0;
1354 enum usp10_script New_Script
= -1;
1356 WORD
*levels
= NULL
;
1357 WORD
*layout_levels
= NULL
;
1358 WORD
*overrides
= NULL
;
1359 WORD
*strength
= NULL
;
1360 enum usp10_script
*scripts
;
1362 WORD baselayout
= 0;
1365 BOOL forceLevels
= FALSE
;
1366 unsigned int consumed
= 0;
1367 HRESULT res
= E_OUTOFMEMORY
;
1369 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1370 psControl
, psState
, pItems
, pcItems
);
1372 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1373 return E_INVALIDARG
;
1375 if (!(scripts
= heap_calloc(cInChars
, sizeof(*scripts
))))
1376 return E_OUTOFMEMORY
;
1378 for (i
= 0; i
< cInChars
; i
++)
1382 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1387 scripts
[i
] = scripts
[i
-1];
1390 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1391 all Indic scripts */
1392 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
!= Script_Undefined
)
1393 scripts
[i
] = last_indic
;
1394 else if (is_indic(scripts
[i
]))
1395 last_indic
= base_indic(scripts
[i
]);
1397 /* Some unicode points :
1398 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1399 (Left Right Embed U+202A - Left Right Override U+202D)
1400 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1401 will force us into bidi mode */
1402 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1403 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1404 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1408 /* Diacritical marks merge with other scripts */
1409 if (scripts
[i
] == Script_Diacritical
)
1414 scripts
[i
] = scripts
[i
-1];
1419 enum usp10_script first_script
= scripts
[i
-1];
1420 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1422 enum usp10_script original
= scripts
[j
];
1423 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1428 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1430 scripts
[j
] = scripts
[i
];
1431 if (original
== Script_Punctuation2
)
1434 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1435 scripts
[i
] = scripts
[j
];
1441 for (i
= 0; i
< cInChars
; i
++)
1443 /* Joiners get merged preferencially right */
1444 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1447 if (i
+1 == cInChars
)
1448 scripts
[i
] = scripts
[i
-1];
1451 for (j
= i
+1; j
< cInChars
; j
++)
1453 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1454 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1456 scripts
[i
] = scripts
[j
];
1464 if (psState
&& psControl
)
1466 if (!(levels
= heap_calloc(cInChars
, sizeof(*levels
))))
1469 if (!(overrides
= heap_calloc(cInChars
, sizeof(*overrides
))))
1472 if (!(layout_levels
= heap_calloc(cInChars
, sizeof(*layout_levels
))))
1475 if (psState
->fOverrideDirection
)
1479 SCRIPT_STATE s
= *psState
;
1480 s
.fOverrideDirection
= FALSE
;
1481 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1482 if (odd(layout_levels
[0]))
1484 else for (i
= 0; i
< cInChars
; i
++)
1485 if (layout_levels
[i
]!=layout_levels
[0])
1492 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1496 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1497 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1499 baselevel
= levels
[0];
1500 baselayout
= layout_levels
[0];
1501 for (i
= 0; i
< cInChars
; i
++)
1502 if (levels
[i
]!=levels
[0])
1504 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1507 heap_free(overrides
);
1508 heap_free(layout_levels
);
1511 layout_levels
= NULL
;
1515 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1516 static const WCHAR repeatable_math_punc
[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1518 if (!(strength
= heap_calloc(cInChars
, sizeof(*strength
))))
1520 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1522 /* We currently mis-level leading Diacriticals */
1523 if (scripts
[0] == Script_Diacritical
)
1524 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1526 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1527 strength
[i
] = BIDI_STRONG
;
1530 /* Math punctuation bordered on both sides by numbers can be
1531 merged into the number */
1532 for (i
= 0; i
< cInChars
; i
++)
1534 if (i
> 0 && i
< cInChars
-1 &&
1535 script_is_numeric(scripts
[i
-1]) &&
1536 wcschr(math_punc
, pwcInChars
[i
]))
1538 if (script_is_numeric(scripts
[i
+1]))
1540 scripts
[i
] = scripts
[i
+1];
1541 levels
[i
] = levels
[i
-1];
1542 strength
[i
] = strength
[i
-1];
1545 else if (wcschr(repeatable_math_punc
, pwcInChars
[i
]))
1548 for (j
= i
+1; j
< cInChars
; j
++)
1550 if (script_is_numeric(scripts
[j
]))
1554 scripts
[i
] = scripts
[j
];
1555 levels
[i
] = levels
[i
-1];
1556 strength
[i
] = strength
[i
-1];
1559 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1565 for (i
= 0; i
< cInChars
; i
++)
1567 /* Numerics at level 0 get bumped to level 2 */
1568 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
)
1569 && levels
[i
] == psState
->uBidiLevel
+ 1)) && script_is_numeric(scripts
[i
]))
1574 /* Joiners get merged preferencially right */
1575 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1578 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1579 strength
[i
] = strength
[i
-1];
1581 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1582 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1583 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1585 strength
[i
] = strength
[j
];
1590 if (psControl
->fMergeNeutralItems
)
1592 /* Merge the neutrals */
1593 for (i
= 0; i
< cInChars
; i
++)
1595 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1598 for (j
= i
; j
> 0; j
--)
1600 if (levels
[i
] != levels
[j
])
1602 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1604 scripts
[i
] = scripts
[j
];
1605 strength
[i
] = strength
[j
];
1610 /* Try going the other way */
1611 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1614 for (j
= i
; j
< cInChars
; j
++)
1616 if (levels
[i
] != levels
[j
])
1618 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1620 scripts
[i
] = scripts
[j
];
1621 strength
[i
] = strength
[j
];
1631 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1632 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1635 if (cnt
== cInChars
) /* All Spaces */
1638 New_Script
= scripts
[cnt
];
1641 pItems
[index
].iCharPos
= 0;
1642 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1644 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1646 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1647 str
= strength
[cnt
];
1655 if (strength
[cnt
] == BIDI_STRONG
)
1656 layoutRTL
= odd(layout_levels
[cnt
]);
1658 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1660 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1661 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1662 if (script_is_numeric(pItems
[index
].a
.eScript
))
1663 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1665 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1666 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1668 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1670 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1671 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1672 layoutRTL
= odd(baselayout
);
1673 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1674 pItems
[index
].a
.fRTL
= odd(baselevel
);
1675 if (script_is_numeric(pItems
[index
].a
.eScript
))
1676 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1678 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1681 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1682 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1683 pItems
[index
].iCharPos
);
1685 for (cnt
=1; cnt
< cInChars
; cnt
++)
1687 if(pwcInChars
[cnt
] != Numeric_space
)
1688 New_Script
= scripts
[cnt
];
1692 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1694 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1695 New_Script
= scripts
[cnt
+j
];
1697 New_Script
= scripts
[cnt
];
1701 /* merge space strengths*/
1702 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1705 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1708 /* changes in level */
1709 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1711 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1714 /* changes in strength */
1715 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1717 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1720 /* changes in script */
1721 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1723 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1727 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1729 layoutRTL
= odd(layout_levels
[cnt
]);
1730 if (script_is_numeric(pItems
[index
].a
.eScript
))
1731 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1736 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
);
1739 if (index
+1 > cMaxItems
)
1743 str
= strength
[cnt
];
1745 pItems
[index
].iCharPos
= cnt
;
1746 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1748 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1750 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1754 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1755 if (layout_levels
[cnt
] == 0)
1758 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1759 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1760 if (script_is_numeric(pItems
[index
].a
.eScript
))
1761 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1763 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1764 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1766 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1768 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1769 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1770 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1771 pItems
[index
].a
.fRTL
= odd(baselevel
);
1772 if (script_is_numeric(pItems
[index
].a
.eScript
))
1773 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1775 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1778 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1782 /* While not strictly necessary according to the spec, make sure the n+1
1783 * item is set up to prevent random behaviour if the caller erroneously
1784 * checks the n+1 structure */
1786 if (index
+ 1 > cMaxItems
) goto nomemory
;
1787 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1789 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1791 /* Set one SCRIPT_STATE item being returned */
1792 if (pcItems
) *pcItems
= index
;
1794 /* Set SCRIPT_ITEM */
1795 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1799 heap_free(overrides
);
1800 heap_free(layout_levels
);
1801 heap_free(strength
);
1806 /***********************************************************************
1807 * ScriptItemizeOpenType (USP10.@)
1809 * Split a Unicode string into shapeable parts.
1812 * pwcInChars [I] String to split.
1813 * cInChars [I] Number of characters in pwcInChars.
1814 * cMaxItems [I] Maximum number of items to return.
1815 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1816 * psState [I] Pointer to a SCRIPT_STATE structure.
1817 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1818 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1819 * pcItems [O] Number of script items returned.
1823 * Failure: Non-zero HRESULT value.
1825 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1826 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1827 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1829 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1832 /***********************************************************************
1833 * ScriptItemize (USP10.@)
1835 * Split a Unicode string into shapeable parts.
1838 * pwcInChars [I] String to split.
1839 * cInChars [I] Number of characters in pwcInChars.
1840 * cMaxItems [I] Maximum number of items to return.
1841 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1842 * psState [I] Pointer to a SCRIPT_STATE structure.
1843 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1844 * pcItems [O] Number of script items returned.
1848 * Failure: Non-zero HRESULT value.
1850 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1851 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1852 SCRIPT_ITEM
*pItems
, int *pcItems
)
1854 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1857 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1861 INT
*lpTabPos
= NULL
;
1866 lpTabPos
= pTabdef
->pTabStops
;
1868 if (pTabdef
&& pTabdef
->iTabOrigin
)
1870 if (pTabdef
->iScale
)
1871 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1873 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1877 cTabStops
= pTabdef
->cTabStops
;
1881 if (pTabdef
->iScale
)
1882 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1884 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1889 if (pTabdef
->iScale
)
1890 defWidth
= (32 * pTabdef
->iScale
) / 4;
1892 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1895 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1897 int position
= *lpTabPos
;
1899 position
= -1 * position
;
1900 if (pTabdef
->iScale
)
1901 position
= (position
* pTabdef
->iScale
) / 4;
1903 position
= position
* psc
->tm
.tmAveCharWidth
;
1905 if( nTabOrg
+ position
> current_x
)
1909 /* a left aligned tab */
1910 x
= (nTabOrg
+ position
) - current_x
;
1915 FIXME("Negative tabstop\n");
1920 if ((!cTabStops
) && (defWidth
> 0))
1921 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1922 else if ((!cTabStops
) && (defWidth
< 0))
1923 FIXME("TODO: Negative defWidth\n");
1928 /***********************************************************************
1929 * Helper function for ScriptStringAnalyse
1931 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1932 const WCHAR
*pwcInChars
, int cChars
)
1934 /* FIXME: When to properly fallback is still a bit of a mystery */
1937 if (psa
->fNoGlyphIndex
)
1940 if (init_script_cache(hdc
, psc
) != S_OK
)
1943 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1946 if (!(glyphs
= heap_calloc(cChars
, sizeof(*glyphs
))))
1948 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1958 static void find_fallback_font(enum usp10_script scriptid
, WCHAR
*FaceName
)
1962 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1964 static const WCHAR szFmt
[] = {'%','x',0};
1966 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1969 swprintf(value
, ARRAY_SIZE(value
), szFmt
, scriptInformation
[scriptid
].scriptTag
);
1970 if (RegQueryValueExW(hkey
, value
, 0, &type
, (BYTE
*)FaceName
, &count
))
1971 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1975 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1978 /***********************************************************************
1979 * ScriptStringAnalyse (USP10.@)
1982 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1983 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1984 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1985 SCRIPT_STATE
*psState
, const int *piDx
,
1986 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1987 SCRIPT_STRING_ANALYSIS
*pssa
)
1989 HRESULT hr
= E_OUTOFMEMORY
;
1990 StringAnalysis
*analysis
= NULL
;
1991 SCRIPT_CONTROL sControl
;
1992 SCRIPT_STATE sState
;
1993 int i
, num_items
= 255;
1995 WCHAR
*iString
= NULL
;
1997 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1998 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1999 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
2003 FIXME("Only Unicode strings are supported\n");
2004 return E_INVALIDARG
;
2006 if (cString
< 1 || !pString
) return E_INVALIDARG
;
2007 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
2009 if (!(analysis
= heap_alloc_zero(sizeof(*analysis
))))
2010 return E_OUTOFMEMORY
;
2011 if (!(analysis
->pItem
= heap_calloc(num_items
+ 1, sizeof(*analysis
->pItem
))))
2014 /* FIXME: handle clipping */
2015 analysis
->clip_len
= cString
;
2016 analysis
->hdc
= hdc
;
2017 analysis
->ssa_flags
= dwFlags
;
2022 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
2025 sControl
= *psControl
;
2027 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
2029 if (dwFlags
& SSA_PASSWORD
)
2031 if (!(iString
= heap_calloc(cString
, sizeof(*iString
))))
2036 for (i
= 0; i
< cString
; i
++)
2037 iString
[i
] = *((const WCHAR
*)pString
);
2041 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
2042 &analysis
->numItems
);
2046 if (hr
== E_OUTOFMEMORY
)
2051 /* set back to out of memory for default goto error behaviour */
2054 if (dwFlags
& SSA_BREAK
)
2056 if (!(analysis
->logattrs
= heap_calloc(cString
, sizeof(*analysis
->logattrs
))))
2059 for (i
= 0; i
< analysis
->numItems
; ++i
)
2060 ScriptBreak(&((const WCHAR
*)pString
)[analysis
->pItem
[i
].iCharPos
],
2061 analysis
->pItem
[i
+ 1].iCharPos
- analysis
->pItem
[i
].iCharPos
,
2062 &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
2065 if (!(analysis
->logical2visual
= heap_calloc(analysis
->numItems
, sizeof(*analysis
->logical2visual
))))
2067 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
2070 if (dwFlags
& SSA_GLYPHS
)
2074 if (!(analysis
->glyphs
= heap_calloc(analysis
->numItems
, sizeof(*analysis
->glyphs
))))
2076 heap_free(BidiLevel
);
2080 for (i
= 0; i
< analysis
->numItems
; i
++)
2082 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
2083 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2084 int numGlyphs
= 1.5 * cChar
+ 16;
2085 WORD
*glyphs
= heap_calloc(numGlyphs
, sizeof(*glyphs
));
2086 WORD
*pwLogClust
= heap_calloc(cChar
, sizeof(*pwLogClust
));
2087 int *piAdvance
= heap_calloc(numGlyphs
, sizeof(*piAdvance
));
2088 SCRIPT_VISATTR
*psva
= heap_calloc(numGlyphs
, sizeof(*psva
));
2089 GOFFSET
*pGoffset
= heap_calloc(numGlyphs
, sizeof(*pGoffset
));
2090 int numGlyphsReturned
;
2091 HFONT originalFont
= 0x0;
2093 /* FIXME: non unicode strings */
2094 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2095 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2097 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
)
2099 heap_free (BidiLevel
);
2101 heap_free (pwLogClust
);
2102 heap_free (piAdvance
);
2104 heap_free (pGoffset
);
2109 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2112 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2113 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2114 lf
.lfFaceName
[0] = 0;
2115 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2116 if (lf
.lfFaceName
[0])
2118 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2119 if (analysis
->glyphs
[i
].fallbackFont
)
2121 ScriptFreeCache(sc
);
2122 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2127 /* FIXME: When we properly shape Hangul remove this check */
2128 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2129 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2131 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2132 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2134 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2135 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2136 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2137 piAdvance
, pGoffset
, &analysis
->glyphs
[i
].abc
);
2139 SelectObject(hdc
,originalFont
);
2141 if (dwFlags
& SSA_TAB
)
2144 for (tabi
= 0; tabi
< cChar
; tabi
++)
2146 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2147 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2148 tab_x
+=piAdvance
[tabi
];
2152 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2153 analysis
->glyphs
[i
].glyphs
= glyphs
;
2154 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2155 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2156 analysis
->glyphs
[i
].psva
= psva
;
2157 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2158 analysis
->glyphs
[i
].iMaxPosX
= -1;
2160 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2165 for (i
= 0; i
< analysis
->numItems
; i
++)
2166 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2169 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2170 heap_free(BidiLevel
);
2178 heap_free(analysis
->glyphs
);
2179 heap_free(analysis
->logattrs
);
2180 heap_free(analysis
->pItem
);
2181 heap_free(analysis
->logical2visual
);
2182 heap_free(analysis
);
2186 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2188 if (pva
[glyph
].fClusterStart
)
2190 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2197 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2208 StringAnalysis
*analysis
;
2211 COLORREF BkColor
= 0x0;
2212 COLORREF TextColor
= 0x0;
2214 INT runStart
, runEnd
;
2215 INT iGlyph
, cGlyphs
;
2216 HFONT oldFont
= 0x0;
2220 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2221 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2223 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2225 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2226 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2232 BkMode
= GetBkMode(analysis
->hdc
);
2233 SetBkMode( analysis
->hdc
, OPAQUE
);
2234 BkColor
= GetBkColor(analysis
->hdc
);
2235 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2238 TextColor
= GetTextColor(analysis
->hdc
);
2239 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2242 if (analysis
->glyphs
[iItem
].fallbackFont
)
2243 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2245 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2246 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2249 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2250 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2252 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2254 if (analysis
->pItem
[iItem
].a
.fRTL
)
2256 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2257 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2259 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2260 crc
.left
= iX
+ off_x
;
2264 if (cStart
>=0 && runStart
)
2265 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2267 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2268 crc
.left
= iX
+ off_x
;
2271 if (analysis
->pItem
[iItem
].a
.fRTL
)
2272 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2274 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2276 if (analysis
->pItem
[iItem
].a
.fRTL
)
2277 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2279 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2283 /* adjust for cluster glyphs when starting */
2284 if (analysis
->pItem
[iItem
].a
.fRTL
)
2285 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2287 i
= analysis
->pItem
[iItem
].iCharPos
;
2289 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2291 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2293 if (analysis
->pItem
[iItem
].a
.fRTL
)
2294 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2296 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2301 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2306 clust_glyph
= iGlyph
+ cGlyphs
;
2307 if (analysis
->pItem
[iItem
].a
.fRTL
)
2312 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2313 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2320 hr
= ScriptTextOut(analysis
->hdc
,
2321 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2322 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2323 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2324 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2325 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2327 TRACE("ScriptTextOut hr=%08x\n", hr
);
2331 SetBkColor(analysis
->hdc
, BkColor
);
2332 SetBkMode( analysis
->hdc
, BkMode
);
2334 SetTextColor(analysis
->hdc
, TextColor
);
2336 if (analysis
->glyphs
[iItem
].fallbackFont
)
2337 SelectObject(analysis
->hdc
, oldFont
);
2342 /***********************************************************************
2343 * ScriptStringOut (USP10.@)
2345 * This function takes the output of ScriptStringAnalyse and joins the segments
2346 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2347 * only processes glyphs.
2350 * ssa [I] buffer to hold the analysed string components
2351 * iX [I] X axis displacement for output
2352 * iY [I] Y axis displacement for output
2353 * uOptions [I] flags controlling output processing
2354 * prc [I] rectangle coordinates
2355 * iMinSel [I] starting pos for substringing output string
2356 * iMaxSel [I] ending pos for substringing output string
2357 * fDisabled [I] controls text highlighting
2361 * Failure: is the value returned by ScriptTextOut
2363 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2372 StringAnalysis
*analysis
;
2376 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2377 ssa
, iX
, iY
, uOptions
, wine_dbgstr_rect(prc
), iMinSel
, iMaxSel
, fDisabled
);
2379 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2380 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2382 for (item
= 0; item
< analysis
->numItems
; item
++)
2384 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2389 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2391 if (iMaxSel
> 0 && iMinSel
< 0)
2393 for (item
= 0; item
< analysis
->numItems
; item
++)
2395 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2404 /***********************************************************************
2405 * ScriptStringCPtoX (USP10.@)
2408 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2412 StringAnalysis
* analysis
= ssa
;
2414 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2416 if (!ssa
|| !pX
) return S_FALSE
;
2417 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2419 /* icp out of range */
2422 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2423 return E_INVALIDARG
;
2426 for(item
=0; item
<analysis
->numItems
; item
++)
2431 i
= analysis
->logical2visual
[item
];
2432 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2433 /* initialize max extents for uninitialized runs */
2434 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2436 if (analysis
->pItem
[i
].a
.fRTL
)
2437 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2438 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2439 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2441 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2442 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2443 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2446 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2448 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2452 icp
-= analysis
->pItem
[i
].iCharPos
;
2453 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2454 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2455 &analysis
->pItem
[i
].a
, &offset
);
2462 /* icp out of range */
2463 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2464 return E_INVALIDARG
;
2467 /***********************************************************************
2468 * ScriptStringXtoCP (USP10.@)
2471 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2473 StringAnalysis
* analysis
= ssa
;
2476 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2478 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2479 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
2484 if (analysis
->pItem
[0].a
.fRTL
)
2487 *piTrailing
= FALSE
;
2497 for(item
=0; item
<analysis
->numItems
; item
++)
2502 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2505 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2506 /* initialize max extents for uninitialized runs */
2507 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2509 if (analysis
->pItem
[i
].a
.fRTL
)
2510 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2511 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2512 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2514 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2515 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2516 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2519 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2521 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2525 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2526 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2527 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2528 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2534 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2535 *piTrailing
= FALSE
;
2541 /***********************************************************************
2542 * ScriptStringFree (USP10.@)
2544 * Free a string analysis.
2547 * pssa [I] string analysis.
2551 * Failure: Non-zero HRESULT value.
2553 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2555 StringAnalysis
* analysis
;
2559 TRACE("(%p)\n", pssa
);
2561 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2563 invalid
= analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
;
2565 if (analysis
->glyphs
)
2567 for (i
= 0; i
< analysis
->numItems
; i
++)
2569 heap_free(analysis
->glyphs
[i
].glyphs
);
2570 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2571 heap_free(analysis
->glyphs
[i
].piAdvance
);
2572 heap_free(analysis
->glyphs
[i
].psva
);
2573 heap_free(analysis
->glyphs
[i
].pGoffset
);
2574 if (analysis
->glyphs
[i
].fallbackFont
)
2575 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2576 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2577 heap_free(analysis
->glyphs
[i
].sc
);
2579 heap_free(analysis
->glyphs
);
2582 heap_free(analysis
->pItem
);
2583 heap_free(analysis
->logattrs
);
2584 heap_free(analysis
->logical2visual
);
2585 heap_free(analysis
);
2587 if (invalid
) return E_INVALIDARG
;
2591 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2592 int direction
, int* iCluster
, int *check_out
)
2596 WORD clust
= pwLogClust
[item
];
2598 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2600 if (pwLogClust
[check
] == clust
)
2603 if (iCluster
&& *iCluster
== -1)
2615 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
)
2620 advance
= piAdvance
[glyph
];
2622 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2623 log_clust_max
= pwLogClust
[0];
2625 log_clust_max
= pwLogClust
[cChars
-1];
2627 if (glyph
> log_clust_max
)
2630 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2633 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2635 if (glyph
> log_clust_max
)
2637 advance
+= piAdvance
[glyph
];
2643 /***********************************************************************
2644 * ScriptCPtoX (USP10.@)
2647 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2651 const WORD
*pwLogClust
,
2652 const SCRIPT_VISATTR
*psva
,
2653 const int *piAdvance
,
2654 const SCRIPT_ANALYSIS
*psa
,
2662 float special_size
= 0.0;
2667 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2668 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2671 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2679 int max_clust
= pwLogClust
[0];
2681 for (item
=0; item
< cGlyphs
; item
++)
2682 if (pwLogClust
[item
] > max_clust
)
2684 ERR("We do not handle non reversed clusters properly\n");
2689 for (item
= max_clust
; item
>=0; item
--)
2690 iMaxPos
+= piAdvance
[item
];
2694 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2696 if (iSpecial
== -1 && (iCluster
== -1 || iCluster
+clust_size
<= item
))
2699 int clust
= pwLogClust
[item
];
2702 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2705 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2707 if (check
>= cChars
&& !iMaxPos
)
2710 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2711 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2713 special_size
/= (cChars
- item
);
2714 iPosX
+= special_size
;
2718 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2721 if (clust_size
== 0)
2725 iPosX
+= advance
/ (float)clust_size
;
2728 else if (iSpecial
!= -1)
2729 iPosX
+= special_size
;
2730 else /* (iCluster != -1) */
2732 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2733 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2736 if (clust_size
== 0)
2740 iPosX
+= adv
/ (float)clust_size
;
2746 iPosX
= iMaxPos
- iPosX
;
2752 TRACE("*piX=%d\n", *piX
);
2756 /* Count the number of characters in a cluster and its starting index*/
2757 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2762 for (i
= 0; i
< cChars
; i
++)
2764 if (pwLogClust
[i
] == cluster_index
)
2766 if (!size
&& start_index
)
2774 else if (size
) break;
2777 *cluster_size
= size
;
2783 To handle multi-glyph clusters we need to find all the glyphs that are
2784 represented in the cluster. This involves finding the glyph whose
2785 index is the cluster index as well as whose glyph indices are greater than
2786 our cluster index but not part of a new cluster.
2788 Then we sum all those glyphs' advances.
2790 static inline int get_cluster_advance(const int* piAdvance
,
2791 const SCRIPT_VISATTR
*psva
,
2792 const WORD
*pwLogClust
, int cGlyphs
,
2793 int cChars
, int cluster
, int direction
)
2804 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2806 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2807 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2808 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2813 glyph_end
= cGlyphs
;
2816 /* Don't fully understand multi-glyph reversed clusters yet,
2817 * do they occur for real or just in our test? */
2818 FIXME("multi-glyph reversed clusters found\n");
2819 glyph_end
= glyph_start
+ 1;
2823 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2824 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2826 if (psva
[i
].fClusterStart
)
2833 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2834 advance
+= piAdvance
[i
];
2840 /***********************************************************************
2841 * ScriptXtoCP (USP10.@)
2844 * Use piAdvance to find the cluster we are looking at.
2845 * Find the character that is the first character of the cluster.
2846 * That is our base piCP.
2847 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2848 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2849 * determine how far through the cluster to advance the cursor.
2851 HRESULT WINAPI
ScriptXtoCP(int iX
,
2854 const WORD
*pwLogClust
,
2855 const SCRIPT_VISATTR
*psva
,
2856 const int *piAdvance
,
2857 const SCRIPT_ANALYSIS
*psa
,
2864 int glyph_index
, cluster_index
;
2867 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2868 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2869 psa
, piCP
, piTrailing
);
2871 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2874 /* Handle an iX < 0 */
2890 /* Looking for non-reversed clusters in a reversed string */
2893 int max_clust
= pwLogClust
[0];
2894 for (i
=0; i
< cChars
; i
++)
2895 if (pwLogClust
[i
] > max_clust
)
2897 FIXME("We do not handle non reversed clusters properly\n");
2902 /* find the glyph_index based in iX */
2905 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2910 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2914 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2917 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2919 /* find the cluster */
2921 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2924 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2927 TRACE("cluster_index %i\n", cluster_index
);
2929 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2931 /* We are off the end of the string */
2937 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2939 TRACE("first char index %i\n",i
);
2940 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2942 /* Check trailing */
2943 if (glyph_index
!= cluster_index
||
2944 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2945 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2946 *piTrailing
= cluster_size
;
2950 if (cluster_size
> 1)
2952 /* Be part way through the glyph cluster based on size and position */
2953 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2954 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2958 /* back up to the beginning of the cluster */
2959 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2960 adv
+= piAdvance
[part_index
];
2961 if (adv
> iX
) adv
= iX
;
2963 TRACE("Multi-char cluster, no snap\n");
2964 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2965 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2968 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2970 if (part_index
) part_index
--;
2974 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2976 if (part_index
> cluster_size
)
2978 adv
+= cluster_part_width
;
2979 part_index
=cluster_size
;
2983 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2988 i
+= (cluster_size
- part_index
);
2990 /* Check trailing */
2991 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2992 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2997 /* Check trailing */
2998 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2999 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
3006 TRACE("Point falls outside of string\n");
3007 if (glyph_index
< 0)
3009 else /* (glyph_index >= cGlyphs) */
3012 /* If not snapping in the reverse direction (such as Hebrew) Then 0
3013 point flow to the next character */
3016 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
3025 TRACE("*piCP=%d\n", *piCP
);
3026 TRACE("*piTrailing=%d\n", *piTrailing
);
3030 /***********************************************************************
3031 * ScriptBreak (USP10.@)
3033 * Retrieve line break information.
3036 * chars [I] Array of characters.
3037 * sa [I] Script analysis.
3038 * la [I] Array of logical attribute structures.
3044 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
3046 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
3048 if (count
< 0 || !la
) return E_INVALIDARG
;
3049 if (count
== 0) return E_FAIL
;
3051 BREAK_line(chars
, count
, sa
, la
);
3056 /***********************************************************************
3057 * ScriptIsComplex (USP10.@)
3059 * Determine if a string is complex.
3062 * chars [I] Array of characters to test.
3063 * len [I] Length in characters.
3071 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
3073 enum usp10_script script
;
3074 unsigned int i
, consumed
;
3076 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
3078 if (!chars
|| len
< 0)
3079 return E_INVALIDARG
;
3081 for (i
= 0; i
< len
; i
+=consumed
)
3083 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3086 script
= get_char_script(chars
,i
,len
, &consumed
);
3087 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3088 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3094 /***********************************************************************
3095 * ScriptShapeOpenType (USP10.@)
3097 * Produce glyphs and visual attributes for a run.
3100 * hdc [I] Device context.
3101 * psc [I/O] Opaque pointer to a script cache.
3102 * psa [I/O] Script analysis.
3103 * tagScript [I] The OpenType tag for the Script
3104 * tagLangSys [I] The OpenType tag for the Language
3105 * rcRangeChars[I] Array of Character counts in each range
3106 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3107 * cRanges [I] Count of ranges
3108 * pwcChars [I] Array of characters specifying the run.
3109 * cChars [I] Number of characters in pwcChars.
3110 * cMaxGlyphs [I] Length of pwOutGlyphs.
3111 * pwLogClust [O] Array of logical cluster info.
3112 * pCharProps [O] Array of character property values
3113 * pwOutGlyphs [O] Array of glyphs.
3114 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3115 * pcGlyphs [O] Number of glyphs returned.
3119 * Failure: Non-zero HRESULT value.
3121 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3122 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3123 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3124 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3125 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3126 int cMaxGlyphs
, WORD
*pwLogClust
,
3127 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3128 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3135 static int once
= 0;
3137 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3139 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3140 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3141 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3143 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3144 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3146 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3147 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3150 if(!once
++) FIXME("Ranges not supported yet\n");
3152 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3155 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3156 if (!pwLogClust
) return E_FAIL
;
3158 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3159 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3161 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3162 for (i
= 0; i
< cChars
; i
++)
3165 if (rtl
) idx
= cChars
- 1 - i
;
3166 /* FIXME: set to better values */
3167 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3168 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3169 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3170 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3171 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3172 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3174 /* FIXME: have the shaping engine set this */
3175 pCharProps
[i
].fCanGlyphAlone
= 0;
3177 pwLogClust
[i
] = idx
;
3180 if (psa
&& !psa
->fNoGlyphIndex
&& ((ScriptCache
*)*psc
)->sfnt
)
3183 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3185 if (!(rChars
= heap_calloc(cChars
, sizeof(*rChars
))))
3186 return E_OUTOFMEMORY
;
3188 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3193 if (rtl
) idx
= cChars
- 1 - i
;
3196 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3200 chInput
= mirror_char(pwcChars
[idx
]);
3202 chInput
= pwcChars
[idx
];
3203 rChars
[i
] = chInput
;
3207 rChars
[i
] = pwcChars
[idx
];
3208 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3211 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3219 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3224 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3232 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3233 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3239 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3240 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3241 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3243 for (i
= 0; i
< cChars
; ++i
)
3245 /* Special case for tabs and joiners. As control characters, ZWNJ
3246 * and ZWJ would in principle get handled by the corresponding
3247 * shaping functions. However, since ZWNJ and ZWJ can get merged
3248 * into adjoining runs during itemisation, these don't generally
3249 * get classified as Script_Control. */
3250 if (pwcChars
[i
] == 0x0009 || pwcChars
[i
] == ZWSP
|| pwcChars
[i
] == ZWNJ
|| pwcChars
[i
] == ZWJ
)
3252 pwOutGlyphs
[pwLogClust
[i
]] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3253 pOutGlyphProps
[pwLogClust
[i
]].sva
.fZeroWidth
= 1;
3260 TRACE("no glyph translation\n");
3261 for (i
= 0; i
< cChars
; i
++)
3264 /* No mirroring done here */
3265 if (rtl
) idx
= cChars
- 1 - i
;
3266 pwOutGlyphs
[i
] = pwcChars
[idx
];
3271 /* overwrite some basic control glyphs to blank */
3272 if (psa
->fNoGlyphIndex
)
3274 if (pwcChars
[idx
] == ZWSP
|| pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3276 pwOutGlyphs
[i
] = 0x20;
3277 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3280 else if (psa
->eScript
== Script_Control
|| pwcChars
[idx
] == ZWSP
3281 || pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3283 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3284 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3286 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3287 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3297 /***********************************************************************
3298 * ScriptShape (USP10.@)
3300 * Produce glyphs and visual attributes for a run.
3303 * hdc [I] Device context.
3304 * psc [I/O] Opaque pointer to a script cache.
3305 * pwcChars [I] Array of characters specifying the run.
3306 * cChars [I] Number of characters in pwcChars.
3307 * cMaxGlyphs [I] Length of pwOutGlyphs.
3308 * psa [I/O] Script analysis.
3309 * pwOutGlyphs [O] Array of glyphs.
3310 * pwLogClust [O] Array of logical cluster info.
3311 * psva [O] Array of visual attributes.
3312 * pcGlyphs [O] Number of glyphs returned.
3316 * Failure: Non-zero HRESULT value.
3318 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3319 int cChars
, int cMaxGlyphs
,
3320 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3321 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3325 SCRIPT_CHARPROP
*charProps
;
3326 SCRIPT_GLYPHPROP
*glyphProps
;
3328 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3329 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3331 if (!(charProps
= heap_calloc(cChars
, sizeof(*charProps
))))
3332 return E_OUTOFMEMORY
;
3334 if (!(glyphProps
= heap_calloc(cMaxGlyphs
, sizeof(*glyphProps
))))
3336 heap_free(charProps
);
3337 return E_OUTOFMEMORY
;
3340 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3344 for (i
= 0; i
< *pcGlyphs
; i
++)
3345 psva
[i
] = glyphProps
[i
].sva
;
3348 heap_free(charProps
);
3349 heap_free(glyphProps
);
3354 /***********************************************************************
3355 * ScriptPlaceOpenType (USP10.@)
3357 * Produce advance widths for a run.
3360 * hdc [I] Device context.
3361 * psc [I/O] Opaque pointer to a script cache.
3362 * psa [I/O] Script analysis.
3363 * tagScript [I] The OpenType tag for the Script
3364 * tagLangSys [I] The OpenType tag for the Language
3365 * rcRangeChars[I] Array of Character counts in each range
3366 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3367 * cRanges [I] Count of ranges
3368 * pwcChars [I] Array of characters specifying the run.
3369 * pwLogClust [I] Array of logical cluster info
3370 * pCharProps [I] Array of character property values
3371 * cChars [I] Number of characters in pwcChars.
3372 * pwGlyphs [I] Array of glyphs.
3373 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3374 * cGlyphs [I] Count of Glyphs
3375 * piAdvance [O] Array of advance widths.
3376 * pGoffset [O] Glyph offsets.
3377 * pABC [O] Combined ABC width.
3381 * Failure: Non-zero HRESULT value.
3384 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3385 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3386 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3387 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3388 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3389 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3390 int cGlyphs
, int *piAdvance
,
3391 GOFFSET
*pGoffset
, ABC
*pABC
3396 static int once
= 0;
3398 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3400 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3401 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3402 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3405 if (!pGlyphProps
) return E_INVALIDARG
;
3406 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3407 if (!pGoffset
) return E_FAIL
;
3410 if (!once
++) FIXME("Ranges not supported yet\n");
3412 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3413 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3415 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3416 for (i
= 0; i
< cGlyphs
; i
++)
3421 /* FIXME: set to more reasonable values */
3422 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3424 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3426 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3427 if (piAdvance
) piAdvance
[i
] = 0;
3431 if (psa
->fNoGlyphIndex
)
3433 if (FAILED(hr
= ScriptGetCMap(hdc
, psc
, &pwGlyphs
[i
], 1, 0, &glyph
))) return hr
;
3438 glyph
= pwGlyphs
[i
];
3443 if (!hdc
) return E_PENDING
;
3444 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3446 if (!GetCharABCWidthsW(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &abc
)) return S_FALSE
;
3451 if (!GetCharWidthW(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
)) return S_FALSE
;
3453 abc
.abcA
= abc
.abcC
= 0;
3456 else if (!get_cache_glyph_widths(psc
, glyph
, &abc
))
3458 if (!hdc
) return E_PENDING
;
3459 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3461 if (!GetCharABCWidthsI(hdc
, glyph
, 1, NULL
, &abc
)) return S_FALSE
;
3466 if (!GetCharWidthI(hdc
, glyph
, 1, NULL
, &width
)) return S_FALSE
;
3468 abc
.abcA
= abc
.abcC
= 0;
3470 set_cache_glyph_widths(psc
, glyph
, &abc
);
3474 pABC
->abcA
+= abc
.abcA
;
3475 pABC
->abcB
+= abc
.abcB
;
3476 pABC
->abcC
+= abc
.abcC
;
3478 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3481 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3483 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3487 /***********************************************************************
3488 * ScriptPlace (USP10.@)
3490 * Produce advance widths for a run.
3493 * hdc [I] Device context.
3494 * psc [I/O] Opaque pointer to a script cache.
3495 * pwGlyphs [I] Array of glyphs.
3496 * cGlyphs [I] Number of glyphs in pwGlyphs.
3497 * psva [I] Array of visual attributes.
3498 * psa [I/O] String analysis.
3499 * piAdvance [O] Array of advance widths.
3500 * pGoffset [O] Glyph offsets.
3501 * pABC [O] Combined ABC width.
3505 * Failure: Non-zero HRESULT value.
3507 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3508 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3509 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3512 SCRIPT_GLYPHPROP
*glyphProps
;
3515 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3516 piAdvance
, pGoffset
, pABC
);
3518 if (!psva
) return E_INVALIDARG
;
3519 if (!pGoffset
) return E_FAIL
;
3521 if (!(glyphProps
= heap_calloc(cGlyphs
, sizeof(*glyphProps
))))
3522 return E_OUTOFMEMORY
;
3524 for (i
= 0; i
< cGlyphs
; i
++)
3525 glyphProps
[i
].sva
= psva
[i
];
3527 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3529 heap_free(glyphProps
);
3534 /***********************************************************************
3535 * ScriptGetCMap (USP10.@)
3537 * Retrieve glyph indices.
3540 * hdc [I] Device context.
3541 * psc [I/O] Opaque pointer to a script cache.
3542 * pwcInChars [I] Array of Unicode characters.
3543 * cChars [I] Number of characters in pwcInChars.
3544 * dwFlags [I] Flags.
3545 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3549 * Failure: Non-zero HRESULT value.
3551 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3552 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3557 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3558 cChars
, dwFlags
, pwOutGlyphs
);
3560 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3564 for (i
= 0; i
< cChars
; i
++)
3567 if (dwFlags
== SGCM_RTL
)
3568 inChar
= mirror_char(pwcInChars
[i
]);
3570 inChar
= pwcInChars
[i
];
3571 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3574 if (!hdc
) return E_PENDING
;
3575 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3576 if (glyph
== 0xffff)
3581 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3588 /***********************************************************************
3589 * ScriptTextOut (USP10.@)
3592 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3593 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3594 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3595 const int *piJustify
, const GOFFSET
*pGoffset
)
3600 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3602 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3603 hdc
, psc
, x
, y
, fuOptions
, wine_dbgstr_rect(lprc
), psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3604 piAdvance
, piJustify
, pGoffset
);
3606 if (!hdc
|| !psc
) return E_INVALIDARG
;
3607 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3609 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3610 fuOptions
|= ETO_IGNORELANGUAGE
;
3611 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3612 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3614 if (!(lpDx
= heap_calloc(cGlyphs
, 2 * sizeof(*lpDx
))))
3615 return E_OUTOFMEMORY
;
3616 fuOptions
|= ETO_PDY
;
3618 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3620 if (!(reordered_glyphs
= heap_calloc(cGlyphs
, sizeof(*reordered_glyphs
))))
3623 return E_OUTOFMEMORY
;
3626 for (i
= 0; i
< cGlyphs
; i
++)
3627 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3631 for (i
= 0; i
< cGlyphs
; i
++)
3633 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3634 lpDx
[i
* 2] = piAdvance
[orig_index
];
3635 lpDx
[i
* 2 + 1] = 0;
3641 x
+= pGoffset
[orig_index
].du
* dir
;
3642 y
+= pGoffset
[orig_index
].dv
;
3646 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3647 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3649 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3650 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3654 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3657 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3663 /***********************************************************************
3664 * ScriptCacheGetHeight (USP10.@)
3666 * Retrieve the height of the font in the cache.
3669 * hdc [I] Device context.
3670 * psc [I/O] Opaque pointer to a script cache.
3671 * height [O] Receives font height.
3675 * Failure: Non-zero HRESULT value.
3677 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3681 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3683 if (!height
) return E_INVALIDARG
;
3684 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3686 *height
= get_cache_height(psc
);
3690 /***********************************************************************
3691 * ScriptGetGlyphABCWidth (USP10.@)
3693 * Retrieve the width of a glyph.
3696 * hdc [I] Device context.
3697 * psc [I/O] Opaque pointer to a script cache.
3698 * glyph [I] Glyph to retrieve the width for.
3699 * abc [O] ABC widths of the glyph.
3703 * Failure: Non-zero HRESULT value.
3705 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3709 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3711 if (!abc
) return E_INVALIDARG
;
3712 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3714 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3716 if (!hdc
) return E_PENDING
;
3717 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3719 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3724 if (!GetCharWidthI(hdc
, glyph
, 1, NULL
, &width
)) return S_FALSE
;
3726 abc
->abcA
= abc
->abcC
= 0;
3728 set_cache_glyph_widths(psc
, glyph
, abc
);
3733 /***********************************************************************
3734 * ScriptLayout (USP10.@)
3736 * Map embedding levels to visual and/or logical order.
3739 * runs [I] Size of level array.
3740 * level [I] Array of embedding levels.
3741 * vistolog [O] Map of embedding levels from visual to logical order.
3742 * logtovis [O] Map of embedding levels from logical to visual order.
3746 * Failure: Non-zero HRESULT value.
3749 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3754 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3756 if (!level
|| (!vistolog
&& !logtovis
))
3757 return E_INVALIDARG
;
3759 if (!(indices
= heap_calloc(runs
, sizeof(*indices
))))
3760 return E_OUTOFMEMORY
;
3764 for( ich
= 0; ich
< runs
; ich
++)
3769 ich
+= BIDI_ReorderV2lLevel(0, indices
+ich
, level
+ich
, runs
- ich
, FALSE
);
3770 memcpy(vistolog
, indices
, runs
* sizeof(*vistolog
));
3775 for( ich
= 0; ich
< runs
; ich
++)
3780 ich
+= BIDI_ReorderL2vLevel(0, indices
+ich
, level
+ich
, runs
- ich
, FALSE
);
3781 memcpy(logtovis
, indices
, runs
* sizeof(*logtovis
));
3788 /***********************************************************************
3789 * ScriptStringGetLogicalWidths (USP10.@)
3791 * Returns logical widths from a string analysis.
3794 * ssa [I] string analysis.
3795 * piDx [O] logical widths returned.
3799 * Failure: a non-zero HRESULT.
3801 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3804 StringAnalysis
*analysis
= ssa
;
3806 TRACE("%p, %p\n", ssa
, piDx
);
3808 if (!analysis
) return S_FALSE
;
3809 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3811 for (i
= 0; i
< analysis
->numItems
; i
++)
3813 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3816 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3819 for (j
= 0; j
< cChar
; j
++)
3822 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3823 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3824 cChar
, j
, direction
, NULL
, NULL
);
3825 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
);
3827 for (k
= 0; k
< clust_size
; k
++)
3829 piDx
[next
] = advance
/ clust_size
;
3838 /***********************************************************************
3839 * ScriptStringValidate (USP10.@)
3841 * Validate a string analysis.
3844 * ssa [I] string analysis.
3848 * Failure: S_FALSE if invalid sequences are found
3849 * or a non-zero HRESULT if it fails.
3851 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3853 StringAnalysis
*analysis
= ssa
;
3855 TRACE("(%p)\n", ssa
);
3857 if (!analysis
) return E_INVALIDARG
;
3858 return analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_INVALID
? S_FALSE
: S_OK
;
3861 /***********************************************************************
3862 * ScriptString_pSize (USP10.@)
3864 * Retrieve width and height of an analysed string.
3867 * ssa [I] string analysis.
3870 * Success: Pointer to a SIZE structure.
3873 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3876 StringAnalysis
*analysis
= ssa
;
3878 TRACE("(%p)\n", ssa
);
3880 if (!analysis
) return NULL
;
3881 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return NULL
;
3883 if (!(analysis
->flags
& SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
))
3885 analysis
->sz
.cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3887 analysis
->sz
.cx
= 0;
3888 for (i
= 0; i
< analysis
->numItems
; i
++)
3890 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
.cy
)
3891 analysis
->sz
.cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3892 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3893 analysis
->sz
.cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3895 analysis
->flags
|= SCRIPT_STRING_ANALYSIS_FLAGS_SIZE
;
3897 return &analysis
->sz
;
3900 /***********************************************************************
3901 * ScriptString_pLogAttr (USP10.@)
3903 * Retrieve logical attributes of an analysed string.
3906 * ssa [I] string analysis.
3909 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3912 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3914 StringAnalysis
*analysis
= ssa
;
3916 TRACE("(%p)\n", ssa
);
3918 if (!analysis
) return NULL
;
3919 if (!(analysis
->ssa_flags
& SSA_BREAK
)) return NULL
;
3920 return analysis
->logattrs
;
3923 /***********************************************************************
3924 * ScriptString_pcOutChars (USP10.@)
3926 * Retrieve the length of a string after clipping.
3929 * ssa [I] String analysis.
3932 * Success: Pointer to the length.
3935 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3937 StringAnalysis
*analysis
= ssa
;
3939 TRACE("(%p)\n", ssa
);
3941 if (!analysis
) return NULL
;
3942 return &analysis
->clip_len
;
3945 /***********************************************************************
3946 * ScriptStringGetOrder (USP10.@)
3948 * Retrieve a glyph order map.
3951 * ssa [I] String analysis.
3952 * order [I/O] Array of glyph positions.
3956 * Failure: a non-zero HRESULT.
3958 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3962 StringAnalysis
*analysis
= ssa
;
3964 TRACE("(%p)\n", ssa
);
3966 if (!analysis
) return S_FALSE
;
3967 if (!(analysis
->ssa_flags
& SSA_GLYPHS
)) return S_FALSE
;
3969 /* FIXME: handle RTL scripts */
3970 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3971 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3977 /***********************************************************************
3978 * ScriptGetLogicalWidths (USP10.@)
3980 * Convert advance widths to logical widths.
3983 * sa [I] Script analysis.
3984 * nbchars [I] Number of characters.
3985 * nbglyphs [I] Number of glyphs.
3986 * glyph_width [I] Array of glyph widths.
3987 * log_clust [I] Array of logical clusters.
3988 * sva [I] Visual attributes.
3989 * widths [O] Array of logical widths.
3993 * Failure: a non-zero HRESULT.
3995 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3996 const int *advances
, const WORD
*log_clust
,
3997 const SCRIPT_VISATTR
*sva
, int *widths
)
3999 int i
, next
= 0, direction
;
4001 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
4002 sa
, nbchars
, nbglyphs
, advances
, log_clust
, sva
, widths
);
4004 if (sa
->fRTL
&& !sa
->fLogicalOrder
)
4009 for (i
= 0; i
< nbchars
; i
++)
4011 int clust_size
= get_cluster_size(log_clust
, nbchars
, i
, direction
, NULL
, NULL
);
4012 int advance
= get_glyph_cluster_advance(advances
, sva
, log_clust
, nbglyphs
, nbchars
, log_clust
[i
], direction
);
4015 for (j
= 0; j
< clust_size
; j
++)
4017 widths
[next
] = advance
/ clust_size
;
4026 /***********************************************************************
4027 * ScriptApplyLogicalWidth (USP10.@)
4029 * Generate glyph advance widths.
4032 * dx [I] Array of logical advance widths.
4033 * num_chars [I] Number of characters.
4034 * num_glyphs [I] Number of glyphs.
4035 * log_clust [I] Array of logical clusters.
4036 * sva [I] Visual attributes.
4037 * advance [I] Array of glyph advance widths.
4038 * sa [I] Script analysis.
4039 * abc [I/O] Summed ABC widths.
4040 * justify [O] Array of glyph advance widths.
4044 * Failure: a non-zero HRESULT.
4046 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
4047 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
4048 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
4049 ABC
*abc
, int *justify
)
4053 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
4054 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
4056 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
4060 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
4061 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
4065 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
4067 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
4071 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
4074 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4075 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4077 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
4080 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
4083 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4084 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4086 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
4089 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
4092 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4093 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4095 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);