ReactOS 0.4.16-dev-338-g34e76ad
usp10.c
Go to the documentation of this file.
1/*
2 * Implementation of Uniscribe Script Processor (usp10.dll)
3 *
4 * Copyright 2005 Steven Edwards for CodeWeavers
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
7 *
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.
12 *
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.
17 *
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
21 *
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.
25 */
26
27#include <stdarg.h>
28#include <stdlib.h>
29#include <math.h>
30#ifdef __REACTOS__
31#include <wchar.h>
32#endif
33
34#include "windef.h"
35#include "winbase.h"
36#include "wingdi.h"
37#include "winuser.h"
38#include "winnls.h"
39#include "winreg.h"
40#include "usp10.h"
41
42#include "usp10_internal.h"
43
44#include "wine/debug.h"
45#include "wine/heap.h"
46
48
49static const struct usp10_script_range
50{
56}
58{
59 /* Basic Latin: U+0000–U+007A */
61 /* Latin-1 Supplement: U+0080–U+00FF */
62 /* Latin Extended-A: U+0100–U+017F */
63 /* Latin Extended-B: U+0180–U+024F */
64 /* IPA Extensions: U+0250–U+02AF */
65 /* Spacing Modifier Letters:U+02B0–U+02FF */
67 /* Combining Diacritical Marks : U+0300–U+036F */
68 { Script_Diacritical,0x300, 0x36f, 0, 0},
69 /* Greek: U+0370–U+03FF */
70 { Script_Greek, 0x370, 0x3ff, 0, 0},
71 /* Cyrillic: U+0400–U+04FF */
72 /* Cyrillic Supplement: U+0500–U+052F */
73 { Script_Cyrillic, 0x400, 0x52f, 0, 0},
74 /* Armenian: U+0530–U+058F */
75 { Script_Armenian, 0x530, 0x58f, 0, 0},
76 /* Hebrew: U+0590–U+05FF */
77 { Script_Hebrew, 0x590, 0x5ff, 0, 0},
78 /* Arabic: U+0600–U+06FF */
79 { Script_Arabic, 0x600, 0x6ef, Script_Arabic_Numeric, 0},
80 /* Defined by Windows */
81 { Script_Persian, 0x6f0, 0x6f9, 0, 0},
82 /* Continue Arabic: U+0600–U+06FF */
83 { Script_Arabic, 0x6fa, 0x6ff, 0, 0},
84 /* Syriac: U+0700–U+074F*/
85 { Script_Syriac, 0x700, 0x74f, 0, 0},
86 /* Arabic Supplement: U+0750–U+077F */
87 { Script_Arabic, 0x750, 0x77f, 0, 0},
88 /* Thaana: U+0780–U+07BF */
89 { Script_Thaana, 0x780, 0x7bf, 0, 0},
90 /* N’Ko: U+07C0–U+07FF */
91 { Script_NKo, 0x7c0, 0x7ff, 0, 0},
92 /* Devanagari: U+0900–U+097F */
94 /* Bengali: U+0980–U+09FF */
95 { Script_Bengali, 0x980, 0x9ff, Script_Bengali_Numeric, 0},
96 /* Gurmukhi: U+0A00–U+0A7F*/
97 { Script_Gurmukhi, 0xa00, 0xa7f, Script_Gurmukhi_Numeric, 0},
98 /* Gujarati: U+0A80–U+0AFF*/
99 { Script_Gujarati, 0xa80, 0xaff, Script_Gujarati_Numeric, 0},
100 /* Oriya: U+0B00–U+0B7F */
101 { Script_Oriya, 0xb00, 0xb7f, Script_Oriya_Numeric, 0},
102 /* Tamil: U+0B80–U+0BFF */
103 { Script_Tamil, 0xb80, 0xbff, Script_Tamil_Numeric, 0},
104 /* Telugu: U+0C00–U+0C7F */
105 { Script_Telugu, 0xc00, 0xc7f, Script_Telugu_Numeric, 0},
106 /* Kannada: U+0C80–U+0CFF */
107 { Script_Kannada, 0xc80, 0xcff, Script_Kannada_Numeric, 0},
108 /* Malayalam: U+0D00–U+0D7F */
109 { Script_Malayalam, 0xd00, 0xd7f, Script_Malayalam_Numeric, 0},
110 /* Sinhala: U+0D80–U+0DFF */
111 { Script_Sinhala, 0xd80, 0xdff, 0, 0},
112 /* Thai: U+0E00–U+0E7F */
113 { Script_Thai, 0xe00, 0xe7f, Script_Thai_Numeric, 0},
114 /* Lao: U+0E80–U+0EFF */
115 { Script_Lao, 0xe80, 0xeff, Script_Lao_Numeric, 0},
116 /* Tibetan: U+0F00–U+0FFF */
117 { Script_Tibetan, 0xf00, 0xfff, 0, 0},
118 /* Myanmar: U+1000–U+109F */
119 { Script_Myanmar, 0x1000, 0x109f, Script_Myanmar_Numeric, 0},
120 /* Georgian: U+10A0–U+10FF */
121 { Script_Georgian, 0x10a0, 0x10ff, 0, 0},
122 /* Hangul Jamo: U+1100–U+11FF */
123 { Script_Hangul, 0x1100, 0x11ff, 0, 0},
124 /* Ethiopic: U+1200–U+137F */
125 /* Ethiopic Extensions: U+1380–U+139F */
126 { Script_Ethiopic, 0x1200, 0x139f, 0, 0},
127 /* Cherokee: U+13A0–U+13FF */
128 { Script_Cherokee, 0x13a0, 0x13ff, 0, 0},
129 /* Canadian Aboriginal Syllabics: U+1400–U+167F */
130 { Script_Canadian, 0x1400, 0x167f, 0, 0},
131 /* Ogham: U+1680–U+169F */
132 { Script_Ogham, 0x1680, 0x169f, 0, 0},
133 /* Runic: U+16A0–U+16F0 */
134 { Script_Runic, 0x16a0, 0x16f0, 0, 0},
135 /* Khmer: U+1780–U+17FF */
136 { Script_Khmer, 0x1780, 0x17ff, Script_Khmer_Numeric, 0},
137 /* Mongolian: U+1800–U+18AF */
138 { Script_Mongolian, 0x1800, 0x18af, Script_Mongolian_Numeric, 0},
139 /* Canadian Aboriginal Syllabics Extended: U+18B0–U+18FF */
140 { Script_Canadian, 0x18b0, 0x18ff, 0, 0},
141 /* Tai Le: U+1950–U+197F */
142 { Script_Tai_Le, 0x1950, 0x197f, 0, 0},
143 /* New Tai Lue: U+1980–U+19DF */
145 /* Khmer Symbols: U+19E0–U+19FF */
146 { Script_Khmer, 0x19e0, 0x19ff, Script_Khmer_Numeric, 0},
147 /* Vedic Extensions: U+1CD0-U+1CFF */
148 { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
149 /* Phonetic Extensions: U+1D00–U+1DBF */
150 { Script_Latin, 0x1d00, 0x1dbf, 0, 0},
151 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
152 { Script_Diacritical,0x1dc0, 0x1dff, 0, 0},
153 /* Latin Extended Additional: U+1E00–U+1EFF */
154 { Script_Latin, 0x1e00, 0x1eff, 0, 0},
155 /* Greek Extended: U+1F00–U+1FFF */
156 { Script_Greek, 0x1f00, 0x1fff, 0, 0},
157 /* General Punctuation: U+2000 –U+206f */
158 { Script_Latin, 0x2000, 0x206f, 0, 0},
159 /* Superscripts and Subscripts : U+2070 –U+209f */
160 /* Currency Symbols : U+20a0 –U+20cf */
161 { Script_Numeric2, 0x2070, 0x2070, 0, 0},
162 { Script_Latin, 0x2071, 0x2073, 0, 0},
163 { Script_Numeric2, 0x2074, 0x2079, 0, 0},
164 { Script_Latin, 0x207a, 0x207f, 0, 0},
165 { Script_Numeric2, 0x2080, 0x2089, 0, 0},
166 { Script_Latin, 0x208a, 0x20cf, 0, 0},
167 /* Letterlike Symbols : U+2100 –U+214f */
168 /* Number Forms : U+2150 –U+218f */
169 /* Arrows : U+2190 –U+21ff */
170 /* Mathematical Operators : U+2200 –U+22ff */
171 /* Miscellaneous Technical : U+2300 –U+23ff */
172 /* Control Pictures : U+2400 –U+243f */
173 /* Optical Character Recognition : U+2440 –U+245f */
174 /* Enclosed Alphanumerics : U+2460 –U+24ff */
175 /* Box Drawing : U+2500 –U+25ff */
176 /* Block Elements : U+2580 –U+259f */
177 /* Geometric Shapes : U+25a0 –U+25ff */
178 /* Miscellaneous Symbols : U+2600 –U+26ff */
179 /* Dingbats : U+2700 –U+27bf */
180 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
181 /* Supplemental Arrows-A : U+27f0 –U+27ff */
182 { Script_Latin, 0x2100, 0x27ff, 0, 0},
183 /* Braille Patterns: U+2800–U+28FF */
184 { Script_Braille, 0x2800, 0x28ff, 0, 0},
185 /* Supplemental Arrows-B : U+2900 –U+297f */
186 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
187 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
188 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
189 { Script_Latin, 0x2900, 0x2bff, 0, 0},
190 /* Latin Extended-C: U+2C60–U+2C7F */
191 { Script_Latin, 0x2c60, 0x2c7f, 0, 0},
192 /* Georgian: U+2D00–U+2D2F */
193 { Script_Georgian, 0x2d00, 0x2d2f, 0, 0},
194 /* Tifinagh: U+2D30–U+2D7F */
195 { Script_Tifinagh, 0x2d30, 0x2d7f, 0, 0},
196 /* Ethiopic Extensions: U+2D80–U+2DDF */
197 { Script_Ethiopic, 0x2d80, 0x2ddf, 0, 0},
198 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
199 { Script_Cyrillic, 0x2de0, 0x2dff, 0, 0},
200 /* CJK Radicals Supplement: U+2E80–U+2EFF */
201 /* Kangxi Radicals: U+2F00–U+2FDF */
202 { Script_CJK_Han, 0x2e80, 0x2fdf, 0, 0},
203 /* Ideographic Description Characters: U+2FF0–U+2FFF */
204 { Script_Ideograph ,0x2ff0, 0x2fff, 0, 0},
205 /* CJK Symbols and Punctuation: U+3000–U+303F */
206 { Script_Ideograph ,0x3000, 0x3004, 0, 0},
207 { Script_CJK_Han ,0x3005, 0x3005, 0, 0},
208 { Script_Ideograph ,0x3006, 0x3006, 0, 0},
209 { Script_CJK_Han ,0x3007, 0x3007, 0, 0},
210 { Script_Ideograph ,0x3008, 0x3020, 0, 0},
211 { Script_CJK_Han ,0x3021, 0x3029, 0, 0},
212 { Script_Ideograph ,0x302a, 0x3030, 0, 0},
213 /* Kana Marks: */
214 { Script_Kana ,0x3031, 0x3035, 0, 0},
215 { Script_Ideograph ,0x3036, 0x3037, 0, 0},
216 { Script_CJK_Han ,0x3038, 0x303b, 0, 0},
217 { Script_Ideograph ,0x303c, 0x303f, 0, 0},
218 /* Hiragana: U+3040–U+309F */
219 /* Katakana: U+30A0–U+30FF */
220 { Script_Kana ,0x3040, 0x30ff, 0, 0},
221 /* Bopomofo: U+3100–U+312F */
222 { Script_Bopomofo ,0x3100, 0x312f, 0, 0},
223 /* Hangul Compatibility Jamo: U+3130–U+318F */
224 { Script_Hangul ,0x3130, 0x318f, 0, 0},
225 /* Kanbun: U+3190–U+319F */
226 { Script_Ideograph ,0x3190, 0x319f, 0, 0},
227 /* Bopomofo Extended: U+31A0–U+31BF */
228 { Script_Bopomofo ,0x31a0, 0x31bf, 0, 0},
229 /* CJK Strokes: U+31C0–U+31EF */
230 { Script_Ideograph ,0x31c0, 0x31ef, 0, 0},
231 /* Katakana Phonetic Extensions: U+31F0–U+31FF */
232 { Script_Kana ,0x31f0, 0x31ff, 0, 0},
233 /* Enclosed CJK Letters and Months: U+3200–U+32FF */
234 { Script_Hangul ,0x3200, 0x321f, 0, 0},
235 { Script_Ideograph ,0x3220, 0x325f, 0, 0},
236 { Script_Hangul ,0x3260, 0x327f, 0, 0},
237 { Script_Ideograph ,0x3280, 0x32ef, 0, 0},
238 { Script_Kana ,0x32d0, 0x31ff, 0, 0},
239 /* CJK Compatibility: U+3300–U+33FF*/
240 { Script_Kana ,0x3300, 0x3357, 0, 0},
241 { Script_Ideograph ,0x3358, 0x33ff, 0, 0},
242 /* CJK Unified Ideographs Extension A: U+3400–U+4DBF */
243 { Script_CJK_Han ,0x3400, 0x4dbf, 0, 0},
244 /* CJK Unified Ideographs: U+4E00–U+9FFF */
245 { Script_CJK_Han ,0x4e00, 0x9fff, 0, 0},
246 /* Yi: U+A000–U+A4CF */
247 { Script_Yi ,0xa000, 0xa4cf, 0, 0},
248 /* Vai: U+A500–U+A63F */
249 { Script_Vai ,0xa500, 0xa63f, Script_Vai_Numeric, 0},
250 /* Cyrillic Extended-B: U+A640–U+A69F */
251 { Script_Cyrillic, 0xa640, 0xa69f, 0, 0},
252 /* Modifier Tone Letters: U+A700–U+A71F */
253 /* Latin Extended-D: U+A720–U+A7FF */
254 { Script_Latin, 0xa700, 0xa7ff, 0, 0},
255 /* Phags-pa: U+A840–U+A87F */
256 { Script_Phags_pa, 0xa840, 0xa87f, 0, 0},
257 /* Devanagari Extended: U+A8E0-U+A8FF */
258 { Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
259 /* Myanmar Extended-A: U+AA60–U+AA7F */
260 { Script_Myanmar, 0xaa60, 0xaa7f, Script_Myanmar_Numeric, 0},
261 /* Hangul Jamo Extended-A: U+A960–U+A97F */
262 { Script_Hangul, 0xa960, 0xa97f, 0, 0},
263 /* Hangul Syllables: U+AC00–U+D7A3 */
264 { Script_Hangul, 0xac00, 0xd7a3, 0, 0},
265 /* Hangul Jamo Extended-B: U+D7B0–U+D7FF */
266 { Script_Hangul, 0xd7b0, 0xd7ff, 0, 0},
267 /* Surrogates Area: U+D800–U+DFFF */
268 { Script_Surrogates, 0xd800, 0xdbfe, 0, 0},
269 { Script_Private, 0xdbff, 0xdc00, 0, 0},
270 { Script_Surrogates, 0xdc01, 0xdfff, 0, 0},
271 /* Private Use Area: U+E000–U+F8FF */
272 { Script_Private, 0xe000, 0xf8ff, 0, 0},
273 /* CJK Compatibility Ideographs: U+F900–U+FAFF */
274 { Script_CJK_Han ,0xf900, 0xfaff, 0, 0},
275 /* Latin Ligatures: U+FB00–U+FB06 */
276 { Script_Latin, 0xfb00, 0xfb06, 0, 0},
277 /* Armenian ligatures U+FB13..U+FB17 */
278 { Script_Armenian, 0xfb13, 0xfb17, 0, 0},
279 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
280 { Script_Hebrew, 0xfb1d, 0xfb4f, 0, 0},
281 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
282 { Script_Arabic, 0xfb50, 0xfdff, 0, 0},
283 /* Vertical Forms: U+FE10–U+FE1F */
284 /* Combining Half Marks: U+FE20–U+FE2F */
285 /* CJK Compatibility Forms: U+FE30–U+FE4F */
286 /* Small Form Variants: U+FE50–U+FE6F */
287 { Script_Ideograph ,0xfe10, 0xfe6f, 0, 0},
288 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
289 { Script_Arabic, 0xfe70, 0xfeff, 0, 0},
290 /* Halfwidth and Fullwidth Forms: U+FF00–FFEF */
291 { Script_Ideograph ,0xff00, 0xff64, Script_Numeric2, 0},
292 { Script_Kana ,0xff65, 0xff9f, 0, 0},
293 { Script_Hangul ,0xffa0, 0xffdf, 0, 0},
294 { Script_Ideograph ,0xffe0, 0xffef, 0, 0},
295 /* Plane - 1 */
296 /* Deseret: U+10400–U+1044F */
297 { Script_Deseret, 0x10400, 0x1044F, 0, 0},
298 /* Osmanya: U+10480–U+104AF */
299 { Script_Osmanya, 0x10480, 0x104AF, Script_Osmanya_Numeric, 0},
300 /* Mathematical Alphanumeric Symbols: U+1D400–U+1D7FF */
301 { Script_MathAlpha, 0x1D400, 0x1D7FF, 0, 0},
303
304/* this must be in order so that the index matches the Script value */
306 {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
307 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
308 0x00000000,
309 {0}},
310 {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
311 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
312 MS_MAKE_TAG('l','a','t','n'),
313 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
314 {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
315 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
316 0x00000000,
317 {0}},
318 {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
319 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
320 0x00000000,
321 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
322 {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
323 {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
324 0x00000000,
325 {0}},
326 {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
327 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
328 0x00000000,
329 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
330 {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
331 {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
332 MS_MAKE_TAG('a','r','a','b'),
333 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
334 {{Script_Arabic_Numeric, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
335 {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
336 MS_MAKE_TAG('a','r','a','b'),
337 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
338 {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
339 {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
340 MS_MAKE_TAG('h','e','b','r'),
341 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
342 {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
343 {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
344 MS_MAKE_TAG('s','y','r','c'),
345 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
346 {{Script_Persian, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
347 {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
348 MS_MAKE_TAG('a','r','a','b'),
349 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
350 {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
351 {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
352 MS_MAKE_TAG('t','h','a','a'),
353 {'M','V',' ','B','o','l','i',0}},
354 {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
355 {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
356 MS_MAKE_TAG('g','r','e','k'),
357 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
358 {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
359 {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
360 MS_MAKE_TAG('c','y','r','l'),
361 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
362 {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
363 {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
364 MS_MAKE_TAG('a','r','m','n'),
365 {'S','y','l','f','a','e','n',0}},
366 {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
367 {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
368 MS_MAKE_TAG('g','e','o','r'),
369 {'S','y','l','f','a','e','n',0}},
370 {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
371 {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
372 MS_MAKE_TAG('s','i','n','h'),
373 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
374 {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
375 {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
376 MS_MAKE_TAG('t','i','b','t'),
377 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
378 {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
379 {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
380 MS_MAKE_TAG('t','i','b','t'),
381 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
382 {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
383 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
384 MS_MAKE_TAG('p','h','a','g'),
385 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
386 {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
387 {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
388 MS_MAKE_TAG('t','h','a','i'),
389 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
390 {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
391 {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
392 MS_MAKE_TAG('t','h','a','i'),
393 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
394 {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
395 {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
396 MS_MAKE_TAG('l','a','o',' '),
397 {'D','o','k','C','h','a','m','p','a',0}},
398 {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
399 {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
400 MS_MAKE_TAG('l','a','o',' '),
401 {'D','o','k','C','h','a','m','p','a',0}},
402 {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
403 {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
404 MS_MAKE_TAG('d','e','v','a'),
405 {'M','a','n','g','a','l',0}},
406 {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
407 {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
408 MS_MAKE_TAG('d','e','v','a'),
409 {'M','a','n','g','a','l',0}},
410 {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
411 {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
412 MS_MAKE_TAG('b','e','n','g'),
413 {'V','r','i','n','d','a',0}},
414 {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
415 {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
416 MS_MAKE_TAG('b','e','n','g'),
417 {'V','r','i','n','d','a',0}},
418 {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
419 {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
420 MS_MAKE_TAG('b','e','n','g'),
421 {'V','r','i','n','d','a',0}},
422 {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
423 {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
424 MS_MAKE_TAG('g','u','r','u'),
425 {'R','a','a','v','i',0}},
426 {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
427 {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
428 MS_MAKE_TAG('g','u','r','u'),
429 {'R','a','a','v','i',0}},
430 {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
431 {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
432 MS_MAKE_TAG('g','u','j','r'),
433 {'S','h','r','u','t','i',0}},
434 {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
435 {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
436 MS_MAKE_TAG('g','u','j','r'),
437 {'S','h','r','u','t','i',0}},
438 {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
439 {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
440 MS_MAKE_TAG('g','u','j','r'),
441 {'S','h','r','u','t','i',0}},
442 {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
443 {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
444 MS_MAKE_TAG('o','r','y','a'),
445 {'K','a','l','i','n','g','a',0}},
446 {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
447 {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
448 MS_MAKE_TAG('o','r','y','a'),
449 {'K','a','l','i','n','g','a',0}},
450 {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
451 {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
452 MS_MAKE_TAG('t','a','m','l'),
453 {'L','a','t','h','a',0}},
454 {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
455 {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
456 MS_MAKE_TAG('t','a','m','l'),
457 {'L','a','t','h','a',0}},
458 {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
459 {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
460 MS_MAKE_TAG('t','e','l','u'),
461 {'G','a','u','t','a','m','i',0}},
462 {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
463 {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
464 MS_MAKE_TAG('t','e','l','u'),
465 {'G','a','u','t','a','m','i',0}},
466 {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
467 {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
468 MS_MAKE_TAG('k','n','d','a'),
469 {'T','u','n','g','a',0}},
470 {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
471 {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
472 MS_MAKE_TAG('k','n','d','a'),
473 {'T','u','n','g','a',0}},
474 {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
475 {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
476 MS_MAKE_TAG('m','l','y','m'),
477 {'K','a','r','t','i','k','a',0}},
478 {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
479 {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
480 MS_MAKE_TAG('m','l','y','m'),
481 {'K','a','r','t','i','k','a',0}},
482 {{Script_Diacritical, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
483 {LANG_ENGLISH, 0, 1, 0, 1, ANSI_CHARSET, 0, 0, 0, 0, 0, 1, 1, 0, 0},
484 0x00000000,
485 {0}},
486 {{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
487 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
488 MS_MAKE_TAG('l','a','t','n'),
489 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
490 {{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
491 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
492 0x00000000,
493 {0}},
494 {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
495 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
496 MS_MAKE_TAG('m','y','m','r'),
497 {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
498 {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
499 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
500 MS_MAKE_TAG('m','y','m','r'),
501 {0}},
502 {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
503 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
504 MS_MAKE_TAG('t','a','l','e'),
505 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
506 {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
507 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
508 MS_MAKE_TAG('t','a','l','u'),
509 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
510 {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
511 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
512 MS_MAKE_TAG('t','a','l','u'),
513 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
514 {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
515 {0x53, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
516 MS_MAKE_TAG('k','h','m','r'),
517 {'D','a','u','n','P','e','n','h',0}},
518 {{Script_Khmer_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
519 {0x53, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
520 MS_MAKE_TAG('k','h','m','r'),
521 {'D','a','u','n','P','e','n','h',0}},
522 {{Script_CJK_Han, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
523 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
524 MS_MAKE_TAG('h','a','n','i'),
525 {0}},
526 {{Script_Ideograph, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
527 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
528 MS_MAKE_TAG('h','a','n','i'),
529 {0}},
530 {{Script_Bopomofo, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
531 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
532 MS_MAKE_TAG('b','o','p','o'),
533 {0}},
534 {{Script_Kana, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
535 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
536 MS_MAKE_TAG('k','a','n','a'),
537 {0}},
538 {{Script_Hangul, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
539 {LANG_KOREAN, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
540 MS_MAKE_TAG('h','a','n','g'),
541 {0}},
542 {{Script_Yi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
543 {LANG_ENGLISH, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
544 MS_MAKE_TAG('y','i',' ',' '),
545 {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
546 {{Script_Ethiopic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
547 {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
548 MS_MAKE_TAG('e','t','h','i'),
549 {'N','y','a','l','a',0}},
550 {{Script_Ethiopic_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
551 {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
552 MS_MAKE_TAG('e','t','h','i'),
553 {'N','y','a','l','a',0}},
554 {{Script_Mongolian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
555 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
556 MS_MAKE_TAG('m','o','n','g'),
557 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
558 {{Script_Mongolian_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
559 {LANG_MONGOLIAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
560 MS_MAKE_TAG('m','o','n','g'),
561 {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
562 {{Script_Tifinagh, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
563 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
564 MS_MAKE_TAG('t','f','n','g'),
565 {'E','b','r','i','m','a',0}},
566 {{Script_NKo, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
567 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
568 MS_MAKE_TAG('n','k','o',' '),
569 {'E','b','r','i','m','a',0}},
570 {{Script_Vai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
571 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
572 MS_MAKE_TAG('v','a','i',' '),
573 {'E','b','r','i','m','a',0}},
574 {{Script_Vai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
575 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
576 MS_MAKE_TAG('v','a','i',' '),
577 {'E','b','r','i','m','a',0}},
578 {{Script_Cherokee, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
579 {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
580 MS_MAKE_TAG('c','h','e','r'),
581 {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
582 {{Script_Canadian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
583 {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
584 MS_MAKE_TAG('c','a','n','s'),
585 {'E','u','p','h','e','m','i','a',0}},
586 {{Script_Ogham, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
587 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
588 MS_MAKE_TAG('o','g','a','m'),
589 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
590 {{Script_Runic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
591 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
592 MS_MAKE_TAG('r','u','n','r'),
593 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
594 {{Script_Braille, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
595 {LANG_ENGLISH, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
596 MS_MAKE_TAG('b','r','a','i'),
597 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
598 {{Script_Surrogates, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
599 {LANG_ENGLISH, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
600 0x00000000,
601 {0}},
602 {{Script_Private, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
603 {0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 1, 0, 0, 0, 0, 1, 0, 0},
604 0x00000000,
605 {0}},
606 {{Script_Deseret, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
607 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
608 MS_MAKE_TAG('d','s','r','t'),
609 {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
610 {{Script_Osmanya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
611 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
612 MS_MAKE_TAG('o','s','m','a'),
613 {'E','b','r','i','m','a',0}},
614 {{Script_Osmanya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
615 {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
616 MS_MAKE_TAG('o','s','m','a'),
617 {'E','b','r','i','m','a',0}},
618 {{Script_MathAlpha, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
619 {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
620 MS_MAKE_TAG('m','a','t','h'),
621 {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
622 {{Script_Hebrew_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
623 {LANG_HEBREW, 0, 1, 0, 0, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
624 MS_MAKE_TAG('h','e','b','r'),
625 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
626 {{Script_Vietnamese_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
627 {LANG_VIETNAMESE, 0, 0, 0, 0, VIETNAMESE_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
628 MS_MAKE_TAG('l','a','t','n'),
629 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
630 {{Script_Thai_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
631 {LANG_THAI, 0, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
632 MS_MAKE_TAG('t','h','a','i'),
633 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
634};
635
637{
679};
680
683{
684 0, 0, &cs_script_cache,
686 0, 0, { (DWORD_PTR)(__FILE__ ": script_cache") }
687};
688static CRITICAL_SECTION cs_script_cache = { &cs_script_cache_dbg, -1, 0, 0, 0, 0 };
690
691typedef struct {
703
705{
708};
709
710typedef struct {
724
725typedef struct {
729
730BOOL usp10_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
731{
732 SIZE_T max_capacity, new_capacity;
733 void *new_elements;
734
735 if (count <= *capacity)
736 return TRUE;
737
738 max_capacity = ~(SIZE_T)0 / size;
739 if (count > max_capacity)
740 return FALSE;
741
742 new_capacity = max(1, *capacity);
743 while (new_capacity < count && new_capacity <= max_capacity / 2)
744 new_capacity *= 2;
745 if (new_capacity < count)
746 new_capacity = count;
747
748 if (!*elements)
749 new_elements = heap_alloc_zero(new_capacity * size);
750 else
751 new_elements = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *elements, new_capacity * size);
752 if (!new_elements)
753 return FALSE;
754
755 *elements = new_elements;
756 *capacity = new_capacity;
757 return TRUE;
758}
759
760/* TODO Fix font properties on Arabic locale */
762{
763 sc->sfp.cBytes = sizeof(sc->sfp);
764
765 if (!sc->sfnt)
766 {
767 sc->sfp.wgBlank = sc->tm.tmBreakChar;
768 sc->sfp.wgDefault = sc->tm.tmDefaultChar;
769 sc->sfp.wgInvalid = sc->sfp.wgBlank;
770 sc->sfp.wgKashida = 0xFFFF;
771 sc->sfp.iKashidaWidth = 0;
772 }
773 else
774 {
775 static const WCHAR chars[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
776 /* U+0020: numeric space
777 U+200B: zero width space
778 U+F71B: unknown char found by black box testing
779 U+0640: kashida */
780 WORD gi[4];
781
783 {
784 if(gi[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
785 sc->sfp.wgBlank = gi[0];
786 else
787 sc->sfp.wgBlank = 0;
788
789 sc->sfp.wgDefault = 0;
790
791 if (gi[2] != 0xFFFF)
792 sc->sfp.wgInvalid = gi[2];
793 else if (gi[1] != 0xFFFF)
794 sc->sfp.wgInvalid = gi[1];
795 else if (gi[0] != 0xFFFF)
796 sc->sfp.wgInvalid = gi[0];
797 else
798 sc->sfp.wgInvalid = 0;
799
800 sc->sfp.wgKashida = gi[3];
801
802 sc->sfp.iKashidaWidth = 0; /* TODO */
803 }
804 else
805 return FALSE;
806 }
807 return TRUE;
808}
809
811{
812 *sfp = sc->sfp;
813}
814
816{
817 return ((ScriptCache *)*psc)->tm.tmHeight;
818}
819
821{
822 return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
823}
824
826{
827 CacheGlyphPage *page = ((ScriptCache *)*psc)->page[c / 0x10000];
828 WORD *block;
829
830 if (!page) return 0;
831 block = page->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
832 if (!block) return 0;
833 return block[(c % 0x10000) & GLYPH_BLOCK_MASK];
834}
835
837{
838 CacheGlyphPage **page = &((ScriptCache *)*psc)->page[c / 0x10000];
839 WORD **block;
840 if (!*page && !(*page = heap_alloc_zero(sizeof(CacheGlyphPage)))) return 0;
841
842 block = &(*page)->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
843 if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
844 return ((*block)[(c % 0x10000) & GLYPH_BLOCK_MASK] = glyph);
845}
846
848{
849 static const ABC nil;
850 ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
851
852 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
853 memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
854 return TRUE;
855}
856
858{
859 ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
860
861 if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
862 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
863 return TRUE;
864}
865
867{
868 ScriptCache *sc;
869 unsigned size;
870 LOGFONTW lf;
871
872 if (!psc) return E_INVALIDARG;
873 if (*psc) return S_OK;
874 if (!hdc) return E_PENDING;
875
876 if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf))
877 {
878 return E_INVALIDARG;
879 }
880 /* Ensure canonical result by zeroing extra space in lfFaceName */
882 memset(lf.lfFaceName + size, 0, sizeof(lf.lfFaceName) - size * sizeof(WCHAR));
883
886 {
887 if (!memcmp(&sc->lf, &lf, sizeof(lf)))
888 {
889 sc->refcount++;
891 *psc = sc;
892 return S_OK;
893 }
894 }
896
897 if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
898 if (!GetTextMetricsW(hdc, &sc->tm))
899 {
900 heap_free(sc);
901 return E_INVALIDARG;
902 }
904 if (size)
905 {
906 sc->otm = heap_alloc(size);
907 sc->otm->otmSize = size;
909 }
910 sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
912 {
913 heap_free(sc);
914 return E_INVALIDARG;
915 }
916 sc->lf = lf;
917 sc->refcount = 1;
918 *psc = sc;
919
923 {
924 if (sc != *psc && !memcmp(&sc->lf, &lf, sizeof(lf)))
925 {
926 /* Another thread won the race. Use their cache instead of ours */
927 list_remove(&sc->entry);
928 sc->refcount++;
930 heap_free(*psc);
931 *psc = sc;
932 return S_OK;
933 }
934 }
936 TRACE("<- %p\n", sc);
937 return S_OK;
938}
939
941{
943 return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
944}
945
946static DWORD decode_surrogate_pair(const WCHAR *str, unsigned int index, unsigned int end)
947{
948 if (index < end-1 && IS_SURROGATE_PAIR(str[index],str[index+1]))
949 {
950 DWORD ch = 0x10000 + ((str[index] - 0xd800) << 10) + (str[index+1] - 0xdc00);
951 TRACE("Surrogate Pair %x %x => %x\n",str[index], str[index+1], ch);
952 return ch;
953 }
954 return 0;
955}
956
957static int __cdecl usp10_compare_script_range(const void *key, const void *value)
958{
959 const struct usp10_script_range *range = value;
960 const DWORD *ch = key;
961
962 if (*ch < range->rangeFirst)
963 return -1;
964 if (*ch > range->rangeLast)
965 return 1;
966 return 0;
967}
968
969static enum usp10_script get_char_script(const WCHAR *str, unsigned int index,
970 unsigned int end, unsigned int *consumed)
971{
972 static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
974 WORD type = 0, type2 = 0;
975 DWORD ch;
976
977 *consumed = 1;
978
979 if (str[index] == 0xc || str[index] == 0x20 || str[index] == 0x202f)
980 return Script_CR;
981
982 /* These punctuation characters are separated out as Latin punctuation */
983 if (wcschr(latin_punc,str[index]))
984 return Script_Punctuation2;
985
986 /* These chars are itemized as Punctuation by Windows */
987 if (str[index] == 0x2212 || str[index] == 0x2044)
988 return Script_Punctuation;
989
990 /* Currency Symbols by Unicode point */
991 switch (str[index])
992 {
993 case 0x09f2:
994 case 0x09f3: return Script_Bengali_Currency;
995 case 0x0af1: return Script_Gujarati_Currency;
996 case 0x0e3f: return Script_Thai_Currency;
997 case 0x20aa: return Script_Hebrew_Currency;
998 case 0x20ab: return Script_Vietnamese_Currency;
999 case 0xfb29: return Script_Hebrew_Currency;
1000 }
1001
1003 GetStringTypeW(CT_CTYPE2, &str[index], 1, &type2);
1004
1005 if (type == 0)
1006 return SCRIPT_UNDEFINED;
1007
1008 if (type & C1_CNTRL)
1009 return Script_Control;
1010
1012 if (ch)
1013 *consumed = 2;
1014 else
1015 ch = str[index];
1016
1019 return (*consumed == 2) ? Script_Surrogates : Script_Undefined;
1020
1021 if (range->numericScript && (type & C1_DIGIT || type2 == C2_ARABICNUMBER))
1022 return range->numericScript;
1023 if (range->punctScript && type & C1_PUNCT)
1024 return range->punctScript;
1025 return range->script;
1026}
1027
1028static int __cdecl compare_FindGlyph(const void *a, const void* b)
1029{
1031 const WORD *idx= (WORD*)b;
1032 int rc = 0;
1033
1034 if ( find->target > *idx)
1035 rc = 1;
1036 else if (find->target < *idx)
1037 rc = -1;
1038
1039 if (!find->ascending)
1040 rc *= -1;
1041 return rc;
1042}
1043
1045{
1046 FindGlyph_struct fgs;
1047 WORD *ptr;
1048 INT k;
1049
1050 if (pwLogClust[0] < pwLogClust[cChars-1])
1051 fgs.ascending = TRUE;
1052 else
1053 fgs.ascending = FALSE;
1054
1055 fgs.target = target;
1056 ptr = bsearch(&fgs, pwLogClust, cChars, sizeof(WORD), compare_FindGlyph);
1057
1058 if (!ptr)
1059 return -1;
1060
1061 for (k = (ptr - pwLogClust)-1; k >= 0 && pwLogClust[k] == target; k--)
1062 ;
1063 k++;
1064
1065 return k;
1066}
1067
1068/***********************************************************************
1069 * ScriptFreeCache (USP10.@)
1070 *
1071 * Free a script cache.
1072 *
1073 * PARAMS
1074 * psc [I/O] Script cache.
1075 *
1076 * RETURNS
1077 * Success: S_OK
1078 * Failure: Non-zero HRESULT value.
1079 */
1081{
1082 TRACE("%p\n", psc);
1083
1084 if (psc && *psc)
1085 {
1086 unsigned int i;
1087 INT n;
1088
1090 if (--((ScriptCache *)*psc)->refcount > 0)
1091 {
1093 *psc = NULL;
1094 return S_OK;
1095 }
1098
1099 for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
1100 {
1101 heap_free(((ScriptCache *)*psc)->widths[i]);
1102 }
1103 for (i = 0; i < NUM_PAGES; i++)
1104 {
1105 unsigned int j;
1106 if (((ScriptCache *)*psc)->page[i])
1107 for (j = 0; j < GLYPH_MAX / GLYPH_BLOCK_SIZE; j++)
1108 heap_free(((ScriptCache *)*psc)->page[i]->glyphs[j]);
1109 heap_free(((ScriptCache *)*psc)->page[i]);
1110 }
1111 heap_free(((ScriptCache *)*psc)->GSUB_Table);
1112 heap_free(((ScriptCache *)*psc)->GDEF_Table);
1113 heap_free(((ScriptCache *)*psc)->CMAP_Table);
1114 heap_free(((ScriptCache *)*psc)->GPOS_Table);
1115 for (n = 0; n < ((ScriptCache *)*psc)->script_count; n++)
1116 {
1117 int j;
1118 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].language_count; j++)
1119 {
1120 int k;
1121 for (k = 0; k < ((ScriptCache *)*psc)->scripts[n].languages[j].feature_count; k++)
1122 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features[k].lookups);
1123 heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features);
1124 }
1125 for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].default_language.feature_count; j++)
1126 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features[j].lookups);
1127 heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features);
1128 heap_free(((ScriptCache *)*psc)->scripts[n].languages);
1129 }
1130 heap_free(((ScriptCache *)*psc)->scripts);
1131 heap_free(((ScriptCache *)*psc)->otm);
1132 heap_free(*psc);
1133 *psc = NULL;
1134 }
1135 return S_OK;
1136}
1137
1138/***********************************************************************
1139 * ScriptGetProperties (USP10.@)
1140 *
1141 * Retrieve a list of script properties.
1142 *
1143 * PARAMS
1144 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1145 * num [I] Pointer to the number of scripts.
1146 *
1147 * RETURNS
1148 * Success: S_OK
1149 * Failure: Non-zero HRESULT value.
1150 *
1151 * NOTES
1152 * Behaviour matches WinXP.
1153 */
1155{
1156 TRACE("(%p,%p)\n", props, num);
1157
1158 if (!props && !num) return E_INVALIDARG;
1159
1160 if (num) *num = ARRAY_SIZE(script_props);
1161 if (props) *props = script_props;
1162
1163 return S_OK;
1164}
1165
1166/***********************************************************************
1167 * ScriptGetFontProperties (USP10.@)
1168 *
1169 * Get information on special glyphs.
1170 *
1171 * PARAMS
1172 * hdc [I] Device context.
1173 * psc [I/O] Opaque pointer to a script cache.
1174 * sfp [O] Font properties structure.
1175 */
1177{
1178 HRESULT hr;
1179
1180 TRACE("%p,%p,%p\n", hdc, psc, sfp);
1181
1182 if (!sfp) return E_INVALIDARG;
1183 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1184
1185 if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
1186 return E_INVALIDARG;
1187
1189
1190 return S_OK;
1191}
1192
1193/***********************************************************************
1194 * ScriptRecordDigitSubstitution (USP10.@)
1195 *
1196 * Record digit substitution settings for a given locale.
1197 *
1198 * PARAMS
1199 * locale [I] Locale identifier.
1200 * sds [I] Structure to record substitution settings.
1201 *
1202 * RETURNS
1203 * Success: S_OK
1204 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1205 *
1206 * SEE ALSO
1207 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1208 */
1210{
1211 DWORD plgid, sub;
1212
1213 TRACE("0x%x, %p\n", locale, sds);
1214
1215 /* This implementation appears to be correct for all languages, but it's
1216 * not clear if sds->DigitSubstitute is ever set to anything except
1217 * CONTEXT or NONE in reality */
1218
1219 if (!sds) return E_POINTER;
1220
1222
1224 return E_INVALIDARG;
1225
1227 sds->TraditionalDigitLanguage = plgid;
1228
1229 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1230 sds->NationalDigitLanguage = plgid;
1231 else
1233
1234 if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
1235 (WCHAR *)&sub, sizeof(sub) / sizeof(WCHAR)))
1236 return E_INVALIDARG;
1237
1238 switch (sub)
1239 {
1240 case 0:
1241 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1243 else
1245 break;
1246 case 1:
1248 break;
1249 case 2:
1251 break;
1252 default:
1254 break;
1255 }
1256
1257 sds->dwReserved = 0;
1258 return S_OK;
1259}
1260
1261/***********************************************************************
1262 * ScriptApplyDigitSubstitution (USP10.@)
1263 *
1264 * Apply digit substitution settings.
1265 *
1266 * PARAMS
1267 * sds [I] Structure with recorded substitution settings.
1268 * sc [I] Script control structure.
1269 * ss [I] Script state structure.
1270 *
1271 * RETURNS
1272 * Success: S_OK
1273 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1274 */
1277{
1279
1280 TRACE("%p, %p, %p\n", sds, sc, ss);
1281
1282 if (!sc || !ss) return E_POINTER;
1283 if (!sds)
1284 {
1285 sds = &psds;
1287 return E_INVALIDARG;
1288 }
1289
1291 sc->fContextDigits = 0;
1292 ss->fDigitSubstitute = 0;
1293
1294 switch (sds->DigitSubstitute) {
1299 return S_OK;
1300 default:
1301 return E_INVALIDARG;
1302 }
1303}
1304
1306{
1308}
1309
1311{
1312 switch (script)
1313 {
1314 case Script_Devanagari:
1316 case Script_Bengali:
1319 case Script_Gurmukhi:
1321 case Script_Gujarati:
1324 case Script_Oriya:
1326 case Script_Tamil:
1328 case Script_Telugu:
1330 case Script_Kannada:
1332 case Script_Malayalam:
1334 default:
1335 return Script_Undefined;
1336 };
1337}
1338
1340{
1342}
1343
1344static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
1348{
1349
1350#define Numeric_space 0x0020
1351#define ZWSP 0x200B
1352#define ZWNJ 0x200C
1353#define ZWJ 0x200D
1354
1355 enum usp10_script last_indic = Script_Undefined;
1356 int cnt = 0, index = 0, str = 0;
1357 enum usp10_script New_Script = -1;
1358 int i;
1359 WORD *levels = NULL;
1360 WORD *layout_levels = NULL;
1361 WORD *overrides = NULL;
1362 WORD *strength = NULL;
1363 enum usp10_script *scripts;
1364 WORD baselevel = 0;
1365 WORD baselayout = 0;
1366 BOOL new_run;
1367 WORD layoutRTL = 0;
1368 BOOL forceLevels = FALSE;
1369 unsigned int consumed = 0;
1371
1372 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
1374
1375 if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
1376 return E_INVALIDARG;
1377
1378 if (!(scripts = heap_calloc(cInChars, sizeof(*scripts))))
1379 return E_OUTOFMEMORY;
1380
1381 for (i = 0; i < cInChars; i++)
1382 {
1383 if (!consumed)
1384 {
1385 scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
1386 consumed --;
1387 }
1388 else
1389 {
1390 scripts[i] = scripts[i-1];
1391 consumed --;
1392 }
1393 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1394 all Indic scripts */
1395 if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic != Script_Undefined)
1396 scripts[i] = last_indic;
1397 else if (is_indic(scripts[i]))
1398 last_indic = base_indic(scripts[i]);
1399
1400 /* Some unicode points :
1401 (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1402 (Left Right Embed U+202A - Left Right Override U+202D)
1403 (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1404 will force us into bidi mode */
1405 if (!forceLevels && ((pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F) ||
1406 (pwcInChars[i] >= 0x202A && pwcInChars[i] <= 0x202E) ||
1407 (pwcInChars[i] >= 0x2066 && pwcInChars[i] <= 0x2069)))
1408
1409 forceLevels = TRUE;
1410
1411 /* Diacritical marks merge with other scripts */
1412 if (scripts[i] == Script_Diacritical)
1413 {
1414 if (i > 0)
1415 {
1416 if (pScriptTags)
1417 scripts[i] = scripts[i-1];
1418 else
1419 {
1420 int j;
1421 BOOL asian = FALSE;
1422 enum usp10_script first_script = scripts[i-1];
1423 for (j = i-1; j >= 0 && scripts[j] == first_script && pwcInChars[j] != Numeric_space; j--)
1424 {
1425 enum usp10_script original = scripts[j];
1426 if (original == Script_Ideograph || original == Script_Kana || original == Script_Yi || original == Script_CJK_Han || original == Script_Bopomofo)
1427 {
1428 asian = TRUE;
1429 break;
1430 }
1431 if (original != Script_MathAlpha && scriptInformation[scripts[j]].props.fComplex)
1432 break;
1433 scripts[j] = scripts[i];
1434 if (original == Script_Punctuation2)
1435 break;
1436 }
1437 if (j >= 0 && (scriptInformation[scripts[j]].props.fComplex || asian))
1438 scripts[i] = scripts[j];
1439 }
1440 }
1441 }
1442 }
1443
1444 for (i = 0; i < cInChars; i++)
1445 {
1446 /* Joiners get merged preferencially right */
1447 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1448 {
1449 int j;
1450 if (i+1 == cInChars)
1451 scripts[i] = scripts[i-1];
1452 else
1453 {
1454 for (j = i+1; j < cInChars; j++)
1455 {
1456 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1457 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1458 {
1459 scripts[i] = scripts[j];
1460 break;
1461 }
1462 }
1463 }
1464 }
1465 }
1466
1467 if (psState && psControl)
1468 {
1469 if (!(levels = heap_calloc(cInChars, sizeof(*levels))))
1470 goto nomemory;
1471
1472 if (!(overrides = heap_calloc(cInChars, sizeof(*overrides))))
1473 goto nomemory;
1474
1475 if (!(layout_levels = heap_calloc(cInChars, sizeof(*layout_levels))))
1476 goto nomemory;
1477
1478 if (psState->fOverrideDirection)
1479 {
1480 if (!forceLevels)
1481 {
1483 s.fOverrideDirection = FALSE;
1484 BIDI_DetermineLevels(pwcInChars, cInChars, &s, psControl, layout_levels, overrides);
1485 if (odd(layout_levels[0]))
1486 forceLevels = TRUE;
1487 else for (i = 0; i < cInChars; i++)
1488 if (layout_levels[i]!=layout_levels[0])
1489 {
1490 forceLevels = TRUE;
1491 break;
1492 }
1493 }
1494
1495 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1496 }
1497 else
1498 {
1499 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels, overrides);
1500 memcpy(layout_levels, levels, cInChars * sizeof(WORD));
1501 }
1502 baselevel = levels[0];
1503 baselayout = layout_levels[0];
1504 for (i = 0; i < cInChars; i++)
1505 if (levels[i]!=levels[0])
1506 break;
1507 if (i >= cInChars && !odd(baselevel) && !odd(psState->uBidiLevel) && !forceLevels)
1508 {
1510 heap_free(overrides);
1511 heap_free(layout_levels);
1512 overrides = NULL;
1513 levels = NULL;
1514 layout_levels = NULL;
1515 }
1516 else
1517 {
1518 static const WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
1519 static const WCHAR repeatable_math_punc[] = {'#','$','%','+','-','/',0x2212, 0x2044,0};
1520
1521 if (!(strength = heap_calloc(cInChars, sizeof(*strength))))
1522 goto nomemory;
1523 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
1524
1525 /* We currently mis-level leading Diacriticals */
1526 if (scripts[0] == Script_Diacritical)
1527 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
1528 {
1529 levels[i] = odd(levels[i])?levels[i]+1:levels[i];
1530 strength[i] = BIDI_STRONG;
1531 }
1532
1533 /* Math punctuation bordered on both sides by numbers can be
1534 merged into the number */
1535 for (i = 0; i < cInChars; i++)
1536 {
1537 if (i > 0 && i < cInChars-1 &&
1538 script_is_numeric(scripts[i-1]) &&
1539 wcschr(math_punc, pwcInChars[i]))
1540 {
1541 if (script_is_numeric(scripts[i+1]))
1542 {
1543 scripts[i] = scripts[i+1];
1544 levels[i] = levels[i-1];
1545 strength[i] = strength[i-1];
1546 i++;
1547 }
1548 else if (wcschr(repeatable_math_punc, pwcInChars[i]))
1549 {
1550 int j;
1551 for (j = i+1; j < cInChars; j++)
1552 {
1553 if (script_is_numeric(scripts[j]))
1554 {
1555 for(;i<j; i++)
1556 {
1557 scripts[i] = scripts[j];
1558 levels[i] = levels[i-1];
1559 strength[i] = strength[i-1];
1560 }
1561 }
1562 else if (pwcInChars[i] != pwcInChars[j]) break;
1563 }
1564 }
1565 }
1566 }
1567
1568 for (i = 0; i < cInChars; i++)
1569 {
1570 /* Numerics at level 0 get bumped to level 2 */
1571 if (!overrides[i] && (levels[i] == 0 || (odd(psState->uBidiLevel)
1572 && levels[i] == psState->uBidiLevel + 1)) && script_is_numeric(scripts[i]))
1573 {
1574 levels[i] = 2;
1575 }
1576
1577 /* Joiners get merged preferencially right */
1578 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1579 {
1580 int j;
1581 if (i+1 == cInChars && levels[i-1] == levels[i])
1582 strength[i] = strength[i-1];
1583 else
1584 for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
1585 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1586 && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1587 {
1588 strength[i] = strength[j];
1589 break;
1590 }
1591 }
1592 }
1594 {
1595 /* Merge the neutrals */
1596 for (i = 0; i < cInChars; i++)
1597 {
1598 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1599 {
1600 int j;
1601 for (j = i; j > 0; j--)
1602 {
1603 if (levels[i] != levels[j])
1604 break;
1605 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1606 {
1607 scripts[i] = scripts[j];
1608 strength[i] = strength[j];
1609 break;
1610 }
1611 }
1612 }
1613 /* Try going the other way */
1614 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1615 {
1616 int j;
1617 for (j = i; j < cInChars; j++)
1618 {
1619 if (levels[i] != levels[j])
1620 break;
1621 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1622 {
1623 scripts[i] = scripts[j];
1624 strength[i] = strength[j];
1625 break;
1626 }
1627 }
1628 }
1629 }
1630 }
1631 }
1632 }
1633
1634 while ((!levels || (levels && cnt+1 < cInChars && levels[cnt+1] == levels[0]))
1635 && (cnt < cInChars && pwcInChars[cnt] == Numeric_space))
1636 cnt++;
1637
1638 if (cnt == cInChars) /* All Spaces */
1639 {
1640 cnt = 0;
1641 New_Script = scripts[cnt];
1642 }
1643
1644 pItems[index].iCharPos = 0;
1645 pItems[index].a = scriptInformation[scripts[cnt]].a;
1646 if (pScriptTags)
1648
1649 if (strength && strength[cnt] == BIDI_STRONG)
1650 str = strength[cnt];
1651 else if (strength)
1652 str = strength[0];
1653
1654 cnt = 0;
1655
1656 if (levels)
1657 {
1658 if (strength[cnt] == BIDI_STRONG)
1659 layoutRTL = odd(layout_levels[cnt]);
1660 else
1661 layoutRTL = (psState->uBidiLevel || odd(layout_levels[cnt]));
1662 if (overrides)
1663 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1664 pItems[index].a.fRTL = odd(levels[cnt]);
1665 if (script_is_numeric(pItems[index].a.eScript))
1666 pItems[index].a.fLayoutRTL = layoutRTL;
1667 else
1668 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1669 pItems[index].a.s.uBidiLevel = levels[cnt];
1670 }
1671 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1672 {
1673 if (pItems[index].a.s.uBidiLevel != baselevel)
1674 pItems[index].a.s.fOverrideDirection = TRUE;
1675 layoutRTL = odd(baselayout);
1676 pItems[index].a.s.uBidiLevel = baselevel;
1677 pItems[index].a.fRTL = odd(baselevel);
1678 if (script_is_numeric(pItems[index].a.eScript))
1679 pItems[index].a.fLayoutRTL = odd(baselayout);
1680 else
1681 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1682 }
1683
1684 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1685 levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
1686 pItems[index].iCharPos);
1687
1688 for (cnt=1; cnt < cInChars; cnt++)
1689 {
1690 if(pwcInChars[cnt] != Numeric_space)
1691 New_Script = scripts[cnt];
1692 else if (levels)
1693 {
1694 int j = 1;
1695 while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
1696 j++;
1697 if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
1698 New_Script = scripts[cnt+j];
1699 else
1700 New_Script = scripts[cnt];
1701 }
1702
1703 new_run = FALSE;
1704 /* merge space strengths*/
1705 if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
1706 str = BIDI_STRONG;
1707
1708 if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
1709 str = BIDI_NEUTRAL;
1710
1711 /* changes in level */
1712 if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
1713 {
1714 TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
1715 new_run = TRUE;
1716 }
1717 /* changes in strength */
1718 else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
1719 {
1720 TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
1721 new_run = TRUE;
1722 }
1723 /* changes in script */
1724 else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
1725 {
1726 TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
1727 new_run = TRUE;
1728 }
1729
1730 if (!new_run && strength && str == BIDI_STRONG)
1731 {
1732 layoutRTL = odd(layout_levels[cnt]);
1733 if (script_is_numeric(pItems[index].a.eScript))
1734 pItems[index].a.fLayoutRTL = layoutRTL;
1735 }
1736
1737 if (new_run)
1738 {
1739 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);
1740
1741 index++;
1742 if (index+1 > cMaxItems)
1743 goto nomemory;
1744
1745 if (strength)
1746 str = strength[cnt];
1747
1748 pItems[index].iCharPos = cnt;
1749 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1750
1751 pItems[index].a = scriptInformation[New_Script].a;
1752 if (pScriptTags)
1754 if (levels)
1755 {
1756 if (overrides)
1757 pItems[index].a.s.fOverrideDirection = (overrides[cnt] != 0);
1758 if (layout_levels[cnt] == 0)
1759 layoutRTL = 0;
1760 else
1761 layoutRTL = (layoutRTL || odd(layout_levels[cnt]));
1762 pItems[index].a.fRTL = odd(levels[cnt]);
1763 if (script_is_numeric(pItems[index].a.eScript))
1764 pItems[index].a.fLayoutRTL = layoutRTL;
1765 else
1766 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1767 pItems[index].a.s.uBidiLevel = levels[cnt];
1768 }
1769 else if (!pItems[index].a.s.uBidiLevel || (overrides && overrides[cnt]))
1770 {
1771 if (pItems[index].a.s.uBidiLevel != baselevel)
1772 pItems[index].a.s.fOverrideDirection = TRUE;
1773 pItems[index].a.s.uBidiLevel = baselevel;
1774 pItems[index].a.fRTL = odd(baselevel);
1775 if (script_is_numeric(pItems[index].a.eScript))
1776 pItems[index].a.fLayoutRTL = layoutRTL;
1777 else
1778 pItems[index].a.fLayoutRTL = pItems[index].a.fRTL;
1779 }
1780
1781 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1782 }
1783 }
1784
1785 /* While not strictly necessary according to the spec, make sure the n+1
1786 * item is set up to prevent random behaviour if the caller erroneously
1787 * checks the n+1 structure */
1788 index++;
1789 if (index + 1 > cMaxItems) goto nomemory;
1790 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1791
1792 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1793
1794 /* Set one SCRIPT_STATE item being returned */
1795 if (pcItems) *pcItems = index;
1796
1797 /* Set SCRIPT_ITEM */
1798 pItems[index].iCharPos = cnt; /* the last item contains the ptr to the lastchar */
1799 res = S_OK;
1800nomemory:
1802 heap_free(overrides);
1803 heap_free(layout_levels);
1804 heap_free(strength);
1805 heap_free(scripts);
1806 return res;
1807}
1808
1809/***********************************************************************
1810 * ScriptItemizeOpenType (USP10.@)
1811 *
1812 * Split a Unicode string into shapeable parts.
1813 *
1814 * PARAMS
1815 * pwcInChars [I] String to split.
1816 * cInChars [I] Number of characters in pwcInChars.
1817 * cMaxItems [I] Maximum number of items to return.
1818 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1819 * psState [I] Pointer to a SCRIPT_STATE structure.
1820 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1821 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
1822 * pcItems [O] Number of script items returned.
1823 *
1824 * RETURNS
1825 * Success: S_OK
1826 * Failure: Non-zero HRESULT value.
1827 */
1831{
1833}
1834
1835/***********************************************************************
1836 * ScriptItemize (USP10.@)
1837 *
1838 * Split a Unicode string into shapeable parts.
1839 *
1840 * PARAMS
1841 * pwcInChars [I] String to split.
1842 * cInChars [I] Number of characters in pwcInChars.
1843 * cMaxItems [I] Maximum number of items to return.
1844 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1845 * psState [I] Pointer to a SCRIPT_STATE structure.
1846 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1847 * pcItems [O] Number of script items returned.
1848 *
1849 * RETURNS
1850 * Success: S_OK
1851 * Failure: Non-zero HRESULT value.
1852 */
1855 SCRIPT_ITEM *pItems, int *pcItems)
1856{
1858}
1859
1860static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1861{
1862 int defWidth;
1863 int cTabStops=0;
1864 INT *lpTabPos = NULL;
1865 INT nTabOrg = 0;
1866 INT x = 0;
1867
1868 if (pTabdef)
1869 lpTabPos = pTabdef->pTabStops;
1870
1871 if (pTabdef && pTabdef->iTabOrigin)
1872 {
1873 if (pTabdef->iScale)
1874 nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1875 else
1876 nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1877 }
1878
1879 if (pTabdef)
1880 cTabStops = pTabdef->cTabStops;
1881
1882 if (cTabStops == 1)
1883 {
1884 if (pTabdef->iScale)
1885 defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1886 else
1887 defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1888 cTabStops = 0;
1889 }
1890 else
1891 {
1892 if (pTabdef->iScale)
1893 defWidth = (32 * pTabdef->iScale) / 4;
1894 else
1895 defWidth = 8 * psc->tm.tmAveCharWidth;
1896 }
1897
1898 for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1899 {
1900 int position = *lpTabPos;
1901 if (position < 0)
1902 position = -1 * position;
1903 if (pTabdef->iScale)
1904 position = (position * pTabdef->iScale) / 4;
1905 else
1906 position = position * psc->tm.tmAveCharWidth;
1907
1908 if( nTabOrg + position > current_x)
1909 {
1910 if( position >= 0)
1911 {
1912 /* a left aligned tab */
1913 x = (nTabOrg + position) - current_x;
1914 break;
1915 }
1916 else
1917 {
1918 FIXME("Negative tabstop\n");
1919 break;
1920 }
1921 }
1922 }
1923 if ((!cTabStops) && (defWidth > 0))
1924 x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1925 else if ((!cTabStops) && (defWidth < 0))
1926 FIXME("TODO: Negative defWidth\n");
1927
1928 return x;
1929}
1930
1931/***********************************************************************
1932 * Helper function for ScriptStringAnalyse
1933 */
1935 const WCHAR *pwcInChars, int cChars )
1936{
1937 /* FIXME: When to properly fallback is still a bit of a mystery */
1938 WORD *glyphs;
1939
1940 if (psa->fNoGlyphIndex)
1941 return FALSE;
1942
1943 if (init_script_cache(hdc, psc) != S_OK)
1944 return FALSE;
1945
1947 return TRUE;
1948
1949 if (!(glyphs = heap_calloc(cChars, sizeof(*glyphs))))
1950 return FALSE;
1951 if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1952 {
1954 return TRUE;
1955 }
1957
1958 return FALSE;
1959}
1960
1961static void find_fallback_font(enum usp10_script scriptid, WCHAR *FaceName)
1962{
1963 HKEY hkey;
1964
1965 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1966 {
1967 static const WCHAR szFmt[] = {'%','x',0};
1968 WCHAR value[10];
1969 DWORD count = LF_FACESIZE * sizeof(WCHAR);
1970 DWORD type;
1971
1972 swprintf(value, szFmt, scriptInformation[scriptid].scriptTag);
1973 if (RegQueryValueExW(hkey, value, 0, &type, (BYTE *)FaceName, &count))
1974 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1975 RegCloseKey(hkey);
1976 }
1977 else
1978 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1979}
1980
1981/***********************************************************************
1982 * ScriptStringAnalyse (USP10.@)
1983 *
1984 */
1986 int cGlyphs, int iCharset, DWORD dwFlags,
1987 int iReqWidth, SCRIPT_CONTROL *psControl,
1988 SCRIPT_STATE *psState, const int *piDx,
1989 SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1991{
1993 StringAnalysis *analysis = NULL;
1994 SCRIPT_CONTROL sControl;
1995 SCRIPT_STATE sState;
1996 int i, num_items = 255;
1997 BYTE *BidiLevel;
1998 WCHAR *iString = NULL;
1999
2000 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
2001 hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
2002 psControl, psState, piDx, pTabdef, pbInClass, pssa);
2003
2004 if (iCharset != -1)
2005 {
2006 FIXME("Only Unicode strings are supported\n");
2007 return E_INVALIDARG;
2008 }
2009 if (cString < 1 || !pString) return E_INVALIDARG;
2010 if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
2011
2012 if (!(analysis = heap_alloc_zero(sizeof(*analysis))))
2013 return E_OUTOFMEMORY;
2014 if (!(analysis->pItem = heap_calloc(num_items + 1, sizeof(*analysis->pItem))))
2015 goto error;
2016
2017 /* FIXME: handle clipping */
2018 analysis->clip_len = cString;
2019 analysis->hdc = hdc;
2020 analysis->ssa_flags = dwFlags;
2021
2022 if (psState)
2023 sState = *psState;
2024 else
2025 memset(&sState, 0, sizeof(SCRIPT_STATE));
2026
2027 if (psControl)
2028 sControl = *psControl;
2029 else
2030 memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
2031
2032 if (dwFlags & SSA_PASSWORD)
2033 {
2034 if (!(iString = heap_calloc(cString, sizeof(*iString))))
2035 {
2036 hr = E_OUTOFMEMORY;
2037 goto error;
2038 }
2039 for (i = 0; i < cString; i++)
2040 iString[i] = *((const WCHAR *)pString);
2041 pString = iString;
2042 }
2043
2044 hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
2045 &analysis->numItems);
2046
2047 if (FAILED(hr))
2048 {
2049 if (hr == E_OUTOFMEMORY)
2050 hr = E_INVALIDARG;
2051 goto error;
2052 }
2053
2054 /* set back to out of memory for default goto error behaviour */
2055 hr = E_OUTOFMEMORY;
2056
2057 if (dwFlags & SSA_BREAK)
2058 {
2059 if (!(analysis->logattrs = heap_calloc(cString, sizeof(*analysis->logattrs))))
2060 goto error;
2061
2062 for (i = 0; i < analysis->numItems; ++i)
2063 ScriptBreak(&((const WCHAR *)pString)[analysis->pItem[i].iCharPos],
2064 analysis->pItem[i + 1].iCharPos - analysis->pItem[i].iCharPos,
2065 &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
2066 }
2067
2068 if (!(analysis->logical2visual = heap_calloc(analysis->numItems, sizeof(*analysis->logical2visual))))
2069 goto error;
2070 if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
2071 goto error;
2072
2073 if (dwFlags & SSA_GLYPHS)
2074 {
2075 int tab_x = 0;
2076
2077 if (!(analysis->glyphs = heap_calloc(analysis->numItems, sizeof(*analysis->glyphs))))
2078 {
2079 heap_free(BidiLevel);
2080 goto error;
2081 }
2082
2083 for (i = 0; i < analysis->numItems; i++)
2084 {
2085 SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
2086 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2087 int numGlyphs = 1.5 * cChar + 16;
2088 WORD *glyphs = heap_calloc(numGlyphs, sizeof(*glyphs));
2089 WORD *pwLogClust = heap_calloc(cChar, sizeof(*pwLogClust));
2090 int *piAdvance = heap_calloc(numGlyphs, sizeof(*piAdvance));
2091 SCRIPT_VISATTR *psva = heap_calloc(numGlyphs, sizeof(*psva));
2092 GOFFSET *pGoffset = heap_calloc(numGlyphs, sizeof(*pGoffset));
2093 int numGlyphsReturned;
2094 HFONT originalFont = 0x0;
2095
2096 /* FIXME: non unicode strings */
2097 const WCHAR* pStr = (const WCHAR*)pString;
2098 analysis->glyphs[i].fallbackFont = NULL;
2099
2100 if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset)
2101 {
2102 heap_free (BidiLevel);
2103 heap_free (glyphs);
2105 heap_free (piAdvance);
2106 heap_free (psva);
2107 heap_free (pGoffset);
2108 hr = E_OUTOFMEMORY;
2109 goto error;
2110 }
2111
2112 if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
2113 {
2114 LOGFONTW lf;
2115 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
2117 lf.lfFaceName[0] = 0;
2118 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
2119 if (lf.lfFaceName[0])
2120 {
2121 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
2122 if (analysis->glyphs[i].fallbackFont)
2123 {
2124 ScriptFreeCache(sc);
2125 originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
2126 }
2127 }
2128 }
2129
2130 /* FIXME: When we properly shape Hangul remove this check */
2131 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && analysis->pItem[i].a.eScript == Script_Hangul)
2132 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2133
2134 if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && !scriptInformation[analysis->pItem[i].a.eScript].props.fComplex && !analysis->pItem[i].a.fRTL)
2135 analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2136
2137 ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos], cChar, numGlyphs,
2138 &analysis->pItem[i].a, glyphs, pwLogClust, psva, &numGlyphsReturned);
2139 hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
2140 piAdvance, pGoffset, &analysis->glyphs[i].abc);
2141 if (originalFont)
2142 SelectObject(hdc,originalFont);
2143
2144 if (dwFlags & SSA_TAB)
2145 {
2146 int tabi = 0;
2147 for (tabi = 0; tabi < cChar; tabi++)
2148 {
2149 if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
2150 piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
2151 tab_x+=piAdvance[tabi];
2152 }
2153 }
2154
2155 analysis->glyphs[i].numGlyphs = numGlyphsReturned;
2156 analysis->glyphs[i].glyphs = glyphs;
2157 analysis->glyphs[i].pwLogClust = pwLogClust;
2158 analysis->glyphs[i].piAdvance = piAdvance;
2159 analysis->glyphs[i].psva = psva;
2160 analysis->glyphs[i].pGoffset = pGoffset;
2161 analysis->glyphs[i].iMaxPosX= -1;
2162
2163 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2164 }
2165 }
2166 else
2167 {
2168 for (i = 0; i < analysis->numItems; i++)
2169 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2170 }
2171
2172 ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
2173 heap_free(BidiLevel);
2174
2175 *pssa = analysis;
2176 heap_free(iString);
2177 return S_OK;
2178
2179error:
2180 heap_free(iString);
2181 heap_free(analysis->glyphs);
2182 heap_free(analysis->logattrs);
2183 heap_free(analysis->pItem);
2184 heap_free(analysis->logical2visual);
2185 heap_free(analysis);
2186 return hr;
2187}
2188
2189static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
2190{
2191 if (pva[glyph].fClusterStart)
2192 return TRUE;
2194 return TRUE;
2195
2196 return FALSE;
2197}
2198
2199
2201 int iX,
2202 int iY,
2203 int iItem,
2204 int cStart,
2205 int cEnd,
2206 UINT uOptions,
2207 const RECT *prc,
2208 BOOL fSelected,
2209 BOOL fDisabled)
2210{
2211 StringAnalysis *analysis;
2212 int off_x = 0;
2213 HRESULT hr;
2214 COLORREF BkColor = 0x0;
2215 COLORREF TextColor = 0x0;
2216 INT BkMode = 0;
2217 INT runStart, runEnd;
2218 INT iGlyph, cGlyphs;
2219 HFONT oldFont = 0x0;
2220 RECT crc;
2221 int i;
2222
2223 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2224 ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
2225
2226 if (!(analysis = ssa)) return E_INVALIDARG;
2227
2228 if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
2229 (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
2230 return S_OK;
2231
2232 CopyRect(&crc,prc);
2233 if (fSelected)
2234 {
2235 BkMode = GetBkMode(analysis->hdc);
2236 SetBkMode( analysis->hdc, OPAQUE);
2237 BkColor = GetBkColor(analysis->hdc);
2239 if (!fDisabled)
2240 {
2241 TextColor = GetTextColor(analysis->hdc);
2243 }
2244 }
2245 if (analysis->glyphs[iItem].fallbackFont)
2246 oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
2247
2248 if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
2249 runStart = cStart - analysis->pItem[iItem].iCharPos;
2250 else
2251 runStart = 0;
2252 if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
2253 runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
2254 else
2255 runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
2256
2257 if (analysis->pItem[iItem].a.fRTL)
2258 {
2259 if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
2260 ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
2261 else
2262 ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
2263 crc.left = iX + off_x;
2264 }
2265 else
2266 {
2267 if (cStart >=0 && runStart)
2268 ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
2269 else
2270 ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
2271 crc.left = iX + off_x;
2272 }
2273
2274 if (analysis->pItem[iItem].a.fRTL)
2275 iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
2276 else
2277 iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
2278
2279 if (analysis->pItem[iItem].a.fRTL)
2280 cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
2281 else
2282 cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
2283
2284 cGlyphs++;
2285
2286 /* adjust for cluster glyphs when starting */
2287 if (analysis->pItem[iItem].a.fRTL)
2288 i = analysis->pItem[iItem+1].iCharPos - 1;
2289 else
2290 i = analysis->pItem[iItem].iCharPos;
2291
2292 for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
2293 {
2294 if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
2295 {
2296 if (analysis->pItem[iItem].a.fRTL)
2297 ScriptStringCPtoX(ssa, i, TRUE, &off_x);
2298 else
2299 ScriptStringCPtoX(ssa, i, FALSE, &off_x);
2300 break;
2301 }
2302 }
2303
2304 if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
2305 {
2306 INT direction;
2307 INT clust_glyph;
2308
2309 clust_glyph = iGlyph + cGlyphs;
2310 if (analysis->pItem[iItem].a.fRTL)
2311 direction = -1;
2312 else
2313 direction = 1;
2314
2315 while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
2316 !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
2317 {
2318 cGlyphs++;
2319 clust_glyph++;
2320 }
2321 }
2322
2323 hr = ScriptTextOut(analysis->hdc,
2324 (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
2325 iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
2326 &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
2327 &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
2328 &analysis->glyphs[iItem].pGoffset[iGlyph]);
2329
2330 TRACE("ScriptTextOut hr=%08x\n", hr);
2331
2332 if (fSelected)
2333 {
2334 SetBkColor(analysis->hdc, BkColor);
2335 SetBkMode( analysis->hdc, BkMode);
2336 if (!fDisabled)
2337 SetTextColor(analysis->hdc, TextColor);
2338 }
2339 if (analysis->glyphs[iItem].fallbackFont)
2340 SelectObject(analysis->hdc, oldFont);
2341
2342 return hr;
2343}
2344
2345/***********************************************************************
2346 * ScriptStringOut (USP10.@)
2347 *
2348 * This function takes the output of ScriptStringAnalyse and joins the segments
2349 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2350 * only processes glyphs.
2351 *
2352 * Parameters:
2353 * ssa [I] buffer to hold the analysed string components
2354 * iX [I] X axis displacement for output
2355 * iY [I] Y axis displacement for output
2356 * uOptions [I] flags controlling output processing
2357 * prc [I] rectangle coordinates
2358 * iMinSel [I] starting pos for substringing output string
2359 * iMaxSel [I] ending pos for substringing output string
2360 * fDisabled [I] controls text highlighting
2361 *
2362 * RETURNS
2363 * Success: S_OK
2364 * Failure: is the value returned by ScriptTextOut
2365 */
2367 int iX,
2368 int iY,
2369 UINT uOptions,
2370 const RECT *prc,
2371 int iMinSel,
2372 int iMaxSel,
2373 BOOL fDisabled)
2374{
2375 StringAnalysis *analysis;
2376 int item;
2377 HRESULT hr;
2378
2379 TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2380 ssa, iX, iY, uOptions, wine_dbgstr_rect(prc), iMinSel, iMaxSel, fDisabled);
2381
2382 if (!(analysis = ssa)) return E_INVALIDARG;
2383 if (!(analysis->ssa_flags & SSA_GLYPHS)) return E_INVALIDARG;
2384
2385 for (item = 0; item < analysis->numItems; item++)
2386 {
2387 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
2388 if (FAILED(hr))
2389 return hr;
2390 }
2391
2392 if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
2393 {
2394 if (iMaxSel > 0 && iMinSel < 0)
2395 iMinSel = 0;
2396 for (item = 0; item < analysis->numItems; item++)
2397 {
2398 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
2399 if (FAILED(hr))
2400 return hr;
2401 }
2402 }
2403
2404 return S_OK;
2405}
2406
2407/***********************************************************************
2408 * ScriptStringCPtoX (USP10.@)
2409 *
2410 */
2412{
2413 int item;
2414 int runningX = 0;
2415 StringAnalysis* analysis = ssa;
2416
2417 TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
2418
2419 if (!ssa || !pX) return S_FALSE;
2420 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
2421
2422 /* icp out of range */
2423 if(icp < 0)
2424 {
2426 return E_INVALIDARG;
2427 }
2428
2429 for(item=0; item<analysis->numItems; item++)
2430 {
2431 int CP, i;
2432 int offset;
2433
2434 i = analysis->logical2visual[item];
2435 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2436 /* initialize max extents for uninitialized runs */
2437 if (analysis->glyphs[i].iMaxPosX == -1)
2438 {
2439 if (analysis->pItem[i].a.fRTL)
2440 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2441 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2442 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2443 else
2444 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2445 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2446 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2447 }
2448
2449 if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
2450 {
2451 runningX += analysis->glyphs[i].iMaxPosX;
2452 continue;
2453 }
2454
2455 icp -= analysis->pItem[i].iCharPos;
2456 ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2457 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2458 &analysis->pItem[i].a, &offset);
2459 runningX += offset;
2460
2461 *pX = runningX;
2462 return S_OK;
2463 }
2464
2465 /* icp out of range */
2467 return E_INVALIDARG;
2468}
2469
2470/***********************************************************************
2471 * ScriptStringXtoCP (USP10.@)
2472 *
2473 */
2474HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
2475{
2476 StringAnalysis* analysis = ssa;
2477 int item;
2478
2479 TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
2480
2481 if (!ssa || !piCh || !piTrailing) return S_FALSE;
2482 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
2483
2484 /* out of range */
2485 if(iX < 0)
2486 {
2487 if (analysis->pItem[0].a.fRTL)
2488 {
2489 *piCh = 1;
2490 *piTrailing = FALSE;
2491 }
2492 else
2493 {
2494 *piCh = -1;
2495 *piTrailing = TRUE;
2496 }
2497 return S_OK;
2498 }
2499
2500 for(item=0; item<analysis->numItems; item++)
2501 {
2502 int i;
2503 int CP;
2504
2505 for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
2506 /* nothing */;
2507
2508 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2509 /* initialize max extents for uninitialized runs */
2510 if (analysis->glyphs[i].iMaxPosX == -1)
2511 {
2512 if (analysis->pItem[i].a.fRTL)
2513 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2514 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2515 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2516 else
2517 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2518 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2519 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2520 }
2521
2522 if (iX > analysis->glyphs[i].iMaxPosX)
2523 {
2524 iX -= analysis->glyphs[i].iMaxPosX;
2525 continue;
2526 }
2527
2528 ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2529 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2530 &analysis->pItem[i].a, piCh, piTrailing);
2531 *piCh += analysis->pItem[i].iCharPos;
2532
2533 return S_OK;
2534 }
2535
2536 /* out of range */
2537 *piCh = analysis->pItem[analysis->numItems].iCharPos;
2538 *piTrailing = FALSE;
2539
2540 return S_OK;
2541}
2542
2543
2544/***********************************************************************
2545 * ScriptStringFree (USP10.@)
2546 *
2547 * Free a string analysis.
2548 *
2549 * PARAMS
2550 * pssa [I] string analysis.
2551 *
2552 * RETURNS
2553 * Success: S_OK
2554 * Failure: Non-zero HRESULT value.
2555 */
2557{
2558 StringAnalysis* analysis;
2559 BOOL invalid;
2560 int i;
2561
2562 TRACE("(%p)\n", pssa);
2563
2564 if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
2565
2567
2568 if (analysis->glyphs)
2569 {
2570 for (i = 0; i < analysis->numItems; i++)
2571 {
2572 heap_free(analysis->glyphs[i].glyphs);
2573 heap_free(analysis->glyphs[i].pwLogClust);
2574 heap_free(analysis->glyphs[i].piAdvance);
2575 heap_free(analysis->glyphs[i].psva);
2576 heap_free(analysis->glyphs[i].pGoffset);
2577 if (analysis->glyphs[i].fallbackFont)
2578 DeleteObject(analysis->glyphs[i].fallbackFont);
2579 ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
2580 heap_free(analysis->glyphs[i].sc);
2581 }
2582 heap_free(analysis->glyphs);
2583 }
2584
2585 heap_free(analysis->pItem);
2586 heap_free(analysis->logattrs);
2587 heap_free(analysis->logical2visual);
2588 heap_free(analysis);
2589
2590 if (invalid) return E_INVALIDARG;
2591 return S_OK;
2592}
2593
2594static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
2595 int direction, int* iCluster, int *check_out)
2596{
2597 int clust_size = 1;
2598 int check;
2599 WORD clust = pwLogClust[item];
2600
2601 for (check = item+direction; check < cChars && check >= 0; check+=direction)
2602 {
2603 if (pwLogClust[check] == clust)
2604 {
2605 clust_size ++;
2606 if (iCluster && *iCluster == -1)
2607 *iCluster = item;
2608 }
2609 else break;
2610 }
2611
2612 if (check_out)
2613 *check_out = check;
2614
2615 return clust_size;
2616}
2617
2618static inline int get_glyph_cluster_advance(const int* piAdvance, const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cGlyphs, int cChars, int glyph, int direction)
2619{
2620 int advance;
2621 int log_clust_max;
2622
2623 advance = piAdvance[glyph];
2624
2625 if (pwLogClust[0] > pwLogClust[cChars-1])
2626 log_clust_max = pwLogClust[0];
2627 else
2628 log_clust_max = pwLogClust[cChars-1];
2629
2630 if (glyph > log_clust_max)
2631 return advance;
2632
2633 for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
2634 {
2635
2636 if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
2637 break;
2638 if (glyph > log_clust_max)
2639 break;
2640 advance += piAdvance[glyph];
2641 }
2642
2643 return advance;
2644}
2645
2646/***********************************************************************
2647 * ScriptCPtoX (USP10.@)
2648 *
2649 */
2651 BOOL fTrailing,
2652 int cChars,
2653 int cGlyphs,
2654 const WORD *pwLogClust,
2655 const SCRIPT_VISATTR *psva,
2656 const int *piAdvance,
2657 const SCRIPT_ANALYSIS *psa,
2658 int *piX)
2659{
2660 int item;
2661 float iPosX;
2662 int iSpecial = -1;
2663 int iCluster = -1;
2664 int clust_size = 1;
2665 float special_size = 0.0;
2666 int iMaxPos = 0;
2667 int advance = 0;
2668 BOOL rtl = FALSE;
2669
2670 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2671 iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2672 psa, piX);
2673
2674 if (psa->fRTL && ! psa->fLogicalOrder)
2675 rtl = TRUE;
2676
2677 if (fTrailing)
2678 iCP++;
2679
2680 if (rtl)
2681 {
2682 int max_clust = pwLogClust[0];
2683
2684 for (item=0; item < cGlyphs; item++)
2685 if (pwLogClust[item] > max_clust)
2686 {
2687 ERR("We do not handle non reversed clusters properly\n");
2688 break;
2689 }
2690
2691 iMaxPos = 0;
2692 for (item = max_clust; item >=0; item --)
2693 iMaxPos += piAdvance[item];
2694 }
2695
2696 iPosX = 0.0;
2697 for (item=0; item < iCP && item < cChars; item++)
2698 {
2699 if (iSpecial == -1 && (iCluster == -1 || iCluster+clust_size <= item))
2700 {
2701 int check;
2702 int clust = pwLogClust[item];
2703
2704 iCluster = -1;
2705 clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2706 &check);
2707
2708 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2709
2710 if (check >= cChars && !iMaxPos)
2711 {
2712 int glyph;
2713 for (glyph = clust; glyph < cGlyphs; glyph++)
2714 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, glyph, 1);
2715 iSpecial = item;
2716 special_size /= (cChars - item);
2717 iPosX += special_size;
2718 }
2719 else
2720 {
2722 {
2723 clust_size --;
2724 if (clust_size == 0)
2725 iPosX += advance;
2726 }
2727 else
2728 iPosX += advance / (float)clust_size;
2729 }
2730 }
2731 else if (iSpecial != -1)
2732 iPosX += special_size;
2733 else /* (iCluster != -1) */
2734 {
2735 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2737 {
2738 clust_size --;
2739 if (clust_size == 0)
2740 iPosX += adv;
2741 }
2742 else
2743 iPosX += adv / (float)clust_size;
2744 }
2745 }
2746
2747 if (iMaxPos > 0)
2748 {
2749 iPosX = iMaxPos - iPosX;
2750 if (iPosX < 0)
2751 iPosX = 0;
2752 }
2753
2754 *piX = iPosX;
2755 TRACE("*piX=%d\n", *piX);
2756 return S_OK;
2757}
2758
2759/* Count the number of characters in a cluster and its starting index*/
2760static inline BOOL get_cluster_data(const WORD *pwLogClust, int cChars, int cluster_index, int *cluster_size, int *start_index)
2761{
2762 int size = 0;
2763 int i;
2764
2765 for (i = 0; i < cChars; i++)
2766 {
2767 if (pwLogClust[i] == cluster_index)
2768 {
2769 if (!size && start_index)
2770 {
2771 *start_index = i;
2772 if (!cluster_size)
2773 return TRUE;
2774 }
2775 size++;
2776 }
2777 else if (size) break;
2778 }
2779 if (cluster_size)
2780 *cluster_size = size;
2781
2782 return (size > 0);
2783}
2784
2785/*
2786 To handle multi-glyph clusters we need to find all the glyphs that are
2787 represented in the cluster. This involves finding the glyph whose
2788 index is the cluster index as well as whose glyph indices are greater than
2789 our cluster index but not part of a new cluster.
2790
2791 Then we sum all those glyphs' advances.
2792*/
2793static inline int get_cluster_advance(const int* piAdvance,
2794 const SCRIPT_VISATTR *psva,
2795 const WORD *pwLogClust, int cGlyphs,
2796 int cChars, int cluster, int direction)
2797{
2798 int glyph_start;
2799 int glyph_end;
2800 int i, advance;
2801
2802 if (direction > 0)
2803 i = 0;
2804 else
2805 i = (cChars - 1);
2806
2807 for (glyph_start = -1, glyph_end = -1; i < cChars && i >= 0 && (glyph_start < 0 || glyph_end < 0); i+=direction)
2808 {
2809 if (glyph_start < 0 && pwLogClust[i] != cluster) continue;
2810 if (pwLogClust[i] == cluster && glyph_start < 0) glyph_start = pwLogClust[i];
2811 if (glyph_start >= 0 && glyph_end < 0 && pwLogClust[i] != cluster) glyph_end = pwLogClust[i];
2812 }
2813 if (glyph_end < 0)
2814 {
2815 if (direction > 0)
2816 glyph_end = cGlyphs;
2817 else
2818 {
2819 /* Don't fully understand multi-glyph reversed clusters yet,
2820 * do they occur for real or just in our test? */
2821 FIXME("multi-glyph reversed clusters found\n");
2822 glyph_end = glyph_start + 1;
2823 }
2824 }
2825
2826 /* Check for fClusterStart, finding this generally would mean a malformed set of data */
2827 for (i = glyph_start+1; i< glyph_end; i++)
2828 {
2829 if (psva[i].fClusterStart)
2830 {
2831 glyph_end = i;
2832 break;
2833 }
2834 }
2835
2836 for (advance = 0, i = glyph_start; i < glyph_end; i++)
2837 advance += piAdvance[i];
2838
2839 return advance;
2840}
2841
2842
2843/***********************************************************************
2844 * ScriptXtoCP (USP10.@)
2845 *
2846 * Basic algorithm :
2847 * Use piAdvance to find the cluster we are looking at.
2848 * Find the character that is the first character of the cluster.
2849 * That is our base piCP.
2850 * If the script snaps to cluster boundaries (Hebrew, Indic, Thai) then we
2851 * are good. Otherwise if the cluster is larger than 1 glyph we need to
2852 * determine how far through the cluster to advance the cursor.
2853 */
2855 int cChars,
2856 int cGlyphs,
2857 const WORD *pwLogClust,
2858 const SCRIPT_VISATTR *psva,
2859 const int *piAdvance,
2860 const SCRIPT_ANALYSIS *psa,
2861 int *piCP,
2862 int *piTrailing)
2863{
2864 int direction = 1;
2865 int iPosX;
2866 int i;
2867 int glyph_index, cluster_index;
2868 int cluster_size;
2869
2870 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2871 iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2872 psa, piCP, piTrailing);
2873
2874 if (psa->fRTL && ! psa->fLogicalOrder)
2875 direction = -1;
2876
2877 /* Handle an iX < 0 */
2878 if (iX < 0)
2879 {
2880 if (direction < 0)
2881 {
2882 *piCP = cChars;
2883 *piTrailing = 0;
2884 }
2885 else
2886 {
2887 *piCP = -1;
2888 *piTrailing = 1;
2889 }
2890 return S_OK;
2891 }
2892
2893 /* Looking for non-reversed clusters in a reversed string */
2894 if (direction < 0)
2895 {
2896 int max_clust = pwLogClust[0];
2897 for (i=0; i< cChars; i++)
2898 if (pwLogClust[i] > max_clust)
2899 {
2900 FIXME("We do not handle non reversed clusters properly\n");
2901 break;
2902 }
2903 }
2904
2905 /* find the glyph_index based in iX */
2906 if (direction > 0)
2907 {
2908 for (glyph_index = -1, iPosX = iX; iPosX >=0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2909 ;
2910 }
2911 else
2912 {
2913 for (glyph_index = -1, iPosX = iX; iPosX > 0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2914 ;
2915 }
2916
2917 TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX, glyph_index, cGlyphs);
2918
2919 *piTrailing = 0;
2920 if (glyph_index >= 0 && glyph_index < cGlyphs)
2921 {
2922 /* find the cluster */
2923 if (direction > 0 )
2924 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] <= glyph_index; cluster_index=pwLogClust[i++])
2925 ;
2926 else
2927 for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] >= glyph_index; cluster_index=pwLogClust[i++])
2928 ;
2929
2930 TRACE("cluster_index %i\n", cluster_index);
2931
2932 if (direction < 0 && iPosX >= 0 && glyph_index != cluster_index)
2933 {
2934 /* We are off the end of the string */
2935 *piCP = -1;
2936 *piTrailing = 1;
2937 return S_OK;
2938 }
2939
2940 get_cluster_data(pwLogClust, cChars, cluster_index, &cluster_size, &i);
2941
2942 TRACE("first char index %i\n",i);
2944 {
2945 /* Check trailing */
2946 if (glyph_index != cluster_index ||
2947 (direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2948 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2949 *piTrailing = cluster_size;
2950 }
2951 else
2952 {
2953 if (cluster_size > 1)
2954 {
2955 /* Be part way through the glyph cluster based on size and position */
2956 int cluster_advance = get_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, cluster_index, direction);
2957 double cluster_part_width = cluster_advance / (float)cluster_size;
2958 double adv;
2959 int part_index;
2960
2961 /* back up to the beginning of the cluster */
2962 for (adv = iPosX, part_index = cluster_index; part_index <= glyph_index; part_index++)
2963 adv += piAdvance[part_index];
2964 if (adv > iX) adv = iX;
2965
2966 TRACE("Multi-char cluster, no snap\n");
2967 TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size, adv);
2968 TRACE("advance %i divides into %f per char\n", cluster_advance, cluster_part_width);
2969 if (direction > 0)
2970 {
2971 for (part_index = 0; adv >= 0; adv-=cluster_part_width, part_index++)
2972 ;
2973 if (part_index) part_index--;
2974 }
2975 else
2976 {
2977 for (part_index = 0; adv > 0; adv-=cluster_part_width, part_index++)
2978 ;
2979 if (part_index > cluster_size)
2980 {
2981 adv += cluster_part_width;
2982 part_index=cluster_size;
2983 }
2984 }
2985
2986 TRACE("base_char %i part_index %i, leftover advance %f\n",i, part_index, adv);
2987
2988 if (direction > 0)
2989 i += part_index;
2990 else
2991 i += (cluster_size - part_index);
2992
2993 /* Check trailing */
2994 if ((direction > 0 && fabs(adv) <= (cluster_part_width / 2.0)) ||
2995 (direction < 0 && adv && fabs(adv) >= (cluster_part_width / 2.0)))
2996 *piTrailing = 1;
2997 }
2998 else
2999 {
3000 /* Check trailing */
3001 if ((direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
3002 (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
3003 *piTrailing = 1;
3004 }
3005 }
3006 }
3007 else
3008 {
3009 TRACE("Point falls outside of string\n");
3010 if (glyph_index < 0)
3011 i = cChars-1;
3012 else /* (glyph_index >= cGlyphs) */
3013 i = cChars;
3014
3015 /* If not snaping in the reverse direction (such as Hebrew) Then 0
3016 point flow to the next character */
3017 if (direction < 0)
3018 {
3019 if (!scriptInformation[psa->eScript].props.fNeedsCaretInfo && abs(iPosX) == piAdvance[glyph_index])
3020 i++;
3021 else
3022 *piTrailing = 1;
3023 }
3024 }
3025
3026 *piCP = i;
3027
3028 TRACE("*piCP=%d\n", *piCP);
3029 TRACE("*piTrailing=%d\n", *piTrailing);
3030 return S_OK;
3031}
3032
3033/***********************************************************************
3034 * ScriptBreak (USP10.@)
3035 *
3036 * Retrieve line break information.
3037 *
3038 * PARAMS
3039 * chars [I] Array of characters.
3040 * sa [I] Script analysis.
3041 * la [I] Array of logical attribute structures.
3042 *
3043 * RETURNS
3044 * Success: S_OK
3045 * Failure: S_FALSE
3046 */
3048{
3049 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
3050
3051 if (count < 0 || !la) return E_INVALIDARG;
3052 if (count == 0) return E_FAIL;
3053
3054 BREAK_line(chars, count, sa, la);
3055
3056 return S_OK;
3057}
3058
3059/***********************************************************************
3060 * ScriptIsComplex (USP10.@)
3061 *
3062 * Determine if a string is complex.
3063 *
3064 * PARAMS
3065 * chars [I] Array of characters to test.
3066 * len [I] Length in characters.
3067 * flag [I] Flag.
3068 *
3069 * RETURNS
3070 * Success: S_OK
3071 * Failure: S_FALSE
3072 *
3073 */
3075{
3076 enum usp10_script script;
3077 unsigned int i, consumed;
3078
3079 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
3080
3081 if (!chars || len < 0)
3082 return E_INVALIDARG;
3083
3084 for (i = 0; i < len; i+=consumed)
3085 {
3086 if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
3087 return S_OK;
3088
3089 script = get_char_script(chars,i,len, &consumed);
3090 if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
3092 return S_OK;
3093 }
3094 return S_FALSE;
3095}
3096
3097/***********************************************************************
3098 * ScriptShapeOpenType (USP10.@)
3099 *
3100 * Produce glyphs and visual attributes for a run.
3101 *
3102 * PARAMS
3103 * hdc [I] Device context.
3104 * psc [I/O] Opaque pointer to a script cache.
3105 * psa [I/O] Script analysis.
3106 * tagScript [I] The OpenType tag for the Script
3107 * tagLangSys [I] The OpenType tag for the Language
3108 * rcRangeChars[I] Array of Character counts in each range
3109 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3110 * cRanges [I] Count of ranges
3111 * pwcChars [I] Array of characters specifying the run.
3112 * cChars [I] Number of characters in pwcChars.
3113 * cMaxGlyphs [I] Length of pwOutGlyphs.
3114 * pwLogClust [O] Array of logical cluster info.
3115 * pCharProps [O] Array of character property values
3116 * pwOutGlyphs [O] Array of glyphs.
3117 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3118 * pcGlyphs [O] Number of glyphs returned.
3119 *
3120 * RETURNS
3121 * Success: S_OK
3122 * Failure: Non-zero HRESULT value.
3123 */
3128 int cRanges, const WCHAR *pwcChars, int cChars,
3132{
3133 HRESULT hr;
3134 int i;
3135 unsigned int g;
3136 BOOL rtl;
3137 int cluster;
3138 static int once = 0;
3139
3140 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3141 hdc, psc, psa,
3142 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3145
3146 if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
3147 psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
3148
3149 if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
3150 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3151
3152 if (cRanges)
3153 if(!once++) FIXME("Ranges not supported yet\n");
3154
3155 rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
3156
3157 *pcGlyphs = cChars;
3158 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3159 if (!pwLogClust) return E_FAIL;
3160
3161 ((ScriptCache *)*psc)->userScript = tagScript;
3162 ((ScriptCache *)*psc)->userLang = tagLangSys;
3163
3164 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3165 for (i = 0; i < cChars; i++)
3166 {
3167 int idx = i;
3168 if (rtl) idx = cChars - 1 - i;
3169 /* FIXME: set to better values */
3170 pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
3171 pOutGlyphProps[i].sva.fClusterStart = 1;
3172 pOutGlyphProps[i].sva.fDiacritic = 0;
3173 pOutGlyphProps[i].sva.fZeroWidth = 0;
3174 pOutGlyphProps[i].sva.fReserved = 0;
3175 pOutGlyphProps[i].sva.fShapeReserved = 0;
3176
3177 /* FIXME: have the shaping engine set this */
3178 pCharProps[i].fCanGlyphAlone = 0;
3179
3180 pwLogClust[i] = idx;
3181 }
3182
3183 if (psa && !psa->fNoGlyphIndex && ((ScriptCache *)*psc)->sfnt)
3184 {
3185 WCHAR *rChars;
3187
3188 if (!(rChars = heap_calloc(cChars, sizeof(*rChars))))
3189 return E_OUTOFMEMORY;
3190
3191 for (i = 0, g = 0, cluster = 0; i < cChars; i++)
3192 {
3193 int idx = i;
3194 DWORD chInput;
3195
3196 if (rtl) idx = cChars - 1 - i;
3197 if (!cluster)
3198 {
3200 if (!chInput)
3201 {
3202 if (psa->fRTL)
3203 chInput = mirror_char(pwcChars[idx]);
3204 else
3205 chInput = pwcChars[idx];
3206 rChars[i] = chInput;
3207 }
3208 else
3209 {
3210 rChars[i] = pwcChars[idx];
3211 rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
3212 cluster = 1;
3213 }
3214 if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
3215 {
3216 WORD glyph;
3217 if (!hdc)
3218 {
3219 heap_free(rChars);
3220 return E_PENDING;
3221 }
3222 if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
3223 {
3224 heap_free(rChars);
3225 return S_FALSE;
3226 }
3227 pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
3228 }
3229 g++;
3230 }
3231 else
3232 {
3233 int k;
3234 cluster--;
3236 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3237 pwLogClust[k]--;
3238 }
3239 }
3240 *pcGlyphs = g;
3241
3245
3246 for (i = 0; i < cChars; ++i)
3247 {
3248 /* Special case for tabs and joiners. As control characters, ZWNJ
3249 * and ZWJ would in principle get handled by the corresponding
3250 * shaping functions. However, since ZWNJ and ZWJ can get merged
3251 * into adjoining runs during itemisation, these don't generally
3252 * get classified as Script_Control. */
3253 if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
3254 {
3255 pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
3256 pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
3257 }
3258 }
3259 heap_free(rChars);
3260 }
3261 else
3262 {
3263 TRACE("no glyph translation\n");
3264 for (i = 0; i < cChars; i++)
3265 {
3266 int idx = i;
3267 /* No mirroring done here */
3268 if (rtl) idx = cChars - 1 - i;
3270
3271 if (!psa)
3272 continue;
3273
3274 /* overwrite some basic control glyphs to blank */
3275 if (psa->fNoGlyphIndex)
3276 {
3277 if (pwcChars[idx] == ZWSP || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3278 {
3279 pwOutGlyphs[i] = 0x20;
3280 pOutGlyphProps[i].sva.fZeroWidth = 1;
3281 }
3282 }
3283 else if (psa->eScript == Script_Control || pwcChars[idx] == ZWSP
3284 || pwcChars[idx] == ZWNJ || pwcChars[idx] == ZWJ)
3285 {
3286 if (pwcChars[idx] == 0x0009 || pwcChars[idx] == 0x000A ||
3287 pwcChars[idx] == 0x000D || pwcChars[idx] >= 0x001C)
3288 {
3289 pwOutGlyphs[i] = ((ScriptCache *)*psc)->sfp.wgBlank;
3290 pOutGlyphProps[i].sva.fZeroWidth = 1;
3291 }
3292 }
3293 }
3294 }
3295
3296 return S_OK;
3297}
3298
3299
3300/***********************************************************************
3301 * ScriptShape (USP10.@)
3302 *
3303 * Produce glyphs and visual attributes for a run.
3304 *
3305 * PARAMS
3306 * hdc [I] Device context.
3307 * psc [I/O] Opaque pointer to a script cache.
3308 * pwcChars [I] Array of characters specifying the run.
3309 * cChars [I] Number of characters in pwcChars.
3310 * cMaxGlyphs [I] Length of pwOutGlyphs.
3311 * psa [I/O] Script analysis.
3312 * pwOutGlyphs [O] Array of glyphs.
3313 * pwLogClust [O] Array of logical cluster info.
3314 * psva [O] Array of visual attributes.
3315 * pcGlyphs [O] Number of glyphs returned.
3316 *
3317 * RETURNS
3318 * Success: S_OK
3319 * Failure: Non-zero HRESULT value.
3320 */
3322 int cChars, int cMaxGlyphs,
3324 SCRIPT_VISATTR *psva, int *pcGlyphs)
3325{
3326 HRESULT hr;
3327 int i;
3328 SCRIPT_CHARPROP *charProps;
3329 SCRIPT_GLYPHPROP *glyphProps;
3330
3331 if (!psva || !pcGlyphs) return E_INVALIDARG;
3332 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3333
3334 if (!(charProps = heap_calloc(cChars, sizeof(*charProps))))
3335 return E_OUTOFMEMORY;
3336
3337 if (!(glyphProps = heap_calloc(cMaxGlyphs, sizeof(*glyphProps))))
3338 {
3339 heap_free(charProps);
3340 return E_OUTOFMEMORY;
3341 }
3342
3344
3345 if (SUCCEEDED(hr))
3346 {
3347 for (i = 0; i < *pcGlyphs; i++)
3348 psva[i] = glyphProps[i].sva;
3349 }
3350
3351 heap_free(charProps);
3352 heap_free(glyphProps);
3353
3354 return hr;
3355}
3356
3357/***********************************************************************
3358 * ScriptPlaceOpenType (USP10.@)
3359 *
3360 * Produce advance widths for a run.
3361 *
3362 * PARAMS
3363 * hdc [I] Device context.
3364 * psc [I/O] Opaque pointer to a script cache.
3365 * psa [I/O] Script analysis.
3366 * tagScript [I] The OpenType tag for the Script
3367 * tagLangSys [I] The OpenType tag for the Language
3368 * rcRangeChars[I] Array of Character counts in each range
3369 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3370 * cRanges [I] Count of ranges
3371 * pwcChars [I] Array of characters specifying the run.
3372 * pwLogClust [I] Array of logical cluster info
3373 * pCharProps [I] Array of character property values
3374 * cChars [I] Number of characters in pwcChars.
3375 * pwGlyphs [I] Array of glyphs.
3376 * pGlyphProps [I] Array of attributes for the retrieved glyphs
3377 * cGlyphs [I] Count of Glyphs
3378 * piAdvance [O] Array of advance widths.
3379 * pGoffset [O] Glyph offsets.
3380 * pABC [O] Combined ABC width.
3381 *
3382 * RETURNS
3383 * Success: S_OK
3384 * Failure: Non-zero HRESULT value.
3385 */
3386
3390 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3392 const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
3393 int cGlyphs, int *piAdvance,
3394 GOFFSET *pGoffset, ABC *pABC
3395)
3396{
3397 HRESULT hr;
3398 int i;
3399 static int once = 0;
3400
3401 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3402 hdc, psc, psa,
3403 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3405 pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
3406 pGoffset, pABC);
3407
3408 if (!pGlyphProps) return E_INVALIDARG;
3409 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3410 if (!pGoffset) return E_FAIL;
3411
3412 if (cRanges)
3413 if (!once++) FIXME("Ranges not supported yet\n");
3414
3415 ((ScriptCache *)*psc)->userScript = tagScript;
3416 ((ScriptCache *)*psc)->userLang = tagLangSys;
3417
3418 if (pABC) memset(pABC, 0, sizeof(ABC));
3419 for (i = 0; i < cGlyphs; i++)
3420 {
3421 WORD glyph;
3422 ABC abc;
3423
3424 /* FIXME: set to more reasonable values */
3425 pGoffset[i].du = pGoffset[i].dv = 0;
3426
3427 if (pGlyphProps[i].sva.fZeroWidth)
3428 {
3429 abc.abcA = abc.abcB = abc.abcC = 0;
3430 if (piAdvance) piAdvance[i] = 0;
3431 continue;
3432 }
3433
3434 if (psa->fNoGlyphIndex)
3435 {
3436 if (FAILED(hr = ScriptGetCMap(hdc, psc, &pwGlyphs[i], 1, 0, &glyph))) return hr;
3437 }
3438 else
3439 {
3440 hr = S_OK;
3441 glyph = pwGlyphs[i];
3442 }
3443
3444 if (hr == S_FALSE)
3445 {
3446 if (!hdc) return E_PENDING;
3448 {
3449 if (!GetCharABCWidthsW(hdc, pwGlyphs[i], pwGlyphs[i], &abc)) return S_FALSE;
3450 }
3451 else
3452 {
3453 INT width;
3454 if (!GetCharWidthW(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
3455 abc.abcB = width;
3456 abc.abcA = abc.abcC = 0;
3457 }
3458 }
3459 else if (!get_cache_glyph_widths(psc, glyph, &abc))
3460 {
3461 if (!hdc) return E_PENDING;
3463 {
3464 if (!GetCharABCWidthsI(hdc, glyph, 1, NULL, &abc)) return S_FALSE;
3465 }
3466 else
3467 {
3468 INT width;
3469 if (!GetCharWidthI(hdc, glyph, 1, NULL, &width)) return S_FALSE;
3470 abc.abcB = width;
3471 abc.abcA = abc.abcC = 0;
3472 }
3473 set_cache_glyph_widths(psc, glyph, &abc);
3474 }
3475 if (pABC)
3476 {
3477 pABC->abcA += abc.abcA;
3478 pABC->abcB += abc.abcB;
3479 pABC->abcC += abc.abcC;
3480 }
3481 if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
3482 }
3483
3484 SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset);
3485
3486 if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
3487 return S_OK;
3488}
3489
3490/***********************************************************************
3491 * ScriptPlace (USP10.@)
3492 *
3493 * Produce advance widths for a run.
3494 *
3495 * PARAMS
3496 * hdc [I] Device context.
3497 * psc [I/O] Opaque pointer to a script cache.
3498 * pwGlyphs [I] Array of glyphs.
3499 * cGlyphs [I] Number of glyphs in pwGlyphs.
3500 * psva [I] Array of visual attributes.
3501 * psa [I/O] String analysis.
3502 * piAdvance [O] Array of advance widths.
3503 * pGoffset [O] Glyph offsets.
3504 * pABC [O] Combined ABC width.
3505 *
3506 * RETURNS
3507 * Success: S_OK
3508 * Failure: Non-zero HRESULT value.
3509 */
3511 int cGlyphs, const SCRIPT_VISATTR *psva,
3512 SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
3513{
3514 HRESULT hr;
3515 SCRIPT_GLYPHPROP *glyphProps;
3516 int i;
3517
3518 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
3519 piAdvance, pGoffset, pABC);
3520
3521 if (!psva) return E_INVALIDARG;
3522 if (!pGoffset) return E_FAIL;
3523
3524 if (!(glyphProps = heap_calloc(cGlyphs, sizeof(*glyphProps))))
3525 return E_OUTOFMEMORY;
3526
3527 for (i = 0; i < cGlyphs; i++)
3528 glyphProps[i].sva = psva[i];
3529
3530 hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
3531
3532 heap_free(glyphProps);
3533
3534 return hr;
3535}
3536
3537/***********************************************************************
3538 * ScriptGetCMap (USP10.@)
3539 *
3540 * Retrieve glyph indices.
3541 *
3542 * PARAMS
3543 * hdc [I] Device context.
3544 * psc [I/O] Opaque pointer to a script cache.
3545 * pwcInChars [I] Array of Unicode characters.
3546 * cChars [I] Number of characters in pwcInChars.
3547 * dwFlags [I] Flags.
3548 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3549 *
3550 * RETURNS
3551 * Success: S_OK
3552 * Failure: Non-zero HRESULT value.
3553 */
3556{
3557 HRESULT hr;
3558 int i;
3559
3560 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc,