2 * Implementation of Uniscribe Script Processor (usp10.dll)
4 * Copyright 2005 Steven Edwards for CodeWeavers
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 * Uniscribe allows for processing of complex scripts such as joining
24 * and filtering characters and bi-directional text with custom line breaks.
39 #include "usp10_internal.h"
41 #include "wine/debug.h"
42 #include "wine/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe
);
46 typedef struct _scriptRange
55 static const scriptRange scriptRanges
[] = {
56 /* Basic Latin: U+0000–U+007A */
57 { Script_Latin
, 0x00, 0x07a , Script_Numeric
, Script_Punctuation
},
58 /* Latin-1 Supplement: U+0080–U+00FF */
59 /* Latin Extended-A: U+0100–U+017F */
60 /* Latin Extended-B: U+0180–U+024F */
61 /* IPA Extensions: U+0250–U+02AF */
62 /* Spacing Modifier Letters:U+02B0–U+02FF */
63 { Script_Latin
, 0x80, 0x2ff , Script_Numeric2
, Script_Punctuation
},
64 /* Combining Diacritical Marks : U+0300–U+036F */
65 { Script_Diacritical
,0x300, 0x36f, 0, 0},
66 /* Greek: U+0370–U+03FF */
67 { Script_Greek
, 0x370, 0x3ff, 0, 0},
68 /* Cyrillic: U+0400–U+04FF */
69 /* Cyrillic Supplement: U+0500–U+052F */
70 { Script_Cyrillic
, 0x400, 0x52f, 0, 0},
71 /* Armenian: U+0530–U+058F */
72 { Script_Armenian
, 0x530, 0x58f, 0, 0},
73 /* Hebrew: U+0590–U+05FF */
74 { Script_Hebrew
, 0x590, 0x5ff, 0, 0},
75 /* Arabic: U+0600–U+06FF */
76 { Script_Arabic
, 0x600, 0x6ef, Script_Arabic_Numeric
, 0},
77 /* Defined by Windows */
78 { Script_Persian
, 0x6f0, 0x6f9, 0, 0},
79 /* Continue Arabic: U+0600–U+06FF */
80 { Script_Arabic
, 0x6fa, 0x6ff, 0, 0},
81 /* Syriac: U+0700–U+074F*/
82 { Script_Syriac
, 0x700, 0x74f, 0, 0},
83 /* Arabic Supplement: U+0750–U+077F */
84 { Script_Arabic
, 0x750, 0x77f, 0, 0},
85 /* Thaana: U+0780–U+07BF */
86 { Script_Thaana
, 0x780, 0x7bf, 0, 0},
87 /* N’Ko: U+07C0–U+07FF */
88 { Script_NKo
, 0x7c0, 0x7ff, 0, 0},
89 /* Devanagari: U+0900–U+097F */
90 { Script_Devanagari
, 0x900, 0x97f, Script_Devanagari_Numeric
, 0},
91 /* Bengali: U+0980–U+09FF */
92 { Script_Bengali
, 0x980, 0x9ff, Script_Bengali_Numeric
, 0},
93 /* Gurmukhi: U+0A00–U+0A7F*/
94 { Script_Gurmukhi
, 0xa00, 0xa7f, Script_Gurmukhi_Numeric
, 0},
95 /* Gujarati: U+0A80–U+0AFF*/
96 { Script_Gujarati
, 0xa80, 0xaff, Script_Gujarati_Numeric
, 0},
97 /* Oriya: U+0B00–U+0B7F */
98 { Script_Oriya
, 0xb00, 0xb7f, Script_Oriya_Numeric
, 0},
99 /* Tamil: U+0B80–U+0BFF */
100 { Script_Tamil
, 0xb80, 0xbff, Script_Tamil_Numeric
, 0},
101 /* Telugu: U+0C00–U+0C7F */
102 { Script_Telugu
, 0xc00, 0xc7f, Script_Telugu_Numeric
, 0},
103 /* Kannada: U+0C80–U+0CFF */
104 { Script_Kannada
, 0xc80, 0xcff, Script_Kannada_Numeric
, 0},
105 /* Malayalam: U+0D00–U+0D7F */
106 { Script_Malayalam
, 0xd00, 0xd7f, Script_Malayalam_Numeric
, 0},
107 /* Sinhala: U+0D80–U+0DFF */
108 { Script_Sinhala
, 0xd80, 0xdff, 0, 0},
109 /* Thai: U+0E00–U+0E7F */
110 { Script_Thai
, 0xe00, 0xe7f, Script_Thai_Numeric
, 0},
111 /* Lao: U+0E80–U+0EFF */
112 { Script_Lao
, 0xe80, 0xeff, Script_Lao_Numeric
, 0},
113 /* Tibetan: U+0F00–U+0FFF */
114 { Script_Tibetan
, 0xf00, 0xfff, 0, 0},
115 /* Myanmar: U+1000–U+109F */
116 { Script_Myanmar
, 0x1000, 0x109f, Script_Myanmar_Numeric
, 0},
117 /* Georgian: U+10A0–U+10FF */
118 { Script_Georgian
, 0x10a0, 0x10ff, 0, 0},
119 /* Hangul Jamo: U+1100–U+11FF */
120 { Script_Hangul
, 0x1100, 0x11ff, 0, 0},
121 /* Ethiopic: U+1200–U+137F */
122 /* Ethiopic Extensions: U+1380–U+139F */
123 { Script_Ethiopic
, 0x1200, 0x139f, 0, 0},
124 /* Cherokee: U+13A0–U+13FF */
125 { Script_Cherokee
, 0x13a0, 0x13ff, 0, 0},
126 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
127 { Script_Canadian
, 0x1400, 0x167f, 0, 0},
128 /* Ogham: U+1680–U+169F */
129 { Script_Ogham
, 0x1680, 0x169f, 0, 0},
130 /* Runic: U+16A0–U+16F0 */
131 { Script_Runic
, 0x16a0, 0x16f0, 0, 0},
132 /* Khmer: U+1780–U+17FF */
133 { Script_Khmer
, 0x1780, 0x17ff, Script_Khmer_Numeric
, 0},
134 /* Mongolian: U+1800–U+18AF */
135 { Script_Mongolian
, 0x1800, 0x18af, Script_Mongolian_Numeric
, 0},
136 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
137 { Script_Canadian
, 0x18b0, 0x18ff, 0, 0},
138 /* Tai Le: U+1950–U+197F */
139 { Script_Tai_Le
, 0x1950, 0x197f, 0, 0},
140 /* New Tai Lue: U+1980–U+19DF */
141 { Script_New_Tai_Lue
,0x1980, 0x19df, Script_New_Tai_Lue_Numeric
, 0},
142 /* Khmer Symbols: U+19E0–U+19FF */
143 { Script_Khmer
, 0x19e0, 0x19ff, Script_Khmer_Numeric
, 0},
144 /* Vedic Extensions: U+1CD0-U+1CFF */
145 { Script_Devanagari
, 0x1cd0, 0x1cff, Script_Devanagari_Numeric
, 0},
146 /* Phonetic Extensions: U+1D00–U+1DBF */
147 { Script_Latin
, 0x1d00, 0x1dbf, 0, 0},
148 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
149 { Script_Diacritical
,0x1dc0, 0x1dff, 0, 0},
150 /* Latin Extended Additional: U+1E00–U+1EFF */
151 { Script_Latin
, 0x1e00, 0x1eff, 0, 0},
152 /* Greek Extended: U+1F00–U+1FFF */
153 { Script_Greek
, 0x1f00, 0x1fff, 0, 0},
154 /* General Punctuation: U+2000 –U+206f */
155 { Script_Latin
, 0x2000, 0x206f, 0, 0},
156 /* Superscripts and Subscripts : U+2070 –U+209f */
157 /* Currency Symbols : U+20a0 –U+20cf */
158 { Script_Numeric2
, 0x2070, 0x2070, 0, 0},
159 { Script_Latin
, 0x2071, 0x2073, 0, 0},
160 { Script_Numeric2
, 0x2074, 0x2079, 0, 0},
161 { Script_Latin
, 0x207a, 0x207f, 0, 0},
162 { Script_Numeric2
, 0x2080, 0x2089, 0, 0},
163 { Script_Latin
, 0x208a, 0x20cf, 0, 0},
164 /* Letterlike Symbols : U+2100 –U+214f */
165 /* Number Forms : U+2150 –U+218f */
166 /* Arrows : U+2190 –U+21ff */
167 /* Mathematical Operators : U+2200 –U+22ff */
168 /* Miscellaneous Technical : U+2300 –U+23ff */
169 /* Control Pictures : U+2400 –U+243f */
170 /* Optical Character Recognition : U+2440 –U+245f */
171 /* Enclosed Alphanumerics : U+2460 –U+24ff */
172 /* Box Drawing : U+2500 –U+25ff */
173 /* Block Elements : U+2580 –U+259f */
174 /* Geometric Shapes : U+25a0 –U+25ff */
175 /* Miscellaneous Symbols : U+2600 –U+26ff */
176 /* Dingbats : U+2700 –U+27bf */
177 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
178 /* Supplemental Arrows-A : U+27f0 –U+27ff */
179 { Script_Latin
, 0x2100, 0x27ff, 0, 0},
180 /* Braille Patterns: U+2800–U+28FF */
181 { Script_Braille
, 0x2800, 0x28ff, 0, 0},
182 /* Supplemental Arrows-B : U+2900 –U+297f */
183 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
184 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
185 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
186 { Script_Latin
, 0x2900, 0x2bff, 0, 0},
187 /* Latin Extended-C: U+2C60–U+2C7F */
188 { Script_Latin
, 0x2c60, 0x2c7f, 0, 0},
189 /* Georgian: U+2D00–U+2D2F */
190 { Script_Georgian
, 0x2d00, 0x2d2f, 0, 0},
191 /* Tifinagh: U+2D30–U+2D7F */
192 { Script_Tifinagh
, 0x2d30, 0x2d7f, 0, 0},
193 /* Ethiopic Extensions: U+2D80–U+2DDF */
194 { Script_Ethiopic
, 0x2d80, 0x2ddf, 0, 0},
195 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
196 { Script_Cyrillic
, 0x2de0, 0x2dff, 0, 0},
197 /* CJK Radicals Supplement: U+2E80–U+2EFF */
198 /* Kangxi Radicals: U+2F00–U+2FDF */
199 { Script_CJK_Han
, 0x2e80, 0x2fdf, 0, 0},
200 /* Ideographic Description Characters: U+2FF0–U+2FFF */
201 { Script_Ideograph
,0x2ff0, 0x2fff, 0, 0},
202 /* CJK Symbols and Punctuation: U+3000–U+303F */
203 { Script_Ideograph
,0x3000, 0x3004, 0, 0},
204 { Script_CJK_Han
,0x3005, 0x3005, 0, 0},
205 { Script_Ideograph
,0x3006, 0x3006, 0, 0},
206 { Script_CJK_Han
,0x3007, 0x3007, 0, 0},
207 { Script_Ideograph
,0x3008, 0x3020, 0, 0},
208 { Script_CJK_Han
,0x3021, 0x3029, 0, 0},
209 { Script_Ideograph
,0x302a, 0x3030, 0, 0},
211 { Script_Kana
,0x3031, 0x3035, 0, 0},
212 { Script_Ideograph
,0x3036, 0x3037, 0, 0},
213 { Script_CJK_Han
,0x3038, 0x303b, 0, 0},
214 { Script_Ideograph
,0x303c, 0x303f, 0, 0},
215 /* Hiragana: U+3040–U+309F */
216 /* Katakana: U+30A0–U+30FF */
217 { Script_Kana
,0x3040, 0x30ff, 0, 0},
218 /* Bopomofo: U+3100–U+312F */
219 { Script_Bopomofo
,0x3100, 0x312f, 0, 0},
220 /* Hangul Compatibility Jamo: U+3130–U+318F */
221 { Script_Hangul
,0x3130, 0x318f, 0, 0},
222 /* Kanbun: U+3190–U+319F */
223 { Script_Ideograph
,0x3190, 0x319f, 0, 0},
224 /* Bopomofo Extended: U+31A0–U+31BF */
225 { Script_Bopomofo
,0x31a0, 0x31bf, 0, 0},
226 /* CJK Strokes: U+31C0–U+31EF */
227 { Script_Ideograph
,0x31c0, 0x31ef, 0, 0},
228 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
229 { Script_Kana
,0x31f0, 0x31ff, 0, 0},
230 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
231 { Script_Hangul
,0x3200, 0x321f, 0, 0},
232 { Script_Ideograph
,0x3220, 0x325f, 0, 0},
233 { Script_Hangul
,0x3260, 0x327f, 0, 0},
234 { Script_Ideograph
,0x3280, 0x32ef, 0, 0},
235 { Script_Kana
,0x32d0, 0x31ff, 0, 0},
236 /* CJK Compatibility: U+3300–U+33FF*/
237 { Script_Kana
,0x3300, 0x3357, 0, 0},
238 { Script_Ideograph
,0x3358, 0x33ff, 0, 0},
239 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
240 { Script_CJK_Han
,0x3400, 0x4dbf, 0, 0},
241 /* CJK Unified Ideographs: U+4E00–U+9FFF */
242 { Script_CJK_Han
,0x4e00, 0x9fff, 0, 0},
243 /* Yi: U+A000–U+A4CF */
244 { Script_Yi
,0xa000, 0xa4cf, 0, 0},
245 /* Vai: U+A500–U+A63F */
246 { Script_Vai
,0xa500, 0xa63f, Script_Vai_Numeric
, 0},
247 /* Cyrillic Extended-B: U+A640–U+A69F */
248 { Script_Cyrillic
, 0xa640, 0xa69f, 0, 0},
249 /* Modifier Tone Letters: U+A700–U+A71F */
250 /* Latin Extended-D: U+A720–U+A7FF */
251 { Script_Latin
, 0xa700, 0xa7ff, 0, 0},
252 /* Phags-pa: U+A840–U+A87F */
253 { Script_Phags_pa
, 0xa840, 0xa87f, 0, 0},
254 /* Devanagari Extended: U+A8E0-U+A8FF */
255 { Script_Devanagari
, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric
, 0},
256 /* Myanmar Extended-A: U+AA60–U+AA7F */
257 { Script_Myanmar
, 0xaa60, 0xaa7f, Script_Myanmar_Numeric
, 0},
258 /* Hangul Jamo Extended-A: U+A960–U+A97F */
259 { Script_Hangul
, 0xa960, 0xa97f, 0, 0},
260 /* Hangul Syllables: U+AC00–U+D7A3 */
261 { Script_Hangul
, 0xac00, 0xd7a3, 0, 0},
262 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
263 { Script_Hangul
, 0xd7b0, 0xd7ff, 0, 0},
264 /* Surrogates Area: U+D800–U+DFFF */
265 { Script_Surrogates
, 0xd800, 0xdbfe, 0, 0},
266 { Script_Private
, 0xdbff, 0xdc00, 0, 0},
267 { Script_Surrogates
, 0xdc01, 0xdfff, 0, 0},
268 /* Private Use Area: U+E000–U+F8FF */
269 { Script_Private
, 0xe000, 0xf8ff, 0, 0},
270 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
271 { Script_CJK_Han
,0xf900, 0xfaff, 0, 0},
272 /* Latin Ligatures: U+FB00–U+FB06 */
273 { Script_Latin
, 0xfb00, 0xfb06, 0, 0},
274 /* Armenian ligatures U+FB13..U+FB17 */
275 { Script_Armenian
, 0xfb13, 0xfb17, 0, 0},
276 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
277 { Script_Hebrew
, 0xfb1d, 0xfb4f, 0, 0},
278 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
279 { Script_Arabic
, 0xfb50, 0xfdff, 0, 0},
280 /* Vertical Forms: U+FE10–U+FE1F */
281 /* Combining Half Marks: U+FE20–U+FE2F */
282 /* CJK Compatibility Forms: U+FE30–U+FE4F */
283 /* Small Form Variants: U+FE50–U+FE6F */
284 { Script_Ideograph
,0xfe10, 0xfe6f, 0, 0},
285 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
286 { Script_Arabic
, 0xfe70, 0xfeff, 0, 0},
287 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
288 { Script_Ideograph
,0xff00, 0xff64, Script_Numeric2
, 0},
289 { Script_Kana
,0xff65, 0xff9f, 0, 0},
290 { Script_Hangul
,0xffa0, 0xffdf, 0, 0},
291 { Script_Ideograph
,0xffe0, 0xffef, 0, 0},
293 /* Deseret: U+10400–U+1044F */
294 { Script_Deseret
, 0x10400, 0x1044F, 0, 0},
295 /* Osmanya: U+10480–U+104AF */
296 { Script_Osmanya
, 0x10480, 0x104AF, Script_Osmanya_Numeric
, 0},
297 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
298 { Script_MathAlpha
, 0x1D400, 0x1D7FF, 0, 0},
300 { SCRIPT_UNDEFINED
, 0, 0, 0}
303 /* this must be in order so that the index matches the Script value */
304 const scriptData scriptInformation
[] = {
305 {{SCRIPT_UNDEFINED
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
306 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
309 {{Script_Latin
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
310 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
311 MS_MAKE_TAG('l','a','t','n'),
312 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
313 {{Script_CR
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
314 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
317 {{Script_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
318 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
320 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
321 {{Script_Control
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
322 {LANG_ENGLISH
, 0, 1, 0, 0, ANSI_CHARSET
, 1, 0, 0, 0, 0, 0, 1, 0, 0},
325 {{Script_Punctuation
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
326 {LANG_NEUTRAL
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
328 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
329 {{Script_Arabic
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
330 {LANG_ARABIC
, 0, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 1, 0},
331 MS_MAKE_TAG('a','r','a','b'),
332 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
333 {{Script_Arabic_Numeric
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
334 {LANG_ARABIC
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
335 MS_MAKE_TAG('a','r','a','b'),
336 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
337 {{Script_Hebrew
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
338 {LANG_HEBREW
, 0, 1, 0, 1, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
339 MS_MAKE_TAG('h','e','b','r'),
340 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
341 {{Script_Syriac
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
342 {LANG_SYRIAC
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 1, 0},
343 MS_MAKE_TAG('s','y','r','c'),
344 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
345 {{Script_Persian
, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
346 {LANG_PERSIAN
, 1, 1, 0, 0, ARABIC_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
347 MS_MAKE_TAG('a','r','a','b'),
348 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
349 {{Script_Thaana
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
350 {LANG_DIVEHI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
351 MS_MAKE_TAG('t','h','a','a'),
352 {'M','V',' ','B','o','l','i',0}},
353 {{Script_Greek
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
354 {LANG_GREEK
, 0, 0, 0, 0, GREEK_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
355 MS_MAKE_TAG('g','r','e','k'),
356 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
357 {{Script_Cyrillic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
358 {LANG_RUSSIAN
, 0, 0, 0, 0, RUSSIAN_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
359 MS_MAKE_TAG('c','y','r','l'),
360 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
361 {{Script_Armenian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
362 {LANG_ARMENIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
363 MS_MAKE_TAG('a','r','m','n'),
364 {'S','y','l','f','a','e','n',0}},
365 {{Script_Georgian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
366 {LANG_GEORGIAN
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
367 MS_MAKE_TAG('g','e','o','r'),
368 {'S','y','l','f','a','e','n',0}},
369 {{Script_Sinhala
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
370 {LANG_SINHALESE
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
371 MS_MAKE_TAG('s','i','n','h'),
372 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
373 {{Script_Tibetan
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
374 {LANG_TIBETAN
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
375 MS_MAKE_TAG('t','i','b','t'),
376 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
377 {{Script_Tibetan_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
378 {LANG_TIBETAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
379 MS_MAKE_TAG('t','i','b','t'),
380 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
381 {{Script_Phags_pa
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
382 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
383 MS_MAKE_TAG('p','h','a','g'),
384 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
385 {{Script_Thai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
386 {LANG_THAI
, 0, 1, 1, 1, THAI_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 1},
387 MS_MAKE_TAG('t','h','a','i'),
388 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
389 {{Script_Thai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
390 {LANG_THAI
, 1, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
391 MS_MAKE_TAG('t','h','a','i'),
392 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
393 {{Script_Lao
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
394 {LANG_LAO
, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 1, 0, 1, 0, 0, 0, 0},
395 MS_MAKE_TAG('l','a','o',' '),
396 {'D','o','k','C','h','a','m','p','a',0}},
397 {{Script_Lao_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
398 {LANG_LAO
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
399 MS_MAKE_TAG('l','a','o',' '),
400 {'D','o','k','C','h','a','m','p','a',0}},
401 {{Script_Devanagari
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
402 {LANG_HINDI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
403 MS_MAKE_TAG('d','e','v','a'),
404 {'M','a','n','g','a','l',0}},
405 {{Script_Devanagari_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
406 {LANG_HINDI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
407 MS_MAKE_TAG('d','e','v','a'),
408 {'M','a','n','g','a','l',0}},
409 {{Script_Bengali
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
410 {LANG_BENGALI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
411 MS_MAKE_TAG('b','e','n','g'),
412 {'V','r','i','n','d','a',0}},
413 {{Script_Bengali_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
414 {LANG_BENGALI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
415 MS_MAKE_TAG('b','e','n','g'),
416 {'V','r','i','n','d','a',0}},
417 {{Script_Bengali_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
418 {LANG_BENGALI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
419 MS_MAKE_TAG('b','e','n','g'),
420 {'V','r','i','n','d','a',0}},
421 {{Script_Gurmukhi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
422 {LANG_PUNJABI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
423 MS_MAKE_TAG('g','u','r','u'),
424 {'R','a','a','v','i',0}},
425 {{Script_Gurmukhi_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
426 {LANG_PUNJABI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
427 MS_MAKE_TAG('g','u','r','u'),
428 {'R','a','a','v','i',0}},
429 {{Script_Gujarati
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
430 {LANG_GUJARATI
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
431 MS_MAKE_TAG('g','u','j','r'),
432 {'S','h','r','u','t','i',0}},
433 {{Script_Gujarati_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
434 {LANG_GUJARATI
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
435 MS_MAKE_TAG('g','u','j','r'),
436 {'S','h','r','u','t','i',0}},
437 {{Script_Gujarati_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
438 {LANG_GUJARATI
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
439 MS_MAKE_TAG('g','u','j','r'),
440 {'S','h','r','u','t','i',0}},
441 {{Script_Oriya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
442 {LANG_ORIYA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
443 MS_MAKE_TAG('o','r','y','a'),
444 {'K','a','l','i','n','g','a',0}},
445 {{Script_Oriya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
446 {LANG_ORIYA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
447 MS_MAKE_TAG('o','r','y','a'),
448 {'K','a','l','i','n','g','a',0}},
449 {{Script_Tamil
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
450 {LANG_TAMIL
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
451 MS_MAKE_TAG('t','a','m','l'),
452 {'L','a','t','h','a',0}},
453 {{Script_Tamil_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
454 {LANG_TAMIL
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
455 MS_MAKE_TAG('t','a','m','l'),
456 {'L','a','t','h','a',0}},
457 {{Script_Telugu
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
458 {LANG_TELUGU
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
459 MS_MAKE_TAG('t','e','l','u'),
460 {'G','a','u','t','a','m','i',0}},
461 {{Script_Telugu_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
462 {LANG_TELUGU
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
463 MS_MAKE_TAG('t','e','l','u'),
464 {'G','a','u','t','a','m','i',0}},
465 {{Script_Kannada
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
466 {LANG_KANNADA
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
467 MS_MAKE_TAG('k','n','d','a'),
468 {'T','u','n','g','a',0}},
469 {{Script_Kannada_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
470 {LANG_KANNADA
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
471 MS_MAKE_TAG('k','n','d','a'),
472 {'T','u','n','g','a',0}},
473 {{Script_Malayalam
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
474 {LANG_MALAYALAM
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
475 MS_MAKE_TAG('m','l','y','m'),
476 {'K','a','r','t','i','k','a',0}},
477 {{Script_Malayalam_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
478 {LANG_MALAYALAM
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
479 MS_MAKE_TAG('m','l','y','m'),
480 {'K','a','r','t','i','k','a',0}},
481 {{Script_Diacritical
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
482 {LANG_ENGLISH
, 0, 1, 0, 1, ANSI_CHARSET
, 0, 0, 0, 0, 0, 1, 1, 0, 0},
485 {{Script_Punctuation2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
486 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
487 MS_MAKE_TAG('l','a','t','n'),
488 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
489 {{Script_Numeric2
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
490 {LANG_ENGLISH
, 1, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
493 {{Script_Myanmar
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
494 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
495 MS_MAKE_TAG('m','y','m','r'),
496 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
497 {{Script_Myanmar_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
498 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
499 MS_MAKE_TAG('m','y','m','r'),
501 {{Script_Tai_Le
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
502 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
503 MS_MAKE_TAG('t','a','l','e'),
504 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
505 {{Script_New_Tai_Lue
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
506 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
507 MS_MAKE_TAG('t','a','l','u'),
508 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
509 {{Script_New_Tai_Lue_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
510 {0, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
511 MS_MAKE_TAG('t','a','l','u'),
512 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
513 {{Script_Khmer
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
514 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 1, 0, 0, 0, 0},
515 MS_MAKE_TAG('k','h','m','r'),
516 {'D','a','u','n','P','e','n','h',0}},
517 {{Script_Khmer_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
518 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
519 MS_MAKE_TAG('k','h','m','r'),
520 {'D','a','u','n','P','e','n','h',0}},
521 {{Script_CJK_Han
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
522 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
523 MS_MAKE_TAG('h','a','n','i'),
525 {{Script_Ideograph
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
526 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
527 MS_MAKE_TAG('h','a','n','i'),
529 {{Script_Bopomofo
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
530 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
531 MS_MAKE_TAG('b','o','p','o'),
533 {{Script_Kana
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
534 {LANG_ENGLISH
, 0, 0, 0, 0, ANSI_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
535 MS_MAKE_TAG('k','a','n','a'),
537 {{Script_Hangul
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
538 {LANG_KOREAN
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
539 MS_MAKE_TAG('h','a','n','g'),
541 {{Script_Yi
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
542 {LANG_ENGLISH
, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
543 MS_MAKE_TAG('y','i',' ',' '),
544 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
545 {{Script_Ethiopic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
546 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
547 MS_MAKE_TAG('e','t','h','i'),
548 {'N','y','a','l','a',0}},
549 {{Script_Ethiopic_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
550 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
551 MS_MAKE_TAG('e','t','h','i'),
552 {'N','y','a','l','a',0}},
553 {{Script_Mongolian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
554 {LANG_MONGOLIAN
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
555 MS_MAKE_TAG('m','o','n','g'),
556 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
557 {{Script_Mongolian_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
558 {LANG_MONGOLIAN
, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
559 MS_MAKE_TAG('m','o','n','g'),
560 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
561 {{Script_Tifinagh
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
562 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
563 MS_MAKE_TAG('t','f','n','g'),
564 {'E','b','r','i','m','a',0}},
565 {{Script_NKo
, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
566 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
567 MS_MAKE_TAG('n','k','o',' '),
568 {'E','b','r','i','m','a',0}},
569 {{Script_Vai
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
570 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
571 MS_MAKE_TAG('v','a','i',' '),
572 {'E','b','r','i','m','a',0}},
573 {{Script_Vai_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
574 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
575 MS_MAKE_TAG('v','a','i',' '),
576 {'E','b','r','i','m','a',0}},
577 {{Script_Cherokee
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
578 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
579 MS_MAKE_TAG('c','h','e','r'),
580 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
581 {{Script_Canadian
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
582 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
583 MS_MAKE_TAG('c','a','n','s'),
584 {'E','u','p','h','e','m','i','a',0}},
585 {{Script_Ogham
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
586 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
587 MS_MAKE_TAG('o','g','a','m'),
588 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
589 {{Script_Runic
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
590 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
591 MS_MAKE_TAG('r','u','n','r'),
592 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
593 {{Script_Braille
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
594 {LANG_ENGLISH
, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
595 MS_MAKE_TAG('b','r','a','i'),
596 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
597 {{Script_Surrogates
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
598 {LANG_ENGLISH
, 0, 1, 0, 1, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 1, 0, 0},
601 {{Script_Private
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
602 {0, 0, 0, 0, 0, DEFAULT_CHARSET
, 0, 1, 0, 0, 0, 0, 1, 0, 0},
605 {{Script_Deseret
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
606 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
607 MS_MAKE_TAG('d','s','r','t'),
608 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
609 {{Script_Osmanya
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
610 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
611 MS_MAKE_TAG('o','s','m','a'),
612 {'E','b','r','i','m','a',0}},
613 {{Script_Osmanya_Numeric
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
614 {0, 1, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
615 MS_MAKE_TAG('o','s','m','a'),
616 {'E','b','r','i','m','a',0}},
617 {{Script_MathAlpha
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
618 {0, 0, 1, 0, 0, DEFAULT_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
619 MS_MAKE_TAG('m','a','t','h'),
620 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
621 {{Script_Hebrew_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
622 {LANG_HEBREW
, 0, 1, 0, 0, HEBREW_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
623 MS_MAKE_TAG('h','e','b','r'),
624 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
625 {{Script_Vietnamese_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
626 {LANG_VIETNAMESE
, 0, 0, 0, 0, VIETNAMESE_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
627 MS_MAKE_TAG('l','a','t','n'),
628 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
629 {{Script_Thai_Currency
, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
630 {LANG_THAI
, 0, 1, 0, 0, THAI_CHARSET
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
631 MS_MAKE_TAG('t','h','a','i'),
632 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
635 static const SCRIPT_PROPERTIES
*script_props
[] =
637 &scriptInformation
[0].props
, &scriptInformation
[1].props
,
638 &scriptInformation
[2].props
, &scriptInformation
[3].props
,
639 &scriptInformation
[4].props
, &scriptInformation
[5].props
,
640 &scriptInformation
[6].props
, &scriptInformation
[7].props
,
641 &scriptInformation
[8].props
, &scriptInformation
[9].props
,
642 &scriptInformation
[10].props
, &scriptInformation
[11].props
,
643 &scriptInformation
[12].props
, &scriptInformation
[13].props
,
644 &scriptInformation
[14].props
, &scriptInformation
[15].props
,
645 &scriptInformation
[16].props
, &scriptInformation
[17].props
,
646 &scriptInformation
[18].props
, &scriptInformation
[19].props
,
647 &scriptInformation
[20].props
, &scriptInformation
[21].props
,
648 &scriptInformation
[22].props
, &scriptInformation
[23].props
,
649 &scriptInformation
[24].props
, &scriptInformation
[25].props
,
650 &scriptInformation
[26].props
, &scriptInformation
[27].props
,
651 &scriptInformation
[28].props
, &scriptInformation
[29].props
,
652 &scriptInformation
[30].props
, &scriptInformation
[31].props
,
653 &scriptInformation
[32].props
, &scriptInformation
[33].props
,
654 &scriptInformation
[34].props
, &scriptInformation
[35].props
,
655 &scriptInformation
[36].props
, &scriptInformation
[37].props
,
656 &scriptInformation
[38].props
, &scriptInformation
[39].props
,
657 &scriptInformation
[40].props
, &scriptInformation
[41].props
,
658 &scriptInformation
[42].props
, &scriptInformation
[43].props
,
659 &scriptInformation
[44].props
, &scriptInformation
[45].props
,
660 &scriptInformation
[46].props
, &scriptInformation
[47].props
,
661 &scriptInformation
[48].props
, &scriptInformation
[49].props
,
662 &scriptInformation
[50].props
, &scriptInformation
[51].props
,
663 &scriptInformation
[52].props
, &scriptInformation
[53].props
,
664 &scriptInformation
[54].props
, &scriptInformation
[55].props
,
665 &scriptInformation
[56].props
, &scriptInformation
[57].props
,
666 &scriptInformation
[58].props
, &scriptInformation
[59].props
,
667 &scriptInformation
[60].props
, &scriptInformation
[61].props
,
668 &scriptInformation
[62].props
, &scriptInformation
[63].props
,
669 &scriptInformation
[64].props
, &scriptInformation
[65].props
,
670 &scriptInformation
[66].props
, &scriptInformation
[67].props
,
671 &scriptInformation
[68].props
, &scriptInformation
[69].props
,
672 &scriptInformation
[70].props
, &scriptInformation
[71].props
,
673 &scriptInformation
[72].props
, &scriptInformation
[73].props
,
674 &scriptInformation
[74].props
, &scriptInformation
[75].props
,
675 &scriptInformation
[76].props
, &scriptInformation
[77].props
,
676 &scriptInformation
[78].props
, &scriptInformation
[79].props
,
677 &scriptInformation
[80].props
, &scriptInformation
[81].props
686 SCRIPT_VISATTR
* psva
;
702 StringGlyphs
* glyphs
;
703 SCRIPT_LOGATTR
* logattrs
;
713 static inline void *heap_alloc(SIZE_T size
)
715 return HeapAlloc(GetProcessHeap(), 0, size
);
718 static inline void *heap_alloc_zero(SIZE_T size
)
720 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
723 static inline BOOL
heap_free(LPVOID mem
)
725 return HeapFree(GetProcessHeap(), 0, mem
);
728 /* TODO Fix font properties on Arabic locale */
729 static inline BOOL
set_cache_font_properties(const HDC hdc
, ScriptCache
*sc
)
733 sc
->sfp
.wgBlank
= sc
->tm
.tmBreakChar
;
734 sc
->sfp
.wgDefault
= sc
->tm
.tmDefaultChar
;
735 sc
->sfp
.wgInvalid
= sc
->sfp
.wgBlank
;
736 sc
->sfp
.wgKashida
= 0xFFFF;
737 sc
->sfp
.iKashidaWidth
= 0;
741 static const WCHAR chars
[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
742 /* U+0020: numeric space
743 U+200B: zero width space
744 U+F71B: unknown char found by black box testing
748 if (GetGlyphIndicesW(hdc
, chars
, 4, gi
, GGI_MARK_NONEXISTING_GLYPHS
) != GDI_ERROR
)
750 if(gi
[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
751 sc
->sfp
.wgBlank
= gi
[0];
755 sc
->sfp
.wgDefault
= 0;
758 sc
->sfp
.wgInvalid
= gi
[2];
759 else if (gi
[1] != 0xFFFF)
760 sc
->sfp
.wgInvalid
= gi
[1];
761 else if (gi
[0] != 0xFFFF)
762 sc
->sfp
.wgInvalid
= gi
[0];
764 sc
->sfp
.wgInvalid
= 0;
766 sc
->sfp
.wgKashida
= gi
[3];
768 sc
->sfp
.iKashidaWidth
= 0; /* TODO */
776 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES
*sfp
, ScriptCache
*sc
)
778 sfp
->wgBlank
= sc
->sfp
.wgBlank
;
779 sfp
->wgDefault
= sc
->sfp
.wgDefault
;
780 sfp
->wgInvalid
= sc
->sfp
.wgInvalid
;
781 sfp
->wgKashida
= sc
->sfp
.wgKashida
;
782 sfp
->iKashidaWidth
= sc
->sfp
.iKashidaWidth
;
785 static inline LONG
get_cache_height(SCRIPT_CACHE
*psc
)
787 return ((ScriptCache
*)*psc
)->tm
.tmHeight
;
790 static inline BYTE
get_cache_pitch_family(SCRIPT_CACHE
*psc
)
792 return ((ScriptCache
*)*psc
)->tm
.tmPitchAndFamily
;
795 static inline WORD
get_cache_glyph(SCRIPT_CACHE
*psc
, DWORD c
)
797 CacheGlyphPage
*page
= ((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
801 block
= page
->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
802 if (!block
) return 0;
803 return block
[(c
% 0x10000) & GLYPH_BLOCK_MASK
];
806 static inline WORD
set_cache_glyph(SCRIPT_CACHE
*psc
, WCHAR c
, WORD glyph
)
808 CacheGlyphPage
**page
= &((ScriptCache
*)*psc
)->page
[c
/ 0x10000];
810 if (!*page
&& !(*page
= heap_alloc_zero(sizeof(CacheGlyphPage
)))) return 0;
812 block
= &(*page
)->glyphs
[(c
% 0x10000) >> GLYPH_BLOCK_SHIFT
];
813 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(WORD
) * GLYPH_BLOCK_SIZE
))) return 0;
814 return ((*block
)[(c
% 0x10000) & GLYPH_BLOCK_MASK
] = glyph
);
817 static inline BOOL
get_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
819 static const ABC nil
;
820 ABC
*block
= ((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
822 if (!block
|| !memcmp(&block
[glyph
& GLYPH_BLOCK_MASK
], &nil
, sizeof(ABC
))) return FALSE
;
823 memcpy(abc
, &block
[glyph
& GLYPH_BLOCK_MASK
], sizeof(ABC
));
827 static inline BOOL
set_cache_glyph_widths(SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
829 ABC
**block
= &((ScriptCache
*)*psc
)->widths
[glyph
>> GLYPH_BLOCK_SHIFT
];
831 if (!*block
&& !(*block
= heap_alloc_zero(sizeof(ABC
) * GLYPH_BLOCK_SIZE
))) return FALSE
;
832 memcpy(&(*block
)[glyph
& GLYPH_BLOCK_MASK
], abc
, sizeof(ABC
));
836 static HRESULT
init_script_cache(const HDC hdc
, SCRIPT_CACHE
*psc
)
841 if (!psc
) return E_INVALIDARG
;
842 if (*psc
) return S_OK
;
843 if (!hdc
) return E_PENDING
;
845 if (!(sc
= heap_alloc_zero(sizeof(ScriptCache
)))) return E_OUTOFMEMORY
;
846 if (!GetTextMetricsW(hdc
, &sc
->tm
))
851 size
= GetOutlineTextMetricsW(hdc
, 0, NULL
);
854 sc
->otm
= heap_alloc(size
);
855 sc
->otm
->otmSize
= size
;
856 GetOutlineTextMetricsW(hdc
, size
, sc
->otm
);
858 if (!GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(LOGFONTW
), &sc
->lf
))
863 sc
->sfnt
= (GetFontData(hdc
, MS_MAKE_TAG('h','e','a','d'), 0, NULL
, 0)!=GDI_ERROR
);
864 if (!set_cache_font_properties(hdc
, sc
))
870 TRACE("<- %p\n", sc
);
874 static WCHAR
mirror_char( WCHAR ch
)
876 extern const WCHAR wine_mirror_map
[] DECLSPEC_HIDDEN
;
877 return ch
+ wine_mirror_map
[wine_mirror_map
[ch
>> 8] + (ch
& 0xff)];
880 static inline DWORD
decode_surrogate_pair(LPCWSTR str
, INT index
, INT end
)
882 if (index
< end
-1 && IS_SURROGATE_PAIR(str
[index
],str
[index
+1]))
884 DWORD ch
= 0x10000 + ((str
[index
] - 0xd800) << 10) + (str
[index
+1] - 0xdc00);
885 TRACE("Surrogate Pair %x %x => %x\n",str
[index
], str
[index
+1], ch
);
891 static WORD
get_char_script( LPCWSTR str
, INT index
, INT end
, INT
*consumed
)
893 static const WCHAR latin_punc
[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
894 WORD type
= 0, type2
= 0;
900 if (str
[index
] == 0xc || str
[index
] == 0x20 || str
[index
] == 0x202f)
903 /* These punctuation characters are separated out as Latin punctuation */
904 if (strchrW(latin_punc
,str
[index
]))
905 return Script_Punctuation2
;
907 /* These chars are itemized as Punctuation by Windows */
908 if (str
[index
] == 0x2212 || str
[index
] == 0x2044)
909 return Script_Punctuation
;
911 /* Currency Symbols by Unicode point */
915 case 0x09f3: return Script_Bengali_Currency
;
916 case 0x0af1: return Script_Gujarati_Currency
;
917 case 0x0e3f: return Script_Thai_Currency
;
918 case 0x20aa: return Script_Hebrew_Currency
;
919 case 0x20ab: return Script_Vietnamese_Currency
;
920 case 0xfb29: return Script_Hebrew_Currency
;
923 GetStringTypeW(CT_CTYPE1
, &str
[index
], 1, &type
);
924 GetStringTypeW(CT_CTYPE2
, &str
[index
], 1, &type2
);
927 return SCRIPT_UNDEFINED
;
930 return Script_Control
;
932 ch
= decode_surrogate_pair(str
, index
, end
);
941 if (ch
< scriptRanges
[i
].rangeFirst
|| scriptRanges
[i
].script
== SCRIPT_UNDEFINED
)
944 if (ch
>= scriptRanges
[i
].rangeFirst
&& ch
<= scriptRanges
[i
].rangeLast
)
946 if (scriptRanges
[i
].numericScript
&& (type
& C1_DIGIT
|| type2
== C2_ARABICNUMBER
))
947 return scriptRanges
[i
].numericScript
;
948 if (scriptRanges
[i
].punctScript
&& type
& C1_PUNCT
)
949 return scriptRanges
[i
].punctScript
;
950 return scriptRanges
[i
].script
;
955 return SCRIPT_UNDEFINED
;
958 static int compare_FindGlyph(const void *a
, const void* b
)
960 const FindGlyph_struct
*find
= (FindGlyph_struct
*)a
;
961 const WORD
*idx
= (WORD
*)b
;
964 if ( find
->target
> *idx
)
966 else if (find
->target
< *idx
)
969 if (!find
->ascending
)
974 int USP10_FindGlyphInLogClust(const WORD
* pwLogClust
, int cChars
, WORD target
)
976 FindGlyph_struct fgs
;
980 if (pwLogClust
[0] < pwLogClust
[cChars
-1])
981 fgs
.ascending
= TRUE
;
983 fgs
.ascending
= FALSE
;
986 ptr
= bsearch(&fgs
, pwLogClust
, cChars
, sizeof(WORD
), compare_FindGlyph
);
991 for (k
= (ptr
- pwLogClust
)-1; k
>= 0 && pwLogClust
[k
] == target
; k
--)
998 /***********************************************************************
999 * ScriptFreeCache (USP10.@)
1001 * Free a script cache.
1004 * psc [I/O] Script cache.
1008 * Failure: Non-zero HRESULT value.
1010 HRESULT WINAPI
ScriptFreeCache(SCRIPT_CACHE
*psc
)
1018 for (i
= 0; i
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; i
++)
1020 heap_free(((ScriptCache
*)*psc
)->widths
[i
]);
1022 for (i
= 0; i
< NUM_PAGES
; i
++)
1025 if (((ScriptCache
*)*psc
)->page
[i
])
1026 for (j
= 0; j
< GLYPH_MAX
/ GLYPH_BLOCK_SIZE
; j
++)
1027 heap_free(((ScriptCache
*)*psc
)->page
[i
]->glyphs
[j
]);
1028 heap_free(((ScriptCache
*)*psc
)->page
[i
]);
1030 heap_free(((ScriptCache
*)*psc
)->GSUB_Table
);
1031 heap_free(((ScriptCache
*)*psc
)->GDEF_Table
);
1032 heap_free(((ScriptCache
*)*psc
)->CMAP_Table
);
1033 heap_free(((ScriptCache
*)*psc
)->GPOS_Table
);
1034 for (n
= 0; n
< ((ScriptCache
*)*psc
)->script_count
; n
++)
1037 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].language_count
; j
++)
1040 for (k
= 0; k
< ((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].feature_count
; k
++)
1041 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
[k
].lookups
);
1042 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
[j
].features
);
1044 for (j
= 0; j
< ((ScriptCache
*)*psc
)->scripts
[n
].default_language
.feature_count
; j
++)
1045 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
[j
].lookups
);
1046 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].default_language
.features
);
1047 heap_free(((ScriptCache
*)*psc
)->scripts
[n
].languages
);
1049 heap_free(((ScriptCache
*)*psc
)->scripts
);
1050 heap_free(((ScriptCache
*)*psc
)->otm
);
1057 /***********************************************************************
1058 * ScriptGetProperties (USP10.@)
1060 * Retrieve a list of script properties.
1063 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1064 * num [I] Pointer to the number of scripts.
1068 * Failure: Non-zero HRESULT value.
1071 * Behaviour matches WinXP.
1073 HRESULT WINAPI
ScriptGetProperties(const SCRIPT_PROPERTIES
***props
, int *num
)
1075 TRACE("(%p,%p)\n", props
, num
);
1077 if (!props
&& !num
) return E_INVALIDARG
;
1079 if (num
) *num
= sizeof(script_props
)/sizeof(script_props
[0]);
1080 if (props
) *props
= script_props
;
1085 /***********************************************************************
1086 * ScriptGetFontProperties (USP10.@)
1088 * Get information on special glyphs.
1091 * hdc [I] Device context.
1092 * psc [I/O] Opaque pointer to a script cache.
1093 * sfp [O] Font properties structure.
1095 HRESULT WINAPI
ScriptGetFontProperties(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_FONTPROPERTIES
*sfp
)
1099 TRACE("%p,%p,%p\n", hdc
, psc
, sfp
);
1101 if (!sfp
) return E_INVALIDARG
;
1102 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
1104 if (sfp
->cBytes
!= sizeof(SCRIPT_FONTPROPERTIES
))
1105 return E_INVALIDARG
;
1107 get_cache_font_properties(sfp
, *psc
);
1112 /***********************************************************************
1113 * ScriptRecordDigitSubstitution (USP10.@)
1115 * Record digit substitution settings for a given locale.
1118 * locale [I] Locale identifier.
1119 * sds [I] Structure to record substitution settings.
1123 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1126 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1128 HRESULT WINAPI
ScriptRecordDigitSubstitution(LCID locale
, SCRIPT_DIGITSUBSTITUTE
*sds
)
1132 TRACE("0x%x, %p\n", locale
, sds
);
1134 /* This implementation appears to be correct for all languages, but it's
1135 * not clear if sds->DigitSubstitute is ever set to anything except
1136 * CONTEXT or NONE in reality */
1138 if (!sds
) return E_POINTER
;
1140 locale
= ConvertDefaultLocale(locale
);
1142 if (!IsValidLocale(locale
, LCID_INSTALLED
))
1143 return E_INVALIDARG
;
1145 plgid
= PRIMARYLANGID(LANGIDFROMLCID(locale
));
1146 sds
->TraditionalDigitLanguage
= plgid
;
1148 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1149 sds
->NationalDigitLanguage
= plgid
;
1151 sds
->NationalDigitLanguage
= LANG_ENGLISH
;
1153 if (!GetLocaleInfoW(locale
, LOCALE_IDIGITSUBSTITUTION
| LOCALE_RETURN_NUMBER
,
1154 (LPWSTR
)&sub
, sizeof(sub
)/sizeof(WCHAR
))) return E_INVALIDARG
;
1159 if (plgid
== LANG_ARABIC
|| plgid
== LANG_FARSI
)
1160 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_CONTEXT
;
1162 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1165 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NONE
;
1168 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_NATIONAL
;
1171 sds
->DigitSubstitute
= SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
;
1175 sds
->dwReserved
= 0;
1179 /***********************************************************************
1180 * ScriptApplyDigitSubstitution (USP10.@)
1182 * Apply digit substitution settings.
1185 * sds [I] Structure with recorded substitution settings.
1186 * sc [I] Script control structure.
1187 * ss [I] Script state structure.
1191 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1193 HRESULT WINAPI
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE
*sds
,
1194 SCRIPT_CONTROL
*sc
, SCRIPT_STATE
*ss
)
1196 SCRIPT_DIGITSUBSTITUTE psds
;
1198 TRACE("%p, %p, %p\n", sds
, sc
, ss
);
1200 if (!sc
|| !ss
) return E_POINTER
;
1204 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT
, &psds
) != S_OK
)
1205 return E_INVALIDARG
;
1208 sc
->uDefaultLanguage
= LANG_ENGLISH
;
1209 sc
->fContextDigits
= 0;
1210 ss
->fDigitSubstitute
= 0;
1212 switch (sds
->DigitSubstitute
) {
1213 case SCRIPT_DIGITSUBSTITUTE_CONTEXT
:
1214 case SCRIPT_DIGITSUBSTITUTE_NATIONAL
:
1215 case SCRIPT_DIGITSUBSTITUTE_NONE
:
1216 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL
:
1219 return E_INVALIDARG
;
1223 static inline BOOL
is_indic(WORD script
)
1225 return (script
>= Script_Devanagari
&& script
<= Script_Malayalam_Numeric
);
1228 static inline WORD
base_indic(WORD script
)
1232 case Script_Devanagari
:
1233 case Script_Devanagari_Numeric
: return Script_Devanagari
;
1234 case Script_Bengali
:
1235 case Script_Bengali_Numeric
:
1236 case Script_Bengali_Currency
: return Script_Bengali
;
1237 case Script_Gurmukhi
:
1238 case Script_Gurmukhi_Numeric
: return Script_Gurmukhi
;
1239 case Script_Gujarati
:
1240 case Script_Gujarati_Numeric
:
1241 case Script_Gujarati_Currency
: return Script_Gujarati
;
1243 case Script_Oriya_Numeric
: return Script_Oriya
;
1245 case Script_Tamil_Numeric
: return Script_Tamil
;
1247 case Script_Telugu_Numeric
: return Script_Telugu
;
1248 case Script_Kannada
:
1249 case Script_Kannada_Numeric
: return Script_Kannada
;
1250 case Script_Malayalam
:
1251 case Script_Malayalam_Numeric
: return Script_Malayalam
;
1257 static BOOL
script_is_numeric(WORD script
)
1259 return scriptInformation
[script
].props
.fNumeric
;
1262 static HRESULT
_ItemizeInternal(const WCHAR
*pwcInChars
, int cInChars
,
1263 int cMaxItems
, const SCRIPT_CONTROL
*psControl
,
1264 const SCRIPT_STATE
*psState
, SCRIPT_ITEM
*pItems
,
1265 OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1268 #define Numeric_space 0x0020
1273 int cnt
= 0, index
= 0, str
= 0;
1274 int New_Script
= -1;
1276 WORD
*levels
= NULL
;
1277 WORD
*layout_levels
= NULL
;
1278 WORD
*overrides
= NULL
;
1279 WORD
*strength
= NULL
;
1280 WORD
*scripts
= NULL
;
1282 WORD baselayout
= 0;
1284 WORD last_indic
= -1;
1286 BOOL forceLevels
= FALSE
;
1288 HRESULT res
= E_OUTOFMEMORY
;
1290 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars
, cInChars
), cInChars
, cMaxItems
,
1291 psControl
, psState
, pItems
, pcItems
);
1293 if (!pwcInChars
|| !cInChars
|| !pItems
|| cMaxItems
< 2)
1294 return E_INVALIDARG
;
1296 scripts
= heap_alloc(cInChars
* sizeof(WORD
));
1298 return E_OUTOFMEMORY
;
1300 for (i
= 0; i
< cInChars
; i
++)
1304 scripts
[i
] = get_char_script(pwcInChars
,i
,cInChars
,&consumed
);
1309 scripts
[i
] = scripts
[i
-1];
1312 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1313 all Indic scripts */
1314 if ((pwcInChars
[i
] == 0x964 || pwcInChars
[i
] ==0x965) && last_indic
> 0)
1315 scripts
[i
] = last_indic
;
1316 else if (is_indic(scripts
[i
]))
1317 last_indic
= base_indic(scripts
[i
]);
1319 /* Some unicode points :
1320 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1321 (Left Right Embed U+202A - Left Right Override U+202D)
1322 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1323 will force us into bidi mode */
1324 if (!forceLevels
&& ((pwcInChars
[i
] >= 0x200B && pwcInChars
[i
] <= 0x200F) ||
1325 (pwcInChars
[i
] >= 0x202A && pwcInChars
[i
] <= 0x202E) ||
1326 (pwcInChars
[i
] >= 0x2066 && pwcInChars
[i
] <= 0x2069)))
1330 /* Diacritical marks merge with other scripts */
1331 if (scripts
[i
] == Script_Diacritical
)
1336 scripts
[i
] = scripts
[i
-1];
1341 WORD first_script
= scripts
[i
-1];
1342 for (j
= i
-1; j
>= 0 && scripts
[j
] == first_script
&& pwcInChars
[j
] != Numeric_space
; j
--)
1344 WORD original
= scripts
[j
];
1345 if (original
== Script_Ideograph
|| original
== Script_Kana
|| original
== Script_Yi
|| original
== Script_CJK_Han
|| original
== Script_Bopomofo
)
1350 if (original
!= Script_MathAlpha
&& scriptInformation
[scripts
[j
]].props
.fComplex
)
1352 scripts
[j
] = scripts
[i
];
1353 if (original
== Script_Punctuation2
)
1356 if (j
>= 0 && (scriptInformation
[scripts
[j
]].props
.fComplex
|| asian
))
1357 scripts
[i
] = scripts
[j
];
1363 for (i
= 0; i
< cInChars
; i
++)
1365 /* Joiners get merged preferencially right */
1366 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1369 if (i
+1 == cInChars
)
1370 scripts
[i
] = scripts
[i
-1];
1373 for (j
= i
+1; j
< cInChars
; j
++)
1375 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1377 scripts
[i
] = scripts
[j
];
1385 if (psState
&& psControl
)
1387 levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1391 overrides
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1395 layout_levels
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1399 if (psState
->fOverrideDirection
)
1403 SCRIPT_STATE s
= *psState
;
1404 s
.fOverrideDirection
= FALSE
;
1405 BIDI_DetermineLevels(pwcInChars
, cInChars
, &s
, psControl
, layout_levels
, overrides
);
1406 if (odd(layout_levels
[0]))
1408 else for (i
= 0; i
< cInChars
; i
++)
1409 if (layout_levels
[i
]!=layout_levels
[0])
1416 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1420 BIDI_DetermineLevels(pwcInChars
, cInChars
, psState
, psControl
, levels
, overrides
);
1421 memcpy(layout_levels
, levels
, cInChars
* sizeof(WORD
));
1423 baselevel
= levels
[0];
1424 baselayout
= layout_levels
[0];
1425 for (i
= 0; i
< cInChars
; i
++)
1426 if (levels
[i
]!=levels
[0])
1428 if (i
>= cInChars
&& !odd(baselevel
) && !odd(psState
->uBidiLevel
) && !forceLevels
)
1431 heap_free(overrides
);
1432 heap_free(layout_levels
);
1435 layout_levels
= NULL
;
1439 static const WCHAR math_punc
[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1440 static const WCHAR repeatable_math_punc
[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1442 strength
= heap_alloc_zero(cInChars
* sizeof(WORD
));
1445 BIDI_GetStrengths(pwcInChars
, cInChars
, psControl
, strength
);
1447 /* We currently mis-level leading Diacriticals */
1448 if (scripts
[0] == Script_Diacritical
)
1449 for (i
= 0; i
< cInChars
&& scripts
[0] == Script_Diacritical
; i
++)
1451 levels
[i
] = odd(levels
[i
])?levels
[i
]+1:levels
[i
];
1452 strength
[i
] = BIDI_STRONG
;
1455 /* Math punctuation bordered on both sides by numbers can be
1456 merged into the number */
1457 for (i
= 0; i
< cInChars
; i
++)
1459 if (i
> 0 && i
< cInChars
-1 &&
1460 script_is_numeric(scripts
[i
-1]) &&
1461 strchrW(math_punc
, pwcInChars
[i
]))
1463 if (script_is_numeric(scripts
[i
+1]))
1465 scripts
[i
] = scripts
[i
+1];
1466 levels
[i
] = levels
[i
-1];
1467 strength
[i
] = strength
[i
-1];
1470 else if (strchrW(repeatable_math_punc
, pwcInChars
[i
]))
1473 for (j
= i
+1; j
< cInChars
; j
++)
1475 if (script_is_numeric(scripts
[j
]))
1479 scripts
[i
] = scripts
[j
];
1480 levels
[i
] = levels
[i
-1];
1481 strength
[i
] = strength
[i
-1];
1484 else if (pwcInChars
[i
] != pwcInChars
[j
]) break;
1490 for (i
= 0; i
< cInChars
; i
++)
1492 /* Numerics at level 0 get bumped to level 2 */
1493 if (!overrides
[i
] && (levels
[i
] == 0 || (odd(psState
->uBidiLevel
)
1494 && levels
[i
] == psState
->uBidiLevel
+ 1)) && script_is_numeric(scripts
[i
]))
1499 /* Joiners get merged preferencially right */
1500 if (i
> 0 && (pwcInChars
[i
] == ZWJ
|| pwcInChars
[i
] == ZWNJ
))
1503 if (i
+1 == cInChars
&& levels
[i
-1] == levels
[i
])
1504 strength
[i
] = strength
[i
-1];
1506 for (j
= i
+1; j
< cInChars
&& levels
[i
] == levels
[j
]; j
++)
1507 if (pwcInChars
[j
] != ZWJ
&& pwcInChars
[j
] != ZWNJ
&& pwcInChars
[j
] != Numeric_space
)
1509 strength
[i
] = strength
[j
];
1514 if (psControl
->fMergeNeutralItems
)
1516 /* Merge the neutrals */
1517 for (i
= 0; i
< cInChars
; i
++)
1519 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1522 for (j
= i
; j
> 0; j
--)
1524 if (levels
[i
] != levels
[j
])
1526 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1528 scripts
[i
] = scripts
[j
];
1529 strength
[i
] = strength
[j
];
1534 /* Try going the other way */
1535 if (strength
[i
] == BIDI_NEUTRAL
|| strength
[i
] == BIDI_WEAK
)
1538 for (j
= i
; j
< cInChars
; j
++)
1540 if (levels
[i
] != levels
[j
])
1542 if ((strength
[j
] == BIDI_STRONG
) || (strength
[i
] == BIDI_NEUTRAL
&& strength
[j
] == BIDI_WEAK
))
1544 scripts
[i
] = scripts
[j
];
1545 strength
[i
] = strength
[j
];
1555 while ((!levels
|| (levels
&& cnt
+1 < cInChars
&& levels
[cnt
+1] == levels
[0]))
1556 && (cnt
< cInChars
&& pwcInChars
[cnt
] == Numeric_space
))
1559 if (cnt
== cInChars
) /* All Spaces */
1562 New_Script
= scripts
[cnt
];
1565 pItems
[index
].iCharPos
= 0;
1566 pItems
[index
].a
= scriptInformation
[scripts
[cnt
]].a
;
1568 pScriptTags
[index
] = scriptInformation
[scripts
[cnt
]].scriptTag
;
1570 if (strength
&& strength
[cnt
] == BIDI_STRONG
)
1571 str
= strength
[cnt
];
1579 if (strength
[cnt
] == BIDI_STRONG
)
1580 layoutRTL
= odd(layout_levels
[cnt
]);
1582 layoutRTL
= (psState
->uBidiLevel
|| odd(layout_levels
[cnt
]));
1584 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1585 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1586 if (script_is_numeric(pItems
[index
].a
.eScript
))
1587 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1589 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1590 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1592 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1594 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1595 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1596 layoutRTL
= odd(baselayout
);
1597 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1598 pItems
[index
].a
.fRTL
= odd(baselevel
);
1599 if (script_is_numeric(pItems
[index
].a
.eScript
))
1600 pItems
[index
].a
.fLayoutRTL
= odd(baselayout
);
1602 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1605 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1606 levels
?levels
[cnt
]:-1, str
, New_Script
, pItems
[index
].a
.eScript
, index
, cnt
,
1607 pItems
[index
].iCharPos
);
1609 for (cnt
=1; cnt
< cInChars
; cnt
++)
1611 if(pwcInChars
[cnt
] != Numeric_space
)
1612 New_Script
= scripts
[cnt
];
1616 while (cnt
+ j
< cInChars
- 1 && pwcInChars
[cnt
+j
] == Numeric_space
&& levels
[cnt
] == levels
[cnt
+j
])
1618 if (cnt
+ j
< cInChars
&& levels
[cnt
] == levels
[cnt
+j
])
1619 New_Script
= scripts
[cnt
+j
];
1621 New_Script
= scripts
[cnt
];
1625 /* merge space strengths*/
1626 if (strength
&& strength
[cnt
] == BIDI_STRONG
&& str
!= BIDI_STRONG
&& New_Script
== pItems
[index
].a
.eScript
)
1629 if (strength
&& strength
[cnt
] == BIDI_NEUTRAL
&& str
== BIDI_STRONG
&& pwcInChars
[cnt
] != Numeric_space
&& New_Script
== pItems
[index
].a
.eScript
)
1632 /* changes in level */
1633 if (levels
&& (levels
[cnt
] != pItems
[index
].a
.s
.uBidiLevel
))
1635 TRACE("Level break(%i/%i)\n",pItems
[index
].a
.s
.uBidiLevel
,levels
[cnt
]);
1638 /* changes in strength */
1639 else if (strength
&& pwcInChars
[cnt
] != Numeric_space
&& str
!= strength
[cnt
])
1641 TRACE("Strength break (%i/%i)\n",str
,strength
[cnt
]);
1644 /* changes in script */
1645 else if (((pwcInChars
[cnt
] != Numeric_space
) && (New_Script
!= -1) && (New_Script
!= pItems
[index
].a
.eScript
)) || (New_Script
== Script_Control
))
1647 TRACE("Script break(%i/%i)\n",pItems
[index
].a
.eScript
,New_Script
);
1651 if (!new_run
&& strength
&& str
== BIDI_STRONG
)
1653 layoutRTL
= odd(layout_levels
[cnt
]);
1654 if (script_is_numeric(pItems
[index
].a
.eScript
))
1655 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1660 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
);
1663 if (index
+1 > cMaxItems
)
1667 str
= strength
[cnt
];
1669 pItems
[index
].iCharPos
= cnt
;
1670 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1672 pItems
[index
].a
= scriptInformation
[New_Script
].a
;
1674 pScriptTags
[index
] = scriptInformation
[New_Script
].scriptTag
;
1678 pItems
[index
].a
.s
.fOverrideDirection
= (overrides
[cnt
] != 0);
1679 if (layout_levels
[cnt
] == 0)
1682 layoutRTL
= (layoutRTL
|| odd(layout_levels
[cnt
]));
1683 pItems
[index
].a
.fRTL
= odd(levels
[cnt
]);
1684 if (script_is_numeric(pItems
[index
].a
.eScript
))
1685 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1687 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1688 pItems
[index
].a
.s
.uBidiLevel
= levels
[cnt
];
1690 else if (!pItems
[index
].a
.s
.uBidiLevel
|| (overrides
&& overrides
[cnt
]))
1692 if (pItems
[index
].a
.s
.uBidiLevel
!= baselevel
)
1693 pItems
[index
].a
.s
.fOverrideDirection
= TRUE
;
1694 pItems
[index
].a
.s
.uBidiLevel
= baselevel
;
1695 pItems
[index
].a
.fRTL
= odd(baselevel
);
1696 if (script_is_numeric(pItems
[index
].a
.eScript
))
1697 pItems
[index
].a
.fLayoutRTL
= layoutRTL
;
1699 pItems
[index
].a
.fLayoutRTL
= pItems
[index
].a
.fRTL
;
1702 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1706 /* While not strictly necessary according to the spec, make sure the n+1
1707 * item is set up to prevent random behaviour if the caller erroneously
1708 * checks the n+1 structure */
1710 if (index
+ 1 > cMaxItems
) goto nomemory
;
1711 memset(&pItems
[index
].a
, 0, sizeof(SCRIPT_ANALYSIS
));
1713 TRACE("index=%d cnt=%d iCharPos=%d\n", index
, cnt
, pItems
[index
].iCharPos
);
1715 /* Set one SCRIPT_STATE item being returned */
1716 if (pcItems
) *pcItems
= index
;
1718 /* Set SCRIPT_ITEM */
1719 pItems
[index
].iCharPos
= cnt
; /* the last item contains the ptr to the lastchar */
1723 heap_free(overrides
);
1724 heap_free(layout_levels
);
1725 heap_free(strength
);
1730 /***********************************************************************
1731 * ScriptItemizeOpenType (USP10.@)
1733 * Split a Unicode string into shapeable parts.
1736 * pwcInChars [I] String to split.
1737 * cInChars [I] Number of characters in pwcInChars.
1738 * cMaxItems [I] Maximum number of items to return.
1739 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1740 * psState [I] Pointer to a SCRIPT_STATE structure.
1741 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1742 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1743 * pcItems [O] Number of script items returned.
1747 * Failure: Non-zero HRESULT value.
1749 HRESULT WINAPI
ScriptItemizeOpenType(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1750 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1751 SCRIPT_ITEM
*pItems
, OPENTYPE_TAG
*pScriptTags
, int *pcItems
)
1753 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, pScriptTags
, pcItems
);
1756 /***********************************************************************
1757 * ScriptItemize (USP10.@)
1759 * Split a Unicode string into shapeable parts.
1762 * pwcInChars [I] String to split.
1763 * cInChars [I] Number of characters in pwcInChars.
1764 * cMaxItems [I] Maximum number of items to return.
1765 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1766 * psState [I] Pointer to a SCRIPT_STATE structure.
1767 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1768 * pcItems [O] Number of script items returned.
1772 * Failure: Non-zero HRESULT value.
1774 HRESULT WINAPI
ScriptItemize(const WCHAR
*pwcInChars
, int cInChars
, int cMaxItems
,
1775 const SCRIPT_CONTROL
*psControl
, const SCRIPT_STATE
*psState
,
1776 SCRIPT_ITEM
*pItems
, int *pcItems
)
1778 return _ItemizeInternal(pwcInChars
, cInChars
, cMaxItems
, psControl
, psState
, pItems
, NULL
, pcItems
);
1781 static inline int getGivenTabWidth(ScriptCache
*psc
, SCRIPT_TABDEF
*pTabdef
, int charPos
, int current_x
)
1785 INT
*lpTabPos
= NULL
;
1790 lpTabPos
= pTabdef
->pTabStops
;
1792 if (pTabdef
&& pTabdef
->iTabOrigin
)
1794 if (pTabdef
->iScale
)
1795 nTabOrg
= (pTabdef
->iTabOrigin
* pTabdef
->iScale
)/4;
1797 nTabOrg
= pTabdef
->iTabOrigin
* psc
->tm
.tmAveCharWidth
;
1801 cTabStops
= pTabdef
->cTabStops
;
1805 if (pTabdef
->iScale
)
1806 defWidth
= ((pTabdef
->pTabStops
[0])*pTabdef
->iScale
) / 4;
1808 defWidth
= (pTabdef
->pTabStops
[0])*psc
->tm
.tmAveCharWidth
;
1812 defWidth
= 8 * psc
->tm
.tmAveCharWidth
;
1814 for (; cTabStops
>0 ; lpTabPos
++, cTabStops
--)
1816 int position
= *lpTabPos
;
1818 position
= -1 * position
;
1819 if (pTabdef
->iScale
)
1820 position
= (position
* pTabdef
->iScale
) / 4;
1822 position
= position
* psc
->tm
.tmAveCharWidth
;
1824 if( nTabOrg
+ position
> current_x
)
1828 /* a left aligned tab */
1829 x
= (nTabOrg
+ *lpTabPos
) - current_x
;
1834 FIXME("Negative tabstop\n");
1839 if ((!cTabStops
) && (defWidth
> 0))
1840 x
=((((current_x
- nTabOrg
) / defWidth
)+1) * defWidth
) - current_x
;
1841 else if ((!cTabStops
) && (defWidth
< 0))
1842 FIXME("TODO: Negative defWidth\n");
1847 /***********************************************************************
1848 * Helper function for ScriptStringAnalyse
1850 static BOOL
requires_fallback(HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
1851 const WCHAR
*pwcInChars
, int cChars
)
1853 /* FIXME: When to properly fallback is still a bit of a mystery */
1856 if (psa
->fNoGlyphIndex
)
1859 if (init_script_cache(hdc
, psc
) != S_OK
)
1862 if (SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
) != S_OK
)
1865 glyphs
= heap_alloc(sizeof(WORD
) * cChars
);
1868 if (ScriptGetCMap(hdc
, psc
, pwcInChars
, cChars
, 0, glyphs
) != S_OK
)
1878 static void find_fallback_font(DWORD scriptid
, LPWSTR FaceName
)
1882 if (!RegOpenKeyA(HKEY_CURRENT_USER
, "Software\\Wine\\Uniscribe\\Fallback", &hkey
))
1884 static const WCHAR szFmt
[] = {'%','x',0};
1886 DWORD count
= LF_FACESIZE
* sizeof(WCHAR
);
1889 sprintfW(value
, szFmt
, scriptInformation
[scriptid
].scriptTag
);
1890 if (RegQueryValueExW(hkey
, value
, 0, &type
, (LPBYTE
)FaceName
, &count
))
1891 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1895 lstrcpyW(FaceName
,scriptInformation
[scriptid
].fallbackFont
);
1898 /***********************************************************************
1899 * ScriptStringAnalyse (USP10.@)
1902 HRESULT WINAPI
ScriptStringAnalyse(HDC hdc
, const void *pString
, int cString
,
1903 int cGlyphs
, int iCharset
, DWORD dwFlags
,
1904 int iReqWidth
, SCRIPT_CONTROL
*psControl
,
1905 SCRIPT_STATE
*psState
, const int *piDx
,
1906 SCRIPT_TABDEF
*pTabdef
, const BYTE
*pbInClass
,
1907 SCRIPT_STRING_ANALYSIS
*pssa
)
1909 HRESULT hr
= E_OUTOFMEMORY
;
1910 StringAnalysis
*analysis
= NULL
;
1911 SCRIPT_CONTROL sControl
;
1912 SCRIPT_STATE sState
;
1913 int i
, num_items
= 255;
1915 WCHAR
*iString
= NULL
;
1917 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1918 hdc
, pString
, cString
, cGlyphs
, iCharset
, dwFlags
, iReqWidth
,
1919 psControl
, psState
, piDx
, pTabdef
, pbInClass
, pssa
);
1923 FIXME("Only Unicode strings are supported\n");
1924 return E_INVALIDARG
;
1926 if (cString
< 1 || !pString
) return E_INVALIDARG
;
1927 if ((dwFlags
& SSA_GLYPHS
) && !hdc
) return E_PENDING
;
1929 if (!(analysis
= heap_alloc_zero(sizeof(StringAnalysis
)))) return E_OUTOFMEMORY
;
1930 if (!(analysis
->pItem
= heap_alloc_zero(num_items
* sizeof(SCRIPT_ITEM
) + 1))) goto error
;
1932 /* FIXME: handle clipping */
1933 analysis
->clip_len
= cString
;
1934 analysis
->hdc
= hdc
;
1935 analysis
->dwFlags
= dwFlags
;
1940 memset(&sState
, 0, sizeof(SCRIPT_STATE
));
1943 sControl
= *psControl
;
1945 memset(&sControl
, 0, sizeof(SCRIPT_CONTROL
));
1947 if (dwFlags
& SSA_PASSWORD
)
1949 iString
= heap_alloc(sizeof(WCHAR
)*cString
);
1955 for (i
= 0; i
< cString
; i
++)
1956 iString
[i
] = *((const WCHAR
*)pString
);
1960 hr
= ScriptItemize(pString
, cString
, num_items
, &sControl
, &sState
, analysis
->pItem
,
1961 &analysis
->numItems
);
1965 if (hr
== E_OUTOFMEMORY
)
1970 /* set back to out of memory for default goto error behaviour */
1973 if (dwFlags
& SSA_BREAK
)
1975 if ((analysis
->logattrs
= heap_alloc(sizeof(SCRIPT_LOGATTR
) * cString
)))
1977 for (i
= 0; i
< analysis
->numItems
; i
++)
1978 ScriptBreak(&((LPWSTR
)pString
)[analysis
->pItem
[i
].iCharPos
], analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
, &analysis
->pItem
[i
].a
, &analysis
->logattrs
[analysis
->pItem
[i
].iCharPos
]);
1984 if (!(analysis
->logical2visual
= heap_alloc_zero(sizeof(int) * analysis
->numItems
)))
1986 if (!(BidiLevel
= heap_alloc_zero(analysis
->numItems
)))
1989 if (dwFlags
& SSA_GLYPHS
)
1992 if (!(analysis
->glyphs
= heap_alloc_zero(sizeof(StringGlyphs
) * analysis
->numItems
)))
1994 heap_free(BidiLevel
);
1998 for (i
= 0; i
< analysis
->numItems
; i
++)
2000 SCRIPT_CACHE
*sc
= (SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
;
2001 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2002 int numGlyphs
= 1.5 * cChar
+ 16;
2003 WORD
*glyphs
= heap_alloc_zero(sizeof(WORD
) * numGlyphs
);
2004 WORD
*pwLogClust
= heap_alloc_zero(sizeof(WORD
) * cChar
);
2005 int *piAdvance
= heap_alloc_zero(sizeof(int) * numGlyphs
);
2006 SCRIPT_VISATTR
*psva
= heap_alloc_zero(sizeof(SCRIPT_VISATTR
) * numGlyphs
);
2007 GOFFSET
*pGoffset
= heap_alloc_zero(sizeof(GOFFSET
) * numGlyphs
);
2008 ABC
*abc
= heap_alloc_zero(sizeof(ABC
));
2009 int numGlyphsReturned
;
2010 HFONT originalFont
= 0x0;
2012 /* FIXME: non unicode strings */
2013 const WCHAR
* pStr
= (const WCHAR
*)pString
;
2014 analysis
->glyphs
[i
].fallbackFont
= NULL
;
2016 if (!glyphs
|| !pwLogClust
|| !piAdvance
|| !psva
|| !pGoffset
|| !abc
)
2018 heap_free (BidiLevel
);
2020 heap_free (pwLogClust
);
2021 heap_free (piAdvance
);
2023 heap_free (pGoffset
);
2029 if ((dwFlags
& SSA_FALLBACK
) && requires_fallback(hdc
, sc
, &analysis
->pItem
[i
].a
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
))
2032 GetObjectW(GetCurrentObject(hdc
, OBJ_FONT
), sizeof(lf
), & lf
);
2033 lf
.lfCharSet
= scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.bCharSet
;
2034 lf
.lfFaceName
[0] = 0;
2035 find_fallback_font(analysis
->pItem
[i
].a
.eScript
, lf
.lfFaceName
);
2036 if (lf
.lfFaceName
[0])
2038 analysis
->glyphs
[i
].fallbackFont
= CreateFontIndirectW(&lf
);
2039 if (analysis
->glyphs
[i
].fallbackFont
)
2041 ScriptFreeCache(sc
);
2042 originalFont
= SelectObject(hdc
, analysis
->glyphs
[i
].fallbackFont
);
2047 /* FIXME: When we properly shape Hangul remove this check */
2048 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& analysis
->pItem
[i
].a
.eScript
== Script_Hangul
)
2049 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2051 if ((dwFlags
& SSA_LINK
) && !analysis
->glyphs
[i
].fallbackFont
&& !scriptInformation
[analysis
->pItem
[i
].a
.eScript
].props
.fComplex
&& !analysis
->pItem
[i
].a
.fRTL
)
2052 analysis
->pItem
[i
].a
.fNoGlyphIndex
= TRUE
;
2054 ScriptShape(hdc
, sc
, &pStr
[analysis
->pItem
[i
].iCharPos
], cChar
, numGlyphs
,
2055 &analysis
->pItem
[i
].a
, glyphs
, pwLogClust
, psva
, &numGlyphsReturned
);
2056 hr
= ScriptPlace(hdc
, sc
, glyphs
, numGlyphsReturned
, psva
, &analysis
->pItem
[i
].a
,
2057 piAdvance
, pGoffset
, abc
);
2059 SelectObject(hdc
,originalFont
);
2061 if (dwFlags
& SSA_TAB
)
2064 for (tabi
= 0; tabi
< cChar
; tabi
++)
2066 if (pStr
[analysis
->pItem
[i
].iCharPos
+tabi
] == 0x0009)
2067 piAdvance
[tabi
] = getGivenTabWidth(analysis
->glyphs
[i
].sc
, pTabdef
, analysis
->pItem
[i
].iCharPos
+tabi
, tab_x
);
2068 tab_x
+=piAdvance
[tabi
];
2072 analysis
->glyphs
[i
].numGlyphs
= numGlyphsReturned
;
2073 analysis
->glyphs
[i
].glyphs
= glyphs
;
2074 analysis
->glyphs
[i
].pwLogClust
= pwLogClust
;
2075 analysis
->glyphs
[i
].piAdvance
= piAdvance
;
2076 analysis
->glyphs
[i
].psva
= psva
;
2077 analysis
->glyphs
[i
].pGoffset
= pGoffset
;
2078 analysis
->glyphs
[i
].abc
= abc
;
2079 analysis
->glyphs
[i
].iMaxPosX
= -1;
2081 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2086 for (i
= 0; i
< analysis
->numItems
; i
++)
2087 BidiLevel
[i
] = analysis
->pItem
[i
].a
.s
.uBidiLevel
;
2090 ScriptLayout(analysis
->numItems
, BidiLevel
, NULL
, analysis
->logical2visual
);
2091 heap_free(BidiLevel
);
2099 heap_free(analysis
->glyphs
);
2100 heap_free(analysis
->logattrs
);
2101 heap_free(analysis
->pItem
);
2102 heap_free(analysis
->logical2visual
);
2103 heap_free(analysis
);
2107 static inline BOOL
does_glyph_start_cluster(const SCRIPT_VISATTR
*pva
, const WORD
*pwLogClust
, int cChars
, int glyph
, int direction
)
2109 if (pva
[glyph
].fClusterStart
)
2111 if (USP10_FindGlyphInLogClust(pwLogClust
, cChars
, glyph
) >= 0)
2118 static HRESULT
SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa
,
2129 StringAnalysis
*analysis
;
2132 COLORREF BkColor
= 0x0;
2133 COLORREF TextColor
= 0x0;
2135 INT runStart
, runEnd
;
2136 INT iGlyph
, cGlyphs
;
2137 HFONT oldFont
= 0x0;
2141 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2142 ssa
, iX
, iY
, iItem
, cStart
, cEnd
, uOptions
, fSelected
, fDisabled
);
2144 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2146 if ((cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
<= cStart
) ||
2147 (cEnd
>= 0 && analysis
->pItem
[iItem
].iCharPos
>= cEnd
))
2153 BkMode
= GetBkMode(analysis
->hdc
);
2154 SetBkMode( analysis
->hdc
, OPAQUE
);
2155 BkColor
= GetBkColor(analysis
->hdc
);
2156 SetBkColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHT
));
2159 TextColor
= GetTextColor(analysis
->hdc
);
2160 SetTextColor(analysis
->hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
2163 if (analysis
->glyphs
[iItem
].fallbackFont
)
2164 oldFont
= SelectObject(analysis
->hdc
, analysis
->glyphs
[iItem
].fallbackFont
);
2166 if (cStart
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cStart
&& analysis
->pItem
[iItem
].iCharPos
<= cStart
)
2167 runStart
= cStart
- analysis
->pItem
[iItem
].iCharPos
;
2170 if (cEnd
>= 0 && analysis
->pItem
[iItem
+1].iCharPos
> cEnd
&& analysis
->pItem
[iItem
].iCharPos
<= cEnd
)
2171 runEnd
= (cEnd
-1) - analysis
->pItem
[iItem
].iCharPos
;
2173 runEnd
= (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
) - 1;
2175 if (analysis
->pItem
[iItem
].a
.fRTL
)
2177 if (cEnd
>= 0 && cEnd
< analysis
->pItem
[iItem
+1].iCharPos
)
2178 ScriptStringCPtoX(ssa
, cEnd
, FALSE
, &off_x
);
2180 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
+1].iCharPos
-1, TRUE
, &off_x
);
2181 crc
.left
= iX
+ off_x
;
2185 if (cStart
>=0 && runStart
)
2186 ScriptStringCPtoX(ssa
, cStart
, FALSE
, &off_x
);
2188 ScriptStringCPtoX(ssa
, analysis
->pItem
[iItem
].iCharPos
, FALSE
, &off_x
);
2189 crc
.left
= iX
+ off_x
;
2192 if (analysis
->pItem
[iItem
].a
.fRTL
)
2193 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
];
2195 iGlyph
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
];
2197 if (analysis
->pItem
[iItem
].a
.fRTL
)
2198 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runStart
] - iGlyph
;
2200 cGlyphs
= analysis
->glyphs
[iItem
].pwLogClust
[runEnd
] - iGlyph
;
2204 /* adjust for cluster glyphs when starting */
2205 if (analysis
->pItem
[iItem
].a
.fRTL
)
2206 i
= analysis
->pItem
[iItem
+1].iCharPos
- 1;
2208 i
= analysis
->pItem
[iItem
].iCharPos
;
2210 for (; i
>=analysis
->pItem
[iItem
].iCharPos
&& i
< analysis
->pItem
[iItem
+1].iCharPos
; (analysis
->pItem
[iItem
].a
.fRTL
)?i
--:i
++)
2212 if (analysis
->glyphs
[iItem
].pwLogClust
[i
- analysis
->pItem
[iItem
].iCharPos
] == iGlyph
)
2214 if (analysis
->pItem
[iItem
].a
.fRTL
)
2215 ScriptStringCPtoX(ssa
, i
, TRUE
, &off_x
);
2217 ScriptStringCPtoX(ssa
, i
, FALSE
, &off_x
);
2222 if (cEnd
< 0 || scriptInformation
[analysis
->pItem
[iItem
].a
.eScript
].props
.fNeedsCaretInfo
)
2227 clust_glyph
= iGlyph
+ cGlyphs
;
2228 if (analysis
->pItem
[iItem
].a
.fRTL
)
2233 while(clust_glyph
< analysis
->glyphs
[iItem
].numGlyphs
&&
2234 !does_glyph_start_cluster(analysis
->glyphs
[iItem
].psva
, analysis
->glyphs
[iItem
].pwLogClust
, (analysis
->pItem
[iItem
+1].iCharPos
- analysis
->pItem
[iItem
].iCharPos
), clust_glyph
, direction
))
2241 hr
= ScriptTextOut(analysis
->hdc
,
2242 (SCRIPT_CACHE
*)&analysis
->glyphs
[iItem
].sc
, iX
+ off_x
,
2243 iY
, uOptions
, &crc
, &analysis
->pItem
[iItem
].a
, NULL
, 0,
2244 &analysis
->glyphs
[iItem
].glyphs
[iGlyph
], cGlyphs
,
2245 &analysis
->glyphs
[iItem
].piAdvance
[iGlyph
], NULL
,
2246 &analysis
->glyphs
[iItem
].pGoffset
[iGlyph
]);
2248 TRACE("ScriptTextOut hr=%08x\n", hr
);
2252 SetBkColor(analysis
->hdc
, BkColor
);
2253 SetBkMode( analysis
->hdc
, BkMode
);
2255 SetTextColor(analysis
->hdc
, TextColor
);
2257 if (analysis
->glyphs
[iItem
].fallbackFont
)
2258 SelectObject(analysis
->hdc
, oldFont
);
2263 /***********************************************************************
2264 * ScriptStringOut (USP10.@)
2266 * This function takes the output of ScriptStringAnalyse and joins the segments
2267 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2268 * only processes glyphs.
2271 * ssa [I] buffer to hold the analysed string components
2272 * iX [I] X axis displacement for output
2273 * iY [I] Y axis displacement for output
2274 * uOptions [I] flags controlling output processing
2275 * prc [I] rectangle coordinates
2276 * iMinSel [I] starting pos for substringing output string
2277 * iMaxSel [I] ending pos for substringing output string
2278 * fDisabled [I] controls text highlighting
2282 * Failure: is the value returned by ScriptTextOut
2284 HRESULT WINAPI
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa
,
2293 StringAnalysis
*analysis
;
2297 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2298 ssa
, iX
, iY
, uOptions
, wine_dbgstr_rect(prc
), iMinSel
, iMaxSel
, fDisabled
);
2300 if (!(analysis
= ssa
)) return E_INVALIDARG
;
2301 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return E_INVALIDARG
;
2303 for (item
= 0; item
< analysis
->numItems
; item
++)
2305 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], -1, -1, uOptions
, prc
, FALSE
, fDisabled
);
2310 if (iMinSel
< iMaxSel
&& (iMinSel
> 0 || iMaxSel
> 0))
2312 if (iMaxSel
> 0 && iMinSel
< 0)
2314 for (item
= 0; item
< analysis
->numItems
; item
++)
2316 hr
= SS_ItemOut( ssa
, iX
, iY
, analysis
->logical2visual
[item
], iMinSel
, iMaxSel
, uOptions
, prc
, TRUE
, fDisabled
);
2325 /***********************************************************************
2326 * ScriptStringCPtoX (USP10.@)
2329 HRESULT WINAPI
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa
, int icp
, BOOL fTrailing
, int* pX
)
2333 StringAnalysis
* analysis
= ssa
;
2335 TRACE("(%p), %d, %d, (%p)\n", ssa
, icp
, fTrailing
, pX
);
2337 if (!ssa
|| !pX
) return S_FALSE
;
2338 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2340 /* icp out of range */
2343 analysis
->invalid
= TRUE
;
2344 return E_INVALIDARG
;
2347 for(item
=0; item
<analysis
->numItems
; item
++)
2352 i
= analysis
->logical2visual
[item
];
2353 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2354 /* initialize max extents for uninitialized runs */
2355 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2357 if (analysis
->pItem
[i
].a
.fRTL
)
2358 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2359 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2360 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2362 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2363 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2364 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2367 if (icp
>= analysis
->pItem
[i
+1].iCharPos
|| icp
< analysis
->pItem
[i
].iCharPos
)
2369 runningX
+= analysis
->glyphs
[i
].iMaxPosX
;
2373 icp
-= analysis
->pItem
[i
].iCharPos
;
2374 ScriptCPtoX(icp
, fTrailing
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2375 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2376 &analysis
->pItem
[i
].a
, &offset
);
2383 /* icp out of range */
2384 analysis
->invalid
= TRUE
;
2385 return E_INVALIDARG
;
2388 /***********************************************************************
2389 * ScriptStringXtoCP (USP10.@)
2392 HRESULT WINAPI
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa
, int iX
, int* piCh
, int* piTrailing
)
2394 StringAnalysis
* analysis
= ssa
;
2397 TRACE("(%p), %d, (%p), (%p)\n", ssa
, iX
, piCh
, piTrailing
);
2399 if (!ssa
|| !piCh
|| !piTrailing
) return S_FALSE
;
2400 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
2405 if (analysis
->pItem
[0].a
.fRTL
)
2408 *piTrailing
= FALSE
;
2418 for(item
=0; item
<analysis
->numItems
; item
++)
2423 for (i
= 0; i
< analysis
->numItems
&& analysis
->logical2visual
[i
] != item
; i
++)
2426 CP
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
2427 /* initialize max extents for uninitialized runs */
2428 if (analysis
->glyphs
[i
].iMaxPosX
== -1)
2430 if (analysis
->pItem
[i
].a
.fRTL
)
2431 ScriptCPtoX(0, FALSE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2432 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2433 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2435 ScriptCPtoX(CP
, TRUE
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2436 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2437 &analysis
->pItem
[i
].a
, &analysis
->glyphs
[i
].iMaxPosX
);
2440 if (iX
> analysis
->glyphs
[i
].iMaxPosX
)
2442 iX
-= analysis
->glyphs
[i
].iMaxPosX
;
2446 ScriptXtoCP(iX
, CP
, analysis
->glyphs
[i
].numGlyphs
, analysis
->glyphs
[i
].pwLogClust
,
2447 analysis
->glyphs
[i
].psva
, analysis
->glyphs
[i
].piAdvance
,
2448 &analysis
->pItem
[i
].a
, piCh
, piTrailing
);
2449 *piCh
+= analysis
->pItem
[i
].iCharPos
;
2455 *piCh
= analysis
->pItem
[analysis
->numItems
].iCharPos
;
2456 *piTrailing
= FALSE
;
2462 /***********************************************************************
2463 * ScriptStringFree (USP10.@)
2465 * Free a string analysis.
2468 * pssa [I] string analysis.
2472 * Failure: Non-zero HRESULT value.
2474 HRESULT WINAPI
ScriptStringFree(SCRIPT_STRING_ANALYSIS
*pssa
)
2476 StringAnalysis
* analysis
;
2480 TRACE("(%p)\n", pssa
);
2482 if (!pssa
|| !(analysis
= *pssa
)) return E_INVALIDARG
;
2484 invalid
= analysis
->invalid
;
2486 if (analysis
->glyphs
)
2488 for (i
= 0; i
< analysis
->numItems
; i
++)
2490 heap_free(analysis
->glyphs
[i
].glyphs
);
2491 heap_free(analysis
->glyphs
[i
].pwLogClust
);
2492 heap_free(analysis
->glyphs
[i
].piAdvance
);
2493 heap_free(analysis
->glyphs
[i
].psva
);
2494 heap_free(analysis
->glyphs
[i
].pGoffset
);
2495 heap_free(analysis
->glyphs
[i
].abc
);
2496 if (analysis
->glyphs
[i
].fallbackFont
)
2497 DeleteObject(analysis
->glyphs
[i
].fallbackFont
);
2498 ScriptFreeCache((SCRIPT_CACHE
*)&analysis
->glyphs
[i
].sc
);
2499 heap_free(analysis
->glyphs
[i
].sc
);
2501 heap_free(analysis
->glyphs
);
2504 heap_free(analysis
->pItem
);
2505 heap_free(analysis
->logattrs
);
2506 heap_free(analysis
->sz
);
2507 heap_free(analysis
->logical2visual
);
2508 heap_free(analysis
);
2510 if (invalid
) return E_INVALIDARG
;
2514 static inline int get_cluster_size(const WORD
*pwLogClust
, int cChars
, int item
,
2515 int direction
, int* iCluster
, int *check_out
)
2519 WORD clust
= pwLogClust
[item
];
2521 for (check
= item
+direction
; check
< cChars
&& check
>= 0; check
+=direction
)
2523 if (pwLogClust
[check
] == clust
)
2526 if (iCluster
&& *iCluster
== -1)
2538 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
)
2543 advance
= piAdvance
[glyph
];
2545 if (pwLogClust
[0] > pwLogClust
[cChars
-1])
2546 log_clust_max
= pwLogClust
[0];
2548 log_clust_max
= pwLogClust
[cChars
-1];
2550 if (glyph
> log_clust_max
)
2553 for (glyph
+=direction
; glyph
< cGlyphs
&& glyph
>= 0; glyph
+=direction
)
2556 if (does_glyph_start_cluster(pva
, pwLogClust
, cChars
, glyph
, direction
))
2558 if (glyph
> log_clust_max
)
2560 advance
+= piAdvance
[glyph
];
2566 /***********************************************************************
2567 * ScriptCPtoX (USP10.@)
2570 HRESULT WINAPI
ScriptCPtoX(int iCP
,
2574 const WORD
*pwLogClust
,
2575 const SCRIPT_VISATTR
*psva
,
2576 const int *piAdvance
,
2577 const SCRIPT_ANALYSIS
*psa
,
2585 float special_size
= 0.0;
2590 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2591 iCP
, fTrailing
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2594 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2602 int max_clust
= pwLogClust
[0];
2604 for (item
=0; item
< cGlyphs
; item
++)
2605 if (pwLogClust
[item
] > max_clust
)
2607 ERR("We do not handle non reversed clusters properly\n");
2612 for (item
= max_clust
; item
>=0; item
--)
2613 iMaxPos
+= piAdvance
[item
];
2617 for (item
=0; item
< iCP
&& item
< cChars
; item
++)
2619 if (iSpecial
== -1 && (iCluster
== -1 || (iCluster
!= -1 && iCluster
+clust_size
<= item
)))
2622 int clust
= pwLogClust
[item
];
2625 clust_size
= get_cluster_size(pwLogClust
, cChars
, item
, 1, &iCluster
,
2628 advance
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, clust
, 1);
2630 if (check
>= cChars
&& !iMaxPos
)
2633 for (glyph
= clust
; glyph
< cGlyphs
; glyph
++)
2634 special_size
+= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, glyph
, 1);
2636 special_size
/= (cChars
- item
);
2637 iPosX
+= special_size
;
2641 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2644 if (clust_size
== 0)
2648 iPosX
+= advance
/ (float)clust_size
;
2651 else if (iSpecial
!= -1)
2652 iPosX
+= special_size
;
2653 else /* (iCluster != -1) */
2655 int adv
= get_glyph_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, pwLogClust
[iCluster
], 1);
2656 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2659 if (clust_size
== 0)
2663 iPosX
+= adv
/ (float)clust_size
;
2669 iPosX
= iMaxPos
- iPosX
;
2675 TRACE("*piX=%d\n", *piX
);
2679 /* Count the number of characters in a cluster and its starting index*/
2680 static inline BOOL
get_cluster_data(const WORD
*pwLogClust
, int cChars
, int cluster_index
, int *cluster_size
, int *start_index
)
2685 for (i
= 0; i
< cChars
; i
++)
2687 if (pwLogClust
[i
] == cluster_index
)
2689 if (!size
&& start_index
)
2697 else if (size
) break;
2700 *cluster_size
= size
;
2706 To handle multi-glyph clusters we need to find all the glyphs that are
2707 represented in the cluster. This involves finding the glyph whose
2708 index is the cluster index as well as whose glyph indices are greater than
2709 our cluster index but not part of a new cluster.
2711 Then we sum all those glyphs' advances.
2713 static inline int get_cluster_advance(const int* piAdvance
,
2714 const SCRIPT_VISATTR
*psva
,
2715 const WORD
*pwLogClust
, int cGlyphs
,
2716 int cChars
, int cluster
, int direction
)
2727 for (glyph_start
= -1, glyph_end
= -1; i
< cChars
&& i
>= 0 && (glyph_start
< 0 || glyph_end
< 0); i
+=direction
)
2729 if (glyph_start
< 0 && pwLogClust
[i
] != cluster
) continue;
2730 if (pwLogClust
[i
] == cluster
&& glyph_start
< 0) glyph_start
= pwLogClust
[i
];
2731 if (glyph_start
>= 0 && glyph_end
< 0 && pwLogClust
[i
] != cluster
) glyph_end
= pwLogClust
[i
];
2736 glyph_end
= cGlyphs
;
2739 /* Don't fully understand multi-glyph reversed clusters yet,
2740 * do they occur for real or just in our test? */
2741 FIXME("multi-glyph reversed clusters found\n");
2742 glyph_end
= glyph_start
+ 1;
2746 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2747 for (i
= glyph_start
+1; i
< glyph_end
; i
++)
2749 if (psva
[i
].fClusterStart
)
2756 for (advance
= 0, i
= glyph_start
; i
< glyph_end
; i
++)
2757 advance
+= piAdvance
[i
];
2763 /***********************************************************************
2764 * ScriptXtoCP (USP10.@)
2767 * Use piAdvance to find the cluster we are looking at.
2768 * Find the character that is the first character of the cluster.
2769 * That is our base piCP.
2770 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2771 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2772 * determine how far through the cluster to advance the cursor.
2774 HRESULT WINAPI
ScriptXtoCP(int iX
,
2777 const WORD
*pwLogClust
,
2778 const SCRIPT_VISATTR
*psva
,
2779 const int *piAdvance
,
2780 const SCRIPT_ANALYSIS
*psa
,
2787 int glyph_index
, cluster_index
;
2790 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2791 iX
, cChars
, cGlyphs
, pwLogClust
, psva
, piAdvance
,
2792 psa
, piCP
, piTrailing
);
2794 if (psa
->fRTL
&& ! psa
->fLogicalOrder
)
2797 /* Handle an iX < 0 */
2813 /* Looking for non-reversed clusters in a reversed string */
2816 int max_clust
= pwLogClust
[0];
2817 for (i
=0; i
< cChars
; i
++)
2818 if (pwLogClust
[i
] > max_clust
)
2820 FIXME("We do not handle non reversed clusters properly\n");
2825 /* find the glyph_index based in iX */
2828 for (glyph_index
= -1, iPosX
= iX
; iPosX
>=0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2833 for (glyph_index
= -1, iPosX
= iX
; iPosX
> 0 && glyph_index
< cGlyphs
; iPosX
-= piAdvance
[glyph_index
+1], glyph_index
++)
2837 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX
, glyph_index
, cGlyphs
);
2840 if (glyph_index
>= 0 && glyph_index
< cGlyphs
)
2842 /* find the cluster */
2844 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] <= glyph_index
; cluster_index
=pwLogClust
[i
++])
2847 for (i
= 0, cluster_index
= pwLogClust
[0]; i
< cChars
&& pwLogClust
[i
] >= glyph_index
; cluster_index
=pwLogClust
[i
++])
2850 TRACE("cluster_index %i\n", cluster_index
);
2852 if (direction
< 0 && iPosX
>= 0 && glyph_index
!= cluster_index
)
2854 /* We are off the end of the string */
2860 get_cluster_data(pwLogClust
, cChars
, cluster_index
, &cluster_size
, &i
);
2862 TRACE("first char index %i\n",i
);
2863 if (scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
)
2865 /* Check trailing */
2866 if (glyph_index
!= cluster_index
||
2867 (direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2868 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2869 *piTrailing
= cluster_size
;
2873 if (cluster_size
> 1)
2875 /* Be part way through the glyph cluster based on size and position */
2876 int cluster_advance
= get_cluster_advance(piAdvance
, psva
, pwLogClust
, cGlyphs
, cChars
, cluster_index
, direction
);
2877 double cluster_part_width
= cluster_advance
/ (float)cluster_size
;
2881 /* back up to the beginning of the cluster */
2882 for (adv
= iPosX
, part_index
= cluster_index
; part_index
<= glyph_index
; part_index
++)
2883 adv
+= piAdvance
[part_index
];
2884 if (adv
> iX
) adv
= iX
;
2886 TRACE("Multi-char cluster, no snap\n");
2887 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size
, adv
);
2888 TRACE("advance %i divides into %f per char\n", cluster_advance
, cluster_part_width
);
2891 for (part_index
= 0; adv
>= 0; adv
-=cluster_part_width
, part_index
++)
2893 if (part_index
) part_index
--;
2897 for (part_index
= 0; adv
> 0; adv
-=cluster_part_width
, part_index
++)
2899 if (part_index
> cluster_size
)
2901 adv
+= cluster_part_width
;
2902 part_index
=cluster_size
;
2906 TRACE("base_char %i part_index %i, leftover advance %f\n",i
, part_index
, adv
);
2911 i
+= (cluster_size
- part_index
);
2913 /* Check trailing */
2914 if ((direction
> 0 && fabs(adv
) <= (cluster_part_width
/ 2.0)) ||
2915 (direction
< 0 && adv
&& fabs(adv
) >= (cluster_part_width
/ 2.0)))
2920 /* Check trailing */
2921 if ((direction
> 0 && abs(iPosX
) <= (piAdvance
[glyph_index
] / 2)) ||
2922 (direction
< 0 && abs(iPosX
) >= (piAdvance
[glyph_index
] / 2)))
2929 TRACE("Point falls outside of string\n");
2930 if (glyph_index
< 0)
2932 else /* (glyph_index >= cGlyphs) */
2935 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2936 point flow to the next character */
2939 if (!scriptInformation
[psa
->eScript
].props
.fNeedsCaretInfo
&& abs(iPosX
) == piAdvance
[glyph_index
])
2948 TRACE("*piCP=%d\n", *piCP
);
2949 TRACE("*piTrailing=%d\n", *piTrailing
);
2953 /***********************************************************************
2954 * ScriptBreak (USP10.@)
2956 * Retrieve line break information.
2959 * chars [I] Array of characters.
2960 * sa [I] Script analysis.
2961 * la [I] Array of logical attribute structures.
2967 HRESULT WINAPI
ScriptBreak(const WCHAR
*chars
, int count
, const SCRIPT_ANALYSIS
*sa
, SCRIPT_LOGATTR
*la
)
2969 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars
, count
), count
, sa
, la
);
2971 if (count
< 0 || !la
) return E_INVALIDARG
;
2972 if (count
== 0) return E_FAIL
;
2974 BREAK_line(chars
, count
, sa
, la
);
2979 /***********************************************************************
2980 * ScriptIsComplex (USP10.@)
2982 * Determine if a string is complex.
2985 * chars [I] Array of characters to test.
2986 * len [I] Length in characters.
2994 HRESULT WINAPI
ScriptIsComplex(const WCHAR
*chars
, int len
, DWORD flag
)
2999 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars
, len
), len
, flag
);
3001 for (i
= 0; i
< len
; i
+=consumed
)
3007 if ((flag
& SIC_ASCIIDIGIT
) && chars
[i
] >= 0x30 && chars
[i
] <= 0x39)
3010 script
= get_char_script(chars
,i
,len
, &consumed
);
3011 if ((scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_COMPLEX
))||
3012 (!scriptInformation
[script
].props
.fComplex
&& (flag
& SIC_NEUTRAL
)))
3018 /***********************************************************************
3019 * ScriptShapeOpenType (USP10.@)
3021 * Produce glyphs and visual attributes for a run.
3024 * hdc [I] Device context.
3025 * psc [I/O] Opaque pointer to a script cache.
3026 * psa [I/O] Script analysis.
3027 * tagScript [I] The OpenType tag for the Script
3028 * tagLangSys [I] The OpenType tag for the Language
3029 * rcRangeChars[I] Array of Character counts in each range
3030 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3031 * cRanges [I] Count of ranges
3032 * pwcChars [I] Array of characters specifying the run.
3033 * cChars [I] Number of characters in pwcChars.
3034 * cMaxGlyphs [I] Length of pwOutGlyphs.
3035 * pwLogClust [O] Array of logical cluster info.
3036 * pCharProps [O] Array of character property values
3037 * pwOutGlyphs [O] Array of glyphs.
3038 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3039 * pcGlyphs [O] Number of glyphs returned.
3043 * Failure: Non-zero HRESULT value.
3045 HRESULT WINAPI
ScriptShapeOpenType( HDC hdc
, SCRIPT_CACHE
*psc
,
3046 SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
,
3047 OPENTYPE_TAG tagLangSys
, int *rcRangeChars
,
3048 TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3049 int cRanges
, const WCHAR
*pwcChars
, int cChars
,
3050 int cMaxGlyphs
, WORD
*pwLogClust
,
3051 SCRIPT_CHARPROP
*pCharProps
, WORD
*pwOutGlyphs
,
3052 SCRIPT_GLYPHPROP
*pOutGlyphProps
, int *pcGlyphs
)
3059 static int once
= 0;
3061 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3063 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3064 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3065 cChars
, cMaxGlyphs
, pwLogClust
, pCharProps
, pwOutGlyphs
, pOutGlyphProps
, pcGlyphs
);
3067 if (psa
) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa
->eScript
, psa
->fRTL
, psa
->fLayoutRTL
,
3068 psa
->fLinkBefore
, psa
->fLinkAfter
, psa
->fLogicalOrder
, psa
->fNoGlyphIndex
);
3070 if (!pOutGlyphProps
|| !pcGlyphs
|| !pCharProps
) return E_INVALIDARG
;
3071 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3074 if(!once
++) FIXME("Ranges not supported yet\n");
3076 rtl
= (psa
&& !psa
->fLogicalOrder
&& psa
->fRTL
);
3079 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3080 if (!pwLogClust
) return E_FAIL
;
3082 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3083 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3085 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3086 for (i
= 0; i
< cChars
; i
++)
3089 if (rtl
) idx
= cChars
- 1 - i
;
3090 /* FIXME: set to better values */
3091 pOutGlyphProps
[i
].sva
.uJustification
= (pwcChars
[idx
] == ' ') ? SCRIPT_JUSTIFY_BLANK
: SCRIPT_JUSTIFY_CHARACTER
;
3092 pOutGlyphProps
[i
].sva
.fClusterStart
= 1;
3093 pOutGlyphProps
[i
].sva
.fDiacritic
= 0;
3094 pOutGlyphProps
[i
].sva
.fZeroWidth
= 0;
3095 pOutGlyphProps
[i
].sva
.fReserved
= 0;
3096 pOutGlyphProps
[i
].sva
.fShapeReserved
= 0;
3098 /* FIXME: have the shaping engine set this */
3099 pCharProps
[i
].fCanGlyphAlone
= 0;
3101 pwLogClust
[i
] = idx
;
3104 if (psa
&& !psa
->fNoGlyphIndex
&& ((ScriptCache
*)*psc
)->sfnt
)
3107 if ((hr
= SHAPE_CheckFontForRequiredFeatures(hdc
, (ScriptCache
*)*psc
, psa
)) != S_OK
) return hr
;
3109 rChars
= heap_alloc(sizeof(WCHAR
) * cChars
);
3110 if (!rChars
) return E_OUTOFMEMORY
;
3111 for (i
= 0, g
= 0, cluster
= 0; i
< cChars
; i
++)
3116 if (rtl
) idx
= cChars
- 1 - i
;
3119 chInput
= decode_surrogate_pair(pwcChars
, idx
, cChars
);
3123 chInput
= mirror_char(pwcChars
[idx
]);
3125 chInput
= pwcChars
[idx
];
3126 rChars
[i
] = chInput
;
3130 rChars
[i
] = pwcChars
[idx
];
3131 rChars
[i
+1] = pwcChars
[(rtl
)?idx
-1:idx
+1];
3134 if (!(pwOutGlyphs
[g
] = get_cache_glyph(psc
, chInput
)))
3142 if (OpenType_CMAP_GetGlyphIndex(hdc
, (ScriptCache
*)*psc
, chInput
, &glyph
, 0) == GDI_ERROR
)
3147 pwOutGlyphs
[g
] = set_cache_glyph(psc
, chInput
, glyph
);
3155 pwLogClust
[idx
] = (rtl
)?pwLogClust
[idx
+1]:pwLogClust
[idx
-1];
3156 for (k
= (rtl
)?idx
-1:idx
+1; k
>= 0 && k
< cChars
; (rtl
)?k
--:k
++)
3162 SHAPE_ContextualShaping(hdc
, (ScriptCache
*)*psc
, psa
, rChars
, cChars
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, pwLogClust
);
3163 SHAPE_ApplyDefaultOpentypeFeatures(hdc
, (ScriptCache
*)*psc
, psa
, pwOutGlyphs
, pcGlyphs
, cMaxGlyphs
, cChars
, pwLogClust
);
3164 SHAPE_CharGlyphProp(hdc
, (ScriptCache
*)*psc
, psa
, pwcChars
, cChars
, pwOutGlyphs
, *pcGlyphs
, pwLogClust
, pCharProps
, pOutGlyphProps
);
3166 for (i
= 0; i
< cChars
; ++i
)
3168 /* Special case for tabs and joiners. As control characters, ZWNJ
3169 * and ZWJ would in principle get handled by the corresponding
3170 * shaping functions. However, since ZWNJ and ZWJ can get merged
3171 * into adjoining runs during itemisation, these don't generally
3172 * get classified as Script_Control. */
3173 if (pwcChars
[i
] == 0x0009 || pwcChars
[i
] == ZWSP
|| pwcChars
[i
] == ZWNJ
|| pwcChars
[i
] == ZWJ
)
3175 pwOutGlyphs
[pwLogClust
[i
]] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3176 pOutGlyphProps
[pwLogClust
[i
]].sva
.fZeroWidth
= 1;
3183 TRACE("no glyph translation\n");
3184 for (i
= 0; i
< cChars
; i
++)
3187 /* No mirroring done here */
3188 if (rtl
) idx
= cChars
- 1 - i
;
3189 pwOutGlyphs
[i
] = pwcChars
[idx
];
3194 /* overwrite some basic control glyphs to blank */
3195 if (psa
->fNoGlyphIndex
)
3197 if (pwcChars
[idx
] == ZWSP
|| pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3199 pwOutGlyphs
[i
] = 0x20;
3200 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3203 else if (psa
->eScript
== Script_Control
|| pwcChars
[idx
] == ZWSP
3204 || pwcChars
[idx
] == ZWNJ
|| pwcChars
[idx
] == ZWJ
)
3206 if (pwcChars
[idx
] == 0x0009 || pwcChars
[idx
] == 0x000A ||
3207 pwcChars
[idx
] == 0x000D || pwcChars
[idx
] >= 0x001C)
3209 pwOutGlyphs
[i
] = ((ScriptCache
*)*psc
)->sfp
.wgBlank
;
3210 pOutGlyphProps
[i
].sva
.fZeroWidth
= 1;
3220 /***********************************************************************
3221 * ScriptShape (USP10.@)
3223 * Produce glyphs and visual attributes for a run.
3226 * hdc [I] Device context.
3227 * psc [I/O] Opaque pointer to a script cache.
3228 * pwcChars [I] Array of characters specifying the run.
3229 * cChars [I] Number of characters in pwcChars.
3230 * cMaxGlyphs [I] Length of pwOutGlyphs.
3231 * psa [I/O] Script analysis.
3232 * pwOutGlyphs [O] Array of glyphs.
3233 * pwLogClust [O] Array of logical cluster info.
3234 * psva [O] Array of visual attributes.
3235 * pcGlyphs [O] Number of glyphs returned.
3239 * Failure: Non-zero HRESULT value.
3241 HRESULT WINAPI
ScriptShape(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcChars
,
3242 int cChars
, int cMaxGlyphs
,
3243 SCRIPT_ANALYSIS
*psa
, WORD
*pwOutGlyphs
, WORD
*pwLogClust
,
3244 SCRIPT_VISATTR
*psva
, int *pcGlyphs
)
3248 SCRIPT_CHARPROP
*charProps
;
3249 SCRIPT_GLYPHPROP
*glyphProps
;
3251 if (!psva
|| !pcGlyphs
) return E_INVALIDARG
;
3252 if (cChars
> cMaxGlyphs
) return E_OUTOFMEMORY
;
3254 charProps
= heap_alloc_zero(sizeof(SCRIPT_CHARPROP
)*cChars
);
3255 if (!charProps
) return E_OUTOFMEMORY
;
3256 glyphProps
= heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP
)*cMaxGlyphs
);
3259 heap_free(charProps
);
3260 return E_OUTOFMEMORY
;
3263 hr
= ScriptShapeOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, pwcChars
, cChars
, cMaxGlyphs
, pwLogClust
, charProps
, pwOutGlyphs
, glyphProps
, pcGlyphs
);
3267 for (i
= 0; i
< *pcGlyphs
; i
++)
3268 psva
[i
] = glyphProps
[i
].sva
;
3271 heap_free(charProps
);
3272 heap_free(glyphProps
);
3277 /***********************************************************************
3278 * ScriptPlaceOpenType (USP10.@)
3280 * Produce advance widths for a run.
3283 * hdc [I] Device context.
3284 * psc [I/O] Opaque pointer to a script cache.
3285 * psa [I/O] Script analysis.
3286 * tagScript [I] The OpenType tag for the Script
3287 * tagLangSys [I] The OpenType tag for the Language
3288 * rcRangeChars[I] Array of Character counts in each range
3289 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3290 * cRanges [I] Count of ranges
3291 * pwcChars [I] Array of characters specifying the run.
3292 * pwLogClust [I] Array of logical cluster info
3293 * pCharProps [I] Array of character property values
3294 * cChars [I] Number of characters in pwcChars.
3295 * pwGlyphs [I] Array of glyphs.
3296 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3297 * cGlyphs [I] Count of Glyphs
3298 * piAdvance [O] Array of advance widths.
3299 * pGoffset [O] Glyph offsets.
3300 * pABC [O] Combined ABC width.
3304 * Failure: Non-zero HRESULT value.
3307 HRESULT WINAPI
ScriptPlaceOpenType( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
,
3308 OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
,
3309 int *rcRangeChars
, TEXTRANGE_PROPERTIES
**rpRangeProperties
,
3310 int cRanges
, const WCHAR
*pwcChars
, WORD
*pwLogClust
,
3311 SCRIPT_CHARPROP
*pCharProps
, int cChars
,
3312 const WORD
*pwGlyphs
, const SCRIPT_GLYPHPROP
*pGlyphProps
,
3313 int cGlyphs
, int *piAdvance
,
3314 GOFFSET
*pGoffset
, ABC
*pABC
3319 static int once
= 0;
3321 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3323 debugstr_an((char*)&tagScript
,4), debugstr_an((char*)&tagLangSys
,4),
3324 rcRangeChars
, rpRangeProperties
, cRanges
, debugstr_wn(pwcChars
, cChars
),
3325 pwLogClust
, pCharProps
, cChars
, pwGlyphs
, pGlyphProps
, cGlyphs
, piAdvance
,
3328 if (!pGlyphProps
) return E_INVALIDARG
;
3329 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3330 if (!pGoffset
) return E_FAIL
;
3333 if (!once
++) FIXME("Ranges not supported yet\n");
3335 ((ScriptCache
*)*psc
)->userScript
= tagScript
;
3336 ((ScriptCache
*)*psc
)->userLang
= tagLangSys
;
3338 if (pABC
) memset(pABC
, 0, sizeof(ABC
));
3339 for (i
= 0; i
< cGlyphs
; i
++)
3342 if (pGlyphProps
[i
].sva
.fZeroWidth
)
3344 abc
.abcA
= abc
.abcB
= abc
.abcC
= 0;
3346 else if (!get_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
))
3348 if (!hdc
) return E_PENDING
;
3349 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
) && !psa
->fNoGlyphIndex
)
3351 if (!GetCharABCWidthsI(hdc
, 0, 1, (WORD
*)&pwGlyphs
[i
], &abc
)) return S_FALSE
;
3356 if (!GetCharWidth32W(hdc
, pwGlyphs
[i
], pwGlyphs
[i
], &width
)) return S_FALSE
;
3358 abc
.abcA
= abc
.abcC
= 0;
3360 set_cache_glyph_widths(psc
, pwGlyphs
[i
], &abc
);
3364 pABC
->abcA
+= abc
.abcA
;
3365 pABC
->abcB
+= abc
.abcB
;
3366 pABC
->abcC
+= abc
.abcC
;
3368 /* FIXME: set to more reasonable values */
3369 pGoffset
[i
].du
= pGoffset
[i
].dv
= 0;
3370 if (piAdvance
) piAdvance
[i
] = abc
.abcA
+ abc
.abcB
+ abc
.abcC
;
3373 SHAPE_ApplyOpenTypePositions(hdc
, (ScriptCache
*)*psc
, psa
, pwGlyphs
, cGlyphs
, piAdvance
, pGoffset
);
3375 if (pABC
) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC
->abcA
, pABC
->abcB
, pABC
->abcC
);
3379 /***********************************************************************
3380 * ScriptPlace (USP10.@)
3382 * Produce advance widths for a run.
3385 * hdc [I] Device context.
3386 * psc [I/O] Opaque pointer to a script cache.
3387 * pwGlyphs [I] Array of glyphs.
3388 * cGlyphs [I] Number of glyphs in pwGlyphs.
3389 * psva [I] Array of visual attributes.
3390 * psa [I/O] String analysis.
3391 * piAdvance [O] Array of advance widths.
3392 * pGoffset [O] Glyph offsets.
3393 * pABC [O] Combined ABC width.
3397 * Failure: Non-zero HRESULT value.
3399 HRESULT WINAPI
ScriptPlace(HDC hdc
, SCRIPT_CACHE
*psc
, const WORD
*pwGlyphs
,
3400 int cGlyphs
, const SCRIPT_VISATTR
*psva
,
3401 SCRIPT_ANALYSIS
*psa
, int *piAdvance
, GOFFSET
*pGoffset
, ABC
*pABC
)
3404 SCRIPT_GLYPHPROP
*glyphProps
;
3407 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc
, psc
, pwGlyphs
, cGlyphs
, psva
, psa
,
3408 piAdvance
, pGoffset
, pABC
);
3410 if (!psva
) return E_INVALIDARG
;
3411 if (!pGoffset
) return E_FAIL
;
3413 glyphProps
= heap_alloc(sizeof(SCRIPT_GLYPHPROP
)*cGlyphs
);
3414 if (!glyphProps
) return E_OUTOFMEMORY
;
3416 for (i
= 0; i
< cGlyphs
; i
++)
3417 glyphProps
[i
].sva
= psva
[i
];
3419 hr
= ScriptPlaceOpenType(hdc
, psc
, psa
, scriptInformation
[psa
->eScript
].scriptTag
, 0, NULL
, NULL
, 0, NULL
, NULL
, NULL
, 0, pwGlyphs
, glyphProps
, cGlyphs
, piAdvance
, pGoffset
, pABC
);
3421 heap_free(glyphProps
);
3426 /***********************************************************************
3427 * ScriptGetCMap (USP10.@)
3429 * Retrieve glyph indices.
3432 * hdc [I] Device context.
3433 * psc [I/O] Opaque pointer to a script cache.
3434 * pwcInChars [I] Array of Unicode characters.
3435 * cChars [I] Number of characters in pwcInChars.
3436 * dwFlags [I] Flags.
3437 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3441 * Failure: Non-zero HRESULT value.
3443 HRESULT WINAPI
ScriptGetCMap(HDC hdc
, SCRIPT_CACHE
*psc
, const WCHAR
*pwcInChars
,
3444 int cChars
, DWORD dwFlags
, WORD
*pwOutGlyphs
)
3449 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc
, psc
, debugstr_wn(pwcInChars
, cChars
),
3450 cChars
, dwFlags
, pwOutGlyphs
);
3452 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3456 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3458 for (i
= 0; i
< cChars
; i
++)
3461 if (dwFlags
== SGCM_RTL
)
3462 inChar
= mirror_char(pwcInChars
[i
]);
3464 inChar
= pwcInChars
[i
];
3465 if (!(pwOutGlyphs
[i
] = get_cache_glyph(psc
, inChar
)))
3468 if (!hdc
) return E_PENDING
;
3469 if (GetGlyphIndicesW(hdc
, &inChar
, 1, &glyph
, GGI_MARK_NONEXISTING_GLYPHS
) == GDI_ERROR
) return S_FALSE
;
3470 if (glyph
== 0xffff)
3475 pwOutGlyphs
[i
] = set_cache_glyph(psc
, inChar
, glyph
);
3481 TRACE("no glyph translation\n");
3482 for (i
= 0; i
< cChars
; i
++)
3485 if (dwFlags
== SGCM_RTL
)
3486 inChar
= mirror_char(pwcInChars
[i
]);
3488 inChar
= pwcInChars
[i
];
3489 pwOutGlyphs
[i
] = inChar
;
3495 /***********************************************************************
3496 * ScriptTextOut (USP10.@)
3499 HRESULT WINAPI
ScriptTextOut(const HDC hdc
, SCRIPT_CACHE
*psc
, int x
, int y
, UINT fuOptions
,
3500 const RECT
*lprc
, const SCRIPT_ANALYSIS
*psa
, const WCHAR
*pwcReserved
,
3501 int iReserved
, const WORD
*pwGlyphs
, int cGlyphs
, const int *piAdvance
,
3502 const int *piJustify
, const GOFFSET
*pGoffset
)
3507 WORD
*reordered_glyphs
= (WORD
*)pwGlyphs
;
3509 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3510 hdc
, psc
, x
, y
, fuOptions
, wine_dbgstr_rect(lprc
), psa
, pwcReserved
, iReserved
, pwGlyphs
, cGlyphs
,
3511 piAdvance
, piJustify
, pGoffset
);
3513 if (!hdc
|| !psc
) return E_INVALIDARG
;
3514 if (!piAdvance
|| !psa
|| !pwGlyphs
) return E_INVALIDARG
;
3516 fuOptions
&= ETO_CLIPPED
+ ETO_OPAQUE
;
3517 fuOptions
|= ETO_IGNORELANGUAGE
;
3518 if (!psa
->fNoGlyphIndex
) /* Have Glyphs? */
3519 fuOptions
|= ETO_GLYPH_INDEX
; /* Say don't do translation to glyph */
3521 lpDx
= heap_alloc(cGlyphs
* sizeof(INT
) * 2);
3522 if (!lpDx
) return E_OUTOFMEMORY
;
3523 fuOptions
|= ETO_PDY
;
3525 if (psa
->fRTL
&& psa
->fLogicalOrder
)
3527 reordered_glyphs
= heap_alloc( cGlyphs
* sizeof(WORD
) );
3528 if (!reordered_glyphs
)
3531 return E_OUTOFMEMORY
;
3534 for (i
= 0; i
< cGlyphs
; i
++)
3535 reordered_glyphs
[i
] = pwGlyphs
[cGlyphs
- 1 - i
];
3539 for (i
= 0; i
< cGlyphs
; i
++)
3541 int orig_index
= (dir
> 0) ? i
: cGlyphs
- 1 - i
;
3542 lpDx
[i
* 2] = piAdvance
[orig_index
];
3543 lpDx
[i
* 2 + 1] = 0;
3549 x
+= pGoffset
[orig_index
].du
* dir
;
3550 y
+= pGoffset
[orig_index
].dv
;
3554 lpDx
[(i
- 1) * 2] += pGoffset
[orig_index
].du
* dir
;
3555 lpDx
[(i
- 1) * 2 + 1] += pGoffset
[orig_index
].dv
;
3557 lpDx
[i
* 2] -= pGoffset
[orig_index
].du
* dir
;
3558 lpDx
[i
* 2 + 1] -= pGoffset
[orig_index
].dv
;
3562 if (!ExtTextOutW(hdc
, x
, y
, fuOptions
, lprc
, reordered_glyphs
, cGlyphs
, lpDx
))
3565 if (reordered_glyphs
!= pwGlyphs
) heap_free( reordered_glyphs
);
3571 /***********************************************************************
3572 * ScriptCacheGetHeight (USP10.@)
3574 * Retrieve the height of the font in the cache.
3577 * hdc [I] Device context.
3578 * psc [I/O] Opaque pointer to a script cache.
3579 * height [O] Receives font height.
3583 * Failure: Non-zero HRESULT value.
3585 HRESULT WINAPI
ScriptCacheGetHeight(HDC hdc
, SCRIPT_CACHE
*psc
, LONG
*height
)
3589 TRACE("(%p, %p, %p)\n", hdc
, psc
, height
);
3591 if (!height
) return E_INVALIDARG
;
3592 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3594 *height
= get_cache_height(psc
);
3598 /***********************************************************************
3599 * ScriptGetGlyphABCWidth (USP10.@)
3601 * Retrieve the width of a glyph.
3604 * hdc [I] Device context.
3605 * psc [I/O] Opaque pointer to a script cache.
3606 * glyph [I] Glyph to retrieve the width for.
3607 * abc [O] ABC widths of the glyph.
3611 * Failure: Non-zero HRESULT value.
3613 HRESULT WINAPI
ScriptGetGlyphABCWidth(HDC hdc
, SCRIPT_CACHE
*psc
, WORD glyph
, ABC
*abc
)
3617 TRACE("(%p, %p, 0x%04x, %p)\n", hdc
, psc
, glyph
, abc
);
3619 if (!abc
) return E_INVALIDARG
;
3620 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3622 if (!get_cache_glyph_widths(psc
, glyph
, abc
))
3624 if (!hdc
) return E_PENDING
;
3625 if ((get_cache_pitch_family(psc
) & TMPF_TRUETYPE
))
3627 if (!GetCharABCWidthsI(hdc
, 0, 1, &glyph
, abc
)) return S_FALSE
;
3632 if (!GetCharWidth32W(hdc
, glyph
, glyph
, &width
)) return S_FALSE
;
3634 abc
->abcA
= abc
->abcC
= 0;
3636 set_cache_glyph_widths(psc
, glyph
, abc
);
3641 /***********************************************************************
3642 * ScriptLayout (USP10.@)
3644 * Map embedding levels to visual and/or logical order.
3647 * runs [I] Size of level array.
3648 * level [I] Array of embedding levels.
3649 * vistolog [O] Map of embedding levels from visual to logical order.
3650 * logtovis [O] Map of embedding levels from logical to visual order.
3654 * Failure: Non-zero HRESULT value.
3657 HRESULT WINAPI
ScriptLayout(int runs
, const BYTE
*level
, int *vistolog
, int *logtovis
)
3662 TRACE("(%d, %p, %p, %p)\n", runs
, level
, vistolog
, logtovis
);
3664 if (!level
|| (!vistolog
&& !logtovis
))
3665 return E_INVALIDARG
;
3667 indexs
= heap_alloc(sizeof(int) * runs
);
3669 return E_OUTOFMEMORY
;
3673 for( ich
= 0; ich
< runs
; ich
++)
3678 ich
+= BIDI_ReorderV2lLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3679 memcpy(vistolog
, indexs
, runs
* sizeof(*vistolog
));
3684 for( ich
= 0; ich
< runs
; ich
++)
3689 ich
+= BIDI_ReorderL2vLevel(0, indexs
+ich
, level
+ich
, runs
- ich
, FALSE
);
3690 memcpy(logtovis
, indexs
, runs
* sizeof(*logtovis
));
3697 /***********************************************************************
3698 * ScriptStringGetLogicalWidths (USP10.@)
3700 * Returns logical widths from a string analysis.
3703 * ssa [I] string analysis.
3704 * piDx [O] logical widths returned.
3708 * Failure: a non-zero HRESULT.
3710 HRESULT WINAPI
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa
, int *piDx
)
3713 StringAnalysis
*analysis
= ssa
;
3715 TRACE("%p, %p\n", ssa
, piDx
);
3717 if (!analysis
) return S_FALSE
;
3718 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3720 for (i
= 0; i
< analysis
->numItems
; i
++)
3722 int cChar
= analysis
->pItem
[i
+1].iCharPos
- analysis
->pItem
[i
].iCharPos
;
3725 if (analysis
->pItem
[i
].a
.fRTL
&& ! analysis
->pItem
[i
].a
.fLogicalOrder
)
3728 for (j
= 0; j
< cChar
; j
++)
3731 int glyph
= analysis
->glyphs
[i
].pwLogClust
[j
];
3732 int clust_size
= get_cluster_size(analysis
->glyphs
[i
].pwLogClust
,
3733 cChar
, j
, direction
, NULL
, NULL
);
3734 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
);
3736 for (k
= 0; k
< clust_size
; k
++)
3738 piDx
[next
] = advance
/ clust_size
;
3747 /***********************************************************************
3748 * ScriptStringValidate (USP10.@)
3750 * Validate a string analysis.
3753 * ssa [I] string analysis.
3757 * Failure: S_FALSE if invalid sequences are found
3758 * or a non-zero HRESULT if it fails.
3760 HRESULT WINAPI
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa
)
3762 StringAnalysis
*analysis
= ssa
;
3764 TRACE("(%p)\n", ssa
);
3766 if (!analysis
) return E_INVALIDARG
;
3767 return (analysis
->invalid
) ? S_FALSE
: S_OK
;
3770 /***********************************************************************
3771 * ScriptString_pSize (USP10.@)
3773 * Retrieve width and height of an analysed string.
3776 * ssa [I] string analysis.
3779 * Success: Pointer to a SIZE structure.
3782 const SIZE
* WINAPI
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa
)
3785 StringAnalysis
*analysis
= ssa
;
3787 TRACE("(%p)\n", ssa
);
3789 if (!analysis
) return NULL
;
3790 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return NULL
;
3794 if (!(analysis
->sz
= heap_alloc(sizeof(SIZE
)))) return NULL
;
3795 analysis
->sz
->cy
= analysis
->glyphs
[0].sc
->tm
.tmHeight
;
3797 analysis
->sz
->cx
= 0;
3798 for (i
= 0; i
< analysis
->numItems
; i
++)
3800 if (analysis
->glyphs
[i
].sc
->tm
.tmHeight
> analysis
->sz
->cy
)
3801 analysis
->sz
->cy
= analysis
->glyphs
[i
].sc
->tm
.tmHeight
;
3802 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++)
3803 analysis
->sz
->cx
+= analysis
->glyphs
[i
].piAdvance
[j
];
3806 return analysis
->sz
;
3809 /***********************************************************************
3810 * ScriptString_pLogAttr (USP10.@)
3812 * Retrieve logical attributes of an analysed string.
3815 * ssa [I] string analysis.
3818 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3821 const SCRIPT_LOGATTR
* WINAPI
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa
)
3823 StringAnalysis
*analysis
= ssa
;
3825 TRACE("(%p)\n", ssa
);
3827 if (!analysis
) return NULL
;
3828 if (!(analysis
->dwFlags
& SSA_BREAK
)) return NULL
;
3829 return analysis
->logattrs
;
3832 /***********************************************************************
3833 * ScriptString_pcOutChars (USP10.@)
3835 * Retrieve the length of a string after clipping.
3838 * ssa [I] String analysis.
3841 * Success: Pointer to the length.
3844 const int * WINAPI
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa
)
3846 StringAnalysis
*analysis
= ssa
;
3848 TRACE("(%p)\n", ssa
);
3850 if (!analysis
) return NULL
;
3851 return &analysis
->clip_len
;
3854 /***********************************************************************
3855 * ScriptStringGetOrder (USP10.@)
3857 * Retrieve a glyph order map.
3860 * ssa [I] String analysis.
3861 * order [I/O] Array of glyph positions.
3865 * Failure: a non-zero HRESULT.
3867 HRESULT WINAPI
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa
, UINT
*order
)
3871 StringAnalysis
*analysis
= ssa
;
3873 TRACE("(%p)\n", ssa
);
3875 if (!analysis
) return S_FALSE
;
3876 if (!(analysis
->dwFlags
& SSA_GLYPHS
)) return S_FALSE
;
3878 /* FIXME: handle RTL scripts */
3879 for (i
= 0, k
= 0; i
< analysis
->numItems
; i
++)
3880 for (j
= 0; j
< analysis
->glyphs
[i
].numGlyphs
; j
++, k
++)
3886 /***********************************************************************
3887 * ScriptGetLogicalWidths (USP10.@)
3889 * Convert advance widths to logical widths.
3892 * sa [I] Script analysis.
3893 * nbchars [I] Number of characters.
3894 * nbglyphs [I] Number of glyphs.
3895 * glyph_width [I] Array of glyph widths.
3896 * log_clust [I] Array of logical clusters.
3897 * sva [I] Visual attributes.
3898 * widths [O] Array of logical widths.
3902 * Failure: a non-zero HRESULT.
3904 HRESULT WINAPI
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS
*sa
, int nbchars
, int nbglyphs
,
3905 const int *advances
, const WORD
*log_clust
,
3906 const SCRIPT_VISATTR
*sva
, int *widths
)
3908 int i
, next
= 0, direction
;
3910 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3911 sa
, nbchars
, nbglyphs
, advances
, log_clust
, sva
, widths
);
3913 if (sa
->fRTL
&& !sa
->fLogicalOrder
)
3918 for (i
= 0; i
< nbchars
; i
++)
3920 int clust_size
= get_cluster_size(log_clust
, nbchars
, i
, direction
, NULL
, NULL
);
3921 int advance
= get_glyph_cluster_advance(advances
, sva
, log_clust
, nbglyphs
, nbchars
, log_clust
[i
], direction
);
3924 for (j
= 0; j
< clust_size
; j
++)
3926 widths
[next
] = advance
/ clust_size
;
3935 /***********************************************************************
3936 * ScriptApplyLogicalWidth (USP10.@)
3938 * Generate glyph advance widths.
3941 * dx [I] Array of logical advance widths.
3942 * num_chars [I] Number of characters.
3943 * num_glyphs [I] Number of glyphs.
3944 * log_clust [I] Array of logical clusters.
3945 * sva [I] Visual attributes.
3946 * advance [I] Array of glyph advance widths.
3947 * sa [I] Script analysis.
3948 * abc [I/O] Summed ABC widths.
3949 * justify [O] Array of glyph advance widths.
3953 * Failure: a non-zero HRESULT.
3955 HRESULT WINAPI
ScriptApplyLogicalWidth(const int *dx
, int num_chars
, int num_glyphs
,
3956 const WORD
*log_clust
, const SCRIPT_VISATTR
*sva
,
3957 const int *advance
, const SCRIPT_ANALYSIS
*sa
,
3958 ABC
*abc
, int *justify
)
3962 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3963 dx
, num_chars
, num_glyphs
, log_clust
, sva
, advance
, sa
, abc
, justify
);
3965 for (i
= 0; i
< num_chars
; i
++) justify
[i
] = advance
[i
];
3969 HRESULT WINAPI
ScriptJustify(const SCRIPT_VISATTR
*sva
, const int *advance
,
3970 int num_glyphs
, int dx
, int min_kashida
, int *justify
)
3974 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva
, advance
, num_glyphs
, dx
, min_kashida
, justify
);
3976 for (i
= 0; i
< num_glyphs
; i
++) justify
[i
] = advance
[i
];
3980 HRESULT WINAPI
ScriptGetFontScriptTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, int cMaxTags
, OPENTYPE_TAG
*pScriptTags
, int *pcTags
)
3983 if (!pScriptTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3984 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3986 return SHAPE_GetFontScriptTags(hdc
, (ScriptCache
*)*psc
, psa
, cMaxTags
, pScriptTags
, pcTags
);
3989 HRESULT WINAPI
ScriptGetFontLanguageTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, int cMaxTags
, OPENTYPE_TAG
*pLangSysTags
, int *pcTags
)
3992 if (!pLangSysTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
3993 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
3995 return SHAPE_GetFontLanguageTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, cMaxTags
, pLangSysTags
, pcTags
);
3998 HRESULT WINAPI
ScriptGetFontFeatureTags( HDC hdc
, SCRIPT_CACHE
*psc
, SCRIPT_ANALYSIS
*psa
, OPENTYPE_TAG tagScript
, OPENTYPE_TAG tagLangSys
, int cMaxTags
, OPENTYPE_TAG
*pFeatureTags
, int *pcTags
)
4001 if (!pFeatureTags
|| !pcTags
|| cMaxTags
== 0) return E_INVALIDARG
;
4002 if ((hr
= init_script_cache(hdc
, psc
)) != S_OK
) return hr
;
4004 return SHAPE_GetFontFeatureTags(hdc
, (ScriptCache
*)*psc
, psa
, tagScript
, tagLangSys
, cMaxTags
, pFeatureTags
, pcTags
);