gdi32/uniscribe: Use wide-char string literals.
[wine.git] / dlls / gdi32 / uniscribe / usp10.c
blob50f38f957b250399f0734cb7880ecfccc9eac0a9
1 /*
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
22 * Notes:
23 * Uniscribe allows for processing of complex scripts such as joining
24 * and filtering characters and bi-directional text with custom line breaks.
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <math.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35 #include "winnls.h"
36 #include "winreg.h"
37 #include "usp10.h"
39 #include "usp10_internal.h"
41 #include "wine/debug.h"
42 #include "wine/heap.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
46 static const struct usp10_script_range
48 enum usp10_script script;
49 DWORD rangeFirst;
50 DWORD rangeLast;
51 enum usp10_script numericScript;
52 enum usp10_script punctScript;
54 script_ranges[] =
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+257f */
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},
210 /* Kana Marks: */
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},
292 /* Plane - 1 */
293 /* Deseret: U+10400–U+1044F */
294 { Script_Deseret, 0x10400, 0x1044F, 0, 0},
295 /* Osmanya: U+10480–U+104AF */
296 { Script_Osmanya, 0x10480, 0x104AF, Script_Osmanya_Numeric, 0},
297 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
298 { Script_MathAlpha, 0x1D400, 0x1D7FF, 0, 0},
301 /* this must be in order so that the index matches the Script value */
302 const scriptData scriptInformation[] = {
303 {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
304 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
305 0x00000000, L""},
306 {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
307 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
308 MS_MAKE_TAG('l','a','t','n'), L"Microsoft Sans Serif"},
309 {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
310 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
311 0x00000000, L""},
312 {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
313 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
314 0x00000000, L"Microsoft Sans Serif"},
315 {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
316 {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
317 0x00000000, L""},
318 {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
319 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
320 0x00000000, L"Microsoft Sans Serif"},
321 {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
322 {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
323 MS_MAKE_TAG('a','r','a','b'), L"Microsoft Sans Serif"},
324 {{Script_Arabic_Numeric, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
325 {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
326 MS_MAKE_TAG('a','r','a','b'), L"Microsoft Sans Serif"},
327 {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
328 {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
329 MS_MAKE_TAG('h','e','b','r'), L"Microsoft Sans Serif"},
330 {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
331 {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
332 MS_MAKE_TAG('s','y','r','c'), L"Estrangelo Edessa"},
333 {{Script_Persian, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
334 {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
335 MS_MAKE_TAG('a','r','a','b'), L"Microsoft Sans Serif"},
336 {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
337 {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
338 MS_MAKE_TAG('t','h','a','a'), L"MV Boli"},
339 {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
340 {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
341 MS_MAKE_TAG('g','r','e','k'), L"Microsoft Sans Serif"},
342 {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
343 {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
344 MS_MAKE_TAG('c','y','r','l'), L"Microsoft Sans Serif"},
345 {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
346 {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
347 MS_MAKE_TAG('a','r','m','n'), L"Sylfaen"},
348 {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
349 {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
350 MS_MAKE_TAG('g','e','o','r'), L"Sylfaen"},
351 {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
352 {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
353 MS_MAKE_TAG('s','i','n','h'), L"Iskoola Pota"},
354 {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
355 {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
356 MS_MAKE_TAG('t','i','b','t'), L"Microsoft Himalaya"},
357 {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
358 {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
359 MS_MAKE_TAG('t','i','b','t'), L"Microsoft Himalaya"},
360 {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
361 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
362 MS_MAKE_TAG('p','h','a','g'), L"Microsoft PhagsPa"},
363 {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
364 {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
365 MS_MAKE_TAG('t','h','a','i'), L"Microsoft Sans Serif"},
366 {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
367 {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
368 MS_MAKE_TAG('t','h','a','i'), L"Microsoft Sans Serif"},
369 {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
370 {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
371 MS_MAKE_TAG('l','a','o',' '), L"DokChampa"},
372 {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
373 {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
374 MS_MAKE_TAG('l','a','o',' '), L"DokChampa"},
375 {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
376 {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
377 MS_MAKE_TAG('d','e','v','a'), L"Mangal"},
378 {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
379 {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
380 MS_MAKE_TAG('d','e','v','a'), L"Mangal"},
381 {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
382 {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
383 MS_MAKE_TAG('b','e','n','g'), L"Vrinda"},
384 {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
385 {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
386 MS_MAKE_TAG('b','e','n','g'), L"Vrinda"},
387 {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
388 {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
389 MS_MAKE_TAG('b','e','n','g'), L"Vrinda"},
390 {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
391 {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
392 MS_MAKE_TAG('g','u','r','u'), L"Raavi"},
393 {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
394 {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
395 MS_MAKE_TAG('g','u','r','u'), L"Raavi"},
396 {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
397 {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
398 MS_MAKE_TAG('g','u','j','r'), L"Shruti"},
399 {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
400 {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
401 MS_MAKE_TAG('g','u','j','r'), L"Shruti"},
402 {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
403 {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
404 MS_MAKE_TAG('g','u','j','r'), L"Shruti"},
405 {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
406 {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
407 MS_MAKE_TAG('o','r','y','a'), L"Kalinga"},
408 {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
409 {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
410 MS_MAKE_TAG('o','r','y','a'), L"Kalinga"},
411 {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
412 {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
413 MS_MAKE_TAG('t','a','m','l'), L"Latha"},
414 {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
415 {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
416 MS_MAKE_TAG('t','a','m','l'), L"Latha"},
417 {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
418 {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
419 MS_MAKE_TAG('t','e','l','u'), L"Gautami"},
420 {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
421 {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
422 MS_MAKE_TAG('t','e','l','u'), L"Gautami"},
423 {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
424 {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
425 MS_MAKE_TAG('k','n','d','a'), L"Tunga"},
426 {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
427 {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
428 MS_MAKE_TAG('k','n','d','a'), L"Tunga"},
429 {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
430 {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
431 MS_MAKE_TAG('m','l','y','m'), L"Kartika"},
432 {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
433 {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
434 MS_MAKE_TAG('m','l','y','m'), L"Kartika"},
435 {{Script_Diacritical, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
436 {LANG_ENGLISH, 0, 1, 0, 1, ANSI_CHARSET, 0, 0, 0, 0, 0, 1, 1, 0, 0},
437 0x00000000, L""},
438 {{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
439 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
440 MS_MAKE_TAG('l','a','t','n'), L"Microsoft Sans Serif"},
441 {{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
442 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
443 0x00000000, L""},
444 {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
445 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
446 MS_MAKE_TAG('m','y','m','r'), L"Myanmar Text"},
447 {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
448 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
449 MS_MAKE_TAG('m','y','m','r'), L""},
450 {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
451 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
452 MS_MAKE_TAG('t','a','l','e'), L"Microsoft Tai Le"},
453 {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
454 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
455 MS_MAKE_TAG('t','a','l','u'), L"Microsoft New Tai Lue"},
456 {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
457 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
458 MS_MAKE_TAG('t','a','l','u'), L"Microsoft New Tai Lue"},
459 {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
460 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
461 MS_MAKE_TAG('k','h','m','r'), L"DaunPenh"},
462 {{Script_Khmer_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
463 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
464 MS_MAKE_TAG('k','h','m','r'), L"DaunPenh"},
465 {{Script_CJK_Han, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
466 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
467 MS_MAKE_TAG('h','a','n','i'), L""},
468 {{Script_Ideograph, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
469 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
470 MS_MAKE_TAG('h','a','n','i'), L""},
471 {{Script_Bopomofo, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
472 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
473 MS_MAKE_TAG('b','o','p','o'), L""},
474 {{Script_Kana, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
475 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
476 MS_MAKE_TAG('k','a','n','a'), L""},
477 {{Script_Hangul, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
478 {LANG_KOREAN, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
479 MS_MAKE_TAG('h','a','n','g'), L""},
480 {{Script_Yi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
481 {LANG_ENGLISH, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
482 MS_MAKE_TAG('y','i',' ',' '), L"Microsoft Yi Baiti"},
483 {{Script_Ethiopic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
484 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
485 MS_MAKE_TAG('e','t','h','i'), L"Nyala"},
486 {{Script_Ethiopic_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
487 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
488 MS_MAKE_TAG('e','t','h','i'), L"Nyala"},
489 {{Script_Mongolian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
490 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
491 MS_MAKE_TAG('m','o','n','g'), L"Mongolian Baiti"},
492 {{Script_Mongolian_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
493 {LANG_MONGOLIAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
494 MS_MAKE_TAG('m','o','n','g'), L"Mongolian Baiti"},
495 {{Script_Tifinagh, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
496 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
497 MS_MAKE_TAG('t','f','n','g'), L"Ebrima"},
498 {{Script_NKo, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
499 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
500 MS_MAKE_TAG('n','k','o',' '), L"Ebrima"},
501 {{Script_Vai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
502 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
503 MS_MAKE_TAG('v','a','i',' '), L"Ebrima"},
504 {{Script_Vai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
505 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
506 MS_MAKE_TAG('v','a','i',' '), L"Ebrima"},
507 {{Script_Cherokee, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
508 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
509 MS_MAKE_TAG('c','h','e','r'), L"Plantagenet Cherokee"},
510 {{Script_Canadian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
511 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
512 MS_MAKE_TAG('c','a','n','s'), L"Euphemia"},
513 {{Script_Ogham, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
514 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
515 MS_MAKE_TAG('o','g','a','m'), L"Segoe UI Symbol"},
516 {{Script_Runic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
517 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
518 MS_MAKE_TAG('r','u','n','r'), L"Segoe UI Symbol"},
519 {{Script_Braille, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
520 {LANG_ENGLISH, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
521 MS_MAKE_TAG('b','r','a','i'), L"Segoe UI Symbol"},
522 {{Script_Surrogates, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
523 {LANG_ENGLISH, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
524 0x00000000, L""},
525 {{Script_Private, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
526 {0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 1, 0, 0, 0, 0, 1, 0, 0},
527 0x00000000, L""},
528 {{Script_Deseret, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
529 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
530 MS_MAKE_TAG('d','s','r','t'), L"Segoe UI Symbol"},
531 {{Script_Osmanya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
532 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
533 MS_MAKE_TAG('o','s','m','a'), L"Ebrima"},
534 {{Script_Osmanya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
535 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
536 MS_MAKE_TAG('o','s','m','a'), L"Ebrima"},
537 {{Script_MathAlpha, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
538 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
539 MS_MAKE_TAG('m','a','t','h'), L"Cambria Math"},
540 {{Script_Hebrew_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
541 {LANG_HEBREW, 0, 1, 0, 0, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
542 MS_MAKE_TAG('h','e','b','r'), L"Microsoft Sans Serif"},
543 {{Script_Vietnamese_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
544 {LANG_VIETNAMESE, 0, 0, 0, 0, VIETNAMESE_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
545 MS_MAKE_TAG('l','a','t','n'), L"Microsoft Sans Serif"},
546 {{Script_Thai_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
547 {LANG_THAI, 0, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
548 MS_MAKE_TAG('t','h','a','i'), L"Microsoft Sans Serif"},
551 static const SCRIPT_PROPERTIES *script_props[] =
553 &scriptInformation[0].props, &scriptInformation[1].props,
554 &scriptInformation[2].props, &scriptInformation[3].props,
555 &scriptInformation[4].props, &scriptInformation[5].props,
556 &scriptInformation[6].props, &scriptInformation[7].props,
557 &scriptInformation[8].props, &scriptInformation[9].props,
558 &scriptInformation[10].props, &scriptInformation[11].props,
559 &scriptInformation[12].props, &scriptInformation[13].props,
560 &scriptInformation[14].props, &scriptInformation[15].props,
561 &scriptInformation[16].props, &scriptInformation[17].props,
562 &scriptInformation[18].props, &scriptInformation[19].props,
563 &scriptInformation[20].props, &scriptInformation[21].props,
564 &scriptInformation[22].props, &scriptInformation[23].props,
565 &scriptInformation[24].props, &scriptInformation[25].props,
566 &scriptInformation[26].props, &scriptInformation[27].props,
567 &scriptInformation[28].props, &scriptInformation[29].props,
568 &scriptInformation[30].props, &scriptInformation[31].props,
569 &scriptInformation[32].props, &scriptInformation[33].props,
570 &scriptInformation[34].props, &scriptInformation[35].props,
571 &scriptInformation[36].props, &scriptInformation[37].props,
572 &scriptInformation[38].props, &scriptInformation[39].props,
573 &scriptInformation[40].props, &scriptInformation[41].props,
574 &scriptInformation[42].props, &scriptInformation[43].props,
575 &scriptInformation[44].props, &scriptInformation[45].props,
576 &scriptInformation[46].props, &scriptInformation[47].props,
577 &scriptInformation[48].props, &scriptInformation[49].props,
578 &scriptInformation[50].props, &scriptInformation[51].props,
579 &scriptInformation[52].props, &scriptInformation[53].props,
580 &scriptInformation[54].props, &scriptInformation[55].props,
581 &scriptInformation[56].props, &scriptInformation[57].props,
582 &scriptInformation[58].props, &scriptInformation[59].props,
583 &scriptInformation[60].props, &scriptInformation[61].props,
584 &scriptInformation[62].props, &scriptInformation[63].props,
585 &scriptInformation[64].props, &scriptInformation[65].props,
586 &scriptInformation[66].props, &scriptInformation[67].props,
587 &scriptInformation[68].props, &scriptInformation[69].props,
588 &scriptInformation[70].props, &scriptInformation[71].props,
589 &scriptInformation[72].props, &scriptInformation[73].props,
590 &scriptInformation[74].props, &scriptInformation[75].props,
591 &scriptInformation[76].props, &scriptInformation[77].props,
592 &scriptInformation[78].props, &scriptInformation[79].props,
593 &scriptInformation[80].props, &scriptInformation[81].props
596 static CRITICAL_SECTION cs_script_cache;
597 static CRITICAL_SECTION_DEBUG cs_script_cache_dbg =
599 0, 0, &cs_script_cache,
600 { &cs_script_cache_dbg.ProcessLocksList, &cs_script_cache_dbg.ProcessLocksList },
601 0, 0, { (DWORD_PTR)(__FILE__ ": script_cache") }
603 static CRITICAL_SECTION cs_script_cache = { &cs_script_cache_dbg, -1, 0, 0, 0, 0 };
604 static struct list script_cache_list = LIST_INIT(script_cache_list);
606 typedef struct {
607 ScriptCache *sc;
608 int numGlyphs;
609 WORD* glyphs;
610 WORD* pwLogClust;
611 int* piAdvance;
612 SCRIPT_VISATTR* psva;
613 GOFFSET* pGoffset;
614 ABC abc;
615 int iMaxPosX;
616 HFONT fallbackFont;
617 } StringGlyphs;
619 enum stringanalysis_flags
621 SCRIPT_STRING_ANALYSIS_FLAGS_SIZE = 0x1,
622 SCRIPT_STRING_ANALYSIS_FLAGS_INVALID = 0x2,
625 typedef struct {
626 HDC hdc;
627 DWORD ssa_flags;
628 DWORD flags;
629 int clip_len;
630 int cItems;
631 int cMaxGlyphs;
632 SCRIPT_ITEM* pItem;
633 int numItems;
634 StringGlyphs* glyphs;
635 SCRIPT_LOGATTR* logattrs;
636 SIZE sz;
637 int* logical2visual;
638 } StringAnalysis;
640 typedef struct {
641 BOOL ascending;
642 WORD target;
643 } FindGlyph_struct;
645 BOOL usp10_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
647 SIZE_T max_capacity, new_capacity;
648 void *new_elements;
650 if (count <= *capacity)
651 return TRUE;
653 max_capacity = ~(SIZE_T)0 / size;
654 if (count > max_capacity)
655 return FALSE;
657 new_capacity = max(1, *capacity);
658 while (new_capacity < count && new_capacity <= max_capacity / 2)
659 new_capacity *= 2;
660 if (new_capacity < count)
661 new_capacity = count;
663 if (!*elements)
664 new_elements = heap_alloc_zero(new_capacity * size);
665 else
666 new_elements = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *elements, new_capacity * size);
667 if (!new_elements)
668 return FALSE;
670 *elements = new_elements;
671 *capacity = new_capacity;
672 return TRUE;
675 /* TODO Fix font properties on Arabic locale */
676 static inline BOOL set_cache_font_properties(const HDC hdc, ScriptCache *sc)
678 sc->sfp.cBytes = sizeof(sc->sfp);
680 if (!sc->sfnt)
682 sc->sfp.wgBlank = sc->tm.tmBreakChar;
683 sc->sfp.wgDefault = sc->tm.tmDefaultChar;
684 sc->sfp.wgInvalid = sc->sfp.wgBlank;
685 sc->sfp.wgKashida = 0xFFFF;
686 sc->sfp.iKashidaWidth = 0;
688 else
690 static const WCHAR chars[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
691 /* U+0020: numeric space
692 U+200B: zero width space
693 U+F71B: unknown char found by black box testing
694 U+0640: kashida */
695 WORD gi[4];
697 if (GetGlyphIndicesW(hdc, chars, 4, gi, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
699 if(gi[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
700 sc->sfp.wgBlank = gi[0];
701 else
702 sc->sfp.wgBlank = 0;
704 sc->sfp.wgDefault = 0;
706 if (gi[2] != 0xFFFF)
707 sc->sfp.wgInvalid = gi[2];
708 else if (gi[1] != 0xFFFF)
709 sc->sfp.wgInvalid = gi[1];
710 else if (gi[0] != 0xFFFF)
711 sc->sfp.wgInvalid = gi[0];
712 else
713 sc->sfp.wgInvalid = 0;
715 sc->sfp.wgKashida = gi[3];
717 sc->sfp.iKashidaWidth = 0; /* TODO */
719 else
720 return FALSE;
722 return TRUE;
725 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES *sfp, ScriptCache *sc)
727 *sfp = sc->sfp;
730 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
732 return ((ScriptCache *)*psc)->tm.tmHeight;
735 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
737 return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
740 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
742 CacheGlyphPage *page = ((ScriptCache *)*psc)->page[c / 0x10000];
743 WORD *block;
745 if (!page) return 0;
746 block = page->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
747 if (!block) return 0;
748 return block[(c % 0x10000) & GLYPH_BLOCK_MASK];
751 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
753 CacheGlyphPage **page = &((ScriptCache *)*psc)->page[c / 0x10000];
754 WORD **block;
755 if (!*page && !(*page = heap_alloc_zero(sizeof(CacheGlyphPage)))) return 0;
757 block = &(*page)->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
758 if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
759 return ((*block)[(c % 0x10000) & GLYPH_BLOCK_MASK] = glyph);
762 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
764 static const ABC nil;
765 ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
767 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
768 memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
769 return TRUE;
772 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
774 ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
776 if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
777 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
778 return TRUE;
781 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
783 ScriptCache *sc;
784 unsigned size;
785 LOGFONTW lf;
787 if (!psc) return E_INVALIDARG;
788 if (*psc) return S_OK;
789 if (!hdc) return E_PENDING;
791 if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf))
793 return E_INVALIDARG;
795 /* Ensure canonical result by zeroing extra space in lfFaceName */
796 size = lstrlenW(lf.lfFaceName);
797 memset(lf.lfFaceName + size, 0, sizeof(lf.lfFaceName) - size * sizeof(WCHAR));
799 EnterCriticalSection(&cs_script_cache);
800 LIST_FOR_EACH_ENTRY(sc, &script_cache_list, ScriptCache, entry)
802 if (!memcmp(&sc->lf, &lf, sizeof(lf)))
804 sc->refcount++;
805 LeaveCriticalSection(&cs_script_cache);
806 *psc = sc;
807 return S_OK;
810 LeaveCriticalSection(&cs_script_cache);
812 if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
813 if (!GetTextMetricsW(hdc, &sc->tm))
815 heap_free(sc);
816 return E_INVALIDARG;
818 size = GetOutlineTextMetricsW(hdc, 0, NULL);
819 if (size)
821 sc->otm = heap_alloc(size);
822 sc->otm->otmSize = size;
823 GetOutlineTextMetricsW(hdc, size, sc->otm);
825 sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
826 if (!set_cache_font_properties(hdc, sc))
828 heap_free(sc);
829 return E_INVALIDARG;
831 sc->lf = lf;
832 sc->refcount = 1;
833 *psc = sc;
835 EnterCriticalSection(&cs_script_cache);
836 list_add_head(&script_cache_list, &sc->entry);
837 LIST_FOR_EACH_ENTRY(sc, &script_cache_list, ScriptCache, entry)
839 if (sc != *psc && !memcmp(&sc->lf, &lf, sizeof(lf)))
841 /* Another thread won the race. Use their cache instead of ours */
842 list_remove(&sc->entry);
843 sc->refcount++;
844 LeaveCriticalSection(&cs_script_cache);
845 heap_free(*psc);
846 *psc = sc;
847 return S_OK;
850 LeaveCriticalSection(&cs_script_cache);
851 TRACE("<- %p\n", sc);
852 return S_OK;
855 static WCHAR mirror_char( WCHAR ch )
857 extern const WCHAR wine_mirror_map[] DECLSPEC_HIDDEN;
858 WCHAR mirror = get_table_entry( wine_mirror_map, ch );
859 return mirror ? mirror : ch;
862 static DWORD decode_surrogate_pair(const WCHAR *str, unsigned int index, unsigned int end)
864 if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
866 DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
867 TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
868 return ch;
870 return 0;
873 static int __cdecl usp10_compare_script_range(const void *key, const void *value)
875 const struct usp10_script_range *range = value;
876 const DWORD *ch = key;
878 if (*ch < range->rangeFirst)
879 return -1;
880 if (*ch > range->rangeLast)
881 return 1;
882 return 0;
885 static enum usp10_script get_char_script(const WCHAR *str, unsigned int index,
886 unsigned int end, unsigned int *consumed)
888 struct usp10_script_range *range;
889 WORD type = 0, type2 = 0;
890 DWORD ch;
892 *consumed = 1;
894 if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
895 return Script_CR;
897 /* These punctuation characters are separated out as Latin punctuation */
898 if (wcschr(L"#$&',;<>?@\\^_`{|}~\x00a0", str[index]))
899 return Script_Punctuation2;
901 /* These chars are itemized as Punctuation by Windows */
902 if (str[index] == 0x2212 || str[index] == 0x2044)
903 return Script_Punctuation;
905 /* Currency Symbols by Unicode point */
906 switch (str[index])
908 case 0x09f2:
909 case 0x09f3: return Script_Bengali_Currency;
910 case 0x0af1: return Script_Gujarati_Currency;
911 case 0x0e3f: return Script_Thai_Currency;
912 case 0x20aa: return Script_Hebrew_Currency;
913 case 0x20ab: return Script_Vietnamese_Currency;
914 case 0xfb29: return Script_Hebrew_Currency;
917 GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
918 GetStringTypeW(CT_CTYPE2, &str[index], 1, &type2);
920 if (type == 0)
921 return SCRIPT_UNDEFINED;
923 if (type & C1_CNTRL)
924 return Script_Control;
926 ch = decode_surrogate_pair(str, index, end);
927 if (ch)
928 *consumed = 2;
929 else
930 ch = str[index];
932 if (!(range = bsearch(&ch, script_ranges, ARRAY_SIZE(script_ranges),
933 sizeof(*script_ranges), usp10_compare_script_range)))
934 return (*consumed == 2) ? Script_Surrogates : Script_Undefined;
936 if (range->numericScript && (type & C1_DIGIT || type2 == C2_ARABICNUMBER))
937 return range->numericScript;
938 if (range->punctScript && type & C1_PUNCT)
939 return range->punctScript;
940 return range->script;
943 static int __cdecl compare_FindGlyph(const void *a, const void* b)
945 const FindGlyph_struct *find = (FindGlyph_struct*)a;
946 const WORD *idx= (WORD*)b;
947 int rc = 0;
949 if ( find->target > *idx)
950 rc = 1;
951 else if (find->target < *idx)
952 rc = -1;
954 if (!find->ascending)
955 rc *= -1;
956 return rc;
959 int USP10_FindGlyphInLogClust(const WORD* pwLogClust, int cChars, WORD target)
961 FindGlyph_struct fgs;
962 WORD *ptr;
963 INT k;
965 if (pwLogClust[0] < pwLogClust[cChars-1])
966 fgs.ascending = TRUE;
967 else
968 fgs.ascending = FALSE;
970 fgs.target = target;
971 ptr = bsearch(&fgs, pwLogClust, cChars, sizeof(WORD), compare_FindGlyph);
973 if (!ptr)
974 return -1;
976 for (k = (ptr - pwLogClust)-1; k >= 0 && pwLogClust[k] == target; k--)
978 k++;
980 return k;
983 /***********************************************************************
984 * ScriptFreeCache (USP10.@)
986 * Free a script cache.
988 * PARAMS
989 * psc [I/O] Script cache.
991 * RETURNS
992 * Success: S_OK
993 * Failure: Non-zero HRESULT value.
995 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
997 TRACE("%p\n", psc);
999 if (psc && *psc)
1001 unsigned int i;
1002 INT n;
1004 EnterCriticalSection(&cs_script_cache);
1005 if (--((ScriptCache *)*psc)->refcount > 0)
1007 LeaveCriticalSection(&cs_script_cache);
1008 *psc = NULL;
1009 return S_OK;
1011 list_remove(&((ScriptCache *)*psc)->entry);
1012 LeaveCriticalSection(&cs_script_cache);
1014 for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
1016 heap_free(((ScriptCache *)*psc)->widths[i]);
1018 for (i = 0; i < NUM_PAGES; i++)
1020 unsigned int j;
1021 if (((ScriptCache *)*psc)->page[i])
1022 for (j = 0; j < GLYPH_MAX / GLYPH_BLOCK_SIZE; j++)
1023 heap_free(((ScriptCache *)*psc)->page[i]->glyphs[j]);
1024 heap_free(((ScriptCache *)*psc)->page[i]);
1026 heap_free(((ScriptCache *)*psc)->GSUB_Table);
1027 heap_free(((ScriptCache *)*psc)->GDEF_Table);
1028 heap_free(((ScriptCache *)*psc)->CMAP_Table);
1029 heap_free(((ScriptCache *)*psc)->GPOS_Table);
1030 for (n = 0; n < ((ScriptCache *)*psc)->script_count; n++)
1032 int j;
1033 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].language_count; j++)
1035 int k;
1036 for (k = 0; k < ((ScriptCache *)*psc)->scripts[n].languages[j].feature_count; k++)
1037 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features[k].lookups);
1038 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features);
1040 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].default_language.feature_count; j++)
1041 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features[j].lookups);
1042 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features);
1043 heap_free(((ScriptCache *)*psc)->scripts[n].languages);
1045 heap_free(((ScriptCache *)*psc)->scripts);
1046 heap_free(((ScriptCache *)*psc)->otm);
1047 heap_free(*psc);
1048 *psc = NULL;
1050 return S_OK;
1053 /***********************************************************************
1054 * ScriptGetProperties (USP10.@)
1056 * Retrieve a list of script properties.
1058 * PARAMS
1059 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1060 * num [I] Pointer to the number of scripts.
1062 * RETURNS
1063 * Success: S_OK
1064 * Failure: Non-zero HRESULT value.
1066 * NOTES
1067 * Behaviour matches WinXP.
1069 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
1071 TRACE("(%p,%p)\n", props, num);
1073 if (!props && !num) return E_INVALIDARG;
1075 if (num) *num = ARRAY_SIZE(script_props);
1076 if (props) *props = script_props;
1078 return S_OK;
1081 /***********************************************************************
1082 * ScriptGetFontProperties (USP10.@)
1084 * Get information on special glyphs.
1086 * PARAMS
1087 * hdc [I] Device context.
1088 * psc [I/O] Opaque pointer to a script cache.
1089 * sfp [O] Font properties structure.
1091 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
1093 HRESULT hr;
1095 TRACE("%p,%p,%p\n", hdc, psc, sfp);
1097 if (!sfp) return E_INVALIDARG;
1098 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1100 if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
1101 return E_INVALIDARG;
1103 get_cache_font_properties(sfp, *psc);
1105 return S_OK;
1108 /***********************************************************************
1109 * ScriptRecordDigitSubstitution (USP10.@)
1111 * Record digit substitution settings for a given locale.
1113 * PARAMS
1114 * locale [I] Locale identifier.
1115 * sds [I] Structure to record substitution settings.
1117 * RETURNS
1118 * Success: S_OK
1119 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1121 * SEE ALSO
1122 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1124 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
1126 DWORD plgid, sub;
1128 TRACE("0x%x, %p\n", locale, sds);
1130 /* This implementation appears to be correct for all languages, but it's
1131 * not clear if sds->DigitSubstitute is ever set to anything except
1132 * CONTEXT or NONE in reality */
1134 if (!sds) return E_POINTER;
1136 locale = ConvertDefaultLocale(locale);
1138 if (!IsValidLocale(locale, LCID_INSTALLED))
1139 return E_INVALIDARG;
1141 plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
1142 sds->TraditionalDigitLanguage = plgid;
1144 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1145 sds->NationalDigitLanguage = plgid;
1146 else
1147 sds->NationalDigitLanguage = LANG_ENGLISH;
1149 if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
1150 (WCHAR *)&sub, sizeof(sub) / sizeof(WCHAR)))
1151 return E_INVALIDARG;
1153 switch (sub)
1155 case 0:
1156 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1157 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
1158 else
1159 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1160 break;
1161 case 1:
1162 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1163 break;
1164 case 2:
1165 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
1166 break;
1167 default:
1168 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
1169 break;
1172 sds->dwReserved = 0;
1173 return S_OK;
1176 /***********************************************************************
1177 * ScriptApplyDigitSubstitution (USP10.@)
1179 * Apply digit substitution settings.
1181 * PARAMS
1182 * sds [I] Structure with recorded substitution settings.
1183 * sc [I] Script control structure.
1184 * ss [I] Script state structure.
1186 * RETURNS
1187 * Success: S_OK
1188 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1190 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds,
1191 SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
1193 SCRIPT_DIGITSUBSTITUTE psds;
1195 TRACE("%p, %p, %p\n", sds, sc, ss);
1197 if (!sc || !ss) return E_POINTER;
1198 if (!sds)
1200 sds = &psds;
1201 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
1202 return E_INVALIDARG;
1205 sc->uDefaultLanguage = LANG_ENGLISH;
1206 sc->fContextDigits = 0;
1207 ss->fDigitSubstitute = 0;
1209 switch (sds->DigitSubstitute) {
1210 case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
1211 case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
1212 case SCRIPT_DIGITSUBSTITUTE_NONE:
1213 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
1214 return S_OK;
1215 default:
1216 return E_INVALIDARG;
1220 static inline BOOL is_indic(enum usp10_script script)
1222 return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
1225 static inline enum usp10_script base_indic(enum usp10_script script)
1227 switch (script)
1229 case Script_Devanagari:
1230 case Script_Devanagari_Numeric: return Script_Devanagari;
1231 case Script_Bengali:
1232 case Script_Bengali_Numeric:
1233 case Script_Bengali_Currency: return Script_Bengali;
1234 case Script_Gurmukhi:
1235 case Script_Gurmukhi_Numeric: return Script_Gurmukhi;
1236 case Script_Gujarati:
1237 case Script_Gujarati_Numeric:
1238 case Script_Gujarati_Currency: return Script_Gujarati;
1239 case Script_Oriya:
1240 case Script_Oriya_Numeric: return Script_Oriya;
1241 case Script_Tamil:
1242 case Script_Tamil_Numeric: return Script_Tamil;
1243 case Script_Telugu:
1244 case Script_Telugu_Numeric: return Script_Telugu;
1245 case Script_Kannada:
1246 case Script_Kannada_Numeric: return Script_Kannada;
1247 case Script_Malayalam:
1248 case Script_Malayalam_Numeric: return Script_Malayalam;
1249 default:
1250 return Script_Undefined;
1254 static BOOL script_is_numeric(enum usp10_script script)
1256 return scriptInformation[script].props.fNumeric;
1259 static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
1260 int cMaxItems, const SCRIPT_CONTROL *psControl,
1261 const SCRIPT_STATE *psState, SCRIPT_ITEM *pItems,
1262 OPENTYPE_TAG *pScriptTags, int *pcItems)
1265 #define Numeric_space 0x0020
1266 #define ZWSP 0x200B
1267 #define ZWNJ 0x200C
1268 #define ZWJ 0x200D
1270 enum usp10_script last_indic = Script_Undefined;
1271 int cnt = 0, index = 0, str = 0;
1272 enum usp10_script New_Script = -1;
1273 int i;
1274 WORD *levels = NULL;
1275 WORD *layout_levels = NULL;
1276 WORD *overrides = NULL;
1277 WORD *strength = NULL;
1278 enum usp10_script *scripts;
1279 WORD baselevel = 0;
1280 WORD baselayout = 0;
1281 BOOL new_run;
1282 WORD layoutRTL = 0;
1283 BOOL forceLevels = FALSE;
1284 unsigned int consumed = 0;
1285 HRESULT res = E_OUTOFMEMORY;
1287 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
1288 psControl, psState, pItems, pcItems);
1290 if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
1291 return E_INVALIDARG;
1293 if (!(scripts = heap_calloc(cInChars, sizeof(*scripts))))
1294 return E_OUTOFMEMORY;
1296 for (i = 0; i < cInChars; i++)
1298 if (!consumed)
1300 scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
1301 consumed --;
1303 else
1305 scripts[i] = scripts[i-1];
1306 consumed --;
1308 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1309 all Indic scripts */
1310 if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic != Script_Undefined)
1311 scripts[i] = last_indic;
1312 else if (is_indic(scripts[i]))
1313 last_indic = base_indic(scripts[i]);
1315 /* Some unicode points :
1316 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1317 (Left Right Embed U+202A - Left Right Override U+202D)
1318 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1319 will force us into bidi mode */
1320 if (!forceLevels && ((pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F) ||
1321 (pwcInChars[i] >= 0x202A && pwcInChars[i] <= 0x202E) ||
1322 (pwcInChars[i] >= 0x2066 && pwcInChars[i] <= 0x2069)))
1324 forceLevels = TRUE;
1326 /* Diacritical marks merge with other scripts */
1327 if (scripts[i] == Script_Diacritical)
1329 if (i > 0)
1331 if (pScriptTags)
1332 scripts[i] = scripts[i-1];
1333 else
1335 int j;
1336 BOOL asian = FALSE;
1337 enum usp10_script first_script = scripts[i-1];
1338 for (j = i-1; j >= 0 && scripts[j] == first_script && pwcInChars[j] != Numeric_space; j--)
1340 enum usp10_script original = scripts[j];
1341 if (original == Script_Ideograph || original == Script_Kana || original == Script_Yi || original == Script_CJK_Han || original == Script_Bopomofo)
1343 asian = TRUE;
1344 break;
1346 if (original != Script_MathAlpha && scriptInformation[scripts[j]].props.fComplex)
1347 break;
1348 scripts[j] = scripts[i];
1349 if (original == Script_Punctuation2)
1350 break;
1352 if (j >= 0 && (scriptInformation[scripts[j]].props.fComplex || asian))
1353 scripts[i] = scripts[j];
1359 for (i = 0; i < cInChars; i++)
1361 /* Joiners get merged preferencially right */
1362 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1364 int j;
1365 if (i+1 == cInChars)
1366 scripts[i] = scripts[i-1];
1367 else
1369 for (j = i+1; j < cInChars; j++)
1371 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1372 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1374 scripts[i] = scripts[j];
1375 break;
1382 if (psState && psControl)
1384 if (!(levels = heap_calloc(cInChars, sizeof(*levels))))
1385 goto nomemory;
1387 if (!(overrides = heap_calloc(cInChars, sizeof(*overrides))))
1388 goto nomemory;
1390 if (!(layout_levels = heap_calloc(cInChars, sizeof(*layout_levels))))
1391 goto nomemory;
1393 if (psState->fOverrideDirection)
1395 if (!forceLevels)
1397 SCRIPT_STATE s = *psState;
1398 s.fOverrideDirection = FALSE;
1399 BIDI_DetermineLevels(pwcInChars, cInChars, &s, psControl, layout_levels, overrides);
1400 if (odd(layout_levels[0]))
1401 forceLevels = TRUE;
1402 else for (i = 0; i < cInChars; i++)
1403 if (layout_levels[i]!=layout_levels[0])
1405 forceLevels = TRUE;
1406 break;
1410 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1412 else
1414 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1415 memcpy(layout_levels, levels, cInChars * sizeof(WORD));
1417 baselevel = levels[0];
1418 baselayout = layout_levels[0];
1419 for (i = 0; i < cInChars; i++)
1420 if (levels[i]!=levels[0])
1421 break;
1422 if (i >= cInChars && !odd(baselevel) && !odd(psState->uBidiLevel) && !forceLevels)
1424 heap_free(levels);
1425 heap_free(overrides);
1426 heap_free(layout_levels);
1427 overrides = NULL;
1428 levels = NULL;
1429 layout_levels = NULL;
1431 else
1433 if (!(strength = heap_calloc(cInChars, sizeof(*strength))))
1434 goto nomemory;
1435 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
1437 /* We currently mis-level leading Diacriticals */
1438 if (scripts[0] == Script_Diacritical)
1439 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
1441 levels[i] = odd(levels[i])?levels[i]+1:levels[i];
1442 strength[i] = BIDI_STRONG;
1445 /* Math punctuation bordered on both sides by numbers can be
1446 merged into the number */
1447 for (i = 0; i < cInChars; i++)
1449 if (i > 0 && i < cInChars-1 &&
1450 script_is_numeric(scripts[i-1]) &&
1451 wcschr(L"#$%+,-./:\x2212\x2044\x00a0", pwcInChars[i]))
1453 if (script_is_numeric(scripts[i+1]))
1455 scripts[i] = scripts[i+1];
1456 levels[i] = levels[i-1];
1457 strength[i] = strength[i-1];
1458 i++;
1460 else if (wcschr(L"#$%+-/\x2212\x2044", pwcInChars[i]))
1462 int j;
1463 for (j = i+1; j < cInChars; j++)
1465 if (script_is_numeric(scripts[j]))
1467 for(;i<j; i++)
1469 scripts[i] = scripts[j];
1470 levels[i] = levels[i-1];
1471 strength[i] = strength[i-1];
1474 else if (pwcInChars[i] != pwcInChars[j]) break;
1480 for (i = 0; i < cInChars; i++)
1482 /* Numerics at level 0 get bumped to level 2 */
1483 if (!overrides[i] && (levels[i] == 0 || (odd(psState->uBidiLevel)
1484 && levels[i] == psState->uBidiLevel + 1)) && script_is_numeric(scripts[i]))
1486 levels[i] = 2;
1489 /* Joiners get merged preferencially right */
1490 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1492 int j;
1493 if (i+1 == cInChars && levels[i-1] == levels[i])
1494 strength[i] = strength[i-1];
1495 else
1496 for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
1497 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1498 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1500 strength[i] = strength[j];
1501 break;
1505 if (psControl->fMergeNeutralItems)
1507 /* Merge the neutrals */
1508 for (i = 0; i < cInChars; i++)
1510 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1512 int j;
1513 for (j = i; j > 0; j--)
1515 if (levels[i] != levels[j])
1516 break;
1517 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1519 scripts[i] = scripts[j];
1520 strength[i] = strength[j];
1521 break;
1525 /* Try going the other way */
1526 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1528 int j;
1529 for (j = i; j < cInChars; j++)
1531 if (levels[i] != levels[j])
1532 break;
1533 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1535 scripts[i] = scripts[j];
1536 strength[i] = strength[j];
1537 break;
1546 while ((!levels || (levels && cnt+1 < cInChars && levels[cnt+1] == levels[0]))
1547 && (cnt < cInChars && pwcInChars[cnt] == Numeric_space))
1548 cnt++;
1550 if (cnt == cInChars) /* All Spaces */
1552 cnt = 0;
1553 New_Script = scripts[cnt];
1556 pItems[index].iCharPos = 0;
1557 pItems[index].a = scriptInformation[scripts[cnt]].a;
1558 if (pScriptTags)
1559 pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
1561 if (strength && strength[cnt] == BIDI_STRONG)
1562 str = strength[cnt];
1563 else if (strength)
1564 str = strength[0];
1566 cnt = 0;
1568 if (levels)
1570 if (strength[cnt] == BIDI_STRONG)
1571 layoutRTL = odd(layout_levels[cnt]);
1572 else
1573 layoutRTL = (psState->uBidiLevel || odd(layout_levels[cnt]));
1574 if (overrides)
1575 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1576 pItems[index].a.fRTL = odd(levels[cnt]);
1577 if (script_is_numeric(pItems[index].a.eScript))
1578 pItems[index].a.fLayoutRTL = layoutRTL;
1579 else
1580 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1581 pItems[index].a.s.uBidiLevel = levels[cnt];
1583 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1585 if (pItems[index].a.s.uBidiLevel != baselevel)
1586 pItems[index].a.s.fOverrideDirection = TRUE;
1587 layoutRTL = odd(baselayout);
1588 pItems[index].a.s.uBidiLevel = baselevel;
1589 pItems[index].a.fRTL = odd(baselevel);
1590 if (script_is_numeric(pItems[index].a.eScript))
1591 pItems[index].a.fLayoutRTL = odd(baselayout);
1592 else
1593 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1596 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1597 levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
1598 pItems[index].iCharPos);
1600 for (cnt=1; cnt < cInChars; cnt++)
1602 if(pwcInChars[cnt] != Numeric_space)
1603 New_Script = scripts[cnt];
1604 else if (levels)
1606 int j = 1;
1607 while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
1608 j++;
1609 if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
1610 New_Script = scripts[cnt+j];
1611 else
1612 New_Script = scripts[cnt];
1615 new_run = FALSE;
1616 /* merge space strengths*/
1617 if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
1618 str = BIDI_STRONG;
1620 if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
1621 str = BIDI_NEUTRAL;
1623 /* changes in level */
1624 if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
1626 TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
1627 new_run = TRUE;
1629 /* changes in strength */
1630 else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
1632 TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
1633 new_run = TRUE;
1635 /* changes in script */
1636 else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
1638 TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
1639 new_run = TRUE;
1642 if (!new_run && strength && str == BIDI_STRONG)
1644 layoutRTL = odd(layout_levels[cnt]);
1645 if (script_is_numeric(pItems[index].a.eScript))
1646 pItems[index].a.fLayoutRTL = layoutRTL;
1649 if (new_run)
1651 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);
1653 index++;
1654 if (index+1 > cMaxItems)
1655 goto nomemory;
1657 if (strength)
1658 str = strength[cnt];
1660 pItems[index].iCharPos = cnt;
1661 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1663 pItems[index].a = scriptInformation[New_Script].a;
1664 if (pScriptTags)
1665 pScriptTags[index] = scriptInformation[New_Script].scriptTag;
1666 if (levels)
1668 if (overrides)
1669 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1670 if (layout_levels[cnt] == 0)
1671 layoutRTL = 0;
1672 else
1673 layoutRTL = (layoutRTL || odd(layout_levels[cnt]));
1674 pItems[index].a.fRTL = odd(levels[cnt]);
1675 if (script_is_numeric(pItems[index].a.eScript))
1676 pItems[index].a.fLayoutRTL = layoutRTL;
1677 else
1678 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1679 pItems[index].a.s.uBidiLevel = levels[cnt];
1681 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1683 if (pItems[index].a.s.uBidiLevel != baselevel)
1684 pItems[index].a.s.fOverrideDirection = TRUE;
1685 pItems[index].a.s.uBidiLevel = baselevel;
1686 pItems[index].a.fRTL = odd(baselevel);
1687 if (script_is_numeric(pItems[index].a.eScript))
1688 pItems[index].a.fLayoutRTL = layoutRTL;
1689 else
1690 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1693 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1697 /* While not strictly necessary according to the spec, make sure the n+1
1698 * item is set up to prevent random behaviour if the caller erroneously
1699 * checks the n+1 structure */
1700 index++;
1701 if (index + 1 > cMaxItems) goto nomemory;
1702 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1704 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1706 /* Set one SCRIPT_STATE item being returned */
1707 if (pcItems) *pcItems = index;
1709 /* Set SCRIPT_ITEM */
1710 pItems[index].iCharPos = cnt; /* the last item contains the ptr to the lastchar */
1711 res = S_OK;
1712 nomemory:
1713 heap_free(levels);
1714 heap_free(overrides);
1715 heap_free(layout_levels);
1716 heap_free(strength);
1717 heap_free(scripts);
1718 return res;
1721 /***********************************************************************
1722 * ScriptItemizeOpenType (USP10.@)
1724 * Split a Unicode string into shapeable parts.
1726 * PARAMS
1727 * pwcInChars [I] String to split.
1728 * cInChars [I] Number of characters in pwcInChars.
1729 * cMaxItems [I] Maximum number of items to return.
1730 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1731 * psState [I] Pointer to a SCRIPT_STATE structure.
1732 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1733 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1734 * pcItems [O] Number of script items returned.
1736 * RETURNS
1737 * Success: S_OK
1738 * Failure: Non-zero HRESULT value.
1740 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1741 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1742 SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
1744 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pScriptTags, pcItems);
1747 /***********************************************************************
1748 * ScriptItemize (USP10.@)
1750 * Split a Unicode string into shapeable parts.
1752 * PARAMS
1753 * pwcInChars [I] String to split.
1754 * cInChars [I] Number of characters in pwcInChars.
1755 * cMaxItems [I] Maximum number of items to return.
1756 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1757 * psState [I] Pointer to a SCRIPT_STATE structure.
1758 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1759 * pcItems [O] Number of script items returned.
1761 * RETURNS
1762 * Success: S_OK
1763 * Failure: Non-zero HRESULT value.
1765 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1766 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1767 SCRIPT_ITEM *pItems, int *pcItems)
1769 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, NULL, pcItems);
1772 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1774 int defWidth;
1775 int cTabStops=0;
1776 INT *lpTabPos = NULL;
1777 INT nTabOrg = 0;
1778 INT x = 0;
1780 if (pTabdef)
1781 lpTabPos = pTabdef->pTabStops;
1783 if (pTabdef && pTabdef->iTabOrigin)
1785 if (pTabdef->iScale)
1786 nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1787 else
1788 nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1791 if (pTabdef)
1792 cTabStops = pTabdef->cTabStops;
1794 if (cTabStops == 1)
1796 if (pTabdef->iScale)
1797 defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1798 else
1799 defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1800 cTabStops = 0;
1802 else
1804 if (pTabdef->iScale)
1805 defWidth = (32 * pTabdef->iScale) / 4;
1806 else
1807 defWidth = 8 * psc->tm.tmAveCharWidth;
1810 for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1812 int position = *lpTabPos;
1813 if (position < 0)
1814 position = -1 * position;
1815 if (pTabdef->iScale)
1816 position = (position * pTabdef->iScale) / 4;
1817 else
1818 position = position * psc->tm.tmAveCharWidth;
1820 if( nTabOrg + position > current_x)
1822 if( position >= 0)
1824 /* a left aligned tab */
1825 x = (nTabOrg + position) - current_x;
1826 break;
1828 else
1830 FIXME("Negative tabstop\n");
1831 break;
1835 if ((!cTabStops) && (defWidth > 0))
1836 x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1837 else if ((!cTabStops) && (defWidth < 0))
1838 FIXME("TODO: Negative defWidth\n");
1840 return x;
1843 /***********************************************************************
1844 * Helper function for ScriptStringAnalyse
1846 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1847 const WCHAR *pwcInChars, int cChars )
1849 /* FIXME: When to properly fallback is still a bit of a mystery */
1850 WORD *glyphs;
1852 if (psa->fNoGlyphIndex)
1853 return FALSE;
1855 if (init_script_cache(hdc, psc) != S_OK)
1856 return FALSE;
1858 if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1859 return TRUE;
1861 if (!(glyphs = heap_calloc(cChars, sizeof(*glyphs))))
1862 return FALSE;
1863 if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1865 heap_free(glyphs);
1866 return TRUE;
1868 heap_free(glyphs);
1870 return FALSE;
1873 static void find_fallback_font(enum usp10_script scriptid, WCHAR *FaceName)
1875 HKEY hkey;
1877 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1879 WCHAR value[10];
1880 DWORD count = LF_FACESIZE * sizeof(WCHAR);
1881 DWORD type;
1883 swprintf(value, ARRAY_SIZE(value), L"%x", scriptInformation[scriptid].scriptTag);
1884 if (RegQueryValueExW(hkey, value, 0, &type, (BYTE *)FaceName, &count))
1885 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1886 RegCloseKey(hkey);
1888 else
1889 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1892 /***********************************************************************
1893 * ScriptStringAnalyse (USP10.@)
1896 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1897 int cGlyphs, int iCharset, DWORD dwFlags,
1898 int iReqWidth, SCRIPT_CONTROL *psControl,
1899 SCRIPT_STATE *psState, const int *piDx,
1900 SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1901 SCRIPT_STRING_ANALYSIS *pssa)
1903 HRESULT hr = E_OUTOFMEMORY;
1904 StringAnalysis *analysis = NULL;
1905 SCRIPT_CONTROL sControl;
1906 SCRIPT_STATE sState;
1907 int i, num_items = 255;
1908 BYTE *BidiLevel;
1909 WCHAR *iString = NULL;
1911 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1912 hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1913 psControl, psState, piDx, pTabdef, pbInClass, pssa);
1915 if (iCharset != -1)
1917 FIXME("Only Unicode strings are supported\n");
1918 return E_INVALIDARG;
1920 if (cString < 1 || !pString) return E_INVALIDARG;
1921 if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1923 if (!(analysis = heap_alloc_zero(sizeof(*analysis))))
1924 return E_OUTOFMEMORY;
1925 if (!(analysis->pItem = heap_calloc(num_items + 1, sizeof(*analysis->pItem))))
1926 goto error;
1928 /* FIXME: handle clipping */
1929 analysis->clip_len = cString;
1930 analysis->hdc = hdc;
1931 analysis->ssa_flags = dwFlags;
1933 if (psState)
1934 sState = *psState;
1935 else
1936 memset(&sState, 0, sizeof(SCRIPT_STATE));
1938 if (psControl)
1939 sControl = *psControl;
1940 else
1941 memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1943 if (dwFlags & SSA_PASSWORD)
1945 if (!(iString = heap_calloc(cString, sizeof(*iString))))
1947 hr = E_OUTOFMEMORY;
1948 goto error;
1950 for (i = 0; i < cString; i++)
1951 iString[i] = *((const WCHAR *)pString);
1952 pString = iString;
1955 hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1956 &analysis->numItems);
1958 if (FAILED(hr))
1960 if (hr == E_OUTOFMEMORY)
1961 hr = E_INVALIDARG;
1962 goto error;
1965 /* set back to out of memory for default goto error behaviour */
1966 hr = E_OUTOFMEMORY;
1968 if (dwFlags & SSA_BREAK)
1970 if (!(analysis->logattrs = heap_calloc(cString, sizeof(*analysis->logattrs))))
1971 goto error;
1973 for (i = 0; i < analysis->numItems; ++i)
1974 ScriptBreak(&((const WCHAR *)pString)[analysis->pItem[i].iCharPos],
1975 analysis->pItem[i + 1].iCharPos - analysis->pItem[i].iCharPos,
1976 &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
1979 if (!(analysis->logical2visual = heap_calloc(analysis->numItems, sizeof(*analysis->logical2visual))))
1980 goto error;
1981 if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
1982 goto error;
1984 if (dwFlags & SSA_GLYPHS)
1986 int tab_x = 0;
1988 if (!(analysis->glyphs = heap_calloc(analysis->numItems, sizeof(*analysis->glyphs))))
1990 heap_free(BidiLevel);
1991 goto error;
1994 for (i = 0; i < analysis->numItems; i++)
1996 SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
1997 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1998 int numGlyphs = 1.5 * cChar + 16;
1999 WORD *glyphs = heap_calloc(numGlyphs, sizeof(*glyphs));
2000 WORD *pwLogClust = heap_calloc(cChar, sizeof(*pwLogClust));
2001 int *piAdvance = heap_calloc(numGlyphs, sizeof(*piAdvance));
2002 SCRIPT_VISATTR *psva = heap_calloc(numGlyphs, sizeof(*psva));
2003 GOFFSET *pGoffset = heap_calloc(numGlyphs, sizeof(*pGoffset));
2004 int numGlyphsReturned;
2005 HFONT originalFont = 0x0;
2007 /* FIXME: non unicode strings */
2008 const WCHAR* pStr = (const WCHAR*)pString;
2009 analysis->glyphs[i].fallbackFont = NULL;
2011 if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset)
2013 heap_free (BidiLevel);
2014 heap_free (glyphs);
2015 heap_free (pwLogClust);
2016 heap_free (piAdvance);
2017 heap_free (psva);
2018 heap_free (pGoffset);
2019 hr = E_OUTOFMEMORY;
2020 goto error;
2023 if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
2025 LOGFONTW lf;
2026 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
2027 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
2028 lf.lfFaceName[0] = 0;
2029 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
2030 if (lf.lfFaceName[0])
2032 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
2033 if (analysis->glyphs[i].fallbackFont)
2035 ScriptFreeCache(sc);
2036 originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
2041 /* FIXME: When we properly shape Hangul remove this check */
2042 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && analysis->pItem[i].a.eScript == Script_Hangul)
2043 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2045 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && !scriptInformation[analysis->pItem[i].a.eScript].props.fComplex && !analysis->pItem[i].a.fRTL)
2046 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2048 ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos], cChar, numGlyphs,
2049 &analysis->pItem[i].a, glyphs, pwLogClust, psva, &numGlyphsReturned);
2050 hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
2051 piAdvance, pGoffset, &analysis->glyphs[i].abc);
2052 if (originalFont)
2053 SelectObject(hdc,originalFont);
2055 if (dwFlags & SSA_TAB)
2057 int tabi = 0;
2058 for (tabi = 0; tabi < cChar; tabi++)
2060 if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
2061 piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
2062 tab_x+=piAdvance[tabi];
2066 analysis->glyphs[i].numGlyphs = numGlyphsReturned;
2067 analysis->glyphs[i].glyphs = glyphs;
2068 analysis->glyphs[i].pwLogClust = pwLogClust;
2069 analysis->glyphs[i].piAdvance = piAdvance;
2070 analysis->glyphs[i].psva = psva;
2071 analysis->glyphs[i].pGoffset = pGoffset;
2072 analysis->glyphs[i].iMaxPosX= -1;
2074 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2077 else
2079 for (i = 0; i < analysis->numItems; i++)
2080 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2083 ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
2084 heap_free(BidiLevel);
2086 *pssa = analysis;
2087 heap_free(iString);
2088 return S_OK;
2090 error:
2091 heap_free(iString);
2092 heap_free(analysis->glyphs);
2093 heap_free(analysis->logattrs);
2094 heap_free(analysis->pItem);
2095 heap_free(analysis->logical2visual);
2096 heap_free(analysis);
2097 return hr;
2100 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
2102 if (pva[glyph].fClusterStart)
2103 return TRUE;
2104 if (USP10_FindGlyphInLogClust(pwLogClust, cChars, glyph) >= 0)
2105 return TRUE;
2107 return FALSE;
2110 static DWORD get_sys_color(INT index)
2112 static DWORD (WINAPI *pGetSysColor)(INT index);
2114 if (!pGetSysColor)
2116 HMODULE user = GetModuleHandleW( L"user32.dll" );
2117 if (user) pGetSysColor = (void *)GetProcAddress( user, "GetSysColor" );
2120 return pGetSysColor(index);
2123 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
2124 int iX,
2125 int iY,
2126 int iItem,
2127 int cStart,
2128 int cEnd,
2129 UINT uOptions,
2130 const RECT *prc,
2131 BOOL fSelected,
2132 BOOL fDisabled)
2134 StringAnalysis *analysis;
2135 int off_x = 0;
2136 HRESULT hr;
2137 COLORREF BkColor = 0x0;
2138 COLORREF TextColor = 0x0;
2139 INT BkMode = 0;
2140 INT runStart, runEnd;
2141 INT iGlyph, cGlyphs;
2142 HFONT oldFont = 0x0;
2143 RECT crc;
2144 int i;
2146 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2147 ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
2149 if (!(analysis = ssa)) return E_INVALIDARG;
2151 if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
2152 (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
2153 return S_OK;
2155 if (prc)
2156 memcpy(&crc, prc, sizeof(crc));
2157 if (fSelected)
2159 BkMode = GetBkMode(analysis->hdc);
2160 SetBkMode( analysis->hdc, OPAQUE);
2161 BkColor = GetBkColor(analysis->hdc);
2162 SetBkColor(analysis->hdc, get_sys_color(COLOR_HIGHLIGHT));
2163 if (!fDisabled)
2165 TextColor = GetTextColor(analysis->hdc);
2166 SetTextColor(analysis->hdc, get_sys_color(COLOR_HIGHLIGHTTEXT));
2169 if (analysis->glyphs[iItem].fallbackFont)
2170 oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
2172 if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
2173 runStart = cStart - analysis->pItem[iItem].iCharPos;
2174 else
2175 runStart = 0;
2176 if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
2177 runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
2178 else
2179 runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
2181 if (analysis->pItem[iItem].a.fRTL)
2183 if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
2184 ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
2185 else
2186 ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
2187 crc.left = iX + off_x;
2189 else
2191 if (cStart >=0 && runStart)
2192 ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
2193 else
2194 ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
2195 crc.left = iX + off_x;
2198 if (analysis->pItem[iItem].a.fRTL)
2199 iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
2200 else
2201 iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
2203 if (analysis->pItem[iItem].a.fRTL)
2204 cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
2205 else
2206 cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
2208 cGlyphs++;
2210 /* adjust for cluster glyphs when starting */
2211 if (analysis->pItem[iItem].a.fRTL)
2212 i = analysis->pItem[iItem+1].iCharPos - 1;
2213 else
2214 i = analysis->pItem[iItem].iCharPos;
2216 for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
2218 if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
2220 if (analysis->pItem[iItem].a.fRTL)
2221 ScriptStringCPtoX(ssa, i, TRUE, &off_x);
2222 else
2223 ScriptStringCPtoX(ssa, i, FALSE, &off_x);
2224 break;
2228 if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
2230 INT direction;
2231 INT clust_glyph;
2233 clust_glyph = iGlyph + cGlyphs;
2234 if (analysis->pItem[iItem].a.fRTL)
2235 direction = -1;
2236 else
2237 direction = 1;
2239 while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
2240 !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
2242 cGlyphs++;
2243 clust_glyph++;
2247 hr = ScriptTextOut(analysis->hdc,
2248 (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
2249 iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
2250 &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
2251 &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
2252 &analysis->glyphs[iItem].pGoffset[iGlyph]);
2254 TRACE("ScriptTextOut hr=%08x\n", hr);
2256 if (fSelected)
2258 SetBkColor(analysis->hdc, BkColor);
2259 SetBkMode( analysis->hdc, BkMode);
2260 if (!fDisabled)
2261 SetTextColor(analysis->hdc, TextColor);
2263 if (analysis->glyphs[iItem].fallbackFont)
2264 SelectObject(analysis->hdc, oldFont);
2266 return hr;
2269 /***********************************************************************
2270 * ScriptStringOut (USP10.@)
2272 * This function takes the output of ScriptStringAnalyse and joins the segments
2273 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2274 * only processes glyphs.
2276 * Parameters:
2277 * ssa [I] buffer to hold the analysed string components
2278 * iX [I] X axis displacement for output
2279 * iY [I] Y axis displacement for output
2280 * uOptions [I] flags controlling output processing
2281 * prc [I] rectangle coordinates
2282 * iMinSel [I] starting pos for substringing output string
2283 * iMaxSel [I] ending pos for substringing output string
2284 * fDisabled [I] controls text highlighting
2286 * RETURNS
2287 * Success: S_OK
2288 * Failure: is the value returned by ScriptTextOut
2290 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
2291 int iX,
2292 int iY,
2293 UINT uOptions,
2294 const RECT *prc,
2295 int iMinSel,
2296 int iMaxSel,
2297 BOOL fDisabled)
2299 StringAnalysis *analysis;
2300 int item;
2301 HRESULT hr;
2303 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2304 ssa, iX, iY, uOptions, wine_dbgstr_rect(prc), iMinSel, iMaxSel, fDisabled);
2306 if (!(analysis = ssa)) return E_INVALIDARG;
2307 if (!(analysis->ssa_flags & SSA_GLYPHS)) return E_INVALIDARG;
2309 for (item = 0; item < analysis->numItems; item++)
2311 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
2312 if (FAILED(hr))
2313 return hr;
2316 if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
2318 if (iMaxSel > 0 && iMinSel < 0)
2319 iMinSel = 0;
2320 for (item = 0; item < analysis->numItems; item++)
2322 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
2323 if (FAILED(hr))
2324 return hr;
2328 return S_OK;
2331 /***********************************************************************
2332 * ScriptStringCPtoX (USP10.@)
2335 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
2337 int item;
2338 int runningX = 0;
2339 StringAnalysis* analysis = ssa;
2341 TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
2343 if (!ssa || !pX) return S_FALSE;
2344 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
2346 /* icp out of range */
2347 if(icp < 0)
2349 analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2350 return E_INVALIDARG;
2353 for(item=0; item<analysis->numItems; item++)
2355 int CP, i;
2356 int offset;
2358 i = analysis->logical2visual[item];
2359 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2360 /* initialize max extents for uninitialized runs */
2361 if (analysis->glyphs[i].iMaxPosX == -1)
2363 if (analysis->pItem[i].a.fRTL)
2364 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2365 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2366 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2367 else
2368 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2369 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2370 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2373 if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
2375 runningX += analysis->glyphs[i].iMaxPosX;
2376 continue;
2379 icp -= analysis->pItem[i].iCharPos;
2380 ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2381 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2382 &analysis->pItem[i].a, &offset);
2383 runningX += offset;
2385 *pX = runningX;
2386 return S_OK;
2389 /* icp out of range */
2390 analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2391 return E_INVALIDARG;
2394 /***********************************************************************
2395 * ScriptStringXtoCP (USP10.@)
2398 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
2400 StringAnalysis* analysis = ssa;
2401 int item;
2403 TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
2405 if (!ssa || !piCh || !piTrailing) return S_FALSE;
2406 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
2408 /* out of range */
2409 if(iX < 0)
2411 if (analysis->pItem[0].a.fRTL)
2413 *piCh = 1;
2414 *piTrailing = FALSE;
2416 else
2418 *piCh = -1;
2419 *piTrailing = TRUE;
2421 return S_OK;
2424 for(item=0; item<analysis->numItems; item++)
2426 int i;
2427 int CP;
2429 for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
2430 /* nothing */;
2432 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2433 /* initialize max extents for uninitialized runs */
2434 if (analysis->glyphs[i].iMaxPosX == -1)
2436 if (analysis->pItem[i].a.fRTL)
2437 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2438 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2439 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2440 else
2441 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2442 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2443 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2446 if (iX > analysis->glyphs[i].iMaxPosX)
2448 iX -= analysis->glyphs[i].iMaxPosX;
2449 continue;
2452 ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2453 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2454 &analysis->pItem[i].a, piCh, piTrailing);
2455 *piCh += analysis->pItem[i].iCharPos;
2457 return S_OK;
2460 /* out of range */
2461 *piCh = analysis->pItem[analysis->numItems].iCharPos;
2462 *piTrailing = FALSE;
2464 return S_OK;
2468 /***********************************************************************
2469 * ScriptStringFree (USP10.@)
2471 * Free a string analysis.
2473 * PARAMS
2474 * pssa [I] string analysis.
2476 * RETURNS
2477 * Success: S_OK
2478 * Failure: Non-zero HRESULT value.
2480 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
2482 StringAnalysis* analysis;
2483 BOOL invalid;
2484 int i;
2486 TRACE("(%p)\n", pssa);
2488 if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
2490 invalid = analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2492 if (analysis->glyphs)
2494 for (i = 0; i < analysis->numItems; i++)
2496 heap_free(analysis->glyphs[i].glyphs);
2497 heap_free(analysis->glyphs[i].pwLogClust);
2498 heap_free(analysis->glyphs[i].piAdvance);
2499 heap_free(analysis->glyphs[i].psva);
2500 heap_free(analysis->glyphs[i].pGoffset);
2501 if (analysis->glyphs[i].fallbackFont)
2502 DeleteObject(analysis->glyphs[i].fallbackFont);
2503 ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
2504 heap_free(analysis->glyphs[i].sc);
2506 heap_free(analysis->glyphs);
2509 heap_free(analysis->pItem);
2510 heap_free(analysis->logattrs);
2511 heap_free(analysis->logical2visual);
2512 heap_free(analysis);
2514 if (invalid) return E_INVALIDARG;
2515 return S_OK;
2518 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
2519 int direction, int* iCluster, int *check_out)
2521 int clust_size = 1;
2522 int check;
2523 WORD clust = pwLogClust[item];
2525 for (check = item+direction; check < cChars && check >= 0; check+=direction)
2527 if (pwLogClust[check] == clust)
2529 clust_size ++;
2530 if (iCluster && *iCluster == -1)
2531 *iCluster = item;
2533 else break;
2536 if (check_out)
2537 *check_out = check;
2539 return clust_size;
2542 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)
2544 int advance;
2545 int log_clust_max;
2547 advance = piAdvance[glyph];
2549 if (pwLogClust[0] > pwLogClust[cChars-1])
2550 log_clust_max = pwLogClust[0];
2551 else
2552 log_clust_max = pwLogClust[cChars-1];
2554 if (glyph > log_clust_max)
2555 return advance;
2557 for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
2560 if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
2561 break;
2562 if (glyph > log_clust_max)
2563 break;
2564 advance += piAdvance[glyph];
2567 return advance;
2570 /***********************************************************************
2571 * ScriptCPtoX (USP10.@)
2574 HRESULT WINAPI ScriptCPtoX(int iCP,
2575 BOOL fTrailing,
2576 int cChars,
2577 int cGlyphs,
2578 const WORD *pwLogClust,
2579 const SCRIPT_VISATTR *psva,
2580 const int *piAdvance,
2581 const SCRIPT_ANALYSIS *psa,
2582 int *piX)
2584 int item;
2585 float iPosX;
2586 int iSpecial = -1;
2587 int iCluster = -1;
2588 int clust_size = 1;
2589 float special_size = 0.0;
2590 int iMaxPos = 0;
2591 int advance = 0;
2592 BOOL rtl = FALSE;
2594 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2595 iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2596 psa, piX);
2598 if (psa->fRTL && ! psa->fLogicalOrder)
2599 rtl = TRUE;
2601 if (fTrailing)
2602 iCP++;
2604 if (rtl)
2606 int max_clust = pwLogClust[0];
2608 for (item=0; item < cGlyphs; item++)
2609 if (pwLogClust[item] > max_clust)
2611 ERR("We do not handle non reversed clusters properly\n");
2612 break;
2615 iMaxPos = 0;
2616 for (item = max_clust; item >=0; item --)
2617 iMaxPos += piAdvance[item];
2620 iPosX = 0.0;
2621 for (item=0; item < iCP && item < cChars; item++)
2623 if (iSpecial == -1 && (iCluster == -1 || iCluster+clust_size <= item))
2625 int check;
2626 int clust = pwLogClust[item];
2628 iCluster = -1;
2629 clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2630 &check);
2632 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2634 if (check >= cChars && !iMaxPos)
2636 int glyph;
2637 for (glyph = clust; glyph < cGlyphs; glyph++)
2638 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, glyph, 1);
2639 iSpecial = item;
2640 special_size /= (cChars - item);
2641 iPosX += special_size;
2643 else
2645 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2647 clust_size --;
2648 if (clust_size == 0)
2649 iPosX += advance;
2651 else
2652 iPosX += advance / (float)clust_size;
2655 else if (iSpecial != -1)
2656 iPosX += special_size;
2657 else /* (iCluster != -1) */
2659 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2660 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2662 clust_size --;
2663 if (clust_size == 0)
2664 iPosX += adv;
2666 else
2667 iPosX += adv / (float)clust_size;
2671 if (iMaxPos > 0)
2673 iPosX = iMaxPos - iPosX;
2674 if (iPosX < 0)
2675 iPosX = 0;
2678 *piX = iPosX;
2679 TRACE("*piX=%d\n", *piX);
2680 return S_OK;
2683 /* Count the number of characters in a cluster and its starting index*/
2684 static inline BOOL get_cluster_data(const WORD *pwLogClust, int cChars, int cluster_index, int *cluster_size, int *start_index)
2686 int size = 0;
2687 int i;
2689 for (i = 0; i < cChars; i++)
2691 if (pwLogClust[i] == cluster_index)
2693 if (!size && start_index)
2695 *start_index = i;
2696 if (!cluster_size)
2697 return TRUE;
2699 size++;
2701 else if (size) break;
2703 if (cluster_size)
2704 *cluster_size = size;
2706 return (size > 0);
2710 To handle multi-glyph clusters we need to find all the glyphs that are
2711 represented in the cluster. This involves finding the glyph whose
2712 index is the cluster index as well as whose glyph indices are greater than
2713 our cluster index but not part of a new cluster.
2715 Then we sum all those glyphs' advances.
2717 static inline int get_cluster_advance(const int* piAdvance,
2718 const SCRIPT_VISATTR *psva,
2719 const WORD *pwLogClust, int cGlyphs,
2720 int cChars, int cluster, int direction)
2722 int glyph_start;
2723 int glyph_end;
2724 int i, advance;
2726 if (direction > 0)
2727 i = 0;
2728 else
2729 i = (cChars - 1);
2731 for (glyph_start = -1, glyph_end = -1; i < cChars && i >= 0 && (glyph_start < 0 || glyph_end < 0); i+=direction)
2733 if (glyph_start < 0 && pwLogClust[i] != cluster) continue;
2734 if (pwLogClust[i] == cluster && glyph_start < 0) glyph_start = pwLogClust[i];
2735 if (glyph_start >= 0 && glyph_end < 0 && pwLogClust[i] != cluster) glyph_end = pwLogClust[i];
2737 if (glyph_end < 0)
2739 if (direction > 0)
2740 glyph_end = cGlyphs;
2741 else
2743 /* Don't fully understand multi-glyph reversed clusters yet,
2744 * do they occur for real or just in our test? */
2745 FIXME("multi-glyph reversed clusters found\n");
2746 glyph_end = glyph_start + 1;
2750 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2751 for (i = glyph_start+1; i< glyph_end; i++)
2753 if (psva[i].fClusterStart)
2755 glyph_end = i;
2756 break;
2760 for (advance = 0, i = glyph_start; i < glyph_end; i++)
2761 advance += piAdvance[i];
2763 return advance;
2767 /***********************************************************************
2768 * ScriptXtoCP (USP10.@)
2770 * Basic algorithm :
2771 * Use piAdvance to find the cluster we are looking at.
2772 * Find the character that is the first character of the cluster.
2773 * That is our base piCP.
2774 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2775 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2776 * determine how far through the cluster to advance the cursor.
2778 HRESULT WINAPI ScriptXtoCP(int iX,
2779 int cChars,
2780 int cGlyphs,
2781 const WORD *pwLogClust,
2782 const SCRIPT_VISATTR *psva,
2783 const int *piAdvance,
2784 const SCRIPT_ANALYSIS *psa,
2785 int *piCP,
2786 int *piTrailing)
2788 int direction = 1;
2789 int iPosX;
2790 int i;
2791 int glyph_index, cluster_index;
2792 int cluster_size;
2794 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2795 iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2796 psa, piCP, piTrailing);
2798 if (psa->fRTL && ! psa->fLogicalOrder)
2799 direction = -1;
2801 /* Handle an iX < 0 */
2802 if (iX < 0)
2804 if (direction < 0)
2806 *piCP = cChars;
2807 *piTrailing = 0;
2809 else
2811 *piCP = -1;
2812 *piTrailing = 1;
2814 return S_OK;
2817 /* Looking for non-reversed clusters in a reversed string */
2818 if (direction < 0)
2820 int max_clust = pwLogClust[0];
2821 for (i=0; i< cChars; i++)
2822 if (pwLogClust[i] > max_clust)
2824 FIXME("We do not handle non reversed clusters properly\n");
2825 break;
2829 /* find the glyph_index based in iX */
2830 if (direction > 0)
2832 for (glyph_index = -1, iPosX = iX; iPosX >=0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2835 else
2837 for (glyph_index = -1, iPosX = iX; iPosX > 0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2841 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX, glyph_index, cGlyphs);
2843 *piTrailing = 0;
2844 if (glyph_index >= 0 && glyph_index < cGlyphs)
2846 /* find the cluster */
2847 if (direction > 0 )
2848 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] <= glyph_index; cluster_index=pwLogClust[i++])
2850 else
2851 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] >= glyph_index; cluster_index=pwLogClust[i++])
2854 TRACE("cluster_index %i\n", cluster_index);
2856 if (direction < 0 && iPosX >= 0 && glyph_index != cluster_index)
2858 /* We are off the end of the string */
2859 *piCP = -1;
2860 *piTrailing = 1;
2861 return S_OK;
2864 get_cluster_data(pwLogClust, cChars, cluster_index, &cluster_size, &i);
2866 TRACE("first char index %i\n",i);
2867 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2869 /* Check trailing */
2870 if (glyph_index != cluster_index ||
2871 (direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2872 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2873 *piTrailing = cluster_size;
2875 else
2877 if (cluster_size > 1)
2879 /* Be part way through the glyph cluster based on size and position */
2880 int cluster_advance = get_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, cluster_index, direction);
2881 double cluster_part_width = cluster_advance / (float)cluster_size;
2882 double adv;
2883 int part_index;
2885 /* back up to the beginning of the cluster */
2886 for (adv = iPosX, part_index = cluster_index; part_index <= glyph_index; part_index++)
2887 adv += piAdvance[part_index];
2888 if (adv > iX) adv = iX;
2890 TRACE("Multi-char cluster, no snap\n");
2891 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size, adv);
2892 TRACE("advance %i divides into %f per char\n", cluster_advance, cluster_part_width);
2893 if (direction > 0)
2895 for (part_index = 0; adv >= 0; adv-=cluster_part_width, part_index++)
2897 if (part_index) part_index--;
2899 else
2901 for (part_index = 0; adv > 0; adv-=cluster_part_width, part_index++)
2903 if (part_index > cluster_size)
2905 adv += cluster_part_width;
2906 part_index=cluster_size;
2910 TRACE("base_char %i part_index %i, leftover advance %f\n",i, part_index, adv);
2912 if (direction > 0)
2913 i += part_index;
2914 else
2915 i += (cluster_size - part_index);
2917 /* Check trailing */
2918 if ((direction > 0 && fabs(adv) <= (cluster_part_width / 2.0)) ||
2919 (direction < 0 && adv && fabs(adv) >= (cluster_part_width / 2.0)))
2920 *piTrailing = 1;
2922 else
2924 /* Check trailing */
2925 if ((direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2926 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2927 *piTrailing = 1;
2931 else
2933 TRACE("Point falls outside of string\n");
2934 if (glyph_index < 0)
2935 i = cChars-1;
2936 else /* (glyph_index >= cGlyphs) */
2937 i = cChars;
2939 /* If not snapping in the reverse direction (such as Hebrew) Then 0
2940 point flow to the next character */
2941 if (direction < 0)
2943 if (!scriptInformation[psa->eScript].props.fNeedsCaretInfo && abs(iPosX) == piAdvance[glyph_index])
2944 i++;
2945 else
2946 *piTrailing = 1;
2950 *piCP = i;
2952 TRACE("*piCP=%d\n", *piCP);
2953 TRACE("*piTrailing=%d\n", *piTrailing);
2954 return S_OK;
2957 /***********************************************************************
2958 * ScriptBreak (USP10.@)
2960 * Retrieve line break information.
2962 * PARAMS
2963 * chars [I] Array of characters.
2964 * sa [I] Script analysis.
2965 * la [I] Array of logical attribute structures.
2967 * RETURNS
2968 * Success: S_OK
2969 * Failure: S_FALSE
2971 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2973 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2975 if (count < 0 || !la) return E_INVALIDARG;
2976 if (count == 0) return E_FAIL;
2978 BREAK_line(chars, count, sa, la);
2980 return S_OK;
2983 /***********************************************************************
2984 * ScriptIsComplex (USP10.@)
2986 * Determine if a string is complex.
2988 * PARAMS
2989 * chars [I] Array of characters to test.
2990 * len [I] Length in characters.
2991 * flag [I] Flag.
2993 * RETURNS
2994 * Success: S_OK
2995 * Failure: S_FALSE
2998 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
3000 enum usp10_script script;
3001 unsigned int i, consumed;
3003 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
3005 if (!chars || len < 0)
3006 return E_INVALIDARG;
3008 for (i = 0; i < len; i+=consumed)
3010 if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
3011 return S_OK;
3013 script = get_char_script(chars,i,len, &consumed);
3014 if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
3015 (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
3016 return S_OK;
3018 return S_FALSE;
3021 /***********************************************************************
3022 * ScriptShapeOpenType (USP10.@)
3024 * Produce glyphs and visual attributes for a run.
3026 * PARAMS
3027 * hdc [I] Device context.
3028 * psc [I/O] Opaque pointer to a script cache.
3029 * psa [I/O] Script analysis.
3030 * tagScript [I] The OpenType tag for the Script
3031 * tagLangSys [I] The OpenType tag for the Language
3032 * rcRangeChars[I] Array of Character counts in each range
3033 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3034 * cRanges [I] Count of ranges
3035 * pwcChars [I] Array of characters specifying the run.
3036 * cChars [I] Number of characters in pwcChars.
3037 * cMaxGlyphs [I] Length of pwOutGlyphs.
3038 * pwLogClust [O] Array of logical cluster info.
3039 * pCharProps [O] Array of character property values
3040 * pwOutGlyphs [O] Array of glyphs.
3041 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3042 * pcGlyphs [O] Number of glyphs returned.
3044 * RETURNS
3045 * Success: S_OK
3046 * Failure: Non-zero HRESULT value.
3048 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
3049 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3050 OPENTYPE_TAG tagLangSys, int *rcRangeChars,
3051 TEXTRANGE_PROPERTIES **rpRangeProperties,
3052 int cRanges, const WCHAR *pwcChars, int cChars,
3053 int cMaxGlyphs, WORD *pwLogClust,
3054 SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
3055 SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
3057 HRESULT hr;
3058 int i;
3059 unsigned int g;
3060 BOOL rtl;
3061 int cluster;
3062 static int once = 0;
3064 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3065 hdc, psc, psa,
3066 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3067 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3068 cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
3070 if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
3071 psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
3073 if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
3074 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3076 if (cRanges)
3077 if(!once++) FIXME("Ranges not supported yet\n");
3079 rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
3081 *pcGlyphs = cChars;
3082 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3083 if (!pwLogClust) return E_FAIL;
3085 ((ScriptCache *)*psc)->userScript = tagScript;
3086 ((ScriptCache *)*psc)->userLang = tagLangSys;
3088 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3089 for (i = 0; i < cChars; i++)
3091 int idx = i;
3092 if (rtl) idx = cChars - 1 - i;
3093 /* FIXME: set to better values */
3094 pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
3095 pOutGlyphProps[i].sva.fClusterStart = 1;
3096 pOutGlyphProps[i].sva.fDiacritic = 0;
3097 pOutGlyphProps[i].sva.fZeroWidth = 0;
3098 pOutGlyphProps[i].sva.fReserved = 0;
3099 pOutGlyphProps[i].sva.fShapeReserved = 0;
3101 /* FIXME: have the shaping engine set this */
3102 pCharProps[i].fCanGlyphAlone = 0;
3104 pwLogClust[i] = idx;
3107 if (psa && !psa->fNoGlyphIndex && ((ScriptCache *)*psc)->sfnt)
3109 WCHAR *rChars;
3110 if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
3112 if (!(rChars = heap_calloc(cChars, sizeof(*rChars))))
3113 return E_OUTOFMEMORY;
3115 for (i = 0, g = 0, cluster = 0; i < cChars; i++)
3117 int idx = i;
3118 DWORD chInput;
3120 if (rtl) idx = cChars - 1 - i;
3121 if (!cluster)
3123 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
3124 if (!chInput)
3126 if (psa->fRTL)
3127 chInput = mirror_char(pwcChars[idx]);
3128 else
3129 chInput = pwcChars[idx];
3130 rChars[i] = chInput;
3132 else
3134 rChars[i] = pwcChars[idx];
3135 rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
3136 cluster = 1;
3138 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
3140 WORD glyph;
3141 if (!hdc)
3143 heap_free(rChars);
3144 return E_PENDING;
3146 if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
3148 heap_free(rChars);
3149 return S_FALSE;
3151 pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
3153 g++;
3155 else
3157 int k;
3158 cluster--;
3159 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
3160 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3161 pwLogClust[k]--;
3164 *pcGlyphs = g;
3166 SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3167 SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
3168 SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
3170 for (i = 0; i < cChars; ++i)
3172 /* Special case for tabs and joiners. As control characters, ZWNJ
3173 * and ZWJ would in principle get handled by the corresponding
3174 * shaping functions. However, since ZWNJ and ZWJ can get merged
3175 * into adjoining runs during itemisation, these don't generally
3176 * get classified as Script_Control. */
3177 if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
3179 pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
3180 pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
3183 heap_free(rChars);
3185 else
3187 TRACE("no glyph translation\n");
3188 for (i = 0; i < cChars; i++)
3190 int idx = i;
3191 /* No mirroring done here */
3192 if (rtl) idx = cChars - 1 - i;
3193 pwOutGlyphs[i] = pwcChars[idx];
3195 if (!psa)
3196 continue;
3198 /* overwrite some basic control glyphs to blank */
3199 if (psa->fNoGlyphIndex)
3201 if (pwcChars[idx] == ZWSP || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3203 pwOutGlyphs[i] = 0x20;
3204 pOutGlyphProps[i].sva.fZeroWidth = 1;
3207 else if (psa->eScript == Script_Control || pwcChars[idx] == ZWSP
3208 || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3210 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
3211 pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)
3213 pwOutGlyphs[i] = ((ScriptCache *)*psc)->sfp.wgBlank;
3214 pOutGlyphProps[i].sva.fZeroWidth = 1;
3220 return S_OK;
3224 /***********************************************************************
3225 * ScriptShape (USP10.@)
3227 * Produce glyphs and visual attributes for a run.
3229 * PARAMS
3230 * hdc [I] Device context.
3231 * psc [I/O] Opaque pointer to a script cache.
3232 * pwcChars [I] Array of characters specifying the run.
3233 * cChars [I] Number of characters in pwcChars.
3234 * cMaxGlyphs [I] Length of pwOutGlyphs.
3235 * psa [I/O] Script analysis.
3236 * pwOutGlyphs [O] Array of glyphs.
3237 * pwLogClust [O] Array of logical cluster info.
3238 * psva [O] Array of visual attributes.
3239 * pcGlyphs [O] Number of glyphs returned.
3241 * RETURNS
3242 * Success: S_OK
3243 * Failure: Non-zero HRESULT value.
3245 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
3246 int cChars, int cMaxGlyphs,
3247 SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
3248 SCRIPT_VISATTR *psva, int *pcGlyphs)
3250 HRESULT hr;
3251 int i;
3252 SCRIPT_CHARPROP *charProps;
3253 SCRIPT_GLYPHPROP *glyphProps;
3255 if (!psva || !pcGlyphs) return E_INVALIDARG;
3256 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3258 if (!(charProps = heap_calloc(cChars, sizeof(*charProps))))
3259 return E_OUTOFMEMORY;
3261 if (!(glyphProps = heap_calloc(cMaxGlyphs, sizeof(*glyphProps))))
3263 heap_free(charProps);
3264 return E_OUTOFMEMORY;
3267 hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
3269 if (SUCCEEDED(hr))
3271 for (i = 0; i < *pcGlyphs; i++)
3272 psva[i] = glyphProps[i].sva;
3275 heap_free(charProps);
3276 heap_free(glyphProps);
3278 return hr;
3281 /***********************************************************************
3282 * ScriptPlaceOpenType (USP10.@)
3284 * Produce advance widths for a run.
3286 * PARAMS
3287 * hdc [I] Device context.
3288 * psc [I/O] Opaque pointer to a script cache.
3289 * psa [I/O] Script analysis.
3290 * tagScript [I] The OpenType tag for the Script
3291 * tagLangSys [I] The OpenType tag for the Language
3292 * rcRangeChars[I] Array of Character counts in each range
3293 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3294 * cRanges [I] Count of ranges
3295 * pwcChars [I] Array of characters specifying the run.
3296 * pwLogClust [I] Array of logical cluster info
3297 * pCharProps [I] Array of character property values
3298 * cChars [I] Number of characters in pwcChars.
3299 * pwGlyphs [I] Array of glyphs.
3300 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3301 * cGlyphs [I] Count of Glyphs
3302 * piAdvance [O] Array of advance widths.
3303 * pGoffset [O] Glyph offsets.
3304 * pABC [O] Combined ABC width.
3306 * RETURNS
3307 * Success: S_OK
3308 * Failure: Non-zero HRESULT value.
3311 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
3312 OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
3313 int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
3314 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3315 SCRIPT_CHARPROP *pCharProps, int cChars,
3316 const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
3317 int cGlyphs, int *piAdvance,
3318 GOFFSET *pGoffset, ABC *pABC
3321 HRESULT hr;
3322 int i;
3323 static int once = 0;
3325 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3326 hdc, psc, psa,
3327 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3328 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3329 pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
3330 pGoffset, pABC);
3332 if (!pGlyphProps) return E_INVALIDARG;
3333 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3334 if (!pGoffset) return E_FAIL;
3336 if (cRanges)
3337 if (!once++) FIXME("Ranges not supported yet\n");
3339 ((ScriptCache *)*psc)->userScript = tagScript;
3340 ((ScriptCache *)*psc)->userLang = tagLangSys;
3342 if (pABC) memset(pABC, 0, sizeof(ABC));
3343 for (i = 0; i < cGlyphs; i++)
3345 WORD glyph;
3346 ABC abc;
3348 /* FIXME: set to more reasonable values */
3349 pGoffset[i].du = pGoffset[i].dv = 0;
3351 if (pGlyphProps[i].sva.fZeroWidth)
3353 abc.abcA = abc.abcB = abc.abcC = 0;
3354 if (piAdvance) piAdvance[i] = 0;
3355 continue;
3358 if (psa->fNoGlyphIndex)
3360 if (FAILED(hr = ScriptGetCMap(hdc, psc, &pwGlyphs[i], 1, 0, &glyph))) return hr;
3362 else
3364 hr = S_OK;
3365 glyph = pwGlyphs[i];
3368 if (hr == S_FALSE)
3370 if (!hdc) return E_PENDING;
3371 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
3373 if (!GetCharABCWidthsW(hdc, pwGlyphs[i], pwGlyphs[i], &abc)) return S_FALSE;
3375 else
3377 INT width;
3378 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
3379 abc.abcB = width;
3380 abc.abcA = abc.abcC = 0;
3383 else if (!get_cache_glyph_widths(psc, glyph, &abc))
3385 if (!hdc) return E_PENDING;
3386 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
3388 if (!GetCharABCWidthsI(hdc, glyph, 1, NULL, &abc)) return S_FALSE;
3390 else
3392 INT width;
3393 if (!GetCharWidthI(hdc, glyph, 1, NULL, &width)) return S_FALSE;
3394 abc.abcB = width;
3395 abc.abcA = abc.abcC = 0;
3397 set_cache_glyph_widths(psc, glyph, &abc);
3399 if (pABC)
3401 pABC->abcA += abc.abcA;
3402 pABC->abcB += abc.abcB;
3403 pABC->abcC += abc.abcC;
3405 if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
3408 SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset);
3410 if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
3411 return S_OK;
3414 /***********************************************************************
3415 * ScriptPlace (USP10.@)
3417 * Produce advance widths for a run.
3419 * PARAMS
3420 * hdc [I] Device context.
3421 * psc [I/O] Opaque pointer to a script cache.
3422 * pwGlyphs [I] Array of glyphs.
3423 * cGlyphs [I] Number of glyphs in pwGlyphs.
3424 * psva [I] Array of visual attributes.
3425 * psa [I/O] String analysis.
3426 * piAdvance [O] Array of advance widths.
3427 * pGoffset [O] Glyph offsets.
3428 * pABC [O] Combined ABC width.
3430 * RETURNS
3431 * Success: S_OK
3432 * Failure: Non-zero HRESULT value.
3434 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
3435 int cGlyphs, const SCRIPT_VISATTR *psva,
3436 SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
3438 HRESULT hr;
3439 SCRIPT_GLYPHPROP *glyphProps;
3440 int i;
3442 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
3443 piAdvance, pGoffset, pABC);
3445 if (!psva) return E_INVALIDARG;
3446 if (!pGoffset) return E_FAIL;
3448 if (!(glyphProps = heap_calloc(cGlyphs, sizeof(*glyphProps))))
3449 return E_OUTOFMEMORY;
3451 for (i = 0; i < cGlyphs; i++)
3452 glyphProps[i].sva = psva[i];
3454 hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
3456 heap_free(glyphProps);
3458 return hr;
3461 /***********************************************************************
3462 * ScriptGetCMap (USP10.@)
3464 * Retrieve glyph indices.
3466 * PARAMS
3467 * hdc [I] Device context.
3468 * psc [I/O] Opaque pointer to a script cache.
3469 * pwcInChars [I] Array of Unicode characters.
3470 * cChars [I] Number of characters in pwcInChars.
3471 * dwFlags [I] Flags.
3472 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3474 * RETURNS
3475 * Success: S_OK
3476 * Failure: Non-zero HRESULT value.
3478 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
3479 int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
3481 HRESULT hr;
3482 int i;
3484 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
3485 cChars, dwFlags, pwOutGlyphs);
3487 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3489 hr = S_OK;
3491 for (i = 0; i < cChars; i++)
3493 WCHAR inChar;
3494 if (dwFlags == SGCM_RTL)
3495 inChar = mirror_char(pwcInChars[i]);
3496 else
3497 inChar = pwcInChars[i];
3498 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
3500 WORD glyph;
3501 if (!hdc) return E_PENDING;
3502 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
3503 if (glyph == 0xffff)
3505 hr = S_FALSE;
3506 glyph = 0x0;
3508 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
3512 return hr;
3515 /***********************************************************************
3516 * ScriptTextOut (USP10.@)
3519 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
3520 const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
3521 int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
3522 const int *piJustify, const GOFFSET *pGoffset)
3524 HRESULT hr = S_OK;
3525 INT i, dir = 1;
3526 INT *lpDx;
3527 WORD *reordered_glyphs = (WORD *)pwGlyphs;
3529 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3530 hdc, psc, x, y, fuOptions, wine_dbgstr_rect(lprc), psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
3531 piAdvance, piJustify, pGoffset);
3533 if (!hdc || !psc) return E_INVALIDARG;
3534 if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
3536 fuOptions &= ETO_CLIPPED | ETO_OPAQUE;
3537 fuOptions |= ETO_IGNORELANGUAGE;
3538 if (!psa->fNoGlyphIndex && *psc && ((ScriptCache *)*psc)->sfnt)
3539 fuOptions |= ETO_GLYPH_INDEX; /* We do actually have glyph indices */
3541 if (!(lpDx = heap_calloc(cGlyphs, 2 * sizeof(*lpDx))))
3542 return E_OUTOFMEMORY;
3543 fuOptions |= ETO_PDY;
3545 if (psa->fRTL && psa->fLogicalOrder)
3547 if (!(reordered_glyphs = heap_calloc(cGlyphs, sizeof(*reordered_glyphs))))
3549 heap_free( lpDx );
3550 return E_OUTOFMEMORY;
3553 for (i = 0; i < cGlyphs; i++)
3554 reordered_glyphs[i] = pwGlyphs[cGlyphs - 1 - i];
3555 dir = -1;
3558 for (i = 0; i < cGlyphs; i++)
3560 int orig_index = (dir > 0) ? i : cGlyphs - 1 - i;
3561 lpDx[i * 2] = piAdvance[orig_index];
3562 lpDx[i * 2 + 1] = 0;
3564 if (pGoffset)
3566 if (i == 0)
3568 x += pGoffset[orig_index].du * dir;
3569 y += pGoffset[orig_index].dv;
3571 else
3573 lpDx[(i - 1) * 2] += pGoffset[orig_index].du * dir;
3574 lpDx[(i - 1) * 2 + 1] += pGoffset[orig_index].dv;
3576 lpDx[i * 2] -= pGoffset[orig_index].du * dir;
3577 lpDx[i * 2 + 1] -= pGoffset[orig_index].dv;
3581 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, reordered_glyphs, cGlyphs, lpDx))
3582 hr = S_FALSE;
3584 if (reordered_glyphs != pwGlyphs) heap_free( reordered_glyphs );
3585 heap_free(lpDx);
3587 return hr;
3590 /***********************************************************************
3591 * ScriptCacheGetHeight (USP10.@)
3593 * Retrieve the height of the font in the cache.
3595 * PARAMS
3596 * hdc [I] Device context.
3597 * psc [I/O] Opaque pointer to a script cache.
3598 * height [O] Receives font height.
3600 * RETURNS
3601 * Success: S_OK
3602 * Failure: Non-zero HRESULT value.
3604 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
3606 HRESULT hr;
3608 TRACE("(%p, %p, %p)\n", hdc, psc, height);
3610 if (!height) return E_INVALIDARG;
3611 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3613 *height = get_cache_height(psc);
3614 return S_OK;
3617 /***********************************************************************
3618 * ScriptGetGlyphABCWidth (USP10.@)
3620 * Retrieve the width of a glyph.
3622 * PARAMS
3623 * hdc [I] Device context.
3624 * psc [I/O] Opaque pointer to a script cache.
3625 * glyph [I] Glyph to retrieve the width for.
3626 * abc [O] ABC widths of the glyph.
3628 * RETURNS
3629 * Success: S_OK
3630 * Failure: Non-zero HRESULT value.
3632 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
3634 HRESULT hr;
3636 TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
3638 if (!abc) return E_INVALIDARG;
3639 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3641 if (!get_cache_glyph_widths(psc, glyph, abc))
3643 if (!hdc) return E_PENDING;
3644 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
3646 if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
3648 else
3650 INT width;
3651 if (!GetCharWidthI(hdc, glyph, 1, NULL, &width)) return S_FALSE;
3652 abc->abcB = width;
3653 abc->abcA = abc->abcC = 0;
3655 set_cache_glyph_widths(psc, glyph, abc);
3657 return S_OK;
3660 /***********************************************************************
3661 * ScriptLayout (USP10.@)
3663 * Map embedding levels to visual and/or logical order.
3665 * PARAMS
3666 * runs [I] Size of level array.
3667 * level [I] Array of embedding levels.
3668 * vistolog [O] Map of embedding levels from visual to logical order.
3669 * logtovis [O] Map of embedding levels from logical to visual order.
3671 * RETURNS
3672 * Success: S_OK
3673 * Failure: Non-zero HRESULT value.
3676 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
3678 int* indices;
3679 int ich;
3681 TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
3683 if (!level || (!vistolog && !logtovis))
3684 return E_INVALIDARG;
3686 if (!(indices = heap_calloc(runs, sizeof(*indices))))
3687 return E_OUTOFMEMORY;
3689 if (vistolog)
3691 for( ich = 0; ich < runs; ich++)
3692 indices[ich] = ich;
3694 ich = 0;
3695 while (ich < runs)
3696 ich += BIDI_ReorderV2lLevel(0, indices+ich, level+ich, runs - ich, FALSE);
3697 memcpy(vistolog, indices, runs * sizeof(*vistolog));
3700 if (logtovis)
3702 for( ich = 0; ich < runs; ich++)
3703 indices[ich] = ich;
3705 ich = 0;
3706 while (ich < runs)
3707 ich += BIDI_ReorderL2vLevel(0, indices+ich, level+ich, runs - ich, FALSE);
3708 memcpy(logtovis, indices, runs * sizeof(*logtovis));
3710 heap_free(indices);
3712 return S_OK;
3715 /***********************************************************************
3716 * ScriptStringGetLogicalWidths (USP10.@)
3718 * Returns logical widths from a string analysis.
3720 * PARAMS
3721 * ssa [I] string analysis.
3722 * piDx [O] logical widths returned.
3724 * RETURNS
3725 * Success: S_OK
3726 * Failure: a non-zero HRESULT.
3728 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
3730 int i, j, next = 0;
3731 StringAnalysis *analysis = ssa;
3733 TRACE("%p, %p\n", ssa, piDx);
3735 if (!analysis) return S_FALSE;
3736 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3738 for (i = 0; i < analysis->numItems; i++)
3740 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
3741 int direction = 1;
3743 if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
3744 direction = -1;
3746 for (j = 0; j < cChar; j++)
3748 int k;
3749 int glyph = analysis->glyphs[i].pwLogClust[j];
3750 int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
3751 cChar, j, direction, NULL, NULL);
3752 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);
3754 for (k = 0; k < clust_size; k++)
3756 piDx[next] = advance / clust_size;
3757 next++;
3758 if (k) j++;
3762 return S_OK;
3765 /***********************************************************************
3766 * ScriptStringValidate (USP10.@)
3768 * Validate a string analysis.
3770 * PARAMS
3771 * ssa [I] string analysis.
3773 * RETURNS
3774 * Success: S_OK
3775 * Failure: S_FALSE if invalid sequences are found
3776 * or a non-zero HRESULT if it fails.
3778 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
3780 StringAnalysis *analysis = ssa;
3782 TRACE("(%p)\n", ssa);
3784 if (!analysis) return E_INVALIDARG;
3785 return analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID ? S_FALSE : S_OK;
3788 /***********************************************************************
3789 * ScriptString_pSize (USP10.@)
3791 * Retrieve width and height of an analysed string.
3793 * PARAMS
3794 * ssa [I] string analysis.
3796 * RETURNS
3797 * Success: Pointer to a SIZE structure.
3798 * Failure: NULL
3800 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
3802 int i, j;
3803 StringAnalysis *analysis = ssa;
3805 TRACE("(%p)\n", ssa);
3807 if (!analysis) return NULL;
3808 if (!(analysis->ssa_flags & SSA_GLYPHS)) return NULL;
3810 if (!(analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_SIZE))
3812 analysis->sz.cy = analysis->glyphs[0].sc->tm.tmHeight;
3814 analysis->sz.cx = 0;
3815 for (i = 0; i < analysis->numItems; i++)
3817 if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz.cy)
3818 analysis->sz.cy = analysis->glyphs[i].sc->tm.tmHeight;
3819 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3820 analysis->sz.cx += analysis->glyphs[i].piAdvance[j];
3822 analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_SIZE;
3824 return &analysis->sz;
3827 /***********************************************************************
3828 * ScriptString_pLogAttr (USP10.@)
3830 * Retrieve logical attributes of an analysed string.
3832 * PARAMS
3833 * ssa [I] string analysis.
3835 * RETURNS
3836 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3837 * Failure: NULL
3839 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
3841 StringAnalysis *analysis = ssa;
3843 TRACE("(%p)\n", ssa);
3845 if (!analysis) return NULL;
3846 if (!(analysis->ssa_flags & SSA_BREAK)) return NULL;
3847 return analysis->logattrs;
3850 /***********************************************************************
3851 * ScriptString_pcOutChars (USP10.@)
3853 * Retrieve the length of a string after clipping.
3855 * PARAMS
3856 * ssa [I] String analysis.
3858 * RETURNS
3859 * Success: Pointer to the length.
3860 * Failure: NULL
3862 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
3864 StringAnalysis *analysis = ssa;
3866 TRACE("(%p)\n", ssa);
3868 if (!analysis) return NULL;
3869 return &analysis->clip_len;
3872 /***********************************************************************
3873 * ScriptStringGetOrder (USP10.@)
3875 * Retrieve a glyph order map.
3877 * PARAMS
3878 * ssa [I] String analysis.
3879 * order [I/O] Array of glyph positions.
3881 * RETURNS
3882 * Success: S_OK
3883 * Failure: a non-zero HRESULT.
3885 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
3887 int i, j;
3888 unsigned int k;
3889 StringAnalysis *analysis = ssa;
3891 TRACE("(%p)\n", ssa);
3893 if (!analysis) return S_FALSE;
3894 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3896 /* FIXME: handle RTL scripts */
3897 for (i = 0, k = 0; i < analysis->numItems; i++)
3898 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3899 order[k] = k;
3901 return S_OK;
3904 /***********************************************************************
3905 * ScriptGetLogicalWidths (USP10.@)
3907 * Convert advance widths to logical widths.
3909 * PARAMS
3910 * sa [I] Script analysis.
3911 * nbchars [I] Number of characters.
3912 * nbglyphs [I] Number of glyphs.
3913 * glyph_width [I] Array of glyph widths.
3914 * log_clust [I] Array of logical clusters.
3915 * sva [I] Visual attributes.
3916 * widths [O] Array of logical widths.
3918 * RETURNS
3919 * Success: S_OK
3920 * Failure: a non-zero HRESULT.
3922 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3923 const int *advances, const WORD *log_clust,
3924 const SCRIPT_VISATTR *sva, int *widths)
3926 int i, next = 0, direction;
3928 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3929 sa, nbchars, nbglyphs, advances, log_clust, sva, widths);
3931 if (sa->fRTL && !sa->fLogicalOrder)
3932 direction = -1;
3933 else
3934 direction = 1;
3936 for (i = 0; i < nbchars; i++)
3938 int clust_size = get_cluster_size(log_clust, nbchars, i, direction, NULL, NULL);
3939 int advance = get_glyph_cluster_advance(advances, sva, log_clust, nbglyphs, nbchars, log_clust[i], direction);
3940 int j;
3942 for (j = 0; j < clust_size; j++)
3944 widths[next] = advance / clust_size;
3945 next++;
3946 if (j) i++;
3950 return S_OK;
3953 /***********************************************************************
3954 * ScriptApplyLogicalWidth (USP10.@)
3956 * Generate glyph advance widths.
3958 * PARAMS
3959 * dx [I] Array of logical advance widths.
3960 * num_chars [I] Number of characters.
3961 * num_glyphs [I] Number of glyphs.
3962 * log_clust [I] Array of logical clusters.
3963 * sva [I] Visual attributes.
3964 * advance [I] Array of glyph advance widths.
3965 * sa [I] Script analysis.
3966 * abc [I/O] Summed ABC widths.
3967 * justify [O] Array of glyph advance widths.
3969 * RETURNS
3970 * Success: S_OK
3971 * Failure: a non-zero HRESULT.
3973 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
3974 const WORD *log_clust, const SCRIPT_VISATTR *sva,
3975 const int *advance, const SCRIPT_ANALYSIS *sa,
3976 ABC *abc, int *justify)
3978 int i;
3980 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3981 dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
3983 for (i = 0; i < num_chars; i++) justify[i] = advance[i];
3984 return S_OK;
3987 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
3988 int num_glyphs, int dx, int min_kashida, int *justify)
3990 int i;
3992 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
3994 for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
3995 return S_OK;
3998 HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
4000 HRESULT hr;
4001 if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4002 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4004 return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
4007 HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
4009 HRESULT hr;
4010 if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4011 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4013 return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
4016 HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
4018 HRESULT hr;
4019 if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4020 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4022 return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);
4025 HRESULT WINAPI ScriptGetFontAlternateGlyphs( HDC hdc, SCRIPT_CACHE *sc, SCRIPT_ANALYSIS *sa, OPENTYPE_TAG tag_script, OPENTYPE_TAG tag_langsys, OPENTYPE_TAG tag_feature,
4026 WORD id, int size, WORD *list, int *count )
4028 FIXME("(%p, %p, %p, %s, %s, %s, 0x%04x, %d, %p, %p)\n", hdc, sc, sa, debugstr_an((char*)&tag_script,4), debugstr_an((char*)&tag_langsys,4),
4029 debugstr_an((char*)&tag_feature,4), id, size, list, count);
4031 if(count)
4032 *count = 0;
4034 return E_NOTIMPL;