usp10: Punctuation fixes.
[wine.git] / dlls / usp10 / usp10.c
blobdb12934438f38898f84927302eda15c58a93e283
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/unicode.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
46 typedef struct _scriptRange
48 WORD script;
49 DWORD rangeFirst;
50 DWORD rangeLast;
51 WORD numericScript;
52 WORD punctScript;
53 } scriptRange;
55 static const scriptRange scriptRanges[] = {
56 /* Basic Latin: U+0000–U+007A */
57 { Script_Latin, 0x00, 0x07a , Script_Numeric, Script_Punctuation},
58 /* Latin-1 Supplement: U+0080–U+00FF */
59 /* Latin Extended-A: U+0100–U+017F */
60 /* Latin Extended-B: U+0180–U+024F */
61 /* IPA Extensions: U+0250–U+02AF */
62 /* Spacing Modifier Letters:U+02B0–U+02FF */
63 { Script_Latin, 0x80, 0x2ff , Script_Numeric2, Script_Punctuation},
64 /* Combining Diacritical Marks : U+0300–U+036F */
65 { Script_Diacritical,0x300, 0x36f, 0, 0},
66 /* Greek: U+0370–U+03FF */
67 { Script_Greek, 0x370, 0x3ff, 0, 0},
68 /* Cyrillic: U+0400–U+04FF */
69 /* Cyrillic Supplement: U+0500–U+052F */
70 { Script_Cyrillic, 0x400, 0x52f, 0, 0},
71 /* Armenian: U+0530–U+058F */
72 { Script_Armenian, 0x530, 0x58f, 0, 0},
73 /* Hebrew: U+0590–U+05FF */
74 { Script_Hebrew, 0x590, 0x5ff, 0, 0},
75 /* Arabic: U+0600–U+06FF */
76 { Script_Arabic, 0x600, 0x6ef, Script_Arabic_Numeric, 0},
77 /* Defined by Windows */
78 { Script_Persian, 0x6f0, 0x6f9, 0, 0},
79 /* Continue Arabic: U+0600–U+06FF */
80 { Script_Arabic, 0x6fa, 0x6ff, 0, 0},
81 /* Syriac: U+0700–U+074F*/
82 { Script_Syriac, 0x700, 0x74f, 0, 0},
83 /* Arabic Supplement: U+0750–U+077F */
84 { Script_Arabic, 0x750, 0x77f, 0, 0},
85 /* Thaana: U+0780–U+07BF */
86 { Script_Thaana, 0x780, 0x7bf, 0, 0},
87 /* N’Ko: U+07C0–U+07FF */
88 { Script_NKo, 0x7c0, 0x7ff, 0, 0},
89 /* Devanagari: U+0900–U+097F */
90 { Script_Devanagari, 0x900, 0x97f, Script_Devanagari_Numeric, 0},
91 /* Bengali: U+0980–U+09FF */
92 { Script_Bengali, 0x980, 0x9ff, Script_Bengali_Numeric, 0},
93 /* Gurmukhi: U+0A00–U+0A7F*/
94 { Script_Gurmukhi, 0xa00, 0xa7f, Script_Gurmukhi_Numeric, 0},
95 /* Gujarati: U+0A80–U+0AFF*/
96 { Script_Gujarati, 0xa80, 0xaff, Script_Gujarati_Numeric, 0},
97 /* Oriya: U+0B00–U+0B7F */
98 { Script_Oriya, 0xb00, 0xb7f, Script_Oriya_Numeric, 0},
99 /* Tamil: U+0B80–U+0BFF */
100 { Script_Tamil, 0xb80, 0xbff, Script_Tamil_Numeric, 0},
101 /* Telugu: U+0C00–U+0C7F */
102 { Script_Telugu, 0xc00, 0xc7f, Script_Telugu_Numeric, 0},
103 /* Kannada: U+0C80–U+0CFF */
104 { Script_Kannada, 0xc80, 0xcff, Script_Kannada_Numeric, 0},
105 /* Malayalam: U+0D00–U+0D7F */
106 { Script_Malayalam, 0xd00, 0xd7f, Script_Malayalam_Numeric, 0},
107 /* Sinhala: U+0D80–U+0DFF */
108 { Script_Sinhala, 0xd80, 0xdff, 0, 0},
109 /* Thai: U+0E00–U+0E7F */
110 { Script_Thai, 0xe00, 0xe7f, Script_Thai_Numeric, 0},
111 /* Lao: U+0E80–U+0EFF */
112 { Script_Lao, 0xe80, 0xeff, Script_Lao_Numeric, 0},
113 /* Tibetan: U+0F00–U+0FFF */
114 { Script_Tibetan, 0xf00, 0xfff, 0, 0},
115 /* Myanmar: U+1000–U+109F */
116 { Script_Myanmar, 0x1000, 0x109f, Script_Myanmar_Numeric, 0},
117 /* Georgian: U+10A0–U+10FF */
118 { Script_Georgian, 0x10a0, 0x10ff, 0, 0},
119 /* Hangul Jamo: U+1100–U+11FF */
120 { Script_Hangul, 0x1100, 0x11ff, 0, 0},
121 /* Ethiopic: U+1200–U+137F */
122 /* Ethiopic Extensions: U+1380–U+139F */
123 { Script_Ethiopic, 0x1200, 0x139f, 0, 0},
124 /* Cherokee: U+13A0–U+13FF */
125 { Script_Cherokee, 0x13a0, 0x13ff, 0, 0},
126 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
127 { Script_Canadian, 0x1400, 0x167f, 0, 0},
128 /* Ogham: U+1680–U+169F */
129 { Script_Ogham, 0x1680, 0x169f, 0, 0},
130 /* Runic: U+16A0–U+16F0 */
131 { Script_Runic, 0x16a0, 0x16f0, 0, 0},
132 /* Khmer: U+1780–U+17FF */
133 { Script_Khmer, 0x1780, 0x17ff, Script_Khmer_Numeric, 0},
134 /* Mongolian: U+1800–U+18AF */
135 { Script_Mongolian, 0x1800, 0x18af, Script_Mongolian_Numeric, 0},
136 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
137 { Script_Canadian, 0x18b0, 0x18ff, 0, 0},
138 /* Tai Le: U+1950–U+197F */
139 { Script_Tai_Le, 0x1950, 0x197f, 0, 0},
140 /* New Tai Lue: U+1980–U+19DF */
141 { Script_New_Tai_Lue,0x1980, 0x19df, Script_New_Tai_Lue_Numeric, 0},
142 /* Khmer Symbols: U+19E0–U+19FF */
143 { Script_Khmer, 0x19e0, 0x19ff, Script_Khmer_Numeric, 0},
144 /* Vedic Extensions: U+1CD0-U+1CFF */
145 { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
146 /* Phonetic Extensions: U+1D00–U+1DBF */
147 { Script_Latin, 0x1d00, 0x1dbf, 0, 0},
148 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
149 { Script_Diacritical,0x1dc0, 0x1dff, 0, 0},
150 /* Latin Extended Additional: U+1E00–U+1EFF */
151 { Script_Latin, 0x1e00, 0x1eff, 0, 0},
152 /* Greek Extended: U+1F00–U+1FFF */
153 { Script_Greek, 0x1f00, 0x1fff, 0, 0},
154 /* General Punctuation: U+2000 –U+206f */
155 { Script_Latin, 0x2000, 0x206f, 0, 0},
156 /* Superscripts and Subscripts : U+2070 –U+209f */
157 /* Currency Symbols : U+20a0 –U+20cf */
158 { Script_Numeric2, 0x2070, 0x2070, 0, 0},
159 { Script_Latin, 0x2071, 0x2073, 0, 0},
160 { Script_Numeric2, 0x2074, 0x2079, 0, 0},
161 { Script_Latin, 0x207a, 0x207f, 0, 0},
162 { Script_Numeric2, 0x2080, 0x2089, 0, 0},
163 { Script_Latin, 0x208a, 0x20cf, 0, 0},
164 /* Letterlike Symbols : U+2100 –U+214f */
165 /* Number Forms : U+2150 –U+218f */
166 /* Arrows : U+2190 –U+21ff */
167 /* Mathematical Operators : U+2200 –U+22ff */
168 /* Miscellaneous Technical : U+2300 –U+23ff */
169 /* Control Pictures : U+2400 –U+243f */
170 /* Optical Character Recognition : U+2440 –U+245f */
171 /* Enclosed Alphanumerics : U+2460 –U+24ff */
172 /* Box Drawing : U+2500 –U+25ff */
173 /* Block Elements : U+2580 –U+259f */
174 /* Geometric Shapes : U+25a0 –U+25ff */
175 /* Miscellaneous Symbols : U+2600 –U+26ff */
176 /* Dingbats : U+2700 –U+27bf */
177 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
178 /* Supplemental Arrows-A : U+27f0 –U+27ff */
179 { Script_Latin, 0x2100, 0x27ff, 0, 0},
180 /* Braille Patterns: U+2800–U+28FF */
181 { Script_Braille, 0x2800, 0x28ff, 0, 0},
182 /* Supplemental Arrows-B : U+2900 –U+297f */
183 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
184 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
185 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
186 { Script_Latin, 0x2900, 0x2bff, 0, 0},
187 /* Latin Extended-C: U+2C60–U+2C7F */
188 { Script_Latin, 0x2c60, 0x2c7f, 0, 0},
189 /* Georgian: U+2D00–U+2D2F */
190 { Script_Georgian, 0x2d00, 0x2d2f, 0, 0},
191 /* Tifinagh: U+2D30–U+2D7F */
192 { Script_Tifinagh, 0x2d30, 0x2d7f, 0, 0},
193 /* Ethiopic Extensions: U+2D80–U+2DDF */
194 { Script_Ethiopic, 0x2d80, 0x2ddf, 0, 0},
195 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
196 { Script_Cyrillic, 0x2de0, 0x2dff, 0, 0},
197 /* CJK Radicals Supplement: U+2E80–U+2EFF */
198 /* Kangxi Radicals: U+2F00–U+2FDF */
199 { Script_CJK_Han, 0x2e80, 0x2fdf, 0, 0},
200 /* Ideographic Description Characters: U+2FF0–U+2FFF */
201 { Script_Ideograph ,0x2ff0, 0x2fff, 0, 0},
202 /* CJK Symbols and Punctuation: U+3000–U+303F */
203 { Script_Ideograph ,0x3000, 0x3004, 0, 0},
204 { Script_CJK_Han ,0x3005, 0x3005, 0, 0},
205 { Script_Ideograph ,0x3006, 0x3006, 0, 0},
206 { Script_CJK_Han ,0x3007, 0x3007, 0, 0},
207 { Script_Ideograph ,0x3008, 0x3020, 0, 0},
208 { Script_CJK_Han ,0x3021, 0x3029, 0, 0},
209 { Script_Ideograph ,0x302a, 0x3030, 0, 0},
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},
299 /* END */
300 { SCRIPT_UNDEFINED, 0, 0, 0}
303 /* this must be in order so that the index matches the Script value */
304 const scriptData scriptInformation[] = {
305 {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
306 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
307 0x00000000,
308 {0}},
309 {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
310 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
311 MS_MAKE_TAG('l','a','t','n'),
312 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
313 {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
314 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
315 0x00000000,
316 {0}},
317 {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
318 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
319 0x00000000,
320 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
321 {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
322 {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
323 0x00000000,
324 {0}},
325 {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
326 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
327 0x00000000,
328 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
329 {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
330 {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
331 MS_MAKE_TAG('a','r','a','b'),
332 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
333 {{Script_Arabic_Numeric, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
334 {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
335 MS_MAKE_TAG('a','r','a','b'),
336 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
337 {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
338 {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
339 MS_MAKE_TAG('h','e','b','r'),
340 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
341 {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
342 {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
343 MS_MAKE_TAG('s','y','r','c'),
344 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
345 {{Script_Persian, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
346 {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
347 MS_MAKE_TAG('s','y','r','c'),
348 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
349 {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
350 {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
351 MS_MAKE_TAG('t','h','a','a'),
352 {'M','V',' ','B','o','l','i',0}},
353 {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
354 {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
355 MS_MAKE_TAG('g','r','e','k'),
356 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
357 {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
358 {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
359 MS_MAKE_TAG('c','y','r','l'),
360 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
361 {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
362 {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
363 MS_MAKE_TAG('a','r','m','n'),
364 {'S','y','l','f','a','e','n',0}},
365 {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
366 {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
367 MS_MAKE_TAG('g','e','o','r'),
368 {'S','y','l','f','a','e','n',0}},
369 {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
370 {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
371 MS_MAKE_TAG('s','i','n','h'),
372 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
373 {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
374 {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
375 MS_MAKE_TAG('t','i','b','t'),
376 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
377 {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
378 {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
379 MS_MAKE_TAG('t','i','b','t'),
380 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
381 {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
382 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
383 MS_MAKE_TAG('p','h','a','g'),
384 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
385 {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
386 {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
387 MS_MAKE_TAG('t','h','a','i'),
388 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
389 {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
390 {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
391 MS_MAKE_TAG('t','h','a','i'),
392 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
393 {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
394 {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
395 MS_MAKE_TAG('l','a','o',' '),
396 {'D','o','k','C','h','a','m','p','a',0}},
397 {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
398 {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
399 MS_MAKE_TAG('l','a','o',' '),
400 {'D','o','k','C','h','a','m','p','a',0}},
401 {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
402 {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
403 MS_MAKE_TAG('d','e','v','a'),
404 {'M','a','n','g','a','l',0}},
405 {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
406 {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
407 MS_MAKE_TAG('d','e','v','a'),
408 {'M','a','n','g','a','l',0}},
409 {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
410 {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
411 MS_MAKE_TAG('b','e','n','g'),
412 {'V','r','i','n','d','a',0}},
413 {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
414 {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
415 MS_MAKE_TAG('b','e','n','g'),
416 {'V','r','i','n','d','a',0}},
417 {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
418 {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
419 MS_MAKE_TAG('b','e','n','g'),
420 {'V','r','i','n','d','a',0}},
421 {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
422 {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
423 MS_MAKE_TAG('g','u','r','u'),
424 {'R','a','a','v','i',0}},
425 {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
426 {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
427 MS_MAKE_TAG('g','u','r','u'),
428 {'R','a','a','v','i',0}},
429 {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
430 {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
431 MS_MAKE_TAG('g','u','j','r'),
432 {'S','h','r','u','t','i',0}},
433 {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
434 {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
435 MS_MAKE_TAG('g','u','j','r'),
436 {'S','h','r','u','t','i',0}},
437 {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
438 {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
439 MS_MAKE_TAG('g','u','j','r'),
440 {'S','h','r','u','t','i',0}},
441 {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
442 {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
443 MS_MAKE_TAG('o','r','y','a'),
444 {'K','a','l','i','n','g','a',0}},
445 {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
446 {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
447 MS_MAKE_TAG('o','r','y','a'),
448 {'K','a','l','i','n','g','a',0}},
449 {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
450 {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
451 MS_MAKE_TAG('t','a','m','l'),
452 {'L','a','t','h','a',0}},
453 {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
454 {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
455 MS_MAKE_TAG('t','a','m','l'),
456 {'L','a','t','h','a',0}},
457 {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
458 {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
459 MS_MAKE_TAG('t','e','l','u'),
460 {'G','a','u','t','a','m','i',0}},
461 {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
462 {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
463 MS_MAKE_TAG('t','e','l','u'),
464 {'G','a','u','t','a','m','i',0}},
465 {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
466 {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
467 MS_MAKE_TAG('k','n','d','a'),
468 {'T','u','n','g','a',0}},
469 {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
470 {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
471 MS_MAKE_TAG('k','n','d','a'),
472 {'T','u','n','g','a',0}},
473 {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
474 {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
475 MS_MAKE_TAG('m','l','y','m'),
476 {'K','a','r','t','i','k','a',0}},
477 {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
478 {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
479 MS_MAKE_TAG('m','l','y','m'),
480 {'K','a','r','t','i','k','a',0}},
481 {{Script_Diacritical, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
482 {LANG_ENGLISH, 0, 1, 0, 1, ANSI_CHARSET, 0, 0, 0, 0, 0, 1, 1, 0, 0},
483 0x00000000,
484 {0}},
485 {{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
486 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
487 MS_MAKE_TAG('l','a','t','n'),
488 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
489 {{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
490 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
491 0x00000000,
492 {0}},
493 {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
494 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
495 MS_MAKE_TAG('m','y','m','r'),
496 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
497 {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
498 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
499 MS_MAKE_TAG('m','y','m','r'),
500 {0}},
501 {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
502 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
503 MS_MAKE_TAG('t','a','l','e'),
504 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
505 {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
506 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
507 MS_MAKE_TAG('t','a','l','u'),
508 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
509 {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
510 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
511 MS_MAKE_TAG('t','a','l','u'),
512 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
513 {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
514 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
515 MS_MAKE_TAG('k','h','m','r'),
516 {'D','a','u','n','P','e','n','h',0}},
517 {{Script_Khmer_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
518 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
519 MS_MAKE_TAG('k','h','m','r'),
520 {'D','a','u','n','P','e','n','h',0}},
521 {{Script_CJK_Han, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
522 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
523 MS_MAKE_TAG('h','a','n','i'),
524 {0}},
525 {{Script_Ideograph, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
526 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
527 MS_MAKE_TAG('h','a','n','i'),
528 {0}},
529 {{Script_Bopomofo, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
530 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
531 MS_MAKE_TAG('b','o','p','o'),
532 {0}},
533 {{Script_Kana, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
534 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
535 MS_MAKE_TAG('k','a','n','a'),
536 {0}},
537 {{Script_Hangul, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
538 {LANG_KOREAN, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
539 MS_MAKE_TAG('h','a','n','g'),
540 {0}},
541 {{Script_Yi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
542 {LANG_ENGLISH, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
543 MS_MAKE_TAG('y','i',' ',' '),
544 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
545 {{Script_Ethiopic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
546 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
547 MS_MAKE_TAG('e','t','h','i'),
548 {'N','y','a','l','a',0}},
549 {{Script_Ethiopic_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
550 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
551 MS_MAKE_TAG('e','t','h','i'),
552 {'N','y','a','l','a',0}},
553 {{Script_Mongolian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
554 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
555 MS_MAKE_TAG('m','o','n','g'),
556 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
557 {{Script_Mongolian_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
558 {LANG_MONGOLIAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
559 MS_MAKE_TAG('m','o','n','g'),
560 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
561 {{Script_Tifinagh, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
562 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
563 MS_MAKE_TAG('t','f','n','g'),
564 {'E','b','r','i','m','a',0}},
565 {{Script_NKo, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
566 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
567 MS_MAKE_TAG('n','k','o',' '),
568 {'E','b','r','i','m','a',0}},
569 {{Script_Vai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
570 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
571 MS_MAKE_TAG('v','a','i',' '),
572 {'E','b','r','i','m','a',0}},
573 {{Script_Vai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
574 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
575 MS_MAKE_TAG('v','a','i',' '),
576 {'E','b','r','i','m','a',0}},
577 {{Script_Cherokee, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
578 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
579 MS_MAKE_TAG('c','h','e','r'),
580 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
581 {{Script_Canadian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
582 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
583 MS_MAKE_TAG('c','a','n','s'),
584 {'E','u','p','h','e','m','i','a',0}},
585 {{Script_Ogham, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
586 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
587 MS_MAKE_TAG('o','g','a','m'),
588 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
589 {{Script_Runic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
590 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
591 MS_MAKE_TAG('r','u','n','r'),
592 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
593 {{Script_Braille, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
594 {LANG_ENGLISH, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
595 MS_MAKE_TAG('b','r','a','i'),
596 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
597 {{Script_Surrogates, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
598 {LANG_ENGLISH, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
599 0x00000000,
600 {0}},
601 {{Script_Private, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
602 {0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 1, 0, 0, 0, 0, 1, 0, 0},
603 0x00000000,
604 {0}},
605 {{Script_Deseret, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
606 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
607 MS_MAKE_TAG('d','s','r','t'),
608 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
609 {{Script_Osmanya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
610 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
611 MS_MAKE_TAG('o','s','m','a'),
612 {'E','b','r','i','m','a',0}},
613 {{Script_Osmanya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
614 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
615 MS_MAKE_TAG('o','s','m','a'),
616 {'E','b','r','i','m','a',0}},
617 {{Script_MathAlpha, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
618 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
619 MS_MAKE_TAG('m','a','t','h'),
620 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
621 {{Script_Hebrew_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
622 {LANG_HEBREW, 0, 1, 0, 0, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
623 MS_MAKE_TAG('h','e','b','r'),
624 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
625 {{Script_Vietnamese_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
626 {LANG_VIETNAMESE, 0, 0, 0, 0, VIETNAMESE_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
627 MS_MAKE_TAG('l','a','t','n'),
628 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
629 {{Script_Thai_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
630 {LANG_THAI, 0, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
631 MS_MAKE_TAG('t','h','a','i'),
632 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
635 static const SCRIPT_PROPERTIES *script_props[] =
637 &scriptInformation[0].props, &scriptInformation[1].props,
638 &scriptInformation[2].props, &scriptInformation[3].props,
639 &scriptInformation[4].props, &scriptInformation[5].props,
640 &scriptInformation[6].props, &scriptInformation[7].props,
641 &scriptInformation[8].props, &scriptInformation[9].props,
642 &scriptInformation[10].props, &scriptInformation[11].props,
643 &scriptInformation[12].props, &scriptInformation[13].props,
644 &scriptInformation[14].props, &scriptInformation[15].props,
645 &scriptInformation[16].props, &scriptInformation[17].props,
646 &scriptInformation[18].props, &scriptInformation[19].props,
647 &scriptInformation[20].props, &scriptInformation[21].props,
648 &scriptInformation[22].props, &scriptInformation[23].props,
649 &scriptInformation[24].props, &scriptInformation[25].props,
650 &scriptInformation[26].props, &scriptInformation[27].props,
651 &scriptInformation[28].props, &scriptInformation[29].props,
652 &scriptInformation[30].props, &scriptInformation[31].props,
653 &scriptInformation[32].props, &scriptInformation[33].props,
654 &scriptInformation[34].props, &scriptInformation[35].props,
655 &scriptInformation[36].props, &scriptInformation[37].props,
656 &scriptInformation[38].props, &scriptInformation[39].props,
657 &scriptInformation[40].props, &scriptInformation[41].props,
658 &scriptInformation[42].props, &scriptInformation[43].props,
659 &scriptInformation[44].props, &scriptInformation[45].props,
660 &scriptInformation[46].props, &scriptInformation[47].props,
661 &scriptInformation[48].props, &scriptInformation[49].props,
662 &scriptInformation[50].props, &scriptInformation[51].props,
663 &scriptInformation[52].props, &scriptInformation[53].props,
664 &scriptInformation[54].props, &scriptInformation[55].props,
665 &scriptInformation[56].props, &scriptInformation[57].props,
666 &scriptInformation[58].props, &scriptInformation[59].props,
667 &scriptInformation[60].props, &scriptInformation[61].props,
668 &scriptInformation[62].props, &scriptInformation[63].props,
669 &scriptInformation[64].props, &scriptInformation[65].props,
670 &scriptInformation[66].props, &scriptInformation[67].props,
671 &scriptInformation[68].props, &scriptInformation[69].props,
672 &scriptInformation[70].props, &scriptInformation[71].props,
673 &scriptInformation[72].props, &scriptInformation[73].props,
674 &scriptInformation[74].props, &scriptInformation[75].props,
675 &scriptInformation[76].props, &scriptInformation[77].props,
676 &scriptInformation[78].props, &scriptInformation[79].props,
677 &scriptInformation[80].props, &scriptInformation[81].props
680 typedef struct {
681 ScriptCache *sc;
682 int numGlyphs;
683 WORD* glyphs;
684 WORD* pwLogClust;
685 int* piAdvance;
686 SCRIPT_VISATTR* psva;
687 GOFFSET* pGoffset;
688 ABC* abc;
689 int iMaxPosX;
690 HFONT fallbackFont;
691 } StringGlyphs;
693 typedef struct {
694 HDC hdc;
695 DWORD dwFlags;
696 BOOL invalid;
697 int clip_len;
698 int cItems;
699 int cMaxGlyphs;
700 SCRIPT_ITEM* pItem;
701 int numItems;
702 StringGlyphs* glyphs;
703 SCRIPT_LOGATTR* logattrs;
704 SIZE* sz;
705 int* logical2visual;
706 } StringAnalysis;
708 typedef struct {
709 BOOL ascending;
710 WORD target;
711 } FindGlyph_struct;
713 static inline void *heap_alloc(SIZE_T size)
715 return HeapAlloc(GetProcessHeap(), 0, size);
718 static inline void *heap_alloc_zero(SIZE_T size)
720 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
723 static inline BOOL heap_free(LPVOID mem)
725 return HeapFree(GetProcessHeap(), 0, mem);
728 /* TODO Fix font properties on Arabic locale */
729 static inline BOOL set_cache_font_properties(const HDC hdc, ScriptCache *sc)
731 if (!sc->sfnt)
733 sc->sfp.wgBlank = sc->tm.tmBreakChar;
734 sc->sfp.wgDefault = sc->tm.tmDefaultChar;
735 sc->sfp.wgInvalid = sc->sfp.wgBlank;
736 sc->sfp.wgKashida = 0xFFFF;
737 sc->sfp.iKashidaWidth = 0;
739 else
741 static const WCHAR chars[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
742 /* U+0020: numeric space
743 U+200B: zero width space
744 U+F71B: unknown char found by black box testing
745 U+0640: kashida */
746 WORD gi[4];
748 if (GetGlyphIndicesW(hdc, chars, 4, gi, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
750 if(gi[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
751 sc->sfp.wgBlank = gi[0];
752 else
753 sc->sfp.wgBlank = 0;
755 sc->sfp.wgDefault = 0;
757 if (gi[2] != 0xFFFF)
758 sc->sfp.wgInvalid = gi[2];
759 else if (gi[1] != 0xFFFF)
760 sc->sfp.wgInvalid = gi[1];
761 else if (gi[0] != 0xFFFF)
762 sc->sfp.wgInvalid = gi[0];
763 else
764 sc->sfp.wgInvalid = 0;
766 sc->sfp.wgKashida = gi[3];
768 sc->sfp.iKashidaWidth = 0; /* TODO */
770 else
771 return FALSE;
773 return TRUE;
776 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES *sfp, ScriptCache *sc)
778 sfp->wgBlank = sc->sfp.wgBlank;
779 sfp->wgDefault = sc->sfp.wgDefault;
780 sfp->wgInvalid = sc->sfp.wgInvalid;
781 sfp->wgKashida = sc->sfp.wgKashida;
782 sfp->iKashidaWidth = sc->sfp.iKashidaWidth;
785 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
787 return ((ScriptCache *)*psc)->tm.tmHeight;
790 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
792 return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
795 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
797 CacheGlyphPage *page = ((ScriptCache *)*psc)->page[c / 0x10000];
798 WORD *block;
800 if (!page) return 0;
801 block = page->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
802 if (!block) return 0;
803 return block[(c % 0x10000) & GLYPH_BLOCK_MASK];
806 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
808 CacheGlyphPage **page = &((ScriptCache *)*psc)->page[c / 0x10000];
809 WORD **block;
810 if (!*page && !(*page = heap_alloc_zero(sizeof(CacheGlyphPage)))) return 0;
812 block = &(*page)->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
813 if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
814 return ((*block)[(c % 0x10000) & GLYPH_BLOCK_MASK] = glyph);
817 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
819 static const ABC nil;
820 ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
822 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
823 memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
824 return TRUE;
827 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
829 ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
831 if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
832 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
833 return TRUE;
836 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
838 ScriptCache *sc;
839 int size;
841 if (!psc) return E_INVALIDARG;
842 if (*psc) return S_OK;
843 if (!hdc) return E_PENDING;
845 if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
846 if (!GetTextMetricsW(hdc, &sc->tm))
848 heap_free(sc);
849 return E_INVALIDARG;
851 size = GetOutlineTextMetricsW(hdc, 0, NULL);
852 if (size)
854 sc->otm = heap_alloc(size);
855 sc->otm->otmSize = size;
856 GetOutlineTextMetricsW(hdc, size, sc->otm);
858 if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
860 heap_free(sc);
861 return E_INVALIDARG;
863 sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
864 if (!set_cache_font_properties(hdc, sc))
866 heap_free(sc);
867 return E_INVALIDARG;
869 *psc = sc;
870 TRACE("<- %p\n", sc);
871 return S_OK;
874 static WCHAR mirror_char( WCHAR ch )
876 extern const WCHAR wine_mirror_map[] DECLSPEC_HIDDEN;
877 return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
880 static inline DWORD decode_surrogate_pair(LPCWSTR str, INT index, INT end)
882 if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
884 DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
885 TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
886 return ch;
888 return 0;
891 static WORD get_char_script( LPCWSTR str, INT index, INT end, INT *consumed)
893 static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
894 WORD type = 0;
895 DWORD ch;
896 int i;
898 *consumed = 1;
900 if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
901 return Script_CR;
903 /* These punctuation characters are separated out as Latin punctuation */
904 if (strchrW(latin_punc,str[index]))
905 return Script_Punctuation2;
907 /* These chars are itemized as Punctuation by Windows */
908 if (str[index] == 0x2212 || str[index] == 0x2044)
909 return Script_Punctuation;
911 /* Currency Symbols by Unicode point */
912 switch (str[index])
914 case 0x09f2:
915 case 0x09f3: return Script_Bengali_Currency;
916 case 0x0af1: return Script_Gujarati_Currency;
917 case 0x0e3f: return Script_Thai_Currency;
918 case 0x20aa: return Script_Hebrew_Currency;
919 case 0x20ab: return Script_Vietnamese_Currency;
920 case 0xfb29: return Script_Hebrew_Currency;
923 GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
925 if (type == 0)
926 return SCRIPT_UNDEFINED;
928 if (type & C1_CNTRL)
929 return Script_Control;
931 ch = decode_surrogate_pair(str, index, end);
932 if (ch)
933 *consumed = 2;
934 else
935 ch = str[index];
937 i = 0;
940 if (ch < scriptRanges[i].rangeFirst || scriptRanges[i].script == SCRIPT_UNDEFINED)
941 break;
943 if (ch >= scriptRanges[i].rangeFirst && ch <= scriptRanges[i].rangeLast)
945 if (scriptRanges[i].numericScript && type & C1_DIGIT)
946 return scriptRanges[i].numericScript;
947 if (scriptRanges[i].punctScript && type & C1_PUNCT)
948 return scriptRanges[i].punctScript;
949 return scriptRanges[i].script;
951 i++;
952 } while (1);
954 return SCRIPT_UNDEFINED;
957 static int compare_FindGlyph(const void *a, const void* b)
959 const FindGlyph_struct *find = (FindGlyph_struct*)a;
960 const WORD *idx= (WORD*)b;
961 int rc = 0;
963 if ( find->target > *idx)
964 rc = 1;
965 else if (find->target < *idx)
966 rc = -1;
968 if (!find->ascending)
969 rc *= -1;
970 return rc;
973 int USP10_FindGlyphInLogClust(const WORD* pwLogClust, int cChars, WORD target)
975 FindGlyph_struct fgs;
976 WORD *ptr;
977 INT k;
979 if (pwLogClust[0] < pwLogClust[cChars-1])
980 fgs.ascending = TRUE;
981 else
982 fgs.ascending = FALSE;
984 fgs.target = target;
985 ptr = bsearch(&fgs, pwLogClust, cChars, sizeof(WORD), compare_FindGlyph);
987 if (!ptr)
988 return -1;
990 for (k = (ptr - pwLogClust)-1; k >= 0 && pwLogClust[k] == target; k--)
992 k++;
994 return k;
997 /***********************************************************************
998 * ScriptFreeCache (USP10.@)
1000 * Free a script cache.
1002 * PARAMS
1003 * psc [I/O] Script cache.
1005 * RETURNS
1006 * Success: S_OK
1007 * Failure: Non-zero HRESULT value.
1009 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
1011 TRACE("%p\n", psc);
1013 if (psc && *psc)
1015 unsigned int i;
1016 INT n;
1017 for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
1019 heap_free(((ScriptCache *)*psc)->widths[i]);
1021 for (i = 0; i < 0x10; i++)
1023 unsigned int j;
1024 if (((ScriptCache *)*psc)->page[i])
1025 for (j = 0; j < GLYPH_MAX / GLYPH_BLOCK_SIZE; j++)
1026 heap_free(((ScriptCache *)*psc)->page[i]->glyphs[j]);
1027 heap_free(((ScriptCache *)*psc)->page[i]);
1029 heap_free(((ScriptCache *)*psc)->GSUB_Table);
1030 heap_free(((ScriptCache *)*psc)->GDEF_Table);
1031 heap_free(((ScriptCache *)*psc)->CMAP_Table);
1032 heap_free(((ScriptCache *)*psc)->GPOS_Table);
1033 for (n = 0; n < ((ScriptCache *)*psc)->script_count; n++)
1035 int j;
1036 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].language_count; j++)
1038 int k;
1039 for (k = 0; k < ((ScriptCache *)*psc)->scripts[n].languages[j].feature_count; k++)
1040 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features[k].lookups);
1041 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features);
1043 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].default_language.feature_count; j++)
1044 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features[j].lookups);
1045 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features);
1046 heap_free(((ScriptCache *)*psc)->scripts[n].languages);
1048 heap_free(((ScriptCache *)*psc)->scripts);
1049 heap_free(((ScriptCache *)*psc)->otm);
1050 heap_free(*psc);
1051 *psc = NULL;
1053 return S_OK;
1056 /***********************************************************************
1057 * ScriptGetProperties (USP10.@)
1059 * Retrieve a list of script properties.
1061 * PARAMS
1062 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1063 * num [I] Pointer to the number of scripts.
1065 * RETURNS
1066 * Success: S_OK
1067 * Failure: Non-zero HRESULT value.
1069 * NOTES
1070 * Behaviour matches WinXP.
1072 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
1074 TRACE("(%p,%p)\n", props, num);
1076 if (!props && !num) return E_INVALIDARG;
1078 if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
1079 if (props) *props = script_props;
1081 return S_OK;
1084 /***********************************************************************
1085 * ScriptGetFontProperties (USP10.@)
1087 * Get information on special glyphs.
1089 * PARAMS
1090 * hdc [I] Device context.
1091 * psc [I/O] Opaque pointer to a script cache.
1092 * sfp [O] Font properties structure.
1094 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
1096 HRESULT hr;
1098 TRACE("%p,%p,%p\n", hdc, psc, sfp);
1100 if (!sfp) return E_INVALIDARG;
1101 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1103 if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
1104 return E_INVALIDARG;
1106 get_cache_font_properties(sfp, *psc);
1108 return S_OK;
1111 /***********************************************************************
1112 * ScriptRecordDigitSubstitution (USP10.@)
1114 * Record digit substitution settings for a given locale.
1116 * PARAMS
1117 * locale [I] Locale identifier.
1118 * sds [I] Structure to record substitution settings.
1120 * RETURNS
1121 * Success: S_OK
1122 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1124 * SEE ALSO
1125 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1127 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
1129 DWORD plgid, sub;
1131 TRACE("0x%x, %p\n", locale, sds);
1133 /* This implementation appears to be correct for all languages, but it's
1134 * not clear if sds->DigitSubstitute is ever set to anything except
1135 * CONTEXT or NONE in reality */
1137 if (!sds) return E_POINTER;
1139 locale = ConvertDefaultLocale(locale);
1141 if (!IsValidLocale(locale, LCID_INSTALLED))
1142 return E_INVALIDARG;
1144 plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
1145 sds->TraditionalDigitLanguage = plgid;
1147 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1148 sds->NationalDigitLanguage = plgid;
1149 else
1150 sds->NationalDigitLanguage = LANG_ENGLISH;
1152 if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
1153 (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
1155 switch (sub)
1157 case 0:
1158 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1159 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
1160 else
1161 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1162 break;
1163 case 1:
1164 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1165 break;
1166 case 2:
1167 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
1168 break;
1169 default:
1170 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
1171 break;
1174 sds->dwReserved = 0;
1175 return S_OK;
1178 /***********************************************************************
1179 * ScriptApplyDigitSubstitution (USP10.@)
1181 * Apply digit substitution settings.
1183 * PARAMS
1184 * sds [I] Structure with recorded substitution settings.
1185 * sc [I] Script control structure.
1186 * ss [I] Script state structure.
1188 * RETURNS
1189 * Success: S_OK
1190 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1192 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds,
1193 SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
1195 SCRIPT_DIGITSUBSTITUTE psds;
1197 TRACE("%p, %p, %p\n", sds, sc, ss);
1199 if (!sc || !ss) return E_POINTER;
1200 if (!sds)
1202 sds = &psds;
1203 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
1204 return E_INVALIDARG;
1207 sc->uDefaultLanguage = LANG_ENGLISH;
1208 sc->fContextDigits = 0;
1209 ss->fDigitSubstitute = 0;
1211 switch (sds->DigitSubstitute) {
1212 case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
1213 case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
1214 case SCRIPT_DIGITSUBSTITUTE_NONE:
1215 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
1216 return S_OK;
1217 default:
1218 return E_INVALIDARG;
1222 static inline BOOL is_indic(WORD script)
1224 return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
1227 static inline WORD base_indic(WORD script)
1229 switch (script)
1231 case Script_Devanagari:
1232 case Script_Devanagari_Numeric: return Script_Devanagari;
1233 case Script_Bengali:
1234 case Script_Bengali_Numeric:
1235 case Script_Bengali_Currency: return Script_Bengali;
1236 case Script_Gurmukhi:
1237 case Script_Gurmukhi_Numeric: return Script_Gurmukhi;
1238 case Script_Gujarati:
1239 case Script_Gujarati_Numeric:
1240 case Script_Gujarati_Currency: return Script_Gujarati;
1241 case Script_Oriya:
1242 case Script_Oriya_Numeric: return Script_Oriya;
1243 case Script_Tamil:
1244 case Script_Tamil_Numeric: return Script_Tamil;
1245 case Script_Telugu:
1246 case Script_Telugu_Numeric: return Script_Telugu;
1247 case Script_Kannada:
1248 case Script_Kannada_Numeric: return Script_Kannada;
1249 case Script_Malayalam:
1250 case Script_Malayalam_Numeric: return Script_Malayalam;
1251 default:
1252 return -1;
1257 static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
1258 int cMaxItems, const SCRIPT_CONTROL *psControl,
1259 const SCRIPT_STATE *psState, SCRIPT_ITEM *pItems,
1260 OPENTYPE_TAG *pScriptTags, int *pcItems)
1263 #define Numeric_space 0x0020
1264 #define ZWNJ 0x200C
1265 #define ZWJ 0x200D
1267 int cnt = 0, index = 0, str = 0;
1268 int New_Script = -1;
1269 int i;
1270 WORD *levels = NULL;
1271 WORD *layout_levels = NULL;
1272 WORD *overrides = NULL;
1273 WORD *strength = NULL;
1274 WORD *scripts = NULL;
1275 WORD baselevel = 0;
1276 WORD baselayout = 0;
1277 BOOL new_run;
1278 WORD last_indic = -1;
1279 WORD layoutRTL = 0;
1280 BOOL forceLevels = FALSE;
1281 INT consumed = 0;
1282 HRESULT res = E_OUTOFMEMORY;
1284 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
1285 psControl, psState, pItems, pcItems);
1287 if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
1288 return E_INVALIDARG;
1290 scripts = heap_alloc(cInChars * sizeof(WORD));
1291 if (!scripts)
1292 return E_OUTOFMEMORY;
1294 for (i = 0; i < cInChars; i++)
1296 if (consumed <= 0)
1298 scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
1299 consumed --;
1301 else
1303 scripts[i] = scripts[i-1];
1304 consumed --;
1306 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1307 all Indic scripts */
1308 if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic > 0)
1309 scripts[i] = last_indic;
1310 else if (is_indic(scripts[i]))
1311 last_indic = base_indic(scripts[i]);
1313 /* Some unicode points :
1314 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1315 (Left Right Embed U+202A - Left Right Override U+202D)
1316 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1317 will force us into bidi mode */
1318 if (!forceLevels && ((pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F) ||
1319 (pwcInChars[i] >= 0x202A && pwcInChars[i] <= 0x202E) ||
1320 (pwcInChars[i] >= 0x2066 && pwcInChars[i] <= 0x2069)))
1322 forceLevels = TRUE;
1324 /* Diacritical marks merge with other scripts */
1325 if (scripts[i] == Script_Diacritical)
1327 if (i > 0)
1329 if (pScriptTags)
1330 scripts[i] = scripts[i-1];
1331 else
1333 int j;
1334 BOOL asian = FALSE;
1335 WORD first_script = scripts[i-1];
1336 for (j = i-1; j >= 0 && scripts[j] == first_script && pwcInChars[j] != Numeric_space; j--)
1338 WORD original = scripts[j];
1339 if (original == Script_Ideograph || original == Script_Kana || original == Script_Yi || original == Script_CJK_Han || original == Script_Bopomofo)
1341 asian = TRUE;
1342 break;
1344 if (original != Script_MathAlpha && scriptInformation[scripts[j]].props.fComplex)
1345 break;
1346 scripts[j] = scripts[i];
1347 if (original == Script_Punctuation2)
1348 break;
1350 if (j >= 0 && (scriptInformation[scripts[j]].props.fComplex || asian))
1351 scripts[i] = scripts[j];
1357 for (i = 0; i < cInChars; i++)
1359 /* Joiners get merged preferencially right */
1360 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
1362 int j;
1363 if (i+1 == cInChars)
1364 scripts[i] = scripts[i-1];
1365 else
1367 for (j = i+1; j < cInChars; j++)
1369 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
1371 scripts[i] = scripts[j];
1372 break;
1379 if (psState && psControl)
1381 levels = heap_alloc_zero(cInChars * sizeof(WORD));
1382 if (!levels)
1383 goto nomemory;
1385 overrides = heap_alloc_zero(cInChars * sizeof(WORD));
1386 if (!overrides)
1387 goto nomemory;
1389 layout_levels = heap_alloc_zero(cInChars * sizeof(WORD));
1390 if (!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 static const WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1434 static const WCHAR repeatable_math_punc[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1436 strength = heap_alloc_zero(cInChars * sizeof(WORD));
1437 if (!strength)
1438 goto nomemory;
1439 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
1441 /* We currently mis-level leading Diacriticals */
1442 if (scripts[0] == Script_Diacritical)
1443 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
1445 levels[i] = odd(levels[i])?levels[i]+1:levels[i];
1446 strength[i] = BIDI_STRONG;
1449 /* Math punctuation bordered on both sides by numbers can be
1450 merged into the number */
1451 for (i = 0; i < cInChars; i++)
1453 if (i > 0 && i < cInChars-1 &&
1454 scripts[i-1] == Script_Numeric &&
1455 strchrW(math_punc, pwcInChars[i]))
1457 if (scripts[i+1] == Script_Numeric)
1459 scripts[i] = Script_Numeric;
1460 levels[i] = levels[i-1];
1461 strength[i] = strength[i-1];
1462 i++;
1464 else if (strchrW(repeatable_math_punc, pwcInChars[i]))
1466 int j;
1467 for (j = i+1; j < cInChars; j++)
1469 if (scripts[j] == Script_Numeric)
1471 for(;i<j; i++)
1473 scripts[i] = Script_Numeric;
1474 levels[i] = levels[i-1];
1475 strength[i] = strength[i-1];
1478 else if (pwcInChars[i] != pwcInChars[j]) break;
1484 for (i = 0; i < cInChars; i++)
1486 /* Script_Numeric at level 0 get bumped to level 2 */
1487 if (!overrides[i] && (levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && scripts[i] == Script_Numeric)
1489 levels[i] = 2;
1492 /* Joiners get merged preferencially right */
1493 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
1495 int j;
1496 if (i+1 == cInChars && levels[i-1] == levels[i])
1497 strength[i] = strength[i-1];
1498 else
1499 for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
1500 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
1502 strength[i] = strength[j];
1503 break;
1507 if (psControl->fMergeNeutralItems)
1509 /* Merge the neutrals */
1510 for (i = 0; i < cInChars; i++)
1512 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1514 int j;
1515 for (j = i; j > 0; j--)
1517 if (levels[i] != levels[j])
1518 break;
1519 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1521 scripts[i] = scripts[j];
1522 strength[i] = strength[j];
1523 break;
1527 /* Try going the other way */
1528 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1530 int j;
1531 for (j = i; j < cInChars; j++)
1533 if (levels[i] != levels[j])
1534 break;
1535 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1537 scripts[i] = scripts[j];
1538 strength[i] = strength[j];
1539 break;
1548 while ((!levels || (levels && cnt+1 < cInChars && levels[cnt+1] == levels[0]))
1549 && (cnt < cInChars && pwcInChars[cnt] == Numeric_space))
1550 cnt++;
1552 if (cnt == cInChars) /* All Spaces */
1554 cnt = 0;
1555 New_Script = scripts[cnt];
1558 pItems[index].iCharPos = 0;
1559 pItems[index].a = scriptInformation[scripts[cnt]].a;
1560 if (pScriptTags)
1561 pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
1563 if (strength && strength[cnt] == BIDI_STRONG)
1564 str = strength[cnt];
1565 else if (strength)
1566 str = strength[0];
1568 cnt = 0;
1570 if (levels)
1572 if (strength[cnt] == BIDI_STRONG)
1573 layoutRTL = odd(layout_levels[cnt]);
1574 else
1575 layoutRTL = (psState->uBidiLevel || odd(layout_levels[cnt]));
1576 if (overrides)
1577 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1578 pItems[index].a.fRTL = odd(levels[cnt]);
1579 if (pItems[index].a.eScript == Script_Numeric ||
1580 pItems[index].a.eScript == Script_Numeric2)
1581 pItems[index].a.fLayoutRTL = layoutRTL;
1582 else
1583 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1584 pItems[index].a.s.uBidiLevel = levels[cnt];
1586 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1588 if (pItems[index].a.s.uBidiLevel != baselevel)
1589 pItems[index].a.s.fOverrideDirection = TRUE;
1590 layoutRTL = odd(baselayout);
1591 pItems[index].a.s.uBidiLevel = baselevel;
1592 pItems[index].a.fRTL = odd(baselevel);
1593 if (pItems[index].a.eScript == Script_Numeric ||
1594 pItems[index].a.eScript == Script_Numeric2)
1595 pItems[index].a.fLayoutRTL = odd(baselayout);
1596 else
1597 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1600 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1601 levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
1602 pItems[index].iCharPos);
1604 for (cnt=1; cnt < cInChars; cnt++)
1606 if(pwcInChars[cnt] != Numeric_space)
1607 New_Script = scripts[cnt];
1608 else if (levels)
1610 int j = 1;
1611 while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
1612 j++;
1613 if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
1614 New_Script = scripts[cnt+j];
1615 else
1616 New_Script = scripts[cnt];
1619 new_run = FALSE;
1620 /* merge space strengths*/
1621 if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
1622 str = BIDI_STRONG;
1624 if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
1625 str = BIDI_NEUTRAL;
1627 /* changes in level */
1628 if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
1630 TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
1631 new_run = TRUE;
1633 /* changes in strength */
1634 else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
1636 TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
1637 new_run = TRUE;
1639 /* changes in script */
1640 else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
1642 TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
1643 new_run = TRUE;
1646 if (!new_run && strength && str == BIDI_STRONG)
1648 layoutRTL = odd(layout_levels[cnt]);
1649 if (pItems[index].a.eScript == Script_Numeric ||
1650 pItems[index].a.eScript == Script_Numeric2)
1651 pItems[index].a.fLayoutRTL = layoutRTL;
1654 if (new_run)
1656 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);
1658 index++;
1659 if (index+1 > cMaxItems)
1660 goto nomemory;
1662 if (strength)
1663 str = strength[cnt];
1665 pItems[index].iCharPos = cnt;
1666 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1668 pItems[index].a = scriptInformation[New_Script].a;
1669 if (pScriptTags)
1670 pScriptTags[index] = scriptInformation[New_Script].scriptTag;
1671 if (levels)
1673 if (overrides)
1674 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1675 if (layout_levels[cnt] == 0)
1676 layoutRTL = 0;
1677 else
1678 layoutRTL = (layoutRTL || odd(layout_levels[cnt]));
1679 pItems[index].a.fRTL = odd(levels[cnt]);
1680 if (pItems[index].a.eScript == Script_Numeric ||
1681 pItems[index].a.eScript == Script_Numeric2)
1682 pItems[index].a.fLayoutRTL = layoutRTL;
1683 else
1684 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1685 pItems[index].a.s.uBidiLevel = levels[cnt];
1687 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1689 if (pItems[index].a.s.uBidiLevel != baselevel)
1690 pItems[index].a.s.fOverrideDirection = TRUE;
1691 pItems[index].a.s.uBidiLevel = baselevel;
1692 pItems[index].a.fRTL = odd(baselevel);
1693 if (pItems[index].a.eScript == Script_Numeric||
1694 pItems[index].a.eScript == Script_Numeric2)
1695 pItems[index].a.fLayoutRTL = layoutRTL;
1696 else
1697 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1700 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1704 /* While not strictly necessary according to the spec, make sure the n+1
1705 * item is set up to prevent random behaviour if the caller erroneously
1706 * checks the n+1 structure */
1707 index++;
1708 if (index + 1 > cMaxItems) goto nomemory;
1709 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1711 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1713 /* Set one SCRIPT_STATE item being returned */
1714 if (pcItems) *pcItems = index;
1716 /* Set SCRIPT_ITEM */
1717 pItems[index].iCharPos = cnt; /* the last item contains the ptr to the lastchar */
1718 res = S_OK;
1719 nomemory:
1720 heap_free(levels);
1721 heap_free(overrides);
1722 heap_free(layout_levels);
1723 heap_free(strength);
1724 heap_free(scripts);
1725 return res;
1728 /***********************************************************************
1729 * ScriptItemizeOpenType (USP10.@)
1731 * Split a Unicode string into shapeable parts.
1733 * PARAMS
1734 * pwcInChars [I] String to split.
1735 * cInChars [I] Number of characters in pwcInChars.
1736 * cMaxItems [I] Maximum number of items to return.
1737 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1738 * psState [I] Pointer to a SCRIPT_STATE structure.
1739 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1740 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1741 * pcItems [O] Number of script items returned.
1743 * RETURNS
1744 * Success: S_OK
1745 * Failure: Non-zero HRESULT value.
1747 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1748 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1749 SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
1751 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pScriptTags, pcItems);
1754 /***********************************************************************
1755 * ScriptItemize (USP10.@)
1757 * Split a Unicode string into shapeable parts.
1759 * PARAMS
1760 * pwcInChars [I] String to split.
1761 * cInChars [I] Number of characters in pwcInChars.
1762 * cMaxItems [I] Maximum number of items to return.
1763 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1764 * psState [I] Pointer to a SCRIPT_STATE structure.
1765 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1766 * pcItems [O] Number of script items returned.
1768 * RETURNS
1769 * Success: S_OK
1770 * Failure: Non-zero HRESULT value.
1772 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1773 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1774 SCRIPT_ITEM *pItems, int *pcItems)
1776 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, NULL, pcItems);
1779 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1781 int defWidth;
1782 int cTabStops=0;
1783 INT *lpTabPos = NULL;
1784 INT nTabOrg = 0;
1785 INT x = 0;
1787 if (pTabdef)
1788 lpTabPos = pTabdef->pTabStops;
1790 if (pTabdef && pTabdef->iTabOrigin)
1792 if (pTabdef->iScale)
1793 nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1794 else
1795 nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1798 if (pTabdef)
1799 cTabStops = pTabdef->cTabStops;
1801 if (cTabStops == 1)
1803 if (pTabdef->iScale)
1804 defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1805 else
1806 defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1807 cTabStops = 0;
1809 else
1810 defWidth = 8 * psc->tm.tmAveCharWidth;
1812 for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1814 int position = *lpTabPos;
1815 if (position < 0)
1816 position = -1 * position;
1817 if (pTabdef->iScale)
1818 position = (position * pTabdef->iScale) / 4;
1819 else
1820 position = position * psc->tm.tmAveCharWidth;
1822 if( nTabOrg + position > current_x)
1824 if( *lpTabPos >= 0)
1826 /* a left aligned tab */
1827 x = (nTabOrg + *lpTabPos) - current_x;
1828 break;
1830 else
1832 FIXME("Negative tabstop\n");
1833 break;
1837 if ((!cTabStops) && (defWidth > 0))
1838 x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1839 else if ((!cTabStops) && (defWidth < 0))
1840 FIXME("TODO: Negative defWidth\n");
1842 return x;
1845 /***********************************************************************
1846 * Helper function for ScriptStringAnalyse
1848 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1849 const WCHAR *pwcInChars, int cChars )
1851 /* FIXME: When to properly fallback is still a bit of a mystery */
1852 WORD *glyphs;
1854 if (psa->fNoGlyphIndex)
1855 return FALSE;
1857 if (init_script_cache(hdc, psc) != S_OK)
1858 return FALSE;
1860 if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1861 return TRUE;
1863 glyphs = heap_alloc(sizeof(WORD) * cChars);
1864 if (!glyphs)
1865 return FALSE;
1866 if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1868 heap_free(glyphs);
1869 return TRUE;
1871 heap_free(glyphs);
1873 return FALSE;
1876 static void find_fallback_font(DWORD scriptid, LPWSTR FaceName)
1878 HKEY hkey;
1880 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1882 static const WCHAR szFmt[] = {'%','x',0};
1883 WCHAR value[10];
1884 DWORD count = LF_FACESIZE * sizeof(WCHAR);
1885 DWORD type;
1887 sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1888 if (RegQueryValueExW(hkey, value, 0, &type, (LPBYTE)FaceName, &count))
1889 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1890 RegCloseKey(hkey);
1892 else
1893 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1896 /***********************************************************************
1897 * ScriptStringAnalyse (USP10.@)
1900 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1901 int cGlyphs, int iCharset, DWORD dwFlags,
1902 int iReqWidth, SCRIPT_CONTROL *psControl,
1903 SCRIPT_STATE *psState, const int *piDx,
1904 SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1905 SCRIPT_STRING_ANALYSIS *pssa)
1907 HRESULT hr = E_OUTOFMEMORY;
1908 StringAnalysis *analysis = NULL;
1909 SCRIPT_CONTROL sControl;
1910 SCRIPT_STATE sState;
1911 int i, num_items = 255;
1912 BYTE *BidiLevel;
1913 WCHAR *iString = NULL;
1915 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1916 hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1917 psControl, psState, piDx, pTabdef, pbInClass, pssa);
1919 if (iCharset != -1)
1921 FIXME("Only Unicode strings are supported\n");
1922 return E_INVALIDARG;
1924 if (cString < 1 || !pString) return E_INVALIDARG;
1925 if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1927 if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1928 if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1930 /* FIXME: handle clipping */
1931 analysis->clip_len = cString;
1932 analysis->hdc = hdc;
1933 analysis->dwFlags = dwFlags;
1935 if (psState)
1936 sState = *psState;
1937 else
1938 memset(&sState, 0, sizeof(SCRIPT_STATE));
1940 if (psControl)
1941 sControl = *psControl;
1942 else
1943 memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1945 if (dwFlags & SSA_PASSWORD)
1947 iString = heap_alloc(sizeof(WCHAR)*cString);
1948 if (!iString)
1950 hr = E_OUTOFMEMORY;
1951 goto error;
1953 for (i = 0; i < cString; i++)
1954 iString[i] = *((const WCHAR *)pString);
1955 pString = iString;
1958 hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1959 &analysis->numItems);
1961 if (FAILED(hr))
1963 if (hr == E_OUTOFMEMORY)
1964 hr = E_INVALIDARG;
1965 goto error;
1968 /* set back to out of memory for default goto error behaviour */
1969 hr = E_OUTOFMEMORY;
1971 if (dwFlags & SSA_BREAK)
1973 if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
1975 for (i = 0; i < analysis->numItems; i++)
1976 ScriptBreak(&((LPWSTR)pString)[analysis->pItem[i].iCharPos], analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos, &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
1978 else
1979 goto error;
1982 if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
1983 goto error;
1984 if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
1985 goto error;
1987 if (dwFlags & SSA_GLYPHS)
1989 int tab_x = 0;
1990 if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
1992 heap_free(BidiLevel);
1993 goto error;
1996 for (i = 0; i < analysis->numItems; i++)
1998 SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
1999 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2000 int numGlyphs = 1.5 * cChar + 16;
2001 WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
2002 WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
2003 int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
2004 SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
2005 GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
2006 ABC *abc = heap_alloc_zero(sizeof(ABC));
2007 int numGlyphsReturned;
2008 HFONT originalFont = 0x0;
2010 /* FIXME: non unicode strings */
2011 const WCHAR* pStr = (const WCHAR*)pString;
2012 analysis->glyphs[i].fallbackFont = NULL;
2014 if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
2016 heap_free (BidiLevel);
2017 heap_free (glyphs);
2018 heap_free (pwLogClust);
2019 heap_free (piAdvance);
2020 heap_free (psva);
2021 heap_free (pGoffset);
2022 heap_free (abc);
2023 hr = E_OUTOFMEMORY;
2024 goto error;
2027 if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
2029 LOGFONTW lf;
2030 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
2031 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
2032 lf.lfFaceName[0] = 0;
2033 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
2034 if (lf.lfFaceName[0])
2036 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
2037 if (analysis->glyphs[i].fallbackFont)
2039 ScriptFreeCache(sc);
2040 originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
2045 /* FIXME: When we properly shape Hangul remove this check */
2046 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && analysis->pItem[i].a.eScript == Script_Hangul)
2047 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2049 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && !scriptInformation[analysis->pItem[i].a.eScript].props.fComplex && !analysis->pItem[i].a.fRTL)
2050 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2052 ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos], cChar, numGlyphs,
2053 &analysis->pItem[i].a, glyphs, pwLogClust, psva, &numGlyphsReturned);
2054 hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
2055 piAdvance, pGoffset, abc);
2056 if (originalFont)
2057 SelectObject(hdc,originalFont);
2059 if (dwFlags & SSA_TAB)
2061 int tabi = 0;
2062 for (tabi = 0; tabi < cChar; tabi++)
2064 if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
2065 piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
2066 tab_x+=piAdvance[tabi];
2070 analysis->glyphs[i].numGlyphs = numGlyphsReturned;
2071 analysis->glyphs[i].glyphs = glyphs;
2072 analysis->glyphs[i].pwLogClust = pwLogClust;
2073 analysis->glyphs[i].piAdvance = piAdvance;
2074 analysis->glyphs[i].psva = psva;
2075 analysis->glyphs[i].pGoffset = pGoffset;
2076 analysis->glyphs[i].abc = abc;
2077 analysis->glyphs[i].iMaxPosX= -1;
2079 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2082 else
2084 for (i = 0; i < analysis->numItems; i++)
2085 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2088 ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
2089 heap_free(BidiLevel);
2091 *pssa = analysis;
2092 heap_free(iString);
2093 return S_OK;
2095 error:
2096 heap_free(iString);
2097 heap_free(analysis->glyphs);
2098 heap_free(analysis->logattrs);
2099 heap_free(analysis->pItem);
2100 heap_free(analysis->logical2visual);
2101 heap_free(analysis);
2102 return hr;
2105 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
2107 if (pva[glyph].fClusterStart)
2108 return TRUE;
2109 if (USP10_FindGlyphInLogClust(pwLogClust, cChars, glyph) >= 0)
2110 return TRUE;
2112 return FALSE;
2116 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
2117 int iX,
2118 int iY,
2119 int iItem,
2120 int cStart,
2121 int cEnd,
2122 UINT uOptions,
2123 const RECT *prc,
2124 BOOL fSelected,
2125 BOOL fDisabled)
2127 StringAnalysis *analysis;
2128 int off_x = 0;
2129 HRESULT hr;
2130 COLORREF BkColor = 0x0;
2131 COLORREF TextColor = 0x0;
2132 INT BkMode = 0;
2133 INT runStart, runEnd;
2134 INT iGlyph, cGlyphs;
2135 HFONT oldFont = 0x0;
2136 RECT crc;
2137 int i;
2139 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2140 ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
2142 if (!(analysis = ssa)) return E_INVALIDARG;
2144 if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
2145 (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
2146 return S_OK;
2148 CopyRect(&crc,prc);
2149 if (fSelected)
2151 BkMode = GetBkMode(analysis->hdc);
2152 SetBkMode( analysis->hdc, OPAQUE);
2153 BkColor = GetBkColor(analysis->hdc);
2154 SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
2155 if (!fDisabled)
2157 TextColor = GetTextColor(analysis->hdc);
2158 SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
2161 if (analysis->glyphs[iItem].fallbackFont)
2162 oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
2164 if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
2165 runStart = cStart - analysis->pItem[iItem].iCharPos;
2166 else
2167 runStart = 0;
2168 if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
2169 runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
2170 else
2171 runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
2173 if (analysis->pItem[iItem].a.fRTL)
2175 if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
2176 ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
2177 else
2178 ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
2179 crc.left = iX + off_x;
2181 else
2183 if (cStart >=0 && runStart)
2184 ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
2185 else
2186 ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
2187 crc.left = iX + off_x;
2190 if (analysis->pItem[iItem].a.fRTL)
2191 iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
2192 else
2193 iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
2195 if (analysis->pItem[iItem].a.fRTL)
2196 cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
2197 else
2198 cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
2200 cGlyphs++;
2202 /* adjust for cluster glyphs when starting */
2203 if (analysis->pItem[iItem].a.fRTL)
2204 i = analysis->pItem[iItem+1].iCharPos - 1;
2205 else
2206 i = analysis->pItem[iItem].iCharPos;
2208 for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
2210 if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
2212 if (analysis->pItem[iItem].a.fRTL)
2213 ScriptStringCPtoX(ssa, i, TRUE, &off_x);
2214 else
2215 ScriptStringCPtoX(ssa, i, FALSE, &off_x);
2216 break;
2220 if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
2222 INT direction;
2223 INT clust_glyph;
2225 clust_glyph = iGlyph + cGlyphs;
2226 if (analysis->pItem[iItem].a.fRTL)
2227 direction = -1;
2228 else
2229 direction = 1;
2231 while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
2232 !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
2234 cGlyphs++;
2235 clust_glyph++;
2239 hr = ScriptTextOut(analysis->hdc,
2240 (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
2241 iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
2242 &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
2243 &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
2244 &analysis->glyphs[iItem].pGoffset[iGlyph]);
2246 TRACE("ScriptTextOut hr=%08x\n", hr);
2248 if (fSelected)
2250 SetBkColor(analysis->hdc, BkColor);
2251 SetBkMode( analysis->hdc, BkMode);
2252 if (!fDisabled)
2253 SetTextColor(analysis->hdc, TextColor);
2255 if (analysis->glyphs[iItem].fallbackFont)
2256 SelectObject(analysis->hdc, oldFont);
2258 return hr;
2261 /***********************************************************************
2262 * ScriptStringOut (USP10.@)
2264 * This function takes the output of ScriptStringAnalyse and joins the segments
2265 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2266 * only processes glyphs.
2268 * Parameters:
2269 * ssa [I] buffer to hold the analysed string components
2270 * iX [I] X axis displacement for output
2271 * iY [I] Y axis displacement for output
2272 * uOptions [I] flags controlling output processing
2273 * prc [I] rectangle coordinates
2274 * iMinSel [I] starting pos for substringing output string
2275 * iMaxSel [I] ending pos for substringing output string
2276 * fDisabled [I] controls text highlighting
2278 * RETURNS
2279 * Success: S_OK
2280 * Failure: is the value returned by ScriptTextOut
2282 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
2283 int iX,
2284 int iY,
2285 UINT uOptions,
2286 const RECT *prc,
2287 int iMinSel,
2288 int iMaxSel,
2289 BOOL fDisabled)
2291 StringAnalysis *analysis;
2292 int item;
2293 HRESULT hr;
2295 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2296 ssa, iX, iY, uOptions, wine_dbgstr_rect(prc), iMinSel, iMaxSel, fDisabled);
2298 if (!(analysis = ssa)) return E_INVALIDARG;
2299 if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
2301 for (item = 0; item < analysis->numItems; item++)
2303 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
2304 if (FAILED(hr))
2305 return hr;
2308 if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
2310 if (iMaxSel > 0 && iMinSel < 0)
2311 iMinSel = 0;
2312 for (item = 0; item < analysis->numItems; item++)
2314 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
2315 if (FAILED(hr))
2316 return hr;
2320 return S_OK;
2323 /***********************************************************************
2324 * ScriptStringCPtoX (USP10.@)
2327 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
2329 int item;
2330 int runningX = 0;
2331 StringAnalysis* analysis = ssa;
2333 TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
2335 if (!ssa || !pX) return S_FALSE;
2336 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2338 /* icp out of range */
2339 if(icp < 0)
2341 analysis->invalid = TRUE;
2342 return E_INVALIDARG;
2345 for(item=0; item<analysis->numItems; item++)
2347 int CP, i;
2348 int offset;
2350 i = analysis->logical2visual[item];
2351 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2352 /* initialize max extents for uninitialized runs */
2353 if (analysis->glyphs[i].iMaxPosX == -1)
2355 if (analysis->pItem[i].a.fRTL)
2356 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2357 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2358 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2359 else
2360 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2361 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2362 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2365 if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
2367 runningX += analysis->glyphs[i].iMaxPosX;
2368 continue;
2371 icp -= analysis->pItem[i].iCharPos;
2372 ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2373 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2374 &analysis->pItem[i].a, &offset);
2375 runningX += offset;
2377 *pX = runningX;
2378 return S_OK;
2381 /* icp out of range */
2382 analysis->invalid = TRUE;
2383 return E_INVALIDARG;
2386 /***********************************************************************
2387 * ScriptStringXtoCP (USP10.@)
2390 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
2392 StringAnalysis* analysis = ssa;
2393 int item;
2395 TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
2397 if (!ssa || !piCh || !piTrailing) return S_FALSE;
2398 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2400 /* out of range */
2401 if(iX < 0)
2403 if (analysis->pItem[0].a.fRTL)
2405 *piCh = 1;
2406 *piTrailing = FALSE;
2408 else
2410 *piCh = -1;
2411 *piTrailing = TRUE;
2413 return S_OK;
2416 for(item=0; item<analysis->numItems; item++)
2418 int i;
2419 int CP;
2421 for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
2422 /* nothing */;
2424 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2425 /* initialize max extents for uninitialized runs */
2426 if (analysis->glyphs[i].iMaxPosX == -1)
2428 if (analysis->pItem[i].a.fRTL)
2429 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2430 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2431 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2432 else
2433 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2434 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2435 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2438 if (iX > analysis->glyphs[i].iMaxPosX)
2440 iX -= analysis->glyphs[i].iMaxPosX;
2441 continue;
2444 ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2445 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2446 &analysis->pItem[i].a, piCh, piTrailing);
2447 *piCh += analysis->pItem[i].iCharPos;
2449 return S_OK;
2452 /* out of range */
2453 *piCh = analysis->pItem[analysis->numItems].iCharPos;
2454 *piTrailing = FALSE;
2456 return S_OK;
2460 /***********************************************************************
2461 * ScriptStringFree (USP10.@)
2463 * Free a string analysis.
2465 * PARAMS
2466 * pssa [I] string analysis.
2468 * RETURNS
2469 * Success: S_OK
2470 * Failure: Non-zero HRESULT value.
2472 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
2474 StringAnalysis* analysis;
2475 BOOL invalid;
2476 int i;
2478 TRACE("(%p)\n", pssa);
2480 if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
2482 invalid = analysis->invalid;
2484 if (analysis->glyphs)
2486 for (i = 0; i < analysis->numItems; i++)
2488 heap_free(analysis->glyphs[i].glyphs);
2489 heap_free(analysis->glyphs[i].pwLogClust);
2490 heap_free(analysis->glyphs[i].piAdvance);
2491 heap_free(analysis->glyphs[i].psva);
2492 heap_free(analysis->glyphs[i].pGoffset);
2493 heap_free(analysis->glyphs[i].abc);
2494 if (analysis->glyphs[i].fallbackFont)
2495 DeleteObject(analysis->glyphs[i].fallbackFont);
2496 ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
2497 heap_free(analysis->glyphs[i].sc);
2499 heap_free(analysis->glyphs);
2502 heap_free(analysis->pItem);
2503 heap_free(analysis->logattrs);
2504 heap_free(analysis->sz);
2505 heap_free(analysis->logical2visual);
2506 heap_free(analysis);
2508 if (invalid) return E_INVALIDARG;
2509 return S_OK;
2512 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
2513 int direction, int* iCluster, int *check_out)
2515 int clust_size = 1;
2516 int check;
2517 WORD clust = pwLogClust[item];
2519 for (check = item+direction; check < cChars && check >= 0; check+=direction)
2521 if (pwLogClust[check] == clust)
2523 clust_size ++;
2524 if (iCluster && *iCluster == -1)
2525 *iCluster = item;
2527 else break;
2530 if (check_out)
2531 *check_out = check;
2533 return clust_size;
2536 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)
2538 int advance;
2539 int log_clust_max;
2541 advance = piAdvance[glyph];
2543 if (pwLogClust[0] > pwLogClust[cChars-1])
2544 log_clust_max = pwLogClust[0];
2545 else
2546 log_clust_max = pwLogClust[cChars-1];
2548 if (glyph > log_clust_max)
2549 return advance;
2551 for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
2554 if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
2555 break;
2556 if (glyph > log_clust_max)
2557 break;
2558 advance += piAdvance[glyph];
2561 return advance;
2564 /***********************************************************************
2565 * ScriptCPtoX (USP10.@)
2568 HRESULT WINAPI ScriptCPtoX(int iCP,
2569 BOOL fTrailing,
2570 int cChars,
2571 int cGlyphs,
2572 const WORD *pwLogClust,
2573 const SCRIPT_VISATTR *psva,
2574 const int *piAdvance,
2575 const SCRIPT_ANALYSIS *psa,
2576 int *piX)
2578 int item;
2579 float iPosX;
2580 int iSpecial = -1;
2581 int iCluster = -1;
2582 int clust_size = 1;
2583 float special_size = 0.0;
2584 int iMaxPos = 0;
2585 int advance = 0;
2586 BOOL rtl = FALSE;
2588 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2589 iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2590 psa, piX);
2592 if (psa->fRTL && ! psa->fLogicalOrder)
2593 rtl = TRUE;
2595 if (fTrailing)
2596 iCP++;
2598 if (rtl)
2600 int max_clust = pwLogClust[0];
2602 for (item=0; item < cGlyphs; item++)
2603 if (pwLogClust[item] > max_clust)
2605 ERR("We do not handle non reversed clusters properly\n");
2606 break;
2609 iMaxPos = 0;
2610 for (item = max_clust; item >=0; item --)
2611 iMaxPos += piAdvance[item];
2614 iPosX = 0.0;
2615 for (item=0; item < iCP && item < cChars; item++)
2617 if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
2619 int check;
2620 int clust = pwLogClust[item];
2622 iCluster = -1;
2623 clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2624 &check);
2626 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2628 if (check >= cChars && !iMaxPos)
2630 int glyph;
2631 for (glyph = clust; glyph < cGlyphs; glyph++)
2632 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, glyph, 1);
2633 iSpecial = item;
2634 special_size /= (cChars - item);
2635 iPosX += special_size;
2637 else
2639 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2641 clust_size --;
2642 if (clust_size == 0)
2643 iPosX += advance;
2645 else
2646 iPosX += advance / (float)clust_size;
2649 else if (iSpecial != -1)
2650 iPosX += special_size;
2651 else /* (iCluster != -1) */
2653 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2654 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2656 clust_size --;
2657 if (clust_size == 0)
2658 iPosX += adv;
2660 else
2661 iPosX += adv / (float)clust_size;
2665 if (iMaxPos > 0)
2667 iPosX = iMaxPos - iPosX;
2668 if (iPosX < 0)
2669 iPosX = 0;
2672 *piX = iPosX;
2673 TRACE("*piX=%d\n", *piX);
2674 return S_OK;
2677 /* Count the number of characters in a cluster and its starting index*/
2678 static inline BOOL get_cluster_data(const WORD *pwLogClust, int cChars, int cluster_index, int *cluster_size, int *start_index)
2680 int size = 0;
2681 int i;
2683 for (i = 0; i < cChars; i++)
2685 if (pwLogClust[i] == cluster_index)
2687 if (!size && start_index)
2689 *start_index = i;
2690 if (!cluster_size)
2691 return TRUE;
2693 size++;
2695 else if (size) break;
2697 if (cluster_size)
2698 *cluster_size = size;
2700 return (size > 0);
2704 To handle multi-glyph clusters we need to find all the glyphs that are
2705 represented in the cluster. This involves finding the glyph whose
2706 index is the cluster index as well as whose glyph indices are greater than
2707 our cluster index but not part of a new cluster.
2709 Then we sum all those glyphs' advances.
2711 static inline int get_cluster_advance(const int* piAdvance,
2712 const SCRIPT_VISATTR *psva,
2713 const WORD *pwLogClust, int cGlyphs,
2714 int cChars, int cluster, int direction)
2716 int glyph_start;
2717 int glyph_end;
2718 int i, advance;
2720 if (direction > 0)
2721 i = 0;
2722 else
2723 i = (cChars - 1);
2725 for (glyph_start = -1, glyph_end = -1; i < cChars && i >= 0 && (glyph_start < 0 || glyph_end < 0); i+=direction)
2727 if (glyph_start < 0 && pwLogClust[i] != cluster) continue;
2728 if (pwLogClust[i] == cluster && glyph_start < 0) glyph_start = pwLogClust[i];
2729 if (glyph_start >= 0 && glyph_end < 0 && pwLogClust[i] != cluster) glyph_end = pwLogClust[i];
2731 if (glyph_end < 0)
2733 if (direction > 0)
2734 glyph_end = cGlyphs;
2735 else
2737 /* Don't fully understand multi-glyph reversed clusters yet,
2738 * do they occur for real or just in our test? */
2739 FIXME("multi-glyph reversed clusters found\n");
2740 glyph_end = glyph_start + 1;
2744 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2745 for (i = glyph_start+1; i< glyph_end; i++)
2747 if (psva[i].fClusterStart)
2749 glyph_end = i;
2750 break;
2754 for (advance = 0, i = glyph_start; i < glyph_end; i++)
2755 advance += piAdvance[i];
2757 return advance;
2761 /***********************************************************************
2762 * ScriptXtoCP (USP10.@)
2764 * Basic algorithm :
2765 * Use piAdvance to find the cluster we are looking at.
2766 * Find the character that is the first character of the cluster.
2767 * That is our base piCP.
2768 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2769 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2770 * determine how far through the cluster to advance the cursor.
2772 HRESULT WINAPI ScriptXtoCP(int iX,
2773 int cChars,
2774 int cGlyphs,
2775 const WORD *pwLogClust,
2776 const SCRIPT_VISATTR *psva,
2777 const int *piAdvance,
2778 const SCRIPT_ANALYSIS *psa,
2779 int *piCP,
2780 int *piTrailing)
2782 int direction = 1;
2783 int iPosX;
2784 int i;
2785 int glyph_index, cluster_index;
2786 int cluster_size;
2788 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2789 iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2790 psa, piCP, piTrailing);
2792 if (psa->fRTL && ! psa->fLogicalOrder)
2793 direction = -1;
2795 /* Handle an iX < 0 */
2796 if (iX < 0)
2798 if (direction < 0)
2800 *piCP = cChars;
2801 *piTrailing = 0;
2803 else
2805 *piCP = -1;
2806 *piTrailing = 1;
2808 return S_OK;
2811 /* Looking for non-reversed clusters in a reversed string */
2812 if (direction < 0)
2814 int max_clust = pwLogClust[0];
2815 for (i=0; i< cChars; i++)
2816 if (pwLogClust[i] > max_clust)
2818 FIXME("We do not handle non reversed clusters properly\n");
2819 break;
2823 /* find the glyph_index based in iX */
2824 if (direction > 0)
2826 for (glyph_index = -1, iPosX = iX; iPosX >=0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2829 else
2831 for (glyph_index = -1, iPosX = iX; iPosX > 0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2835 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX, glyph_index, cGlyphs);
2837 *piTrailing = 0;
2838 if (glyph_index >= 0 && glyph_index < cGlyphs)
2840 /* find the cluster */
2841 if (direction > 0 )
2842 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] <= glyph_index; cluster_index=pwLogClust[i++])
2844 else
2845 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] >= glyph_index; cluster_index=pwLogClust[i++])
2848 TRACE("cluster_index %i\n", cluster_index);
2850 if (direction < 0 && iPosX >= 0 && glyph_index != cluster_index)
2852 /* We are off the end of the string */
2853 *piCP = -1;
2854 *piTrailing = 1;
2855 return S_OK;
2858 get_cluster_data(pwLogClust, cChars, cluster_index, &cluster_size, &i);
2860 TRACE("first char index %i\n",i);
2861 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2863 /* Check trailing */
2864 if (glyph_index != cluster_index ||
2865 (direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2866 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2867 *piTrailing = cluster_size;
2869 else
2871 if (cluster_size > 1)
2873 /* Be part way through the glyph cluster based on size and position */
2874 int cluster_advance = get_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, cluster_index, direction);
2875 double cluster_part_width = cluster_advance / (float)cluster_size;
2876 double adv;
2877 int part_index;
2879 /* back up to the beginning of the cluster */
2880 for (adv = iPosX, part_index = cluster_index; part_index <= glyph_index; part_index++)
2881 adv += piAdvance[part_index];
2882 if (adv > iX) adv = iX;
2884 TRACE("Multi-char cluster, no snap\n");
2885 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size, adv);
2886 TRACE("advance %i divides into %f per char\n", cluster_advance, cluster_part_width);
2887 if (direction > 0)
2889 for (part_index = 0; adv >= 0; adv-=cluster_part_width, part_index++)
2891 if (part_index) part_index--;
2893 else
2895 for (part_index = 0; adv > 0; adv-=cluster_part_width, part_index++)
2897 if (part_index > cluster_size)
2899 adv += cluster_part_width;
2900 part_index=cluster_size;
2904 TRACE("base_char %i part_index %i, leftover advance %f\n",i, part_index, adv);
2906 if (direction > 0)
2907 i += part_index;
2908 else
2909 i += (cluster_size - part_index);
2911 /* Check trailing */
2912 if ((direction > 0 && fabs(adv) <= (cluster_part_width / 2.0)) ||
2913 (direction < 0 && adv && fabs(adv) >= (cluster_part_width / 2.0)))
2914 *piTrailing = 1;
2916 else
2918 /* Check trailing */
2919 if ((direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2920 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2921 *piTrailing = 1;
2925 else
2927 TRACE("Point falls outside of string\n");
2928 if (glyph_index < 0)
2929 i = cChars-1;
2930 else /* (glyph_index >= cGlyphs) */
2931 i = cChars;
2933 /* If not snaping in the reverse direction (such as Hebrew) Then 0
2934 point flow to the next character */
2935 if (direction < 0)
2937 if (!scriptInformation[psa->eScript].props.fNeedsCaretInfo && abs(iPosX) == piAdvance[glyph_index])
2938 i++;
2939 else
2940 *piTrailing = 1;
2944 *piCP = i;
2946 TRACE("*piCP=%d\n", *piCP);
2947 TRACE("*piTrailing=%d\n", *piTrailing);
2948 return S_OK;
2951 /***********************************************************************
2952 * ScriptBreak (USP10.@)
2954 * Retrieve line break information.
2956 * PARAMS
2957 * chars [I] Array of characters.
2958 * sa [I] Script analysis.
2959 * la [I] Array of logical attribute structures.
2961 * RETURNS
2962 * Success: S_OK
2963 * Failure: S_FALSE
2965 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2967 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2969 if (count < 0 || !la) return E_INVALIDARG;
2970 if (count == 0) return E_FAIL;
2972 BREAK_line(chars, count, sa, la);
2974 return S_OK;
2977 /***********************************************************************
2978 * ScriptIsComplex (USP10.@)
2980 * Determine if a string is complex.
2982 * PARAMS
2983 * chars [I] Array of characters to test.
2984 * len [I] Length in characters.
2985 * flag [I] Flag.
2987 * RETURNS
2988 * Success: S_OK
2989 * Failure: S_FALSE
2992 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
2994 int i;
2995 INT consumed = 0;
2997 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
2999 for (i = 0; i < len; i+=consumed)
3001 int script;
3002 if (i >= len)
3003 break;
3005 if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
3006 return S_OK;
3008 script = get_char_script(chars,i,len, &consumed);
3009 if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
3010 (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
3011 return S_OK;
3013 return S_FALSE;
3016 /***********************************************************************
3017 * ScriptShapeOpenType (USP10.@)
3019 * Produce glyphs and visual attributes for a run.
3021 * PARAMS
3022 * hdc [I] Device context.
3023 * psc [I/O] Opaque pointer to a script cache.
3024 * psa [I/O] Script analysis.
3025 * tagScript [I] The OpenType tag for the Script
3026 * tagLangSys [I] The OpenType tag for the Language
3027 * rcRangeChars[I] Array of Character counts in each range
3028 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3029 * cRanges [I] Count of ranges
3030 * pwcChars [I] Array of characters specifying the run.
3031 * cChars [I] Number of characters in pwcChars.
3032 * cMaxGlyphs [I] Length of pwOutGlyphs.
3033 * pwLogClust [O] Array of logical cluster info.
3034 * pCharProps [O] Array of character property values
3035 * pwOutGlyphs [O] Array of glyphs.
3036 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3037 * pcGlyphs [O] Number of glyphs returned.
3039 * RETURNS
3040 * Success: S_OK
3041 * Failure: Non-zero HRESULT value.
3043 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
3044 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3045 OPENTYPE_TAG tagLangSys, int *rcRangeChars,
3046 TEXTRANGE_PROPERTIES **rpRangeProperties,
3047 int cRanges, const WCHAR *pwcChars, int cChars,
3048 int cMaxGlyphs, WORD *pwLogClust,
3049 SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
3050 SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
3052 HRESULT hr;
3053 int i;
3054 unsigned int g;
3055 BOOL rtl;
3056 int cluster;
3057 static int once = 0;
3059 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3060 hdc, psc, psa,
3061 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3062 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3063 cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
3065 if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
3066 psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
3068 if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
3069 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3071 if (cRanges)
3072 if(!once++) FIXME("Ranges not supported yet\n");
3074 rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
3076 *pcGlyphs = cChars;
3077 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3078 if (!pwLogClust) return E_FAIL;
3080 ((ScriptCache *)*psc)->userScript = tagScript;
3081 ((ScriptCache *)*psc)->userLang = tagLangSys;
3083 /* set fNoGlyphIndex non truetype/opentype fonts */
3084 if (psa && !psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
3085 psa->fNoGlyphIndex = TRUE;
3087 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3088 for (i = 0; i < cChars; i++)
3090 int idx = i;
3091 if (rtl) idx = cChars - 1 - i;
3092 /* FIXME: set to better values */
3093 pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
3094 pOutGlyphProps[i].sva.fClusterStart = 1;
3095 pOutGlyphProps[i].sva.fDiacritic = 0;
3096 pOutGlyphProps[i].sva.fZeroWidth = 0;
3097 pOutGlyphProps[i].sva.fReserved = 0;
3098 pOutGlyphProps[i].sva.fShapeReserved = 0;
3100 /* FIXME: have the shaping engine set this */
3101 pCharProps[i].fCanGlyphAlone = 0;
3103 pwLogClust[i] = idx;
3106 if (psa && !psa->fNoGlyphIndex)
3108 WCHAR *rChars;
3109 if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
3111 rChars = heap_alloc(sizeof(WCHAR) * cChars);
3112 if (!rChars) return E_OUTOFMEMORY;
3113 for (i = 0, g = 0, cluster = 0; i < cChars; i++)
3115 int idx = i;
3116 DWORD chInput;
3118 if (rtl) idx = cChars - 1 - i;
3119 if (!cluster)
3121 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
3122 if (!chInput)
3124 if (psa->fRTL)
3125 chInput = mirror_char(pwcChars[idx]);
3126 else
3127 chInput = pwcChars[idx];
3128 /* special case for tabs */
3129 if (chInput == 0x0009)
3130 chInput = 0x0020;
3131 rChars[i] = chInput;
3133 else
3135 rChars[i] = pwcChars[idx];
3136 rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
3137 cluster = 1;
3139 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
3141 WORD glyph;
3142 if (!hdc)
3144 heap_free(rChars);
3145 return E_PENDING;
3147 if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
3149 heap_free(rChars);
3150 return S_FALSE;
3152 pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
3154 g++;
3156 else
3158 int k;
3159 cluster--;
3160 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
3161 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3162 pwLogClust[k]--;
3165 *pcGlyphs = g;
3167 SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3168 SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
3169 SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
3170 heap_free(rChars);
3172 else
3174 TRACE("no glyph translation\n");
3175 for (i = 0; i < cChars; i++)
3177 int idx = i;
3178 /* No mirroring done here */
3179 if (rtl) idx = cChars - 1 - i;
3180 pwOutGlyphs[i] = pwcChars[idx];
3182 /* overwrite some basic control glyphs to blank */
3183 if (psa && psa->eScript == Script_Control &&
3184 pwcChars[idx] < ((ScriptCache *)*psc)->tm.tmFirstChar)
3186 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
3187 pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)
3188 pwOutGlyphs[i] = ((ScriptCache *)*psc)->sfp.wgBlank;
3193 return S_OK;
3197 /***********************************************************************
3198 * ScriptShape (USP10.@)
3200 * Produce glyphs and visual attributes for a run.
3202 * PARAMS
3203 * hdc [I] Device context.
3204 * psc [I/O] Opaque pointer to a script cache.
3205 * pwcChars [I] Array of characters specifying the run.
3206 * cChars [I] Number of characters in pwcChars.
3207 * cMaxGlyphs [I] Length of pwOutGlyphs.
3208 * psa [I/O] Script analysis.
3209 * pwOutGlyphs [O] Array of glyphs.
3210 * pwLogClust [O] Array of logical cluster info.
3211 * psva [O] Array of visual attributes.
3212 * pcGlyphs [O] Number of glyphs returned.
3214 * RETURNS
3215 * Success: S_OK
3216 * Failure: Non-zero HRESULT value.
3218 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
3219 int cChars, int cMaxGlyphs,
3220 SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
3221 SCRIPT_VISATTR *psva, int *pcGlyphs)
3223 HRESULT hr;
3224 int i;
3225 SCRIPT_CHARPROP *charProps;
3226 SCRIPT_GLYPHPROP *glyphProps;
3228 if (!psva || !pcGlyphs) return E_INVALIDARG;
3229 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3231 charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
3232 if (!charProps) return E_OUTOFMEMORY;
3233 glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
3234 if (!glyphProps)
3236 heap_free(charProps);
3237 return E_OUTOFMEMORY;
3240 hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
3242 if (SUCCEEDED(hr))
3244 for (i = 0; i < *pcGlyphs; i++)
3245 psva[i] = glyphProps[i].sva;
3248 heap_free(charProps);
3249 heap_free(glyphProps);
3251 return hr;
3254 /***********************************************************************
3255 * ScriptPlaceOpenType (USP10.@)
3257 * Produce advance widths for a run.
3259 * PARAMS
3260 * hdc [I] Device context.
3261 * psc [I/O] Opaque pointer to a script cache.
3262 * psa [I/O] Script analysis.
3263 * tagScript [I] The OpenType tag for the Script
3264 * tagLangSys [I] The OpenType tag for the Language
3265 * rcRangeChars[I] Array of Character counts in each range
3266 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3267 * cRanges [I] Count of ranges
3268 * pwcChars [I] Array of characters specifying the run.
3269 * pwLogClust [I] Array of logical cluster info
3270 * pCharProps [I] Array of character property values
3271 * cChars [I] Number of characters in pwcChars.
3272 * pwGlyphs [I] Array of glyphs.
3273 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3274 * cGlyphs [I] Count of Glyphs
3275 * piAdvance [O] Array of advance widths.
3276 * pGoffset [O] Glyph offsets.
3277 * pABC [O] Combined ABC width.
3279 * RETURNS
3280 * Success: S_OK
3281 * Failure: Non-zero HRESULT value.
3284 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
3285 OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
3286 int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
3287 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3288 SCRIPT_CHARPROP *pCharProps, int cChars,
3289 const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
3290 int cGlyphs, int *piAdvance,
3291 GOFFSET *pGoffset, ABC *pABC
3294 HRESULT hr;
3295 int i;
3296 static int once = 0;
3298 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3299 hdc, psc, psa,
3300 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3301 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3302 pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
3303 pGoffset, pABC);
3305 if (!pGlyphProps) return E_INVALIDARG;
3306 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3307 if (!pGoffset) return E_FAIL;
3309 if (cRanges)
3310 if (!once++) FIXME("Ranges not supported yet\n");
3312 ((ScriptCache *)*psc)->userScript = tagScript;
3313 ((ScriptCache *)*psc)->userLang = tagLangSys;
3315 if (pABC) memset(pABC, 0, sizeof(ABC));
3316 for (i = 0; i < cGlyphs; i++)
3318 ABC abc;
3319 if (pGlyphProps[i].sva.fZeroWidth)
3321 abc.abcA = abc.abcB = abc.abcC = 0;
3323 else if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
3325 if (!hdc) return E_PENDING;
3326 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
3328 if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
3330 else
3332 INT width;
3333 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
3334 abc.abcB = width;
3335 abc.abcA = abc.abcC = 0;
3337 set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
3339 if (pABC)
3341 pABC->abcA += abc.abcA;
3342 pABC->abcB += abc.abcB;
3343 pABC->abcC += abc.abcC;
3345 /* FIXME: set to more reasonable values */
3346 pGoffset[i].du = pGoffset[i].dv = 0;
3347 if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
3350 SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset);
3352 if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
3353 return S_OK;
3356 /***********************************************************************
3357 * ScriptPlace (USP10.@)
3359 * Produce advance widths for a run.
3361 * PARAMS
3362 * hdc [I] Device context.
3363 * psc [I/O] Opaque pointer to a script cache.
3364 * pwGlyphs [I] Array of glyphs.
3365 * cGlyphs [I] Number of glyphs in pwGlyphs.
3366 * psva [I] Array of visual attributes.
3367 * psa [I/O] String analysis.
3368 * piAdvance [O] Array of advance widths.
3369 * pGoffset [O] Glyph offsets.
3370 * pABC [O] Combined ABC width.
3372 * RETURNS
3373 * Success: S_OK
3374 * Failure: Non-zero HRESULT value.
3376 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
3377 int cGlyphs, const SCRIPT_VISATTR *psva,
3378 SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
3380 HRESULT hr;
3381 SCRIPT_GLYPHPROP *glyphProps;
3382 int i;
3384 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
3385 piAdvance, pGoffset, pABC);
3387 if (!psva) return E_INVALIDARG;
3388 if (!pGoffset) return E_FAIL;
3390 glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
3391 if (!glyphProps) return E_OUTOFMEMORY;
3393 for (i = 0; i < cGlyphs; i++)
3394 glyphProps[i].sva = psva[i];
3396 hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
3398 heap_free(glyphProps);
3400 return hr;
3403 /***********************************************************************
3404 * ScriptGetCMap (USP10.@)
3406 * Retrieve glyph indices.
3408 * PARAMS
3409 * hdc [I] Device context.
3410 * psc [I/O] Opaque pointer to a script cache.
3411 * pwcInChars [I] Array of Unicode characters.
3412 * cChars [I] Number of characters in pwcInChars.
3413 * dwFlags [I] Flags.
3414 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3416 * RETURNS
3417 * Success: S_OK
3418 * Failure: Non-zero HRESULT value.
3420 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
3421 int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
3423 HRESULT hr;
3424 int i;
3426 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
3427 cChars, dwFlags, pwOutGlyphs);
3429 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3431 hr = S_OK;
3433 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3435 for (i = 0; i < cChars; i++)
3437 WCHAR inChar;
3438 if (dwFlags == SGCM_RTL)
3439 inChar = mirror_char(pwcInChars[i]);
3440 else
3441 inChar = pwcInChars[i];
3442 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
3444 WORD glyph;
3445 if (!hdc) return E_PENDING;
3446 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
3447 if (glyph == 0xffff)
3449 hr = S_FALSE;
3450 glyph = 0x0;
3452 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
3456 else
3458 TRACE("no glyph translation\n");
3459 for (i = 0; i < cChars; i++)
3461 WCHAR inChar;
3462 if (dwFlags == SGCM_RTL)
3463 inChar = mirror_char(pwcInChars[i]);
3464 else
3465 inChar = pwcInChars[i];
3466 pwOutGlyphs[i] = inChar;
3469 return hr;
3472 /***********************************************************************
3473 * ScriptTextOut (USP10.@)
3476 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
3477 const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
3478 int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
3479 const int *piJustify, const GOFFSET *pGoffset)
3481 HRESULT hr = S_OK;
3482 INT i, dir = 1;
3483 INT *lpDx;
3484 WORD *reordered_glyphs = (WORD *)pwGlyphs;
3486 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3487 hdc, psc, x, y, fuOptions, wine_dbgstr_rect(lprc), psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
3488 piAdvance, piJustify, pGoffset);
3490 if (!hdc || !psc) return E_INVALIDARG;
3491 if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
3493 fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
3494 fuOptions |= ETO_IGNORELANGUAGE;
3495 if (!psa->fNoGlyphIndex) /* Have Glyphs? */
3496 fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */
3498 lpDx = heap_alloc(cGlyphs * sizeof(INT) * 2);
3499 if (!lpDx) return E_OUTOFMEMORY;
3500 fuOptions |= ETO_PDY;
3502 if (psa->fRTL && psa->fLogicalOrder)
3504 reordered_glyphs = heap_alloc( cGlyphs * sizeof(WORD) );
3505 if (!reordered_glyphs)
3507 heap_free( lpDx );
3508 return E_OUTOFMEMORY;
3511 for (i = 0; i < cGlyphs; i++)
3512 reordered_glyphs[i] = pwGlyphs[cGlyphs - 1 - i];
3513 dir = -1;
3516 for (i = 0; i < cGlyphs; i++)
3518 int orig_index = (dir > 0) ? i : cGlyphs - 1 - i;
3519 lpDx[i * 2] = piAdvance[orig_index];
3520 lpDx[i * 2 + 1] = 0;
3522 if (pGoffset)
3524 if (i == 0)
3526 x += pGoffset[orig_index].du * dir;
3527 y += pGoffset[orig_index].dv;
3529 else
3531 lpDx[(i - 1) * 2] += pGoffset[orig_index].du * dir;
3532 lpDx[(i - 1) * 2 + 1] += pGoffset[orig_index].dv;
3534 lpDx[i * 2] -= pGoffset[orig_index].du * dir;
3535 lpDx[i * 2 + 1] -= pGoffset[orig_index].dv;
3539 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, reordered_glyphs, cGlyphs, lpDx))
3540 hr = S_FALSE;
3542 if (reordered_glyphs != pwGlyphs) heap_free( reordered_glyphs );
3543 heap_free(lpDx);
3545 return hr;
3548 /***********************************************************************
3549 * ScriptCacheGetHeight (USP10.@)
3551 * Retrieve the height of the font in the cache.
3553 * PARAMS
3554 * hdc [I] Device context.
3555 * psc [I/O] Opaque pointer to a script cache.
3556 * height [O] Receives font height.
3558 * RETURNS
3559 * Success: S_OK
3560 * Failure: Non-zero HRESULT value.
3562 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
3564 HRESULT hr;
3566 TRACE("(%p, %p, %p)\n", hdc, psc, height);
3568 if (!height) return E_INVALIDARG;
3569 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3571 *height = get_cache_height(psc);
3572 return S_OK;
3575 /***********************************************************************
3576 * ScriptGetGlyphABCWidth (USP10.@)
3578 * Retrieve the width of a glyph.
3580 * PARAMS
3581 * hdc [I] Device context.
3582 * psc [I/O] Opaque pointer to a script cache.
3583 * glyph [I] Glyph to retrieve the width for.
3584 * abc [O] ABC widths of the glyph.
3586 * RETURNS
3587 * Success: S_OK
3588 * Failure: Non-zero HRESULT value.
3590 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
3592 HRESULT hr;
3594 TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
3596 if (!abc) return E_INVALIDARG;
3597 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3599 if (!get_cache_glyph_widths(psc, glyph, abc))
3601 if (!hdc) return E_PENDING;
3602 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
3604 if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
3606 else
3608 INT width;
3609 if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
3610 abc->abcB = width;
3611 abc->abcA = abc->abcC = 0;
3613 set_cache_glyph_widths(psc, glyph, abc);
3615 return S_OK;
3618 /***********************************************************************
3619 * ScriptLayout (USP10.@)
3621 * Map embedding levels to visual and/or logical order.
3623 * PARAMS
3624 * runs [I] Size of level array.
3625 * level [I] Array of embedding levels.
3626 * vistolog [O] Map of embedding levels from visual to logical order.
3627 * logtovis [O] Map of embedding levels from logical to visual order.
3629 * RETURNS
3630 * Success: S_OK
3631 * Failure: Non-zero HRESULT value.
3634 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
3636 int* indexs;
3637 int ich;
3639 TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
3641 if (!level || (!vistolog && !logtovis))
3642 return E_INVALIDARG;
3644 indexs = heap_alloc(sizeof(int) * runs);
3645 if (!indexs)
3646 return E_OUTOFMEMORY;
3648 if (vistolog)
3650 for( ich = 0; ich < runs; ich++)
3651 indexs[ich] = ich;
3653 ich = 0;
3654 while (ich < runs)
3655 ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3656 memcpy(vistolog, indexs, runs * sizeof(*vistolog));
3659 if (logtovis)
3661 for( ich = 0; ich < runs; ich++)
3662 indexs[ich] = ich;
3664 ich = 0;
3665 while (ich < runs)
3666 ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3667 memcpy(logtovis, indexs, runs * sizeof(*logtovis));
3669 heap_free(indexs);
3671 return S_OK;
3674 /***********************************************************************
3675 * ScriptStringGetLogicalWidths (USP10.@)
3677 * Returns logical widths from a string analysis.
3679 * PARAMS
3680 * ssa [I] string analysis.
3681 * piDx [O] logical widths returned.
3683 * RETURNS
3684 * Success: S_OK
3685 * Failure: a non-zero HRESULT.
3687 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
3689 int i, j, next = 0;
3690 StringAnalysis *analysis = ssa;
3692 TRACE("%p, %p\n", ssa, piDx);
3694 if (!analysis) return S_FALSE;
3695 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
3697 for (i = 0; i < analysis->numItems; i++)
3699 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
3700 int direction = 1;
3702 if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
3703 direction = -1;
3705 for (j = 0; j < cChar; j++)
3707 int k;
3708 int glyph = analysis->glyphs[i].pwLogClust[j];
3709 int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
3710 cChar, j, direction, NULL, NULL);
3711 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);
3713 for (k = 0; k < clust_size; k++)
3715 piDx[next] = advance / clust_size;
3716 next++;
3717 if (k) j++;
3721 return S_OK;
3724 /***********************************************************************
3725 * ScriptStringValidate (USP10.@)
3727 * Validate a string analysis.
3729 * PARAMS
3730 * ssa [I] string analysis.
3732 * RETURNS
3733 * Success: S_OK
3734 * Failure: S_FALSE if invalid sequences are found
3735 * or a non-zero HRESULT if it fails.
3737 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
3739 StringAnalysis *analysis = ssa;
3741 TRACE("(%p)\n", ssa);
3743 if (!analysis) return E_INVALIDARG;
3744 return (analysis->invalid) ? S_FALSE : S_OK;
3747 /***********************************************************************
3748 * ScriptString_pSize (USP10.@)
3750 * Retrieve width and height of an analysed string.
3752 * PARAMS
3753 * ssa [I] string analysis.
3755 * RETURNS
3756 * Success: Pointer to a SIZE structure.
3757 * Failure: NULL
3759 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
3761 int i, j;
3762 StringAnalysis *analysis = ssa;
3764 TRACE("(%p)\n", ssa);
3766 if (!analysis) return NULL;
3767 if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
3769 if (!analysis->sz)
3771 if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
3772 analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
3774 analysis->sz->cx = 0;
3775 for (i = 0; i < analysis->numItems; i++)
3777 if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
3778 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
3779 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3780 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
3783 return analysis->sz;
3786 /***********************************************************************
3787 * ScriptString_pLogAttr (USP10.@)
3789 * Retrieve logical attributes of an analysed string.
3791 * PARAMS
3792 * ssa [I] string analysis.
3794 * RETURNS
3795 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3796 * Failure: NULL
3798 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
3800 StringAnalysis *analysis = ssa;
3802 TRACE("(%p)\n", ssa);
3804 if (!analysis) return NULL;
3805 if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
3806 return analysis->logattrs;
3809 /***********************************************************************
3810 * ScriptString_pcOutChars (USP10.@)
3812 * Retrieve the length of a string after clipping.
3814 * PARAMS
3815 * ssa [I] String analysis.
3817 * RETURNS
3818 * Success: Pointer to the length.
3819 * Failure: NULL
3821 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
3823 StringAnalysis *analysis = ssa;
3825 TRACE("(%p)\n", ssa);
3827 if (!analysis) return NULL;
3828 return &analysis->clip_len;
3831 /***********************************************************************
3832 * ScriptStringGetOrder (USP10.@)
3834 * Retrieve a glyph order map.
3836 * PARAMS
3837 * ssa [I] String analysis.
3838 * order [I/O] Array of glyph positions.
3840 * RETURNS
3841 * Success: S_OK
3842 * Failure: a non-zero HRESULT.
3844 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
3846 int i, j;
3847 unsigned int k;
3848 StringAnalysis *analysis = ssa;
3850 TRACE("(%p)\n", ssa);
3852 if (!analysis) return S_FALSE;
3853 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
3855 /* FIXME: handle RTL scripts */
3856 for (i = 0, k = 0; i < analysis->numItems; i++)
3857 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3858 order[k] = k;
3860 return S_OK;
3863 /***********************************************************************
3864 * ScriptGetLogicalWidths (USP10.@)
3866 * Convert advance widths to logical widths.
3868 * PARAMS
3869 * sa [I] Script analysis.
3870 * nbchars [I] Number of characters.
3871 * nbglyphs [I] Number of glyphs.
3872 * glyph_width [I] Array of glyph widths.
3873 * log_clust [I] Array of logical clusters.
3874 * sva [I] Visual attributes.
3875 * widths [O] Array of logical widths.
3877 * RETURNS
3878 * Success: S_OK
3879 * Failure: a non-zero HRESULT.
3881 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3882 const int *glyph_width, const WORD *log_clust,
3883 const SCRIPT_VISATTR *sva, int *widths)
3885 int i;
3887 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3888 sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);
3890 /* FIXME */
3891 for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
3892 return S_OK;
3895 /***********************************************************************
3896 * ScriptApplyLogicalWidth (USP10.@)
3898 * Generate glyph advance widths.
3900 * PARAMS
3901 * dx [I] Array of logical advance widths.
3902 * num_chars [I] Number of characters.
3903 * num_glyphs [I] Number of glyphs.
3904 * log_clust [I] Array of logical clusters.
3905 * sva [I] Visual attributes.
3906 * advance [I] Array of glyph advance widths.
3907 * sa [I] Script analysis.
3908 * abc [I/O] Summed ABC widths.
3909 * justify [O] Array of glyph advance widths.
3911 * RETURNS
3912 * Success: S_OK
3913 * Failure: a non-zero HRESULT.
3915 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
3916 const WORD *log_clust, const SCRIPT_VISATTR *sva,
3917 const int *advance, const SCRIPT_ANALYSIS *sa,
3918 ABC *abc, int *justify)
3920 int i;
3922 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3923 dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
3925 for (i = 0; i < num_chars; i++) justify[i] = advance[i];
3926 return S_OK;
3929 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
3930 int num_glyphs, int dx, int min_kashida, int *justify)
3932 int i;
3934 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
3936 for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
3937 return S_OK;
3940 HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
3942 HRESULT hr;
3943 if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
3944 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3946 return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
3949 HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
3951 HRESULT hr;
3952 if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
3953 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3955 return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
3958 HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
3960 HRESULT hr;
3961 if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
3962 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3964 return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);