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.
27 #include "usp10_internal.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe
);
35 static const struct usp10_script_range
37 enum usp10_script script
;
40 enum usp10_script numericScript
;
41 enum usp10_script punctScript
;
45 /* Basic Latin: U+0000–U+007A */
46 { Script_Latin
, 0x00, 0x07a , Script_Numeric
, Script_Punctuation
},
47 /* Latin-1 Supplement: U+0080–U+00FF */
48 /* Latin Extended-A: U+0100–U+017F */
49 /* Latin Extended-B: U+0180–U+024F */
50 /* IPA Extensions: U+0250–U+02AF */
51 /* Spacing Modifier Letters:U+02B0–U+02FF */
52 { Script_Latin
, 0x80, 0x2ff , Script_Numeric2
, Script_Punctuation
},
53 /* Combining Diacritical Marks : U+0300–U+036F */
54 { Script_Diacritical
,0x300, 0x36f, 0, 0},
55 /* Greek: U+0370–U+03FF */
56 { Script_Greek
, 0x370, 0x3ff, 0, 0},
57 /* Cyrillic: U+0400–U+04FF */
58 /* Cyrillic Supplement: U+0500–U+052F */
59 { Script_Cyrillic
, 0x400, 0x52f, 0, 0},
60 /* Armenian: U+0530–U+058F */
61 { Script_Armenian
, 0x530, 0x58f, 0, 0},
62 /* Hebrew: U+0590–U+05FF */
63 { Script_Hebrew
, 0x590, 0x5ff, 0, 0},
64 /* Arabic: U+0600–U+06FF */
65 { Script_Arabic
, 0x600, 0x6ef, Script_Arabic_Numeric
, 0},
66 /* Defined by Windows */
67 { Script_Persian
, 0x6f0, 0x6f9, 0, 0},
68 /* Continue Arabic: U+0600–U+06FF */
69 { Script_Arabic
, 0x6fa, 0x6ff, 0, 0},
70 /* Syriac: U+0700–U+074F*/
71 { Script_Syriac
, 0x700, 0x74f, 0, 0},
72 /* Arabic Supplement: U+0750–U+077F */
73 { Script_Arabic
, 0x750, 0x77f, 0, 0},
74 /* Thaana: U+0780–U+07BF */
75 { Script_Thaana
, 0x780, 0x7bf, 0, 0},
76 /* N’Ko: U+07C0–U+07FF */
77 { Script_NKo
, 0x7c0, 0x7ff, 0, 0},
78 /* Devanagari: U+0900–U+097F */
79 { Script_Devanagari
, 0x900, 0x97f, Script_Devanagari_Numeric
, 0},
80 /* Bengali: U+0980–U+09FF */
81 { Script_Bengali
, 0x980, 0x9ff, Script_Bengali_Numeric
, 0},
82 /* Gurmukhi: U+0A00–U+0A7F*/
83 { Script_Gurmukhi
, 0xa00, 0xa7f, Script_Gurmukhi_Numeric
, 0},
84 /* Gujarati: U+0A80–U+0AFF*/
85 { Script_Gujarati
, 0xa80, 0xaff, Script_Gujarati_Numeric
, 0},
86 /* Oriya: U+0B00–U+0B7F */
87 { Script_Oriya
, 0xb00, 0xb7f, Script_Oriya_Numeric
, 0},
88 /* Tamil: U+0B80–U+0BFF */
89 { Script_Tamil
, 0xb80, 0xbff, Script_Tamil_Numeric
, 0},
90 /* Telugu: U+0C00–U+0C7F */
91 { Script_Telugu
, 0xc00, 0xc7f, Script_Telugu_Numeric
, 0},
92 /* Kannada: U+0C80–U+0CFF */
93 { Script_Kannada
, 0xc80, 0xcff, Script_Kannada_Numeric
, 0},
94 /* Malayalam: U+0D00–U+0D7F */
95 { Script_Malayalam
, 0xd00, 0xd7f, Script_Malayalam_Numeric
, 0},
96 /* Sinhala: U+0D80–U+0DFF */
97 { Script_Sinhala
, 0xd80, 0xdff, 0, 0},
98 /* Thai: U+0E00–U+0E7F */
99 { Script_Thai
, 0xe00, 0xe7f, Script_Thai_Numeric
, 0},
100 /* Lao: U+0E80–U+0EFF */
101 { Script_Lao
, 0xe80, 0xeff, Script_Lao_Numeric
, 0},
102 /* Tibetan: U+0F00–U+0FFF */
103 { Script_Tibetan
, 0xf00, 0xfff, 0, 0},
104 /* Myanmar: U+1000–U+109F */
105 { Script_Myanmar
, 0x1000, 0x109f, Script_Myanmar_Numeric
, 0},
106 /* Georgian: U+10A0–U+10FF */
107 { Script_Georgian
, 0x10a0, 0x10ff, 0, 0},
108 /* Hangul Jamo: U+1100–U+11FF */
109 { Script_Hangul
, 0x1100, 0x11ff, 0, 0},
110 /* Ethiopic: U+1200–U+137F */
111 /* Ethiopic Extensions: U+1380–U+139F */
112 { Script_Ethiopic
, 0x1200, 0x139f, 0, 0},
113 /* Cherokee: U+13A0–U+13FF */
114 { Script_Cherokee
, 0x13a0, 0x13ff, 0, 0},
115 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
116 { Script_Canadian
, 0x1400, 0x167f, 0, 0},
117 /* Ogham: U+1680–U+169F */
118 { Script_Ogham
, 0x1680, 0x169f, 0, 0},
119 /* Runic: U+16A0–U+16F0 */
120 { Script_Runic
, 0x16a0, 0x16f0, 0, 0},
121 /* Khmer: U+1780–U+17FF */
122 { Script_Khmer
, 0x1780, 0x17ff, Script_Khmer_Numeric
, 0},
123 /* Mongolian: U+1800–U+18AF */
124 { Script_Mongolian
, 0x1800, 0x18af, Script_Mongolian_Numeric
, 0},
125 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
126 { Script_Canadian
, 0x18b0, 0x18ff, 0, 0},
127 /* Tai Le: U+1950–U+197F */
128 { Script_Tai_Le
, 0x1950, 0x197f, 0, 0},
129 /* New Tai Lue: U+1980–U+19DF */
130 { Script_New_Tai_Lue
,0x1980, 0x19df, Script_New_Tai_Lue_Numeric
, 0},
131 /* Khmer Symbols: U+19E0–U+19FF */
132 { Script_Khmer
, 0x19e0, 0x19ff, Script_Khmer_Numeric
, 0},
133 /* Vedic Extensions: U+1CD0-U+1CFF */
134 { Script_Devanagari
, 0x1cd0, 0x1cff, Script_Devanagari_Numeric
, 0},
135 /* Phonetic Extensions: U+1D00–U+1DBF */
136 { Script_Latin
, 0x1d00, 0x1dbf, 0, 0},
137 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
138 { Script_Diacritical
,0x1dc0, 0x1dff, 0, 0},
139 /* Latin Extended Additional: U+1E00–U+1EFF */
140 { Script_Latin
, 0x1e00, 0x1eff, 0, 0},
141 /* Greek Extended: U+1F00–U+1FFF */
142 { Script_Greek
, 0x1f00, 0x1fff, 0, 0},
143 /* General Punctuation: U+2000 –U+206f */
144 { Script_Latin
, 0x2000, 0x206f, 0, 0},
145 /* Superscripts and Subscripts : U+2070 –U+209f */
146 /* Currency Symbols : U+20a0 –U+20cf */
147 { Script_Numeric2
, 0x2070, 0x2070, 0, 0},
148 { Script_Latin
, 0x2071, 0x2073, 0, 0},
149 { Script_Numeric2
, 0x2074, 0x2079, 0, 0},
150 { Script_Latin
, 0x207a, 0x207f, 0, 0},
151 { Script_Numeric2
, 0x2080, 0x2089, 0, 0},
152 { Script_Latin
, 0x208a, 0x20cf, 0, 0},
153 /* Letterlike Symbols : U+2100 –U+214f */
154 /* Number Forms : U+2150 –U+218f */
155 /* Arrows : U+2190 –U+21ff */
156 /* Mathematical Operators : U+2200 –U+22ff */
157 /* Miscellaneous Technical : U+2300 –U+23ff */
158 /* Control Pictures : U+2400 –U+243f */
159 /* Optical Character Recognition : U+2440 –U+245f */
160 /* Enclosed Alphanumerics : U+2460 –U+24ff */
161 /* Box Drawing : U+2500 –U+25ff */
162 /* Block Elements : U+2580 –U+259f */
163 /* Geometric Shapes : U+25a0 –U+25ff */
164 /* Miscellaneous Symbols : U+2600 –U+26ff */
165 /* Dingbats : U+2700 –U+27bf */
166 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
167 /* Supplemental Arrows-A : U+27f0 –U+27ff */
168 { Script_Latin
, 0x2100, 0x27ff, 0, 0},
169 /* Braille Patterns: U+2800–U+28FF */
170 { Script_Braille
, 0x2800, 0x28ff, 0, 0},
171 /* Supplemental Arrows-B : U+2900 –U+297f */
172 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
173 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
174 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
175 { Script_Latin
, 0x2900, 0x2bff, 0, 0},
176 /* Latin Extended-C: U+2C60–U+2C7F */
177 { Script_Latin
, 0x2c60, 0x2c7f, 0, 0},
178 /* Georgian: U+2D00–U+2D2F */
179 { Script_Georgian
, 0x2d00, 0x2d2f, 0, 0},
180 /* Tifinagh: U+2D30–U+2D7F */
181 { Script_Tifinagh
, 0x2d30, 0x2d7f, 0, 0},
182 /* Ethiopic Extensions: U+2D80–U+2DDF */
183 { Script_Ethiopic
, 0x2d80, 0x2ddf, 0, 0},
184 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
185 { Script_Cyrillic
, 0x2de0, 0x2dff, 0, 0},
186 /* CJK Radicals Supplement: U+2E80–U+2EFF */
187 /* Kangxi Radicals: U+2F00–U+2FDF */
188 { Script_CJK_Han
, 0x2e80, 0x2fdf, 0, 0},
189 /* Ideographic Description Characters: U+2FF0–U+2FFF */
190 { Script_Ideograph
,0x2ff0, 0x2fff, 0, 0},
191 /* CJK Symbols and Punctuation: U+3000–U+303F */
192 { Script_Ideograph
,0x3000, 0x3004, 0, 0},
193 { Script_CJK_Han
,0x3005, 0x3005, 0, 0},
194 { Script_Ideograph
,0x3006, 0x3006, 0, 0},
195 { Script_CJK_Han
,0x3007, 0x3007, 0, 0},
196 { Script_Ideograph
,0x3008, 0x3020, 0, 0},
197 { Script_CJK_Han
,0x3021, 0x3029, 0, 0},
198 { Script_Ideograph
,0x302a, 0x3030, 0, 0},
200 { Script_Kana
,0x3031, 0x3035, 0, 0},
201 { Script_Ideograph
,0x3036, 0x3037, 0, 0},
202 { Script_CJK_Han
,0x3038, 0x303b, 0, 0},
203 { Script_Ideograph
,0x303c, 0x303f, 0, 0},
204 /* Hiragana: U+3040–U+309F */
205 /* Katakana: U+30A0–U+30FF */
206 { Script_Kana
,0x3040, 0x30ff, 0, 0},
207 /* Bopomofo: U+3100–U+312F */
208 { Script_Bopomofo
,0x3100, 0x312f, 0, 0},
209 /* Hangul Compatibility Jamo: U+3130–U+318F */
210 { Script_Hangul
,0x3130, 0x318f, 0, 0},
211 /* Kanbun: U+3190–U+319F */
212 { Script_Ideograph
,0x3190, 0x319f, 0, 0},
213 /* Bopomofo Extended: U+31A0–U+31BF */
214 { Script_Bopomofo
,0x31a0, 0x31bf, 0, 0},
215 /* CJK Strokes: U+31C0–U+31EF */
216 { Script_Ideograph
,0x31c0, 0x31ef, 0, 0},
217 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
218 { Script_Kana
,0x31f0, 0x31ff, 0, 0},
219 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
220 { Script_Hangul
,0x3200, 0x321f, 0, 0},
221 { Script_Ideograph
,0x3220, 0x325f, 0, 0},
222 { Script_Hangul
,0x3260, 0x327f, 0, 0},
223 { Script_Ideograph
,0x3280, 0x32ef, 0, 0},
224 { Script_Kana
,0x32d0, 0x31ff, 0, 0},
225 /* CJK Compatibility: U+3300–U+33FF*/
226 { Script_Kana
,0x3300, 0x3357, 0, 0},
227 { Script_Ideograph
,0x3358, 0x33ff, 0, 0},
228 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
229 { Script_CJK_Han
,0x3400, 0x4dbf, 0, 0},
230 /* CJK Unified Ideographs: U+4E00–U+9FFF */
231 { Script_CJK_Han
,0x4e00, 0x9fff, 0, 0},
232 /* Yi: U+A000–U+A4CF */
233 { Script_Yi
,0xa000, 0xa4cf, 0, 0},
234 /* Vai: U+A500–U+A63F */
235 { Script_Vai
,0xa500, 0xa63f, Script_Vai_Numeric
, 0},
236 /* Cyrillic Extended-B: U+A640–U+A69F */
237 { Script_Cyrillic
, 0xa640, 0xa69f, 0, 0},
238 /* Modifier Tone Letters: U+A700–U+A71F */
239 /* Latin Extended-D: U+A720–U+A7FF */
240 { Script_Latin
, 0xa700, 0xa7ff, 0, 0},
241 /* Phags-pa: U+A840–U+A87F */
242 { Script_Phags_pa
, 0xa840, 0xa87f, 0, 0},
243 /* Devanagari Extended: U+A8E0-U+A8FF */
244 { Script_Devanagari
, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric
, 0},
245 /* Myanmar Extended-A: U+AA60–U+AA7F */
246 { Script_Myanmar
, 0xaa60, 0xaa7f, Script_Myanmar_Numeric
, 0},
247 /* Hangul Jamo Extended-A: U+A960–U+A97F */
248 { Script_Hangul
, 0xa960, 0xa97f, 0, 0},
249 /* Hangul Syllables: U+AC00–U+D7A3 */
250 { Script_Hangul
, 0xac00, 0xd7a3, 0, 0},
251 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
252 { Script_Hangul
, 0xd7b0, 0xd7ff, 0, 0},
253 /* Surrogates Area: U+D800–U+DFFF */
254 { Script_Surrogates
, 0xd800, 0xdbfe, 0, 0},
255 { Script_Private
, 0xdbff, 0xdc00, 0, 0},
256 { Script_Surrogates
, 0xdc01, 0xdfff, 0, 0},
257 /* Private Use Area: U+E000–U+F8FF */
258 { Script_Private
, 0xe000, 0xf8ff, 0, 0},
259 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
260 { Script_CJK_Han
,0xf900, 0xfaff, 0, 0},
261 /* Latin Ligatures: U+FB00–U+FB06 */
262 { Script_Latin
, 0xfb00, 0xfb06, 0, 0},
263 /* Armenian ligatures U+FB13..U+FB17 */
264 { Script_Armenian
, 0xfb13, 0xfb17, 0, 0},
265 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
266 { Script_Hebrew
, 0xfb1d, 0xfb4f, 0, 0},
267 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
268 { Script_Arabic
, 0xfb50, 0xfdff, 0, 0},
269 /* Vertical Forms: U+FE10–U+FE1F */
270 /* Combining Half Marks: U+FE20–U+FE2F */
271 /* CJK Compatibility Forms: U+FE30–U+FE4F */
272 /* Small Form Variants: U+FE50–U+FE6F */
273 { Script_Ideograph
,0xfe10, 0xfe6f, 0, 0},
274 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
275 { Script_Arabic
, 0xfe70, 0xfeff, 0, 0},
276 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
277 { Script_Ideograph
,0xff00, 0xff64, Script_Numeric2
, 0},
278 { Script_Kana
,0xff65, 0xff9f, 0, 0},
279 { Script_Hangul
,0xffa0, 0xffdf, 0, 0},
280 { Script_Ideograph
,0xffe0, 0xffef, 0, 0},
282 /* Deseret: U+10400–U+1044F */
283 { Script_Deseret
, 0x10400, 0x1044F, 0, 0},
284 /* Osmanya: U+10480–U+104AF */
285 { Script_Osmanya
, 0x10480, 0x104AF, Script_Osmanya_Numeric
, 0},
286 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
287 { Script_MathAlpha
, 0x1D400, 0x1D7FF, 0, 0},
290 /* this must be in order so that the index matches the Script value */
291 const scriptData scriptInformation
[] = {
292 {{SCRIPT_UNDEFINED
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
293 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
296 {{Script_Latin
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
297 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
298 MS_MAKE_TAG('l','a','t','n'),
299 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
300 {{Script_CR
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
301 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
304 {{Script_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
305 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
307 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
308 {{Script_Control
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
309 {LANG_ENGLISH
, 0, 1, 0, 0, ANSI_CHARSET
, 1, 0, 0, 0, 0, 0, 1, 0, 0},
312 {{Script_Punctuation
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
313 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
315 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
316 {{Script_Arabic
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
317 {LANG_ARABIC
, 0, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 1, 0},
318 MS_MAKE_TAG('a','r','a','b'),
319 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
320 {{Script_Arabic_Numeric
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
321 {LANG_ARABIC
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
322 MS_MAKE_TAG('a','r','a','b'),
323 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
324 {{Script_Hebrew
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
325 {LANG_HEBREW
, 0, 1, 0, 1, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
326 MS_MAKE_TAG('h','e','b','r'),
327 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
328 {{Script_Syriac
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
329 {LANG_SYRIAC
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 1, 0},
330 MS_MAKE_TAG('s','y','r','c'),
331 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
332 {{Script_Persian
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
333 {LANG_PERSIAN
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
334 MS_MAKE_TAG('a','r','a','b'),
335 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
336 {{Script_Thaana
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
337 {LANG_DIVEHI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
338 MS_MAKE_TAG('t','h','a','a'),
339 {'M','V',' ','B','o','l','i',0}},
340 {{Script_Greek
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
341 {LANG_GREEK
, 0, 0, 0, 0, GREEK_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
342 MS_MAKE_TAG('g','r','e','k'),
343 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
344 {{Script_Cyrillic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
345 {LANG_RUSSIAN
, 0, 0, 0, 0, RUSSIAN_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
346 MS_MAKE_TAG('c','y','r','l'),
347 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
348 {{Script_Armenian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
349 {LANG_ARMENIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
350 MS_MAKE_TAG('a','r','m','n'),
351 {'S','y','l','f','a','e','n',0}},
352 {{Script_Georgian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
353 {LANG_GEORGIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
354 MS_MAKE_TAG('g','e','o','r'),
355 {'S','y','l','f','a','e','n',0}},
356 {{Script_Sinhala
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
357 {LANG_SINHALESE
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
358 MS_MAKE_TAG('s','i','n','h'),
359 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
360 {{Script_Tibetan
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
361 {LANG_TIBETAN
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
362 MS_MAKE_TAG('t','i','b','t'),
363 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
364 {{Script_Tibetan_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
365 {LANG_TIBETAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
366 MS_MAKE_TAG('t','i','b','t'),
367 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
368 {{Script_Phags_pa
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
369 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
370 MS_MAKE_TAG('p','h','a','g'),
371 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
372 {{Script_Thai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
373 {LANG_THAI
, 0, 1, 1, 1, THAI_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 1},
374 MS_MAKE_TAG('t','h','a','i'),
375 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
376 {{Script_Thai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
377 {LANG_THAI
, 1, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
378 MS_MAKE_TAG('t','h','a','i'),
379 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
380 {{Script_Lao
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
381 {LANG_LAO
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
382 MS_MAKE_TAG('l','a','o',' '),
383 {'D','o','k','C','h','a','m','p','a',0}},
384 {{Script_Lao_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
385 {LANG_LAO
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
386 MS_MAKE_TAG('l','a','o',' '),
387 {'D','o','k','C','h','a','m','p','a',0}},
388 {{Script_Devanagari
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
389 {LANG_HINDI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
390 MS_MAKE_TAG('d','e','v','a'),
391 {'M','a','n','g','a','l',0}},
392 {{Script_Devanagari_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
393 {LANG_HINDI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
394 MS_MAKE_TAG('d','e','v','a'),
395 {'M','a','n','g','a','l',0}},
396 {{Script_Bengali
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
397 {LANG_BENGALI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
398 MS_MAKE_TAG('b','e','n','g'),
399 {'V','r','i','n','d','a',0}},
400 {{Script_Bengali_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
401 {LANG_BENGALI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
402 MS_MAKE_TAG('b','e','n','g'),
403 {'V','r','i','n','d','a',0}},
404 {{Script_Bengali_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
405 {LANG_BENGALI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
406 MS_MAKE_TAG('b','e','n','g'),
407 {'V','r','i','n','d','a',0}},
408 {{Script_Gurmukhi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
409 {LANG_PUNJABI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
410 MS_MAKE_TAG('g','u','r','u'),
411 {'R','a','a','v','i',0}},
412 {{Script_Gurmukhi_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
413 {LANG_PUNJABI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
414 MS_MAKE_TAG('g','u','r','u'),
415 {'R','a','a','v','i',0}},
416 {{Script_Gujarati
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
417 {LANG_GUJARATI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
418 MS_MAKE_TAG('g','u','j','r'),
419 {'S','h','r','u','t','i',0}},
420 {{Script_Gujarati_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
421 {LANG_GUJARATI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
422 MS_MAKE_TAG('g','u','j','r'),
423 {'S','h','r','u','t','i',0}},
424 {{Script_Gujarati_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
425 {LANG_GUJARATI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
426 MS_MAKE_TAG('g','u','j','r'),
427 {'S','h','r','u','t','i',0}},
428 {{Script_Oriya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
429 {LANG_ORIYA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
430 MS_MAKE_TAG('o','r','y','a'),
431 {'K','a','l','i','n','g','a',0}},
432 {{Script_Oriya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
433 {LANG_ORIYA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
434 MS_MAKE_TAG('o','r','y','a'),
435 {'K','a','l','i','n','g','a',0}},
436 {{Script_Tamil
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
437 {LANG_TAMIL
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
438 MS_MAKE_TAG('t','a','m','l'),
439 {'L','a','t','h','a',0}},
440 {{Script_Tamil_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
441 {LANG_TAMIL
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
442 MS_MAKE_TAG('t','a','m','l'),
443 {'L','a','t','h','a',0}},
444 {{Script_Telugu
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
445 {LANG_TELUGU
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
446 MS_MAKE_TAG('t','e','l','u'),
447 {'G','a','u','t','a','m','i',0}},
448 {{Script_Telugu_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
449 {LANG_TELUGU
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
450 MS_MAKE_TAG('t','e','l','u'),
451 {'G','a','u','t','a','m','i',0}},
452 {{Script_Kannada
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
453 {LANG_KANNADA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
454 MS_MAKE_TAG('k','n','d','a'),
455 {'T','u','n','g','a',0}},
456 {{Script_Kannada_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
457 {LANG_KANNADA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
458 MS_MAKE_TAG('k','n','d','a'),
459 {'T','u','n','g','a',0}},
460 {{Script_Malayalam
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
461 {LANG_MALAYALAM
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
462 MS_MAKE_TAG('m','l','y','m'),
463 {'K','a','r','t','i','k','a',0}},
464 {{Script_Malayalam_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
465 {LANG_MALAYALAM
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
466 MS_MAKE_TAG('m','l','y','m'),
467 {'K','a','r','t','i','k','a',0}},
468 {{Script_Diacritical
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
469 {LANG_ENGLISH
, 0, 1, 0, 1, ANSI_CHARSET
, 0, 0, 0, 0, 0, 1, 1, 0, 0},
472 {{Script_Punctuation2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
473 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
474 MS_MAKE_TAG('l','a','t','n'),
475 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
476 {{Script_Numeric2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
477 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
480 {{Script_Myanmar
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
481 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
482 MS_MAKE_TAG('m','y','m','r'),
483 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
484 {{Script_Myanmar_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
485 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
486 MS_MAKE_TAG('m','y','m','r'),
488 {{Script_Tai_Le
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
489 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
490 MS_MAKE_TAG('t','a','l','e'),
491 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
492 {{Script_New_Tai_Lue
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
493 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
494 MS_MAKE_TAG('t','a','l','u'),
495 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
496 {{Script_New_Tai_Lue_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
497 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
498 MS_MAKE_TAG('t','a','l','u'),
499 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
500 {{Script_Khmer
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
501 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
502 MS_MAKE_TAG('k','h','m','r'),
503 {'D','a','u','n','P','e','n','h',0}},
504 {{Script_Khmer_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
505 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
506 MS_MAKE_TAG('k','h','m','r'),
507 {'D','a','u','n','P','e','n','h',0}},
508 {{Script_CJK_Han
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
509 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
510 MS_MAKE_TAG('h','a','n','i'),
512 {{Script_Ideograph
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
513 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
514 MS_MAKE_TAG('h','a','n','i'),
516 {{Script_Bopomofo
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
517 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
518 MS_MAKE_TAG('b','o','p','o'),
520 {{Script_Kana
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
521 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
522 MS_MAKE_TAG('k','a','n','a'),
524 {{Script_Hangul
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
525 {LANG_KOREAN
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
526 MS_MAKE_TAG('h','a','n','g'),
528 {{Script_Yi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
529 {LANG_ENGLISH
, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
530 MS_MAKE_TAG('y','i',' ',' '),
531 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
532 {{Script_Ethiopic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
533 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
534 MS_MAKE_TAG('e','t','h','i'),
535 {'N','y','a','l','a',0}},
536 {{Script_Ethiopic_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
537 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
538 MS_MAKE_TAG('e','t','h','i'),
539 {'N','y','a','l','a',0}},
540 {{Script_Mongolian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
541 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
542 MS_MAKE_TAG('m','o','n','g'),
543 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
544 {{Script_Mongolian_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
545 {LANG_MONGOLIAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
546 MS_MAKE_TAG('m','o','n','g'),
547 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
548 {{Script_Tifinagh
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
549 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
550 MS_MAKE_TAG('t','f','n','g'),
551 {'E','b','r','i','m','a',0}},
552 {{Script_NKo
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
553 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
554 MS_MAKE_TAG('n','k','o',' '),
555 {'E','b','r','i','m','a',0}},
556 {{Script_Vai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
557 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
558 MS_MAKE_TAG('v','a','i',' '),
559 {'E','b','r','i','m','a',0}},
560 {{Script_Vai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
561 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
562 MS_MAKE_TAG('v','a','i',' '),
563 {'E','b','r','i','m','a',0}},
564 {{Script_Cherokee
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
565 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
566 MS_MAKE_TAG('c','h','e','r'),
567 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
568 {{Script_Canadian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
569 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
570 MS_MAKE_TAG('c','a','n','s'),
571 {'E','u','p','h','e','m','i','a',0}},
572 {{Script_Ogham
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
573 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
574 MS_MAKE_TAG('o','g','a','m'),
575 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
576 {{Script_Runic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
577 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
578 MS_MAKE_TAG('r','u','n','r'),
579 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
580 {{Script_Braille
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
581 {LANG_ENGLISH
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
582 MS_MAKE_TAG('b','r','a','i'),
583 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
584 {{Script_Surrogates
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
585 {LANG_ENGLISH
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
588 {{Script_Private
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
589 {0, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 1, 0, 0, 0, 0, 1, 0, 0},
592 {{Script_Deseret
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
593 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
594 MS_MAKE_TAG('d','s','r','t'),
595 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
596 {{Script_Osmanya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
597 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
598 MS_MAKE_TAG('o','s','m','a'),
599 {'E','b','r','i','m','a',0}},
600 {{Script_Osmanya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
601 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
602 MS_MAKE_TAG('o','s','m','a'),
603 {'E','b','r','i','m','a',0}},
604 {{Script_MathAlpha
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
605 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
606 MS_MAKE_TAG('m','a','t','h'),
607 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
608 {{Script_Hebrew_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
609 {LANG_HEBREW
, 0, 1, 0, 0, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
610 MS_MAKE_TAG('h','e','b','r'),
611 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
612 {{Script_Vietnamese_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
613 {LANG_VIETNAMESE
, 0, 0, 0, 0, VIETNAMESE_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
614 MS_MAKE_TAG('l','a','t','n'),
615 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
616 {{Script_Thai_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
617 {LANG_THAI
, 0, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
618 MS_MAKE_TAG('t','h','a','i'),
619 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
622 static const SCRIPT_PROPERTIES
*script_props
[] =
624 &scriptInformation
[0].props
, &scriptInformation
[1].props
,
625 &scriptInformation
[2].props
, &scriptInformation
[3].props
,
626 &scriptInformation
[4].props
, &scriptInformation
[5].props
,
627 &scriptInformation
[6].props
, &scriptInformation
[7].props
,
628 &scriptInformation
[8].props
, &scriptInformation
[9].props
,
629 &scriptInformation
[10].props
, &scriptInformation
[11].props
,
630 &scriptInformation
[12].props
, &scriptInformation
[13].props
,
631 &scriptInformation
[14].props
, &scriptInformation
[15].props
,
632 &scriptInformation
[16].props
, &scriptInformation
[17].props
,
633 &scriptInformation
[18].props
, &scriptInformation
[19].props
,
634 &scriptInformation
[20].props
, &scriptInformation
[21].props
,
635 &scriptInformation
[22].props
, &scriptInformation
[23].props
,
636 &scriptInformation
[24].props
, &scriptInformation
[25].props
,
637 &scriptInformation
[26].props
, &scriptInformation
[27].props
,
638 &scriptInformation
[28].props
, &scriptInformation
[29].props
,
639 &scriptInformation
[30].props
, &scriptInformation
[31].props
,
640 &scriptInformation
[32].props
, &scriptInformation
[33].props
,
641 &scriptInformation
[34].props
, &scriptInformation
[35].props
,
642 &scriptInformation
[36].props
, &scriptInformation
[37].props
,
643 &scriptInformation
[38].props
, &scriptInformation
[39].props
,
644 &scriptInformation
[40].props
, &scriptInformation
[41].props
,
645 &scriptInformation
[42].props
, &scriptInformation
[43].props
,
646 &scriptInformation
[44].props
, &scriptInformation
[45].props
,
647 &scriptInformation
[46].props
, &scriptInformation
[47].props
,
648 &scriptInformation
[48].props
, &scriptInformation
[49].props
,
649 &scriptInformation
[50].props
, &scriptInformation
[51].props
,
650 &scriptInformation
[52].props
, &scriptInformation
[53].props
,
651 &scriptInformation
[54].props
, &scriptInformation
[55].props
,
652 &scriptInformation
[56].props
, &scriptInformation
[57].props
,
653 &scriptInformation
[58].props
, &scriptInformation
[59].props
,
654 &scriptInformation
[60].props
, &scriptInformation
[61].props
,
655 &scriptInformation
[62].props
, &scriptInformation
[63].props
,
656 &scriptInformation
[64].props
, &scriptInformation
[65].props
,
657 &scriptInformation
[66].props
, &scriptInformation
[67].props
,
658 &scriptInformation
[68].props
, &scriptInformation
[69].props
,
659 &scriptInformation
[70].props
, &scriptInformation
[71].props
,
660 &scriptInformation
[72].props
, &scriptInformation
[73].props
,
661 &scriptInformation
[74].props
, &scriptInformation
[75].props
,
662 &scriptInformation
[76].props
, &scriptInformation
[77].props
,
663 &scriptInformation
[78].props
, &scriptInformation
[79].props
,
664 &scriptInformation
[80].props
, &scriptInformation
[81].props
673 SCRIPT_VISATTR
* psva
;
689 StringGlyphs
* glyphs
;
690 SCRIPT_LOGATTR
* logattrs
;
700 BOOL
usp10_array_reserve(void **elements
, SIZE_T
*capacity
, SIZE_T count
, SIZE_T size
)
702 SIZE_T max_capacity
, new_capacity
;
705 if (count
<= *capacity
)
708 max_capacity
= ~(SIZE_T
)0 / size
;
709 if (count
> max_capacity
)
712 new_capacity
= max(1, *capacity
);
713 while (new_capacity
< count
&& new_capacity
<= max_capacity
/ 2)
715 if (new_capacity
< count
)
716 new_capacity
= count
;
719 new_elements
= heap_alloc_zero(new_capacity
* size
);
721 new_elements
= HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, *elements
, new_capacity
* size
);
725 *elements
= new_elements
;
726 *capacity
= new_capacity
;
730 /* TODO Fix font properties on Arabic locale */
731 static inline BOOL
set_cache_font_properties(const HDC hdc
, ScriptCache
*sc
)
735 sc
->sfp
.wgBlank
= sc
->tm
.tmBreakChar
;
736 sc
->sfp
.wgDefault
= sc
->tm
.tmDefaultChar
;
737 sc
->sfp
.wgInvalid
= sc
->sfp
.wgBlank
;
738 sc
->sfp
.wgKashida
= 0xFFFF;
739 sc
->sfp
.iKashidaWidth
= 0;
743 static const WCHAR chars
[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
744 /* U+0020: numeric space
745 U+200B: zero width space
746 U+F71B: unknown char found by black box testing
750 if (GetGlyphIndicesW(hdc
, chars
, 4, gi
, GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
752 if(gi
[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
753 sc
->sfp
.wgBlank
= gi
[0];
757 sc
->sfp
.wgDefault
= 0;
760 sc
->sfp
.wgInvalid
= gi
[2];
761 else if (gi
[1] != 0xFFFF)
762 sc
->sfp
.wgInvalid
= gi
[1];
763 else if (gi
[0] != 0xFFFF)
764 sc
->sfp
.wgInvalid
= gi
[0];
766 sc
->sfp
.wgInvalid
= 0;
768 sc
->sfp
.wgKashida
= gi
[3];
770 sc
->sfp
.iKashidaWidth
= 0; /* TODO */
778 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES
*sfp
, ScriptCache
*sc
)
780 sfp
->wgBlank
= sc
->sfp
.wgBlank
;
781 sfp
->wgDefault
= sc
->sfp
.wgDefault
;
782 sfp
->wgInvalid
= sc
->sfp
.wgInvalid
;
783 sfp
->wgKashida
= sc
->sfp
.wgKashida
;
784 sfp
->iKashidaWidth
= sc
->sfp
.iKashidaWidth
;
787 static inline LONG
get_cache_height(SCRIPT_CACHE
*psc
)
789 return ((ScriptCache
*)*psc
)->tm
.tmHeight
;
792 static inline BYTE
get_cache_pitch_family(SCRIPT_CACHE
*psc
)
794 return ((ScriptCache
*)*psc
)->tm
.tmPitchAndFamily
;
797 static inline WORD
get_cache_glyph(SCRIPT_CACHE
*psc
, DWORD c
)
799 CacheGlyphPage
*page
= ((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
803 block
= page
->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
804 if (!block
) return 0;
805 return block
[(c
% 0x10000) & GLYPH_BLOCK_MASK
];
808 static inline WORD
set_cache_glyph(SCRIPT_CACHE
*psc
, WCHAR c
, WORD glyph
)
810 CacheGlyphPage
**page
= &((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
812 if (!*page
&& !(*page
= heap_alloc_zero(sizeof(CacheGlyphPage
)))) return 0;
814 block
= &(*page
)->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
815 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(WORD
) * GLYPH_BLOCK_SIZE
))) return 0;
816 return ((*block
)[(c
% 0x10000) & GLYPH_BLOCK_MASK
] = glyph
);
819 static inline BOOL
get_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
821 static const ABC nil
;
822 ABC
*block
= ((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
824 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(ABC
))) return FALSE
;
825 memcpy(abc
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(ABC
));
829 static inline BOOL
set_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
831 ABC
**block
= &((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
833 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(ABC
) * GLYPH_BLOCK_SIZE
))) return FALSE
;
834 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], abc
, sizeof(ABC
));
838 static HRESULT
init_script_cache(const HDC hdc
, SCRIPT_CACHE
*psc
)
843 if (!psc
) return E_INVALIDARG
;
844 if (*psc
) return S_OK
;
845 if (!hdc
) return E_PENDING
;
847 if (!(sc
= heap_alloc_zero(sizeof(ScriptCache
)))) return E_OUTOFMEMORY
;
848 if (!GetTextMetricsW(hdc
, &sc
->tm
))
853 size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
856 sc
->otm
= heap_alloc(size
);
857 sc
->otm
->otmSize
= size
;
858 GetOutlineTextMetricsW(hdc
, size
, sc
->otm
);
860 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(LOGFONTW
), &sc
->lf
))
865 sc
->sfnt
= (GetFontData(hdc
, MS_MAKE_TAG('h','e','a','d'), 0, NULL
, 0)!=GDI_ERROR
);
866 if (!set_cache_font_properties(hdc
, sc
))
872 TRACE("<- %p\n", sc
);
876 static WCHAR
mirror_char( WCHAR ch
)
878 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
879 return ch
+ wine_mirror_map
[wine_mirror_map
[ch
>> 8] + (ch
& 0xff)];
882 static DWORD
decode_surrogate_pair(const WCHAR
*str
, unsigned int index
, unsigned int end
)
884 if (index
< end
-1 && IS_SURROGATE_PAIR(str
[index
],str
[index
+1]))
886 DWORD ch
= 0x10000 + ((str
[index
] - 0xd800) << 10) + (str
[index
+1] - 0xdc00);
887 TRACE("Surrogate Pair %x %x => %x\n",str
[index
], str
[index
+1], ch
);
893 static int usp10_compare_script_range(const void *key
, const void *value
)
895 const struct usp10_script_range
*range
= value
;
896 const DWORD
*ch
= key
;
898 if (*ch
< range
->rangeFirst
)
900 if (*ch
> range
->rangeLast
)
905 static enum usp10_script
get_char_script(const WCHAR
*str
, unsigned int index
,
906 unsigned int end
, unsigned int *consumed
)
908 static const WCHAR latin_punc
[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
909 struct usp10_script_range
*range
;
910 WORD type
= 0, type2
= 0;
915 if (str
[index
] == 0xc || str
[index
] == 0x20 || str
[index
] == 0x202f)
918 /* These punctuation characters are separated out as Latin punctuation */
919 if (strchrW(latin_punc
,str
[index
]))
920 return Script_Punctuation2
;
922 /* These chars are itemized as Punctuation by Windows */
923 if (str
[index
] == 0x2212 || str
[index
] == 0x2044)
924 return Script_Punctuation
;
926 /* Currency Symbols by Unicode point */
930 case 0x09f3: return Script_Bengali_Currency
;
931 case 0x0af1: return Script_Gujarati_Currency
;
932 case 0x0e3f: return Script_Thai_Currency
;
933 case 0x20aa: return Script_Hebrew_Currency
;
934 case 0x20ab: return Script_Vietnamese_Currency
;
935 case 0xfb29: return Script_Hebrew_Currency
;
938 GetStringTypeW(CT_CTYPE1
, &str
[index
], 1, &type
);
939 GetStringTypeW(CT_CTYPE2
, &str
[index
], 1, &type2
);
942 return SCRIPT_UNDEFINED
;
945 return Script_Control
;
947 ch
= decode_surrogate_pair(str
, index
, end
);
953 if (!(range
= bsearch(&ch
, script_ranges
, ARRAY_SIZE(script_ranges
),
954 sizeof(*script_ranges
), usp10_compare_script_range
)))
955 return (*consumed
== 2) ? Script_Surrogates
: Script_Undefined
;
957 if (range
->numericScript
&& (type
& C1_DIGIT
|| type2
== C2_ARABICNUMBER
))
958 return range
->numericScript
;
959 if (range
->punctScript
&& type
& C1_PUNCT
)
960 return range
->punctScript
;
961 return range
->script
;
964 static int compare_FindGlyph(const void *a
, const void* b
)
966 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
967 const WORD
*idx
= (WORD
*)b
;
970 if ( find
->target
> *idx
)
972 else if (find
->target
< *idx
)
975 if (!find
->ascending
)
980 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
982 FindGlyph_struct fgs
;
986 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
987 fgs
.ascending
= TRUE
;
989 fgs
.ascending
= FALSE
;
992 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
997 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
1004 /***********************************************************************
1005 * ScriptFreeCache (USP10.@)
1007 * Free a script cache.
1010 * psc [I/O] Script cache.
1014 * Failure: Non-zero HRESULT value.
1016 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1024 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1026 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1028 for (i
= 0; i
< NUM_PAGES
; i
++)
1031 if (((ScriptCache
*)*psc
)->page
[i
])
1032 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1033 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1034 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1036 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1037 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1038 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1039 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1040 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1043 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1046 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1047 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1048 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1050 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1051 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1052 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1053 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1055 heap_free(((ScriptCache
*)*psc
)->scripts
);
1056 heap_free(((ScriptCache
*)*psc
)->otm
);
1063 /***********************************************************************
1064 * ScriptGetProperties (USP10.@)
1066 * Retrieve a list of script properties.
1069 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1070 * num [I] Pointer to the number of scripts.
1074 * Failure: Non-zero HRESULT value.
1077 * Behaviour matches WinXP.
1079 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1081 TRACE("(%p,%p)\n", props
, num
);
1083 if (!props
&& !num
) return E_INVALIDARG
;
1085 if (num
) *num
= sizeof(script_props
)/sizeof(script_props
[0]);
1086 if (props
) *props
= script_props
;
1091 /***********************************************************************
1092 * ScriptGetFontProperties (USP10.@)
1094 * Get information on special glyphs.
1097 * hdc [I] Device context.
1098 * psc [I/O] Opaque pointer to a script cache.
1099 * sfp [O] Font properties structure.
1101 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1105 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1107 if (!sfp
) return E_INVALIDARG
;
1108 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1110 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1111 return E_INVALIDARG
;
1113 get_cache_font_properties(sfp
, *psc
);
1118 /***********************************************************************
1119 * ScriptRecordDigitSubstitution (USP10.@)
1121 * Record digit substitution settings for a given locale.
1124 * locale [I] Locale identifier.
1125 * sds [I] Structure to record substitution settings.
1129 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1132 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1134 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1138 TRACE("0x%x, %p\n", locale
, sds
);
1140 /* This implementation appears to be correct for all languages, but it's
1141 * not clear if sds->DigitSubstitute is ever set to anything except
1142 * CONTEXT or NONE in reality */
1144 if (!sds
) return E_POINTER
;
1146 locale
= ConvertDefaultLocale(locale
);
1148 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1149 return E_INVALIDARG
;
1151 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1152 sds
->TraditionalDigitLanguage
= plgid
;
1154 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1155 sds
->NationalDigitLanguage
= plgid
;
1157 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1159 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1160 (WCHAR
*)&sub
, sizeof(sub
) / sizeof(WCHAR
)))
1161 return E_INVALIDARG
;
1166 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1167 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1169 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1172 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1175 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1178 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1182 sds
->dwReserved
= 0;
1186 /***********************************************************************
1187 * ScriptApplyDigitSubstitution (USP10.@)
1189 * Apply digit substitution settings.
1192 * sds [I] Structure with recorded substitution settings.
1193 * sc [I] Script control structure.
1194 * ss [I] Script state structure.
1198 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1200 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1201 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1203 SCRIPT_DIGITSUBSTITUTE psds
;
1205 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1207 if (!sc
|| !ss
) return E_POINTER
;
1211 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1212 return E_INVALIDARG
;
1215 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1216 sc
->fContextDigits
= 0;
1217 ss
->fDigitSubstitute
= 0;
1219 switch (sds
->DigitSubstitute
) {
1220 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1221 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1222 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1223 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1226 return E_INVALIDARG
;
1230 static inline BOOL
is_indic(enum usp10_script script
)
1232 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1235 static inline enum usp10_script
base_indic(enum usp10_script script
)
1239 case Script_Devanagari
:
1240 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1241 case Script_Bengali
:
1242 case Script_Bengali_Numeric
:
1243 case Script_Bengali_Currency
: return Script_Bengali
;
1244 case Script_Gurmukhi
:
1245 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1246 case Script_Gujarati
:
1247 case Script_Gujarati_Numeric
:
1248 case Script_Gujarati_Currency
: return Script_Gujarati
;
1250 case Script_Oriya_Numeric
: return Script_Oriya
;
1252 case Script_Tamil_Numeric
: return Script_Tamil
;
1254 case Script_Telugu_Numeric
: return Script_Telugu
;
1255 case Script_Kannada
:
1256 case Script_Kannada_Numeric
: return Script_Kannada
;
1257 case Script_Malayalam
:
1258 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1260 return Script_Undefined
;
1264 static BOOL
script_is_numeric(enum usp10_script script
)
1266 return scriptInformation
[script
].props
.fNumeric
;
1269 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1270 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1271 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1272 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1275 #define Numeric_space 0x0020
1280 enum usp10_script last_indic
= Script_Undefined
;
1281 int cnt
= 0, index
= 0, str
= 0;
1282 enum usp10_script New_Script
= -1;
1284 WORD
*levels
= NULL
;
1285 WORD
*layout_levels
= NULL
;
1286 WORD
*overrides
= NULL
;
1287 WORD
*strength
= NULL
;
1288 enum usp10_script
*scripts
;
1290 WORD baselayout
= 0;
1293 BOOL forceLevels
= FALSE
;
1294 unsigned int consumed
= 0;
1295 HRESULT res
= E_OUTOFMEMORY
;
1297 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1298 psControl
, psState
, pItems
, pcItems
);
1300 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1301 return E_INVALIDARG
;
1303 if (!(scripts
= heap_alloc(cInChars
* sizeof(*scripts
))))
1304 return E_OUTOFMEMORY
;
1306 for (i
= 0; i
< cInChars
; i
++)
1310 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1315 scripts
[i
] = scripts
[i
-1];
1318 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1319 all Indic scripts */
1320 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
!= Script_Undefined
)
1321 scripts
[i
] = last_indic
;
1322 else if (is_indic(scripts
[i
]))
1323 last_indic
= base_indic(scripts
[i
]);
1325 /* Some unicode points :
1326 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1327 (Left Right Embed U+202A - Left Right Override U+202D)
1328 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1329 will force us into bidi mode */
1330 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1331 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1332 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1336 /* Diacritical marks merge with other scripts */
1337 if (scripts
[i
] == Script_Diacritical
)
1342 scripts
[i
] = scripts
[i
-1];
1347 enum usp10_script first_script
= scripts
[i
-1];
1348 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1350 enum usp10_script original
= scripts
[j
];
1351 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1356 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1358 scripts
[j
] = scripts
[i
];
1359 if (original
== Script_Punctuation2
)
1362 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1363 scripts
[i
] = scripts
[j
];
1369 for (i
= 0; i
< cInChars
; i
++)
1371 /* Joiners get merged preferencially right */
1372 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1375 if (i
+1 == cInChars
)
1376 scripts
[i
] = scripts
[i
-1];
1379 for (j
= i
+1; j
< cInChars
; j
++)
1381 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1382 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1384 scripts
[i
] = scripts
[j
];
1392 if (psState
&& psControl
)
1394 levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1398 overrides
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1402 layout_levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1406 if (psState
->fOverrideDirection
)
1410 SCRIPT_STATE s
= *psState
;
1411 s
.fOverrideDirection
= FALSE
;
1412 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1413 if (odd(layout_levels
[0]))
1415 else for (i
= 0; i
< cInChars
; i
++)
1416 if (layout_levels
[i
]!=layout_levels
[0])
1423 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1427 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1428 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1430 baselevel
= levels
[0];
1431 baselayout
= layout_levels
[0];
1432 for (i
= 0; i
< cInChars
; i
++)
1433 if (levels
[i
]!=levels
[0])
1435 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1438 heap_free(overrides
);
1439 heap_free(layout_levels
);
1442 layout_levels
= NULL
;
1446 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1447 static const WCHAR repeatable_math_punc
[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1449 strength
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1452 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1454 /* We currently mis-level leading Diacriticals */
1455 if (scripts
[0] == Script_Diacritical
)
1456 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1458 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1459 strength
[i
] = BIDI_STRONG
;
1462 /* Math punctuation bordered on both sides by numbers can be
1463 merged into the number */
1464 for (i
= 0; i
< cInChars
; i
++)
1466 if (i
> 0 && i
< cInChars
-1 &&
1467 script_is_numeric(scripts
[i
-1]) &&
1468 strchrW(math_punc
, pwcInChars
[i
]))
1470 if (script_is_numeric(scripts
[i
+1]))
1472 scripts
[i
] = scripts
[i
+1];
1473 levels
[i
] = levels
[i
-1];
1474 strength
[i
] = strength
[i
-1];
1477 else if (strchrW(repeatable_math_punc
, pwcInChars
[i
]))
1480 for (j
= i
+1; j
< cInChars
; j
++)
1482 if (script_is_numeric(scripts
[j
]))
1486 scripts
[i
] = scripts
[j
];
1487 levels
[i
] = levels
[i
-1];
1488 strength
[i
] = strength
[i
-1];
1491 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1497 for (i
= 0; i
< cInChars
; i
++)
1499 /* Numerics at level 0 get bumped to level 2 */
1500 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
)
1501 && levels
[i
] == psState
->uBidiLevel
+ 1)) && script_is_numeric(scripts
[i
]))
1506 /* Joiners get merged preferencially right */
1507 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
|| pwcInChars
[i
] == ZWSP
))
1510 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1511 strength
[i
] = strength
[i
-1];
1513 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1514 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
1515 && pwcInChars
[j
] != ZWSP
&& pwcInChars
[j
] != Numeric_space
)
1517 strength
[i
] = strength
[j
];
1522 if (psControl
->fMergeNeutralItems
)
1524 /* Merge the neutrals */
1525 for (i
= 0; i
< cInChars
; i
++)
1527 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1530 for (j
= i
; j
> 0; j
--)
1532 if (levels
[i
] != levels
[j
])
1534 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1536 scripts
[i
] = scripts
[j
];
1537 strength
[i
] = strength
[j
];
1542 /* Try going the other way */
1543 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1546 for (j
= i
; j
< cInChars
; j
++)
1548 if (levels
[i
] != levels
[j
])
1550 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1552 scripts
[i
] = scripts
[j
];
1553 strength
[i
] = strength
[j
];
1563 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1564 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1567 if (cnt
== cInChars
) /* All Spaces */
1570 New_Script
= scripts
[cnt
];
1573 pItems
[index
].iCharPos
= 0;
1574 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1576 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1578 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1579 str
= strength
[cnt
];
1587 if (strength
[cnt
] == BIDI_STRONG
)
1588 layoutRTL
= odd(layout_levels
[cnt
]);
1590 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1592 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1593 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1594 if (script_is_numeric(pItems
[index
].a
.eScript
))
1595 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1597 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1598 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1600 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1602 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1603 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1604 layoutRTL
= odd(baselayout
);
1605 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1606 pItems
[index
].a
.fRTL
= odd(baselevel
);
1607 if (script_is_numeric(pItems
[index
].a
.eScript
))
1608 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1610 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1613 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1614 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1615 pItems
[index
].iCharPos
);
1617 for (cnt
=1; cnt
< cInChars
; cnt
++)
1619 if(pwcInChars
[cnt
] != Numeric_space
)
1620 New_Script
= scripts
[cnt
];
1624 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1626 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1627 New_Script
= scripts
[cnt
+j
];
1629 New_Script
= scripts
[cnt
];
1633 /* merge space strengths*/
1634 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1637 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1640 /* changes in level */
1641 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1643 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1646 /* changes in strength */
1647 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1649 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1652 /* changes in script */
1653 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1655 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1659 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1661 layoutRTL
= odd(layout_levels
[cnt
]);
1662 if (script_is_numeric(pItems
[index
].a
.eScript
))
1663 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1668 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
);
1671 if (index
+1 > cMaxItems
)
1675 str
= strength
[cnt
];
1677 pItems
[index
].iCharPos
= cnt
;
1678 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1680 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1682 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1686 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1687 if (layout_levels
[cnt
] == 0)
1690 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1691 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1692 if (script_is_numeric(pItems
[index
].a
.eScript
))
1693 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1695 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1696 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1698 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1700 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1701 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1702 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1703 pItems
[index
].a
.fRTL
= odd(baselevel
);
1704 if (script_is_numeric(pItems
[index
].a
.eScript
))
1705 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1707 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1710 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1714 /* While not strictly necessary according to the spec, make sure the n+1
1715 * item is set up to prevent random behaviour if the caller erroneously
1716 * checks the n+1 structure */
1718 if (index
+ 1 > cMaxItems
) goto nomemory
;
1719 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1721 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1723 /* Set one SCRIPT_STATE item being returned */
1724 if (pcItems
) *pcItems
= index
;
1726 /* Set SCRIPT_ITEM */
1727 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1731 heap_free(overrides
);
1732 heap_free(layout_levels
);
1733 heap_free(strength
);
1738 /***********************************************************************
1739 * ScriptItemizeOpenType (USP10.@)
1741 * Split a Unicode string into shapeable parts.
1744 * pwcInChars [I] String to split.
1745 * cInChars [I] Number of characters in pwcInChars.
1746 * cMaxItems [I] Maximum number of items to return.
1747 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1748 * psState [I] Pointer to a SCRIPT_STATE structure.
1749 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1750 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1751 * pcItems [O] Number of script items returned.
1755 * Failure: Non-zero HRESULT value.
1757 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1758 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1759 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1761 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1764 /***********************************************************************
1765 * ScriptItemize (USP10.@)
1767 * Split a Unicode string into shapeable parts.
1770 * pwcInChars [I] String to split.
1771 * cInChars [I] Number of characters in pwcInChars.
1772 * cMaxItems [I] Maximum number of items to return.
1773 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1774 * psState [I] Pointer to a SCRIPT_STATE structure.
1775 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1776 * pcItems [O] Number of script items returned.
1780 * Failure: Non-zero HRESULT value.
1782 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1783 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1784 SCRIPT_ITEM
*pItems
, int *pcItems
)
1786 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1789 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1793 INT
*lpTabPos
= NULL
;
1798 lpTabPos
= pTabdef
->pTabStops
;
1800 if (pTabdef
&& pTabdef
->iTabOrigin
)
1802 if (pTabdef
->iScale
)
1803 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1805 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1809 cTabStops
= pTabdef
->cTabStops
;
1813 if (pTabdef
->iScale
)
1814 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1816 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1821 if (pTabdef
->iScale
)
1822 defWidth
= (32 * pTabdef
->iScale
) / 4;
1824 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1827 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1829 int position
= *lpTabPos
;
1831 position
= -1 * position
;
1832 if (pTabdef
->iScale
)
1833 position
= (position
* pTabdef
->iScale
) / 4;
1835 position
= position
* psc
->tm
.tmAveCharWidth
;
1837 if( nTabOrg
+ position
> current_x
)
1841 /* a left aligned tab */
1842 x
= (nTabOrg
+ position
) - current_x
;
1847 FIXME("Negative tabstop\n");
1852 if ((!cTabStops
) && (defWidth
> 0))
1853 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1854 else if ((!cTabStops
) && (defWidth
< 0))
1855 FIXME("TODO: Negative defWidth\n");
1860 /***********************************************************************
1861 * Helper function for ScriptStringAnalyse
1863 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1864 const WCHAR
*pwcInChars
, int cChars
)
1866 /* FIXME: When to properly fallback is still a bit of a mystery */
1869 if (psa
->fNoGlyphIndex
)
1872 if (init_script_cache(hdc
, psc
) != S_OK
)
1875 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1878 glyphs
= heap_alloc(sizeof(WORD
) * cChars
);
1881 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1891 static void find_fallback_font(enum usp10_script scriptid
, WCHAR
*FaceName
)
1895 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1897 static const WCHAR szFmt
[] = {'%','x',0};
1899 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1902 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1903 if (RegQueryValueExW(hkey
, value
, 0, &type
, (BYTE
*)FaceName
, &count
))
1904 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1908 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1911 /***********************************************************************
1912 * ScriptStringAnalyse (USP10.@)
1915 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1916 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1917 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1918 SCRIPT_STATE
*psState
, const int *piDx
,
1919 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1920 SCRIPT_STRING_ANALYSIS
*pssa
)
1922 HRESULT hr
= E_OUTOFMEMORY
;
1923 StringAnalysis
*analysis
= NULL
;
1924 SCRIPT_CONTROL sControl
;
1925 SCRIPT_STATE sState
;
1926 int i
, num_items
= 255;
1928 WCHAR
*iString
= NULL
;
1930 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1931 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1932 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
1936 FIXME("Only Unicode strings are supported\n");
1937 return E_INVALIDARG
;
1939 if (cString
< 1 || !pString
) return E_INVALIDARG
;
1940 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
1942 if (!(analysis
= heap_alloc_zero(sizeof(StringAnalysis
)))) return E_OUTOFMEMORY
;
1943 if (!(analysis
->pItem
= heap_alloc_zero(num_items
* sizeof(SCRIPT_ITEM
) + 1))) goto error
;
1945 /* FIXME: handle clipping */
1946 analysis
->clip_len
= cString
;
1947 analysis
->hdc
= hdc
;
1948 analysis
->dwFlags
= dwFlags
;
1953 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
1956 sControl
= *psControl
;
1958 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
1960 if (dwFlags
& SSA_PASSWORD
)
1962 iString
= heap_alloc(sizeof(WCHAR
)*cString
);
1968 for (i
= 0; i
< cString
; i
++)
1969 iString
[i
] = *((const WCHAR
*)pString
);
1973 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
1974 &analysis
->numItems
);
1978 if (hr
== E_OUTOFMEMORY
)
1983 /* set back to out of memory for default goto error behaviour */
1986 if (dwFlags
& SSA_BREAK
)
1988 if ((analysis
->logattrs
= heap_alloc(sizeof(SCRIPT_LOGATTR
) * cString
)))
1990 for (i
= 0; i
< analysis
->numItems
; i
++)
1991 ScriptBreak(&((WCHAR
*)pString
)[analysis
->pItem
[i
].iCharPos
],
1992 analysis
->pItem
[i
+ 1].iCharPos
- analysis
->pItem
[i
].iCharPos
,
1993 &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
1999 if (!(analysis
->logical2visual
= heap_alloc_zero(sizeof(int) * analysis
->numItems
)))
2001 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
2004 if (dwFlags
& SSA_GLYPHS
)
2007 if (!(analysis
->glyphs
= heap_alloc_zero(sizeof(StringGlyphs
) * analysis
->numItems
)))
2009 heap_free(BidiLevel
);
2013 for (i
= 0; i
< analysis
->numItems
; i
++)
2015 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
2016 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2017 int numGlyphs
= 1.5 * cChar
+ 16;
2018 WORD
*glyphs
= heap_alloc_zero(sizeof(WORD
) * numGlyphs
);
2019 WORD
*pwLogClust
= heap_alloc_zero(sizeof(WORD
) * cChar
);
2020 int *piAdvance
= heap_alloc_zero(sizeof(int) * numGlyphs
);
2021 SCRIPT_VISATTR
*psva
= heap_alloc_zero(sizeof(SCRIPT_VISATTR
) * numGlyphs
);
2022 GOFFSET
*pGoffset
= heap_alloc_zero(sizeof(GOFFSET
) * numGlyphs
);
2023 ABC
*abc
= heap_alloc_zero(sizeof(ABC
));
2024 int numGlyphsReturned
;
2025 HFONT originalFont
= 0x0;
2027 /* FIXME: non unicode strings */
2028 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2029 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2031 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
|| !abc
)
2033 heap_free (BidiLevel
);
2035 heap_free (pwLogClust
);
2036 heap_free (piAdvance
);
2038 heap_free (pGoffset
);
2044 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2047 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2048 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2049 lf
.lfFaceName
[0] = 0;
2050 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2051 if (lf
.lfFaceName
[0])
2053 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2054 if (analysis
->glyphs
[i
].fallbackFont
)
2056 ScriptFreeCache(sc
);
2057 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2062 /* FIXME: When we properly shape Hangul remove this check */
2063 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2064 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2066 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2067 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2069 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2070 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2071 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2072 piAdvance
, pGoffset
, abc
);
2074 SelectObject(hdc
,originalFont
);
2076 if (dwFlags
& SSA_TAB
)
2079 for (tabi
= 0; tabi
< cChar
; tabi
++)
2081 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2082 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2083 tab_x
+=piAdvance
[tabi
];
2087 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2088 analysis
->glyphs
[i
].glyphs
= glyphs
;
2089 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2090 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2091 analysis
->glyphs
[i
].psva
= psva
;
2092 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2093 analysis
->glyphs
[i
].abc
= abc
;
2094 analysis
->glyphs
[i
].iMaxPosX
= -1;
2096 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2101 for (i
= 0; i
< analysis
->numItems
; i
++)
2102 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2105 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2106 heap_free(BidiLevel
);
2114 heap_free(analysis
->glyphs
);
2115 heap_free(analysis
->logattrs
);
2116 heap_free(analysis
->pItem
);
2117 heap_free(analysis
->logical2visual
);
2118 heap_free(analysis
);
2122 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2124 if (pva
[glyph
].fClusterStart
)
2126 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2133 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2144 StringAnalysis
*analysis
;
2147 COLORREF BkColor
= 0x0;
2148 COLORREF TextColor
= 0x0;
2150 INT runStart
, runEnd
;
2151 INT iGlyph
, cGlyphs
;
2152 HFONT oldFont
= 0x0;
2156 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2157 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2159 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2161 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2162 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2168 BkMode
= GetBkMode(analysis
->hdc
);
2169 SetBkMode( analysis
->hdc
, OPAQUE
);
2170 BkColor
= GetBkColor(analysis
->hdc
);
2171 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2174 TextColor
= GetTextColor(analysis
->hdc
);
2175 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2178 if (analysis
->glyphs
[iItem
].fallbackFont
)
2179 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2181 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2182 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2185 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2186 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2188 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2190 if (analysis
->pItem
[iItem
].a
.fRTL
)
2192 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2193 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2195 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2196 crc
.left
= iX
+ off_x
;
2200 if (cStart
>=0 && runStart
)
2201 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2203 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2204 crc
.left
= iX
+ off_x
;
2207 if (analysis
->pItem
[iItem
].a
.fRTL
)
2208 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2210 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2212 if (analysis
->pItem
[iItem
].a
.fRTL
)
2213 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2215 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2219 /* adjust for cluster glyphs when starting */
2220 if (analysis
->pItem
[iItem
].a
.fRTL
)
2221 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2223 i
= analysis
->pItem
[iItem
].iCharPos
;
2225 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2227 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2229 if (analysis
->pItem
[iItem
].a
.fRTL
)
2230 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2232 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2237 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2242 clust_glyph
= iGlyph
+ cGlyphs
;
2243 if (analysis
->pItem
[iItem
].a
.fRTL
)
2248 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2249 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2256 hr
= ScriptTextOut(analysis
->hdc
,
2257 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2258 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2259 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2260 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2261 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2263 TRACE("ScriptTextOut hr=%08x\n", hr
);
2267 SetBkColor(analysis
->hdc
, BkColor
);
2268 SetBkMode( analysis
->hdc
, BkMode
);
2270 SetTextColor(analysis
->hdc
, TextColor
);
2272 if (analysis
->glyphs
[iItem
].fallbackFont
)
2273 SelectObject(analysis
->hdc
, oldFont
);
2278 /***********************************************************************
2279 * ScriptStringOut (USP10.@)
2281 * This function takes the output of ScriptStringAnalyse and joins the segments
2282 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2283 * only processes glyphs.
2286 * ssa [I] buffer to hold the analysed string components
2287 * iX [I] X axis displacement for output
2288 * iY [I] Y axis displacement for output
2289 * uOptions [I] flags controlling output processing
2290 * prc [I] rectangle coordinates
2291 * iMinSel [I] starting pos for substringing output string
2292 * iMaxSel [I] ending pos for substringing output string
2293 * fDisabled [I] controls text highlighting
2297 * Failure: is the value returned by ScriptTextOut
2299 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2308 StringAnalysis
*analysis
;
2312 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2313 ssa
, iX
, iY
, uOptions
, wine_dbgstr_rect(prc
), iMinSel
, iMaxSel
, fDisabled
);
2315 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2316 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2318 for (item
= 0; item
< analysis
->numItems
; item
++)
2320 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2325 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2327 if (iMaxSel
> 0 && iMinSel
< 0)
2329 for (item
= 0; item
< analysis
->numItems
; item
++)
2331 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2340 /***********************************************************************
2341 * ScriptStringCPtoX (USP10.@)
2344 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2348 StringAnalysis
* analysis
= ssa
;
2350 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2352 if (!ssa
|| !pX
) return S_FALSE
;
2353 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2355 /* icp out of range */
2358 analysis
->invalid
= TRUE
;
2359 return E_INVALIDARG
;
2362 for(item
=0; item
<analysis
->numItems
; item
++)
2367 i
= analysis
->logical2visual
[item
];
2368 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2369 /* initialize max extents for uninitialized runs */
2370 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2372 if (analysis
->pItem
[i
].a
.fRTL
)
2373 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2374 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2375 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2377 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2378 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2379 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2382 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2384 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2388 icp
-= analysis
->pItem
[i
].iCharPos
;
2389 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2390 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2391 &analysis
->pItem
[i
].a
, &offset
);
2398 /* icp out of range */
2399 analysis
->invalid
= TRUE
;
2400 return E_INVALIDARG
;
2403 /***********************************************************************
2404 * ScriptStringXtoCP (USP10.@)
2407 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2409 StringAnalysis
* analysis
= ssa
;
2412 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2414 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2415 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2420 if (analysis
->pItem
[0].a
.fRTL
)
2423 *piTrailing
= FALSE
;
2433 for(item
=0; item
<analysis
->numItems
; item
++)
2438 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2441 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2442 /* initialize max extents for uninitialized runs */
2443 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2445 if (analysis
->pItem
[i
].a
.fRTL
)
2446 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2447 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2448 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2450 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2451 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2452 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2455 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2457 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2461 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2462 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2463 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2464 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2470 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2471 *piTrailing
= FALSE
;
2477 /***********************************************************************
2478 * ScriptStringFree (USP10.@)
2480 * Free a string analysis.
2483 * pssa [I] string analysis.
2487 * Failure: Non-zero HRESULT value.
2489 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2491 StringAnalysis
* analysis
;
2495 TRACE("(%p)\n", pssa
);
2497 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2499 invalid
= analysis
->invalid
;
2501 if (analysis
->glyphs
)
2503 for (i
= 0; i
< analysis
->numItems
; i
++)
2505 heap_free(analysis
->glyphs
[i
].glyphs
);
2506 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2507 heap_free(analysis
->glyphs
[i
].piAdvance
);
2508 heap_free(analysis
->glyphs
[i
].psva
);
2509 heap_free(analysis
->glyphs
[i
].pGoffset
);
2510 heap_free(analysis
->glyphs
[i
].abc
);
2511 if (analysis
->glyphs
[i
].fallbackFont
)
2512 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2513 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2514 heap_free(analysis
->glyphs
[i
].sc
);
2516 heap_free(analysis
->glyphs
);
2519 heap_free(analysis
->pItem
);
2520 heap_free(analysis
->logattrs
);
2521 heap_free(analysis
->sz
);
2522 heap_free(analysis
->logical2visual
);
2523 heap_free(analysis
);
2525 if (invalid
) return E_INVALIDARG
;
2529 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2530 int direction
, int* iCluster
, int *check_out
)
2534 WORD clust
= pwLogClust
[item
];
2536 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2538 if (pwLogClust
[check
] == clust
)
2541 if (iCluster
&& *iCluster
== -1)
2553 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
)
2558 advance
= piAdvance
[glyph
];
2560 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2561 log_clust_max
= pwLogClust
[0];
2563 log_clust_max
= pwLogClust
[cChars
-1];
2565 if (glyph
> log_clust_max
)
2568 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2571 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2573 if (glyph
> log_clust_max
)
2575 advance
+= piAdvance
[glyph
];
2581 /***********************************************************************
2582 * ScriptCPtoX (USP10.@)
2585 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2589 const WORD
*pwLogClust
,
2590 const SCRIPT_VISATTR
*psva
,
2591 const int *piAdvance
,
2592 const SCRIPT_ANALYSIS
*psa
,
2600 float special_size
= 0.0;
2605 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2606 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2609 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2617 int max_clust
= pwLogClust
[0];
2619 for (item
=0; item
< cGlyphs
; item
++)
2620 if (pwLogClust
[item
] > max_clust
)
2622 ERR("We do not handle non reversed clusters properly\n");
2627 for (item
= max_clust
; item
>=0; item
--)
2628 iMaxPos
+= piAdvance
[item
];
2632 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2634 if (iSpecial
== -1 && (iCluster
== -1 || (iCluster
!= -1 && iCluster
+clust_size
<= item
)))
2637 int clust
= pwLogClust
[item
];
2640 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2643 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2645 if (check
>= cChars
&& !iMaxPos
)
2648 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2649 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2651 special_size
/= (cChars
- item
);
2652 iPosX
+= special_size
;
2656 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2659 if (clust_size
== 0)
2663 iPosX
+= advance
/ (float)clust_size
;
2666 else if (iSpecial
!= -1)
2667 iPosX
+= special_size
;
2668 else /* (iCluster != -1) */
2670 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2671 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2674 if (clust_size
== 0)
2678 iPosX
+= adv
/ (float)clust_size
;
2684 iPosX
= iMaxPos
- iPosX
;
2690 TRACE("*piX=%d\n", *piX
);
2694 /* Count the number of characters in a cluster and its starting index*/
2695 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2700 for (i
= 0; i
< cChars
; i
++)
2702 if (pwLogClust
[i
] == cluster_index
)
2704 if (!size
&& start_index
)
2712 else if (size
) break;
2715 *cluster_size
= size
;
2721 To handle multi-glyph clusters we need to find all the glyphs that are
2722 represented in the cluster. This involves finding the glyph whose
2723 index is the cluster index as well as whose glyph indices are greater than
2724 our cluster index but not part of a new cluster.
2726 Then we sum all those glyphs' advances.
2728 static inline int get_cluster_advance(const int* piAdvance
,
2729 const SCRIPT_VISATTR
*psva
,
2730 const WORD
*pwLogClust
, int cGlyphs
,
2731 int cChars
, int cluster
, int direction
)
2742 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2744 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2745 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2746 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2751 glyph_end
= cGlyphs
;
2754 /* Don't fully understand multi-glyph reversed clusters yet,
2755 * do they occur for real or just in our test? */
2756 FIXME("multi-glyph reversed clusters found\n");
2757 glyph_end
= glyph_start
+ 1;
2761 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2762 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2764 if (psva
[i
].fClusterStart
)
2771 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2772 advance
+= piAdvance
[i
];
2778 /***********************************************************************
2779 * ScriptXtoCP (USP10.@)
2782 * Use piAdvance to find the cluster we are looking at.
2783 * Find the character that is the first character of the cluster.
2784 * That is our base piCP.
2785 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2786 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2787 * determine how far through the cluster to advance the cursor.
2789 HRESULT WINAPI
ScriptXtoCP(int iX
,
2792 const WORD
*pwLogClust
,
2793 const SCRIPT_VISATTR
*psva
,
2794 const int *piAdvance
,
2795 const SCRIPT_ANALYSIS
*psa
,
2802 int glyph_index
, cluster_index
;
2805 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2806 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2807 psa
, piCP
, piTrailing
);
2809 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2812 /* Handle an iX < 0 */
2828 /* Looking for non-reversed clusters in a reversed string */
2831 int max_clust
= pwLogClust
[0];
2832 for (i
=0; i
< cChars
; i
++)
2833 if (pwLogClust
[i
] > max_clust
)
2835 FIXME("We do not handle non reversed clusters properly\n");
2840 /* find the glyph_index based in iX */
2843 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2848 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2852 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2855 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2857 /* find the cluster */
2859 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2862 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2865 TRACE("cluster_index %i\n", cluster_index
);
2867 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2869 /* We are off the end of the string */
2875 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2877 TRACE("first char index %i\n",i
);
2878 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2880 /* Check trailing */
2881 if (glyph_index
!= cluster_index
||
2882 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2883 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2884 *piTrailing
= cluster_size
;
2888 if (cluster_size
> 1)
2890 /* Be part way through the glyph cluster based on size and position */
2891 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2892 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2896 /* back up to the beginning of the cluster */
2897 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2898 adv
+= piAdvance
[part_index
];
2899 if (adv
> iX
) adv
= iX
;
2901 TRACE("Multi-char cluster, no snap\n");
2902 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2903 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2906 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2908 if (part_index
) part_index
--;
2912 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2914 if (part_index
> cluster_size
)
2916 adv
+= cluster_part_width
;
2917 part_index
=cluster_size
;
2921 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2926 i
+= (cluster_size
- part_index
);
2928 /* Check trailing */
2929 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2930 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2935 /* Check trailing */
2936 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2937 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2944 TRACE("Point falls outside of string\n");
2945 if (glyph_index
< 0)
2947 else /* (glyph_index >= cGlyphs) */
2950 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2951 point flow to the next character */
2954 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
2963 TRACE("*piCP=%d\n", *piCP
);
2964 TRACE("*piTrailing=%d\n", *piTrailing
);
2968 /***********************************************************************
2969 * ScriptBreak (USP10.@)
2971 * Retrieve line break information.
2974 * chars [I] Array of characters.
2975 * sa [I] Script analysis.
2976 * la [I] Array of logical attribute structures.
2982 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
2984 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
2986 if (count
< 0 || !la
) return E_INVALIDARG
;
2987 if (count
== 0) return E_FAIL
;
2989 BREAK_line(chars
, count
, sa
, la
);
2994 /***********************************************************************
2995 * ScriptIsComplex (USP10.@)
2997 * Determine if a string is complex.
3000 * chars [I] Array of characters to test.
3001 * len [I] Length in characters.
3009 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
3011 enum usp10_script script
;
3012 unsigned int i
, consumed
;
3014 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
3016 if (!chars
|| len
< 0)
3017 return E_INVALIDARG
;
3019 for (i
= 0; i
< len
; i
+=consumed
)
3024 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3027 script
= get_char_script(chars
,i
,len
, &consumed
);
3028 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3029 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3035 /***********************************************************************
3036 * ScriptShapeOpenType (USP10.@)
3038 * Produce glyphs and visual attributes for a run.
3041 * hdc [I] Device context.
3042 * psc [I/O] Opaque pointer to a script cache.
3043 * psa [I/O] Script analysis.
3044 * tagScript [I] The OpenType tag for the Script
3045 * tagLangSys [I] The OpenType tag for the Language
3046 * rcRangeChars[I] Array of Character counts in each range
3047 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3048 * cRanges [I] Count of ranges
3049 * pwcChars [I] Array of characters specifying the run.
3050 * cChars [I] Number of characters in pwcChars.
3051 * cMaxGlyphs [I] Length of pwOutGlyphs.
3052 * pwLogClust [O] Array of logical cluster info.
3053 * pCharProps [O] Array of character property values
3054 * pwOutGlyphs [O] Array of glyphs.
3055 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3056 * pcGlyphs [O] Number of glyphs returned.
3060 * Failure: Non-zero HRESULT value.
3062 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3063 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3064 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3065 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3066 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3067 int cMaxGlyphs
, WORD
*pwLogClust
,
3068 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3069 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3076 static int once
= 0;
3078 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3080 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3081 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3082 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3084 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3085 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3087 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3088 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3091 if(!once
++) FIXME("Ranges not supported yet\n");
3093 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3096 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3097 if (!pwLogClust
) return E_FAIL
;
3099 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3100 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3102 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3103 for (i
= 0; i
< cChars
; i
++)
3106 if (rtl
) idx
= cChars
- 1 - i
;
3107 /* FIXME: set to better values */
3108 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3109 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3110 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3111 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3112 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3113 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3115 /* FIXME: have the shaping engine set this */
3116 pCharProps
[i
].fCanGlyphAlone
= 0;
3118 pwLogClust
[i
] = idx
;
3121 if (psa
&& !psa
->fNoGlyphIndex
&& ((ScriptCache
*)*psc
)->sfnt
)
3124 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3126 rChars
= heap_alloc(sizeof(WCHAR
) * cChars
);
3127 if (!rChars
) return E_OUTOFMEMORY
;
3128 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3133 if (rtl
) idx
= cChars
- 1 - i
;
3136 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3140 chInput
= mirror_char(pwcChars
[idx
]);
3142 chInput
= pwcChars
[idx
];
3143 rChars
[i
] = chInput
;
3147 rChars
[i
] = pwcChars
[idx
];
3148 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3151 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3159 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3164 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3172 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3173 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3179 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3180 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3181 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3183 for (i
= 0; i
< cChars
; ++i
)
3185 /* Special case for tabs and joiners. As control characters, ZWNJ
3186 * and ZWJ would in principle get handled by the corresponding
3187 * shaping functions. However, since ZWNJ and ZWJ can get merged
3188 * into adjoining runs during itemisation, these don't generally
3189 * get classified as Script_Control. */
3190 if (pwcChars
[i
] == 0x0009 || pwcChars
[i
] == ZWSP
|| pwcChars
[i
] == ZWNJ
|| pwcChars
[i
] == ZWJ
)
3192 pwOutGlyphs
[pwLogClust
[i
]] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3193 pOutGlyphProps
[pwLogClust
[i
]].sva
.fZeroWidth
= 1;
3200 TRACE("no glyph translation\n");
3201 for (i
= 0; i
< cChars
; i
++)
3204 /* No mirroring done here */
3205 if (rtl
) idx
= cChars
- 1 - i
;
3206 pwOutGlyphs
[i
] = pwcChars
[idx
];
3211 /* overwrite some basic control glyphs to blank */
3212 if (psa
->fNoGlyphIndex
)
3214 if (pwcChars
[idx
] == ZWSP
|| pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3216 pwOutGlyphs
[i
] = 0x20;
3217 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3220 else if (psa
->eScript
== Script_Control
|| pwcChars
[idx
] == ZWSP
3221 || pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3223 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3224 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3226 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3227 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3237 /***********************************************************************
3238 * ScriptShape (USP10.@)
3240 * Produce glyphs and visual attributes for a run.
3243 * hdc [I] Device context.
3244 * psc [I/O] Opaque pointer to a script cache.
3245 * pwcChars [I] Array of characters specifying the run.
3246 * cChars [I] Number of characters in pwcChars.
3247 * cMaxGlyphs [I] Length of pwOutGlyphs.
3248 * psa [I/O] Script analysis.
3249 * pwOutGlyphs [O] Array of glyphs.
3250 * pwLogClust [O] Array of logical cluster info.
3251 * psva [O] Array of visual attributes.
3252 * pcGlyphs [O] Number of glyphs returned.
3256 * Failure: Non-zero HRESULT value.
3258 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3259 int cChars
, int cMaxGlyphs
,
3260 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3261 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3265 SCRIPT_CHARPROP
*charProps
;
3266 SCRIPT_GLYPHPROP
*glyphProps
;
3268 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3269 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3271 charProps
= heap_alloc_zero(sizeof(SCRIPT_CHARPROP
)*cChars
);
3272 if (!charProps
) return E_OUTOFMEMORY
;
3273 glyphProps
= heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP
)*cMaxGlyphs
);
3276 heap_free(charProps
);
3277 return E_OUTOFMEMORY
;
3280 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3284 for (i
= 0; i
< *pcGlyphs
; i
++)
3285 psva
[i
] = glyphProps
[i
].sva
;
3288 heap_free(charProps
);
3289 heap_free(glyphProps
);
3294 /***********************************************************************
3295 * ScriptPlaceOpenType (USP10.@)
3297 * Produce advance widths for a run.
3300 * hdc [I] Device context.
3301 * psc [I/O] Opaque pointer to a script cache.
3302 * psa [I/O] Script analysis.
3303 * tagScript [I] The OpenType tag for the Script
3304 * tagLangSys [I] The OpenType tag for the Language
3305 * rcRangeChars[I] Array of Character counts in each range
3306 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3307 * cRanges [I] Count of ranges
3308 * pwcChars [I] Array of characters specifying the run.
3309 * pwLogClust [I] Array of logical cluster info
3310 * pCharProps [I] Array of character property values
3311 * cChars [I] Number of characters in pwcChars.
3312 * pwGlyphs [I] Array of glyphs.
3313 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3314 * cGlyphs [I] Count of Glyphs
3315 * piAdvance [O] Array of advance widths.
3316 * pGoffset [O] Glyph offsets.
3317 * pABC [O] Combined ABC width.
3321 * Failure: Non-zero HRESULT value.
3324 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3325 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3326 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3327 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3328 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3329 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3330 int cGlyphs
, int *piAdvance
,
3331 GOFFSET
*pGoffset
, ABC
*pABC
3336 static int once
= 0;
3338 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3340 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3341 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3342 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3345 if (!pGlyphProps
) return E_INVALIDARG
;
3346 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3347 if (!pGoffset
) return E_FAIL
;
3350 if (!once
++) FIXME("Ranges not supported yet\n");
3352 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3353 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3355 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3356 for (i
= 0; i
< cGlyphs
; i
++)
3359 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3361 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3363 else if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3366 if (!hdc
) return E_PENDING
;
3367 if (get_cache_pitch_family(psc
) & TMPF_TRUETYPE
)
3369 if (psa
->fNoGlyphIndex
)
3370 ret
= GetCharABCWidthsW(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &abc
);
3372 ret
= GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
);
3373 if (!ret
) return S_FALSE
;
3378 if (psa
->fNoGlyphIndex
)
3379 ret
= GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
);
3381 ret
= GetCharWidthI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &width
);
3382 if (!ret
) return S_FALSE
;
3384 abc
.abcA
= abc
.abcC
= 0;
3386 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3390 pABC
->abcA
+= abc
.abcA
;
3391 pABC
->abcB
+= abc
.abcB
;
3392 pABC
->abcC
+= abc
.abcC
;
3394 /* FIXME: set to more reasonable values */
3395 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3396 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3399 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3401 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3405 /***********************************************************************
3406 * ScriptPlace (USP10.@)
3408 * Produce advance widths for a run.
3411 * hdc [I] Device context.
3412 * psc [I/O] Opaque pointer to a script cache.
3413 * pwGlyphs [I] Array of glyphs.
3414 * cGlyphs [I] Number of glyphs in pwGlyphs.
3415 * psva [I] Array of visual attributes.
3416 * psa [I/O] String analysis.
3417 * piAdvance [O] Array of advance widths.
3418 * pGoffset [O] Glyph offsets.
3419 * pABC [O] Combined ABC width.
3423 * Failure: Non-zero HRESULT value.
3425 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3426 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3427 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3430 SCRIPT_GLYPHPROP
*glyphProps
;
3433 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3434 piAdvance
, pGoffset
, pABC
);
3436 if (!psva
) return E_INVALIDARG
;
3437 if (!pGoffset
) return E_FAIL
;
3439 glyphProps
= heap_alloc(sizeof(SCRIPT_GLYPHPROP
)*cGlyphs
);
3440 if (!glyphProps
) return E_OUTOFMEMORY
;
3442 for (i
= 0; i
< cGlyphs
; i
++)
3443 glyphProps
[i
].sva
= psva
[i
];
3445 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3447 heap_free(glyphProps
);
3452 /***********************************************************************
3453 * ScriptGetCMap (USP10.@)
3455 * Retrieve glyph indices.
3458 * hdc [I] Device context.
3459 * psc [I/O] Opaque pointer to a script cache.
3460 * pwcInChars [I] Array of Unicode characters.
3461 * cChars [I] Number of characters in pwcInChars.
3462 * dwFlags [I] Flags.
3463 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3467 * Failure: Non-zero HRESULT value.
3469 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3470 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3475 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3476 cChars
, dwFlags
, pwOutGlyphs
);
3478 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3482 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3484 for (i
= 0; i
< cChars
; i
++)
3487 if (dwFlags
== SGCM_RTL
)
3488 inChar
= mirror_char(pwcInChars
[i
]);
3490 inChar
= pwcInChars
[i
];
3491 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3494 if (!hdc
) return E_PENDING
;
3495 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3496 if (glyph
== 0xffff)
3501 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3507 TRACE("no glyph translation\n");
3508 for (i
= 0; i
< cChars
; i
++)
3511 if (dwFlags
== SGCM_RTL
)
3512 inChar
= mirror_char(pwcInChars
[i
]);
3514 inChar
= pwcInChars
[i
];
3515 pwOutGlyphs
[i
] = inChar
;
3521 /***********************************************************************
3522 * ScriptTextOut (USP10.@)
3525 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3526 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3527 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3528 const int *piJustify
, const GOFFSET
*pGoffset
)
3533 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3535 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3536 hdc
, psc
, x
, y
, fuOptions
, wine_dbgstr_rect(lprc
), psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3537 piAdvance
, piJustify
, pGoffset
);
3539 if (!hdc
|| !psc
) return E_INVALIDARG
;
3540 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3542 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3543 fuOptions
|= ETO_IGNORELANGUAGE
;
3544 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3545 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3547 lpDx
= heap_alloc(cGlyphs
* sizeof(INT
) * 2);
3548 if (!lpDx
) return E_OUTOFMEMORY
;
3549 fuOptions
|= ETO_PDY
;
3551 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3553 reordered_glyphs
= heap_alloc( cGlyphs
* sizeof(WORD
) );
3554 if (!reordered_glyphs
)
3557 return E_OUTOFMEMORY
;
3560 for (i
= 0; i
< cGlyphs
; i
++)
3561 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3565 for (i
= 0; i
< cGlyphs
; i
++)
3567 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3568 lpDx
[i
* 2] = piAdvance
[orig_index
];
3569 lpDx
[i
* 2 + 1] = 0;
3575 x
+= pGoffset
[orig_index
].du
* dir
;
3576 y
+= pGoffset
[orig_index
].dv
;
3580 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3581 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3583 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3584 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3588 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3591 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3597 /***********************************************************************
3598 * ScriptCacheGetHeight (USP10.@)
3600 * Retrieve the height of the font in the cache.
3603 * hdc [I] Device context.
3604 * psc [I/O] Opaque pointer to a script cache.
3605 * height [O] Receives font height.
3609 * Failure: Non-zero HRESULT value.
3611 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3615 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3617 if (!height
) return E_INVALIDARG
;
3618 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3620 *height
= get_cache_height(psc
);
3624 /***********************************************************************
3625 * ScriptGetGlyphABCWidth (USP10.@)
3627 * Retrieve the width of a glyph.
3630 * hdc [I] Device context.
3631 * psc [I/O] Opaque pointer to a script cache.
3632 * glyph [I] Glyph to retrieve the width for.
3633 * abc [O] ABC widths of the glyph.
3637 * Failure: Non-zero HRESULT value.
3639 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3643 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3645 if (!abc
) return E_INVALIDARG
;
3646 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3648 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3650 if (!hdc
) return E_PENDING
;
3651 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3653 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3658 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3660 abc
->abcA
= abc
->abcC
= 0;
3662 set_cache_glyph_widths(psc
, glyph
, abc
);
3667 /***********************************************************************
3668 * ScriptLayout (USP10.@)
3670 * Map embedding levels to visual and/or logical order.
3673 * runs [I] Size of level array.
3674 * level [I] Array of embedding levels.
3675 * vistolog [O] Map of embedding levels from visual to logical order.
3676 * logtovis [O] Map of embedding levels from logical to visual order.
3680 * Failure: Non-zero HRESULT value.
3683 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3688 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3690 if (!level
|| (!vistolog
&& !logtovis
))
3691 return E_INVALIDARG
;
3693 indexs
= heap_alloc(sizeof(int) * runs
);
3695 return E_OUTOFMEMORY
;
3699 for( ich
= 0; ich
< runs
; ich
++)
3704 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3705 memcpy(vistolog
, indexs
, runs
* sizeof(*vistolog
));
3710 for( ich
= 0; ich
< runs
; ich
++)
3715 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3716 memcpy(logtovis
, indexs
, runs
* sizeof(*logtovis
));
3723 /***********************************************************************
3724 * ScriptStringGetLogicalWidths (USP10.@)
3726 * Returns logical widths from a string analysis.
3729 * ssa [I] string analysis.
3730 * piDx [O] logical widths returned.
3734 * Failure: a non-zero HRESULT.
3736 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3739 StringAnalysis
*analysis
= ssa
;
3741 TRACE("%p, %p\n", ssa
, piDx
);
3743 if (!analysis
) return S_FALSE
;
3744 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3746 for (i
= 0; i
< analysis
->numItems
; i
++)
3748 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3751 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3754 for (j
= 0; j
< cChar
; j
++)
3757 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3758 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3759 cChar
, j
, direction
, NULL
, NULL
);
3760 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
);
3762 for (k
= 0; k
< clust_size
; k
++)
3764 piDx
[next
] = advance
/ clust_size
;
3773 /***********************************************************************
3774 * ScriptStringValidate (USP10.@)
3776 * Validate a string analysis.
3779 * ssa [I] string analysis.
3783 * Failure: S_FALSE if invalid sequences are found
3784 * or a non-zero HRESULT if it fails.
3786 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3788 StringAnalysis
*analysis
= ssa
;
3790 TRACE("(%p)\n", ssa
);
3792 if (!analysis
) return E_INVALIDARG
;
3793 return (analysis
->invalid
) ? S_FALSE
: S_OK
;
3796 /***********************************************************************
3797 * ScriptString_pSize (USP10.@)
3799 * Retrieve width and height of an analysed string.
3802 * ssa [I] string analysis.
3805 * Success: Pointer to a SIZE structure.
3808 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3811 StringAnalysis
*analysis
= ssa
;
3813 TRACE("(%p)\n", ssa
);
3815 if (!analysis
) return NULL
;
3816 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return NULL
;
3820 if (!(analysis
->sz
= heap_alloc(sizeof(SIZE
)))) return NULL
;
3821 analysis
->sz
->cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3823 analysis
->sz
->cx
= 0;
3824 for (i
= 0; i
< analysis
->numItems
; i
++)
3826 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
->cy
)
3827 analysis
->sz
->cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3828 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3829 analysis
->sz
->cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3832 return analysis
->sz
;
3835 /***********************************************************************
3836 * ScriptString_pLogAttr (USP10.@)
3838 * Retrieve logical attributes of an analysed string.
3841 * ssa [I] string analysis.
3844 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3847 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3849 StringAnalysis
*analysis
= ssa
;
3851 TRACE("(%p)\n", ssa
);
3853 if (!analysis
) return NULL
;
3854 if (!(analysis
->dwFlags
& SSA_BREAK
)) return NULL
;
3855 return analysis
->logattrs
;
3858 /***********************************************************************
3859 * ScriptString_pcOutChars (USP10.@)
3861 * Retrieve the length of a string after clipping.
3864 * ssa [I] String analysis.
3867 * Success: Pointer to the length.
3870 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3872 StringAnalysis
*analysis
= ssa
;
3874 TRACE("(%p)\n", ssa
);
3876 if (!analysis
) return NULL
;
3877 return &analysis
->clip_len
;
3880 /***********************************************************************
3881 * ScriptStringGetOrder (USP10.@)
3883 * Retrieve a glyph order map.
3886 * ssa [I] String analysis.
3887 * order [I/O] Array of glyph positions.
3891 * Failure: a non-zero HRESULT.
3893 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3897 StringAnalysis
*analysis
= ssa
;
3899 TRACE("(%p)\n", ssa
);
3901 if (!analysis
) return S_FALSE
;
3902 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3904 /* FIXME: handle RTL scripts */
3905 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3906 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3912 /***********************************************************************
3913 * ScriptGetLogicalWidths (USP10.@)
3915 * Convert advance widths to logical widths.
3918 * sa [I] Script analysis.
3919 * nbchars [I] Number of characters.
3920 * nbglyphs [I] Number of glyphs.
3921 * glyph_width [I] Array of glyph widths.
3922 * log_clust [I] Array of logical clusters.
3923 * sva [I] Visual attributes.
3924 * widths [O] Array of logical widths.
3928 * Failure: a non-zero HRESULT.
3930 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3931 const int *advances
, const WORD
*log_clust
,
3932 const SCRIPT_VISATTR
*sva
, int *widths
)
3934 int i
, next
= 0, direction
;
3936 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3937 sa
, nbchars
, nbglyphs
, advances
, log_clust
, sva
, widths
);
3939 if (sa
->fRTL
&& !sa
->fLogicalOrder
)
3944 for (i
= 0; i
< nbchars
; i
++)
3946 int clust_size
= get_cluster_size(log_clust
, nbchars
, i
, direction
, NULL
, NULL
);
3947 int advance
= get_glyph_cluster_advance(advances
, sva
, log_clust
, nbglyphs
, nbchars
, log_clust
[i
], direction
);
3950 for (j
= 0; j
< clust_size
; j
++)
3952 widths
[next
] = advance
/ clust_size
;
3961 /***********************************************************************
3962 * ScriptApplyLogicalWidth (USP10.@)
3964 * Generate glyph advance widths.
3967 * dx [I] Array of logical advance widths.
3968 * num_chars [I] Number of characters.
3969 * num_glyphs [I] Number of glyphs.
3970 * log_clust [I] Array of logical clusters.
3971 * sva [I] Visual attributes.
3972 * advance [I] Array of glyph advance widths.
3973 * sa [I] Script analysis.
3974 * abc [I/O] Summed ABC widths.
3975 * justify [O] Array of glyph advance widths.
3979 * Failure: a non-zero HRESULT.
3981 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
3982 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
3983 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
3984 ABC
*abc
, int *justify
)
3988 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3989 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
3991 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
3995 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
3996 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
4000 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
4002 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
4006 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
4009 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4010 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4012 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
4015 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
4018 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4019 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4021 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
4024 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
4027 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4028 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4030 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);
4034 BOOL gbLpkPresent
= FALSE
;
4035 VOID WINAPI
LpkPresent()
4037 gbLpkPresent
= TRUE
; /* Turn it on this way! Wine is out of control! */