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
47 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
48
49 static const struct usp10_script_range
50 {
51 enum usp10_script script;
52 DWORD rangeFirst;
53 DWORD rangeLast;
54 enum usp10_script numericScript;
55 enum usp10_script punctScript;
56 }
57 script_ranges[] =
58 {
59 /* Basic Latin: U+0000–U+007A */
60 { Script_Latin, 0x00, 0x07a , Script_Numeric, Script_Punctuation},
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 */
66 { Script_Latin, 0x80, 0x2ff , Script_Numeric2, Script_Punctuation},
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 */
93 { Script_Devanagari, 0x900, 0x97f, Script_Devanagari_Numeric, 0},
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 */
144 { Script_New_Tai_Lue,0x1980, 0x19df, Script_New_Tai_Lue_Numeric, 0},
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},
302 };
303
304 /* this must be in order so that the index matches the Script value */
305 const scriptData scriptInformation[] = {
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
636 static const SCRIPT_PROPERTIES *script_props[] =
637 {
638 &scriptInformation[0].props, &scriptInformation[1].props,
639 &scriptInformation[2].props, &scriptInformation[3].props,
640 &scriptInformation[4].props, &scriptInformation[5].props,
641 &scriptInformation[6].props, &scriptInformation[7].props,
642 &scriptInformation[8].props, &scriptInformation[9].props,
643 &scriptInformation[10].props, &scriptInformation[11].props,
644 &scriptInformation[12].props, &scriptInformation[13].props,
645 &scriptInformation[14].props, &scriptInformation[15].props,
646 &scriptInformation[16].props, &scriptInformation[17].props,
647 &scriptInformation[18].props, &scriptInformation[19].props,
648 &scriptInformation[20].props, &scriptInformation[21].props,
649 &scriptInformation[22].props, &scriptInformation[23].props,
650 &scriptInformation[24].props, &scriptInformation[25].props,
651 &scriptInformation[26].props, &scriptInformation[27].props,
652 &scriptInformation[28].props, &scriptInformation[29].props,
653 &scriptInformation[30].props, &scriptInformation[31].props,
654 &scriptInformation[32].props, &scriptInformation[33].props,
655 &scriptInformation[34].props, &scriptInformation[35].props,
656 &scriptInformation[36].props, &scriptInformation[37].props,
657 &scriptInformation[38].props, &scriptInformation[39].props,
658 &scriptInformation[40].props, &scriptInformation[41].props,
659 &scriptInformation[42].props, &scriptInformation[43].props,
660 &scriptInformation[44].props, &scriptInformation[45].props,
661 &scriptInformation[46].props, &scriptInformation[47].props,
662 &scriptInformation[48].props, &scriptInformation[49].props,
663 &scriptInformation[50].props, &scriptInformation[51].props,
664 &scriptInformation[52].props, &scriptInformation[53].props,
665 &scriptInformation[54].props, &scriptInformation[55].props,
666 &scriptInformation[56].props, &scriptInformation[57].props,
667 &scriptInformation[58].props, &scriptInformation[59].props,
668 &scriptInformation[60].props, &scriptInformation[61].props,
669 &scriptInformation[62].props, &scriptInformation[63].props,
670 &scriptInformation[64].props, &scriptInformation[65].props,
671 &scriptInformation[66].props, &scriptInformation[67].props,
672 &scriptInformation[68].props, &scriptInformation[69].props,
673 &scriptInformation[70].props, &scriptInformation[71].props,
674 &scriptInformation[72].props, &scriptInformation[73].props,
675 &scriptInformation[74].props, &scriptInformation[75].props,
676 &scriptInformation[76].props, &scriptInformation[77].props,
677 &scriptInformation[78].props, &scriptInformation[79].props,
678 &scriptInformation[80].props, &scriptInformation[81].props
679 };
680
681 static CRITICAL_SECTION cs_script_cache;
682 static CRITICAL_SECTION_DEBUG cs_script_cache_dbg =
683 {
684 0, 0, &cs_script_cache,
685 { &cs_script_cache_dbg.ProcessLocksList, &cs_script_cache_dbg.ProcessLocksList },
686 0, 0, { (DWORD_PTR)(__FILE__ ": script_cache") }
687 };
688 static CRITICAL_SECTION cs_script_cache = { &cs_script_cache_dbg, -1, 0, 0, 0, 0 };
689 static struct list script_cache_list = LIST_INIT(script_cache_list);
690
691 typedef struct {
692 ScriptCache *sc;
693 int numGlyphs;
694 WORD* glyphs;
695 WORD* pwLogClust;
696 int* piAdvance;
697 SCRIPT_VISATTR* psva;
698 GOFFSET* pGoffset;
699 ABC abc;
700 int iMaxPosX;
701 HFONT fallbackFont;
702 } StringGlyphs;
703
704 enum stringanalysis_flags
705 {
706 SCRIPT_STRING_ANALYSIS_FLAGS_SIZE = 0x1,
707 SCRIPT_STRING_ANALYSIS_FLAGS_INVALID = 0x2,
708 };
709
710 typedef struct {
711 HDC hdc;
712 DWORD ssa_flags;
713 DWORD flags;
714 int clip_len;
715 int cItems;
716 int cMaxGlyphs;
717 SCRIPT_ITEM* pItem;
718 int numItems;
719 StringGlyphs* glyphs;
720 SCRIPT_LOGATTR* logattrs;
721 SIZE sz;
722 int* logical2visual;
723 } StringAnalysis;
724
725 typedef struct {
726 BOOL ascending;
727 WORD target;
728 } FindGlyph_struct;
729
usp10_array_reserve(void ** elements,SIZE_T * capacity,SIZE_T count,SIZE_T size)730 BOOL 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 */
set_cache_font_properties(const HDC hdc,ScriptCache * sc)761 static inline BOOL set_cache_font_properties(const HDC hdc, ScriptCache *sc)
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
782 if (GetGlyphIndicesW(hdc, chars, 4, gi, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
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
get_cache_font_properties(SCRIPT_FONTPROPERTIES * sfp,ScriptCache * sc)810 static inline void get_cache_font_properties(SCRIPT_FONTPROPERTIES *sfp, ScriptCache *sc)
811 {
812 *sfp = sc->sfp;
813 }
814
get_cache_height(SCRIPT_CACHE * psc)815 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
816 {
817 return ((ScriptCache *)*psc)->tm.tmHeight;
818 }
819
get_cache_pitch_family(SCRIPT_CACHE * psc)820 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
821 {
822 return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
823 }
824
get_cache_glyph(SCRIPT_CACHE * psc,DWORD c)825 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, DWORD c)
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
set_cache_glyph(SCRIPT_CACHE * psc,WCHAR c,WORD glyph)836 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
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
get_cache_glyph_widths(SCRIPT_CACHE * psc,WORD glyph,ABC * abc)847 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
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
set_cache_glyph_widths(SCRIPT_CACHE * psc,WORD glyph,ABC * abc)857 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
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
init_script_cache(const HDC hdc,SCRIPT_CACHE * psc)866 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
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 */
881 size = lstrlenW(lf.lfFaceName);
882 memset(lf.lfFaceName + size, 0, sizeof(lf.lfFaceName) - size * sizeof(WCHAR));
883
884 EnterCriticalSection(&cs_script_cache);
885 LIST_FOR_EACH_ENTRY(sc, &script_cache_list, ScriptCache, entry)
886 {
887 if (!memcmp(&sc->lf, &lf, sizeof(lf)))
888 {
889 sc->refcount++;
890 LeaveCriticalSection(&cs_script_cache);
891 *psc = sc;
892 return S_OK;
893 }
894 }
895 LeaveCriticalSection(&cs_script_cache);
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 }
903 size = GetOutlineTextMetricsW(hdc, 0, NULL);
904 if (size)
905 {
906 sc->otm = heap_alloc(size);
907 sc->otm->otmSize = size;
908 GetOutlineTextMetricsW(hdc, size, sc->otm);
909 }
910 sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
911 if (!set_cache_font_properties(hdc, sc))
912 {
913 heap_free(sc);
914 return E_INVALIDARG;
915 }
916 sc->lf = lf;
917 sc->refcount = 1;
918 *psc = sc;
919
920 EnterCriticalSection(&cs_script_cache);
921 list_add_head(&script_cache_list, &sc->entry);
922 LIST_FOR_EACH_ENTRY(sc, &script_cache_list, ScriptCache, entry)
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++;
929 LeaveCriticalSection(&cs_script_cache);
930 heap_free(*psc);
931 *psc = sc;
932 return S_OK;
933 }
934 }
935 LeaveCriticalSection(&cs_script_cache);
936 TRACE("<- %p\n", sc);
937 return S_OK;
938 }
939
mirror_char(WCHAR ch)940 static WCHAR mirror_char( WCHAR ch )
941 {
942 extern const WCHAR wine_mirror_map[] DECLSPEC_HIDDEN;
943 return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
944 }
945
decode_surrogate_pair(const WCHAR * str,unsigned int index,unsigned int end)946 static 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
usp10_compare_script_range(const void * key,const void * value)957 static 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
get_char_script(const WCHAR * str,unsigned int index,unsigned int end,unsigned int * consumed)969 static 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};
973 struct usp10_script_range *range;
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
1002 GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
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
1011 ch = decode_surrogate_pair(str, index, end);
1012 if (ch)
1013 *consumed = 2;
1014 else
1015 ch = str[index];
1016
1017 if (!(range = bsearch(&ch, script_ranges, ARRAY_SIZE(script_ranges),
1018 sizeof(*script_ranges), usp10_compare_script_range)))
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
compare_FindGlyph(const void * a,const void * b)1028 static int __cdecl compare_FindGlyph(const void *a, const void* b)
1029 {
1030 const FindGlyph_struct *find = (FindGlyph_struct*)a;
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
USP10_FindGlyphInLogClust(const WORD * pwLogClust,int cChars,WORD target)1044 int USP10_FindGlyphInLogClust(const WORD* pwLogClust, int cChars, WORD target)
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 */
ScriptFreeCache(SCRIPT_CACHE * psc)1080 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
1081 {
1082 TRACE("%p\n", psc);
1083
1084 if (psc && *psc)
1085 {
1086 unsigned int i;
1087 INT n;
1088
1089 EnterCriticalSection(&cs_script_cache);
1090 if (--((ScriptCache *)*psc)->refcount > 0)
1091 {
1092 LeaveCriticalSection(&cs_script_cache);
1093 *psc = NULL;
1094 return S_OK;
1095 }
1096 list_remove(&((ScriptCache *)*psc)->entry);
1097 LeaveCriticalSection(&cs_script_cache);
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 */
ScriptGetProperties(const SCRIPT_PROPERTIES *** props,int * num)1154 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
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 */
ScriptGetFontProperties(HDC hdc,SCRIPT_CACHE * psc,SCRIPT_FONTPROPERTIES * sfp)1176 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
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
1188 get_cache_font_properties(sfp, *psc);
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 */
ScriptRecordDigitSubstitution(LCID locale,SCRIPT_DIGITSUBSTITUTE * sds)1209 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
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
1221 locale = ConvertDefaultLocale(locale);
1222
1223 if (!IsValidLocale(locale, LCID_INSTALLED))
1224 return E_INVALIDARG;
1225
1226 plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
1227 sds->TraditionalDigitLanguage = plgid;
1228
1229 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1230 sds->NationalDigitLanguage = plgid;
1231 else
1232 sds->NationalDigitLanguage = LANG_ENGLISH;
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)
1242 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
1243 else
1244 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1245 break;
1246 case 1:
1247 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
1248 break;
1249 case 2:
1250 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
1251 break;
1252 default:
1253 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
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 */
ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE * sds,SCRIPT_CONTROL * sc,SCRIPT_STATE * ss)1275 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds,
1276 SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
1277 {
1278 SCRIPT_DIGITSUBSTITUTE psds;
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;
1286 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
1287 return E_INVALIDARG;
1288 }
1289
1290 sc->uDefaultLanguage = LANG_ENGLISH;
1291 sc->fContextDigits = 0;
1292 ss->fDigitSubstitute = 0;
1293
1294 switch (sds->DigitSubstitute) {
1295 case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
1296 case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
1297 case SCRIPT_DIGITSUBSTITUTE_NONE:
1298 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
1299 return S_OK;
1300 default:
1301 return E_INVALIDARG;
1302 }
1303 }
1304
is_indic(enum usp10_script script)1305 static inline BOOL is_indic(enum usp10_script script)
1306 {
1307 return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
1308 }
1309
base_indic(enum usp10_script script)1310 static inline enum usp10_script base_indic(enum usp10_script script)
1311 {
1312 switch (script)
1313 {
1314 case Script_Devanagari:
1315 case Script_Devanagari_Numeric: return Script_Devanagari;
1316 case Script_Bengali:
1317 case Script_Bengali_Numeric:
1318 case Script_Bengali_Currency: return Script_Bengali;
1319 case Script_Gurmukhi:
1320 case Script_Gurmukhi_Numeric: return Script_Gurmukhi;
1321 case Script_Gujarati:
1322 case Script_Gujarati_Numeric:
1323 case Script_Gujarati_Currency: return Script_Gujarati;
1324 case Script_Oriya:
1325 case Script_Oriya_Numeric: return Script_Oriya;
1326 case Script_Tamil:
1327 case Script_Tamil_Numeric: return Script_Tamil;
1328 case Script_Telugu:
1329 case Script_Telugu_Numeric: return Script_Telugu;
1330 case Script_Kannada:
1331 case Script_Kannada_Numeric: return Script_Kannada;
1332 case Script_Malayalam:
1333 case Script_Malayalam_Numeric: return Script_Malayalam;
1334 default:
1335 return Script_Undefined;
1336 };
1337 }
1338
script_is_numeric(enum usp10_script script)1339 static BOOL script_is_numeric(enum usp10_script script)
1340 {
1341 return scriptInformation[script].props.fNumeric;
1342 }
1343
_ItemizeInternal(const WCHAR * pwcInChars,int cInChars,int cMaxItems,const SCRIPT_CONTROL * psControl,const SCRIPT_STATE * psState,SCRIPT_ITEM * pItems,OPENTYPE_TAG * pScriptTags,int * pcItems)1344 static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
1345 int cMaxItems, const SCRIPT_CONTROL *psControl,
1346 const SCRIPT_STATE *psState, SCRIPT_ITEM *pItems,
1347 OPENTYPE_TAG *pScriptTags, int *pcItems)
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;
1370 HRESULT res = E_OUTOFMEMORY;
1371
1372 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
1373 psControl, psState, pItems, pcItems);
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 {
1482 SCRIPT_STATE s = *psState;
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 {
1509 heap_free(levels);
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 }
1593 if (psControl->fMergeNeutralItems)
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)
1647 pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
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)
1753 pScriptTags[index] = scriptInformation[New_Script].scriptTag;
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;
1800 nomemory:
1801 heap_free(levels);
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 */
ScriptItemizeOpenType(const WCHAR * pwcInChars,int cInChars,int cMaxItems,const SCRIPT_CONTROL * psControl,const SCRIPT_STATE * psState,SCRIPT_ITEM * pItems,OPENTYPE_TAG * pScriptTags,int * pcItems)1828 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1829 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1830 SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
1831 {
1832 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pScriptTags, pcItems);
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 */
ScriptItemize(const WCHAR * pwcInChars,int cInChars,int cMaxItems,const SCRIPT_CONTROL * psControl,const SCRIPT_STATE * psState,SCRIPT_ITEM * pItems,int * pcItems)1853 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1854 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1855 SCRIPT_ITEM *pItems, int *pcItems)
1856 {
1857 return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, NULL, pcItems);
1858 }
1859
getGivenTabWidth(ScriptCache * psc,SCRIPT_TABDEF * pTabdef,int charPos,int current_x)1860 static 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 */
requires_fallback(HDC hdc,SCRIPT_CACHE * psc,SCRIPT_ANALYSIS * psa,const WCHAR * pwcInChars,int cChars)1934 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
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
1946 if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
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 {
1953 heap_free(glyphs);
1954 return TRUE;
1955 }
1956 heap_free(glyphs);
1957
1958 return FALSE;
1959 }
1960
find_fallback_font(enum usp10_script scriptid,WCHAR * FaceName)1961 static 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 */
ScriptStringAnalyse(HDC hdc,const void * pString,int cString,int cGlyphs,int iCharset,DWORD dwFlags,int iReqWidth,SCRIPT_CONTROL * psControl,SCRIPT_STATE * psState,const int * piDx,SCRIPT_TABDEF * pTabdef,const BYTE * pbInClass,SCRIPT_STRING_ANALYSIS * pssa)1985 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
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,
1990 SCRIPT_STRING_ANALYSIS *pssa)
1991 {
1992 HRESULT hr = E_OUTOFMEMORY;
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);
2104 heap_free (pwLogClust);
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);
2116 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
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
2179 error:
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
does_glyph_start_cluster(const SCRIPT_VISATTR * pva,const WORD * pwLogClust,int cChars,int glyph,int direction)2189 static 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;
2193 if (USP10_FindGlyphInLogClust(pwLogClust, cChars, glyph) >= 0)
2194 return TRUE;
2195
2196 return FALSE;
2197 }
2198
2199
SS_ItemOut(SCRIPT_STRING_ANALYSIS ssa,int iX,int iY,int iItem,int cStart,int cEnd,UINT uOptions,const RECT * prc,BOOL fSelected,BOOL fDisabled)2200 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
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);
2238 SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
2239 if (!fDisabled)
2240 {
2241 TextColor = GetTextColor(analysis->hdc);
2242 SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
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 */
ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,int iX,int iY,UINT uOptions,const RECT * prc,int iMinSel,int iMaxSel,BOOL fDisabled)2366 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
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 */
ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa,int icp,BOOL fTrailing,int * pX)2411 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
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 {
2425 analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
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 */
2466 analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
2467 return E_INVALIDARG;
2468 }
2469
2470 /***********************************************************************
2471 * ScriptStringXtoCP (USP10.@)
2472 *
2473 */
ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa,int iX,int * piCh,int * piTrailing)2474 HRESULT 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 */
ScriptStringFree(SCRIPT_STRING_ANALYSIS * pssa)2556 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
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
2566 invalid = analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
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
get_cluster_size(const WORD * pwLogClust,int cChars,int item,int direction,int * iCluster,int * check_out)2594 static 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
get_glyph_cluster_advance(const int * piAdvance,const SCRIPT_VISATTR * pva,const WORD * pwLogClust,int cGlyphs,int cChars,int glyph,int direction)2618 static inline int get_glyph_cluster_advance(const int* piAdvance, const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cGlyphs, int cChars, int glyph, int direction)
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 */
ScriptCPtoX(int iCP,BOOL fTrailing,int cChars,int cGlyphs,const WORD * pwLogClust,const SCRIPT_VISATTR * psva,const int * piAdvance,const SCRIPT_ANALYSIS * psa,int * piX)2650 HRESULT WINAPI ScriptCPtoX(int iCP,
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 {
2721 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
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);
2736 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
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*/
get_cluster_data(const WORD * pwLogClust,int cChars,int cluster_index,int * cluster_size,int * start_index)2760 static 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 */
get_cluster_advance(const int * piAdvance,const SCRIPT_VISATTR * psva,const WORD * pwLogClust,int cGlyphs,int cChars,int cluster,int direction)2793 static 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 */
ScriptXtoCP(int iX,int cChars,int cGlyphs,const WORD * pwLogClust,const SCRIPT_VISATTR * psva,const int * piAdvance,const SCRIPT_ANALYSIS * psa,int * piCP,int * piTrailing)2854 HRESULT WINAPI ScriptXtoCP(int iX,
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);
2943 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
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 */
ScriptBreak(const WCHAR * chars,int count,const SCRIPT_ANALYSIS * sa,SCRIPT_LOGATTR * la)3047 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
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 */
ScriptIsComplex(const WCHAR * chars,int len,DWORD flag)3074 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
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))||
3091 (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
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 */
ScriptShapeOpenType(HDC hdc,SCRIPT_CACHE * psc,SCRIPT_ANALYSIS * psa,OPENTYPE_TAG tagScript,OPENTYPE_TAG tagLangSys,int * rcRangeChars,TEXTRANGE_PROPERTIES ** rpRangeProperties,int cRanges,const WCHAR * pwcChars,int cChars,int cMaxGlyphs,WORD * pwLogClust,SCRIPT_CHARPROP * pCharProps,WORD * pwOutGlyphs,SCRIPT_GLYPHPROP * pOutGlyphProps,int * pcGlyphs)3124 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
3125 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3126 OPENTYPE_TAG tagLangSys, int *rcRangeChars,
3127 TEXTRANGE_PROPERTIES **rpRangeProperties,
3128 int cRanges, const WCHAR *pwcChars, int cChars,
3129 int cMaxGlyphs, WORD *pwLogClust,
3130 SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
3131 SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
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),
3143 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3144 cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
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;
3186 if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
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 {
3199 chInput = decode_surrogate_pair(pwcChars, idx, cChars);
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--;
3235 pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
3236 for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3237 pwLogClust[k]--;
3238 }
3239 }
3240 *pcGlyphs = g;
3241
3242 SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3243 SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
3244 SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
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;
3269 pwOutGlyphs[i] = pwcChars[idx];
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 */
ScriptShape(HDC hdc,SCRIPT_CACHE * psc,const WCHAR * pwcChars,int cChars,int cMaxGlyphs,SCRIPT_ANALYSIS * psa,WORD * pwOutGlyphs,WORD * pwLogClust,SCRIPT_VISATTR * psva,int * pcGlyphs)3321 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
3322 int cChars, int cMaxGlyphs,
3323 SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
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
3343 hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
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
ScriptPlaceOpenType(HDC hdc,SCRIPT_CACHE * psc,SCRIPT_ANALYSIS * psa,OPENTYPE_TAG tagScript,OPENTYPE_TAG tagLangSys,int * rcRangeChars,TEXTRANGE_PROPERTIES ** rpRangeProperties,int cRanges,const WCHAR * pwcChars,WORD * pwLogClust,SCRIPT_CHARPROP * pCharProps,int cChars,const WORD * pwGlyphs,const SCRIPT_GLYPHPROP * pGlyphProps,int cGlyphs,int * piAdvance,GOFFSET * pGoffset,ABC * pABC)3387 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
3388 OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
3389 int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
3390 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3391 SCRIPT_CHARPROP *pCharProps, int cChars,
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),
3404 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
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;
3447 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
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;
3462 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
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 */
ScriptPlace(HDC hdc,SCRIPT_CACHE * psc,const WORD * pwGlyphs,int cGlyphs,const SCRIPT_VISATTR * psva,SCRIPT_ANALYSIS * psa,int * piAdvance,GOFFSET * pGoffset,ABC * pABC)3510 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
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 */
ScriptGetCMap(HDC hdc,SCRIPT_CACHE * psc,const WCHAR * pwcInChars,int cChars,DWORD dwFlags,WORD * pwOutGlyphs)3554 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
3555 int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
3556 {
3557 HRESULT hr;
3558 int i;
3559
3560 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
3561 cChars, dwFlags, pwOutGlyphs);
3562
3563 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3564
3565 hr = S_OK;
3566
3567 for (i = 0; i < cChars; i++)
3568 {
3569 WCHAR inChar;
3570 if (dwFlags == SGCM_RTL)
3571 inChar = mirror_char(pwcInChars[i]);
3572 else
3573 inChar = pwcInChars[i];
3574 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
3575 {
3576 WORD glyph;
3577 if (!hdc) return E_PENDING;
3578 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
3579 if (glyph == 0xffff)
3580 {
3581 hr = S_FALSE;
3582 glyph = 0x0;
3583 }
3584 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
3585 }
3586 }
3587
3588 return hr;
3589 }
3590
3591 /***********************************************************************
3592 * ScriptTextOut (USP10.@)
3593 *
3594 */
ScriptTextOut(const HDC hdc,SCRIPT_CACHE * psc,int x,int y,UINT fuOptions,const RECT * lprc,const SCRIPT_ANALYSIS * psa,const WCHAR * pwcReserved,int iReserved,const WORD * pwGlyphs,int cGlyphs,const int * piAdvance,const int * piJustify,const GOFFSET * pGoffset)3595 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
3596 const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
3597 int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
3598 const int *piJustify, const GOFFSET *pGoffset)
3599 {
3600 HRESULT hr = S_OK;
3601 INT i, dir = 1;
3602 INT *lpDx;
3603 WORD *reordered_glyphs = (WORD *)pwGlyphs;
3604
3605 TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3606 hdc, psc, x, y, fuOptions, wine_dbgstr_rect(lprc), psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
3607 piAdvance, piJustify, pGoffset);
3608
3609 if (!hdc || !psc) return E_INVALIDARG;
3610 if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
3611
3612 fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
3613 fuOptions |= ETO_IGNORELANGUAGE;
3614 if (!psa->fNoGlyphIndex) /* Have Glyphs? */
3615 fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */
3616
3617 if (!(lpDx = heap_calloc(cGlyphs, 2 * sizeof(*lpDx))))
3618 return E_OUTOFMEMORY;
3619 fuOptions |= ETO_PDY;
3620
3621 if (psa->fRTL && psa->fLogicalOrder)
3622 {
3623 if (!(reordered_glyphs = heap_calloc(cGlyphs, sizeof(*reordered_glyphs))))
3624 {
3625 heap_free( lpDx );
3626 return E_OUTOFMEMORY;
3627 }
3628
3629 for (i = 0; i < cGlyphs; i++)
3630 reordered_glyphs[i] = pwGlyphs[cGlyphs - 1 - i];
3631 dir = -1;
3632 }
3633
3634 for (i = 0; i < cGlyphs; i++)
3635 {
3636 int orig_index = (dir > 0) ? i : cGlyphs - 1 - i;
3637 lpDx[i * 2] = piAdvance[orig_index];
3638 lpDx[i * 2 + 1] = 0;
3639
3640 if (pGoffset)
3641 {
3642 if (i == 0)
3643 {
3644 x += pGoffset[orig_index].du * dir;
3645 y += pGoffset[orig_index].dv;
3646 }
3647 else
3648 {
3649 lpDx[(i - 1) * 2] += pGoffset[orig_index].du * dir;
3650 lpDx[(i - 1) * 2 + 1] += pGoffset[orig_index].dv;
3651 }
3652 lpDx[i * 2] -= pGoffset[orig_index].du * dir;
3653 lpDx[i * 2 + 1] -= pGoffset[orig_index].dv;
3654 }
3655 }
3656
3657 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, reordered_glyphs, cGlyphs, lpDx))
3658 hr = S_FALSE;
3659
3660 if (reordered_glyphs != pwGlyphs) heap_free( reordered_glyphs );
3661 heap_free(lpDx);
3662
3663 return hr;
3664 }
3665
3666 /***********************************************************************
3667 * ScriptCacheGetHeight (USP10.@)
3668 *
3669 * Retrieve the height of the font in the cache.
3670 *
3671 * PARAMS
3672 * hdc [I] Device context.
3673 * psc [I/O] Opaque pointer to a script cache.
3674 * height [O] Receives font height.
3675 *
3676 * RETURNS
3677 * Success: S_OK
3678 * Failure: Non-zero HRESULT value.
3679 */
ScriptCacheGetHeight(HDC hdc,SCRIPT_CACHE * psc,LONG * height)3680 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
3681 {
3682 HRESULT hr;
3683
3684 TRACE("(%p, %p, %p)\n", hdc, psc, height);
3685
3686 if (!height) return E_INVALIDARG;
3687 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3688
3689 *height = get_cache_height(psc);
3690 return S_OK;
3691 }
3692
3693 /***********************************************************************
3694 * ScriptGetGlyphABCWidth (USP10.@)
3695 *
3696 * Retrieve the width of a glyph.
3697 *
3698 * PARAMS
3699 * hdc [I] Device context.
3700 * psc [I/O] Opaque pointer to a script cache.
3701 * glyph [I] Glyph to retrieve the width for.
3702 * abc [O] ABC widths of the glyph.
3703 *
3704 * RETURNS
3705 * Success: S_OK
3706 * Failure: Non-zero HRESULT value.
3707 */
ScriptGetGlyphABCWidth(HDC hdc,SCRIPT_CACHE * psc,WORD glyph,ABC * abc)3708 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
3709 {
3710 HRESULT hr;
3711
3712 TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
3713
3714 if (!abc) return E_INVALIDARG;
3715 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3716
3717 if (!get_cache_glyph_widths(psc, glyph, abc))
3718 {
3719 if (!hdc) return E_PENDING;
3720 if (get_cache_pitch_family(psc) & TMPF_TRUETYPE)
3721 {
3722 if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
3723 }
3724 else
3725 {
3726 INT width;
3727 if (!GetCharWidthI(hdc, glyph, 1, NULL, &width)) return S_FALSE;
3728 abc->abcB = width;
3729 abc->abcA = abc->abcC = 0;
3730 }
3731 set_cache_glyph_widths(psc, glyph, abc);
3732 }
3733 return S_OK;
3734 }
3735
3736 /***********************************************************************
3737 * ScriptLayout (USP10.@)
3738 *
3739 * Map embedding levels to visual and/or logical order.
3740 *
3741 * PARAMS
3742 * runs [I] Size of level array.
3743 * level [I] Array of embedding levels.
3744 * vistolog [O] Map of embedding levels from visual to logical order.
3745 * logtovis [O] Map of embedding levels from logical to visual order.
3746 *
3747 * RETURNS
3748 * Success: S_OK
3749 * Failure: Non-zero HRESULT value.
3750 *
3751 */
ScriptLayout(int runs,const BYTE * level,int * vistolog,int * logtovis)3752 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
3753 {
3754 int* indexs;
3755 int ich;
3756
3757 TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
3758
3759 if (!level || (!vistolog && !logtovis))
3760 return E_INVALIDARG;
3761
3762 if (!(indexs = heap_calloc(runs, sizeof(*indexs))))
3763 return E_OUTOFMEMORY;
3764
3765 if (vistolog)
3766 {
3767 for( ich = 0; ich < runs; ich++)
3768 indexs[ich] = ich;
3769
3770 ich = 0;
3771 while (ich < runs)
3772 ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3773 memcpy(vistolog, indexs, runs * sizeof(*vistolog));
3774 }
3775
3776 if (logtovis)
3777 {
3778 for( ich = 0; ich < runs; ich++)
3779 indexs[ich] = ich;
3780
3781 ich = 0;
3782 while (ich < runs)
3783 ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3784 memcpy(logtovis, indexs, runs * sizeof(*logtovis));
3785 }
3786 heap_free(indexs);
3787
3788 return S_OK;
3789 }
3790
3791 /***********************************************************************
3792 * ScriptStringGetLogicalWidths (USP10.@)
3793 *
3794 * Returns logical widths from a string analysis.
3795 *
3796 * PARAMS
3797 * ssa [I] string analysis.
3798 * piDx [O] logical widths returned.
3799 *
3800 * RETURNS
3801 * Success: S_OK
3802 * Failure: a non-zero HRESULT.
3803 */
ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa,int * piDx)3804 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
3805 {
3806 int i, j, next = 0;
3807 StringAnalysis *analysis = ssa;
3808
3809 TRACE("%p, %p\n", ssa, piDx);
3810
3811 if (!analysis) return S_FALSE;
3812 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3813
3814 for (i = 0; i < analysis->numItems; i++)
3815 {
3816 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
3817 int direction = 1;
3818
3819 if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
3820 direction = -1;
3821
3822 for (j = 0; j < cChar; j++)
3823 {
3824 int k;
3825 int glyph = analysis->glyphs[i].pwLogClust[j];
3826 int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
3827 cChar, j, direction, NULL, NULL);
3828 int advance = get_glyph_cluster_advance(analysis->glyphs[i].piAdvance, analysis->glyphs[i].psva, analysis->glyphs[i].pwLogClust, analysis->glyphs[i].numGlyphs, cChar, glyph, direction);
3829
3830 for (k = 0; k < clust_size; k++)
3831 {
3832 piDx[next] = advance / clust_size;
3833 next++;
3834 if (k) j++;
3835 }
3836 }
3837 }
3838 return S_OK;
3839 }
3840
3841 /***********************************************************************
3842 * ScriptStringValidate (USP10.@)
3843 *
3844 * Validate a string analysis.
3845 *
3846 * PARAMS
3847 * ssa [I] string analysis.
3848 *
3849 * RETURNS
3850 * Success: S_OK
3851 * Failure: S_FALSE if invalid sequences are found
3852 * or a non-zero HRESULT if it fails.
3853 */
ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)3854 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
3855 {
3856 StringAnalysis *analysis = ssa;
3857
3858 TRACE("(%p)\n", ssa);
3859
3860 if (!analysis) return E_INVALIDARG;
3861 return analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID ? S_FALSE : S_OK;
3862 }
3863
3864 /***********************************************************************
3865 * ScriptString_pSize (USP10.@)
3866 *
3867 * Retrieve width and height of an analysed string.
3868 *
3869 * PARAMS
3870 * ssa [I] string analysis.
3871 *
3872 * RETURNS
3873 * Success: Pointer to a SIZE structure.
3874 * Failure: NULL
3875 */
ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)3876 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
3877 {
3878 int i, j;
3879 StringAnalysis *analysis = ssa;
3880
3881 TRACE("(%p)\n", ssa);
3882
3883 if (!analysis) return NULL;
3884 if (!(analysis->ssa_flags & SSA_GLYPHS)) return NULL;
3885
3886 if (!(analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_SIZE))
3887 {
3888 analysis->sz.cy = analysis->glyphs[0].sc->tm.tmHeight;
3889
3890 analysis->sz.cx = 0;
3891 for (i = 0; i < analysis->numItems; i++)
3892 {
3893 if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz.cy)
3894 analysis->sz.cy = analysis->glyphs[i].sc->tm.tmHeight;
3895 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3896 analysis->sz.cx += analysis->glyphs[i].piAdvance[j];
3897 }
3898 analysis->flags |= SCRIPT_STRING_ANALYSIS_FLAGS_SIZE;
3899 }
3900 return &analysis->sz;
3901 }
3902
3903 /***********************************************************************
3904 * ScriptString_pLogAttr (USP10.@)
3905 *
3906 * Retrieve logical attributes of an analysed string.
3907 *
3908 * PARAMS
3909 * ssa [I] string analysis.
3910 *
3911 * RETURNS
3912 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3913 * Failure: NULL
3914 */
ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)3915 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
3916 {
3917 StringAnalysis *analysis = ssa;
3918
3919 TRACE("(%p)\n", ssa);
3920
3921 if (!analysis) return NULL;
3922 if (!(analysis->ssa_flags & SSA_BREAK)) return NULL;
3923 return analysis->logattrs;
3924 }
3925
3926 /***********************************************************************
3927 * ScriptString_pcOutChars (USP10.@)
3928 *
3929 * Retrieve the length of a string after clipping.
3930 *
3931 * PARAMS
3932 * ssa [I] String analysis.
3933 *
3934 * RETURNS
3935 * Success: Pointer to the length.
3936 * Failure: NULL
3937 */
ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)3938 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
3939 {
3940 StringAnalysis *analysis = ssa;
3941
3942 TRACE("(%p)\n", ssa);
3943
3944 if (!analysis) return NULL;
3945 return &analysis->clip_len;
3946 }
3947
3948 /***********************************************************************
3949 * ScriptStringGetOrder (USP10.@)
3950 *
3951 * Retrieve a glyph order map.
3952 *
3953 * PARAMS
3954 * ssa [I] String analysis.
3955 * order [I/O] Array of glyph positions.
3956 *
3957 * RETURNS
3958 * Success: S_OK
3959 * Failure: a non-zero HRESULT.
3960 */
ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa,UINT * order)3961 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
3962 {
3963 int i, j;
3964 unsigned int k;
3965 StringAnalysis *analysis = ssa;
3966
3967 TRACE("(%p)\n", ssa);
3968
3969 if (!analysis) return S_FALSE;
3970 if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3971
3972 /* FIXME: handle RTL scripts */
3973 for (i = 0, k = 0; i < analysis->numItems; i++)
3974 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3975 order[k] = k;
3976
3977 return S_OK;
3978 }
3979
3980 /***********************************************************************
3981 * ScriptGetLogicalWidths (USP10.@)
3982 *
3983 * Convert advance widths to logical widths.
3984 *
3985 * PARAMS
3986 * sa [I] Script analysis.
3987 * nbchars [I] Number of characters.
3988 * nbglyphs [I] Number of glyphs.
3989 * glyph_width [I] Array of glyph widths.
3990 * log_clust [I] Array of logical clusters.
3991 * sva [I] Visual attributes.
3992 * widths [O] Array of logical widths.
3993 *
3994 * RETURNS
3995 * Success: S_OK
3996 * Failure: a non-zero HRESULT.
3997 */
ScriptGetLogicalWidths(const SCRIPT_ANALYSIS * sa,int nbchars,int nbglyphs,const int * advances,const WORD * log_clust,const SCRIPT_VISATTR * sva,int * widths)3998 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3999 const int *advances, const WORD *log_clust,
4000 const SCRIPT_VISATTR *sva, int *widths)
4001 {
4002 int i, next = 0, direction;
4003
4004 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
4005 sa, nbchars, nbglyphs, advances, log_clust, sva, widths);
4006
4007 if (sa->fRTL && !sa->fLogicalOrder)
4008 direction = -1;
4009 else
4010 direction = 1;
4011
4012 for (i = 0; i < nbchars; i++)
4013 {
4014 int clust_size = get_cluster_size(log_clust, nbchars, i, direction, NULL, NULL);
4015 int advance = get_glyph_cluster_advance(advances, sva, log_clust, nbglyphs, nbchars, log_clust[i], direction);
4016 int j;
4017
4018 for (j = 0; j < clust_size; j++)
4019 {
4020 widths[next] = advance / clust_size;
4021 next++;
4022 if (j) i++;
4023 }
4024 }
4025
4026 return S_OK;
4027 }
4028
4029 /***********************************************************************
4030 * ScriptApplyLogicalWidth (USP10.@)
4031 *
4032 * Generate glyph advance widths.
4033 *
4034 * PARAMS
4035 * dx [I] Array of logical advance widths.
4036 * num_chars [I] Number of characters.
4037 * num_glyphs [I] Number of glyphs.
4038 * log_clust [I] Array of logical clusters.
4039 * sva [I] Visual attributes.
4040 * advance [I] Array of glyph advance widths.
4041 * sa [I] Script analysis.
4042 * abc [I/O] Summed ABC widths.
4043 * justify [O] Array of glyph advance widths.
4044 *
4045 * RETURNS
4046 * Success: S_OK
4047 * Failure: a non-zero HRESULT.
4048 */
ScriptApplyLogicalWidth(const int * dx,int num_chars,int num_glyphs,const WORD * log_clust,const SCRIPT_VISATTR * sva,const int * advance,const SCRIPT_ANALYSIS * sa,ABC * abc,int * justify)4049 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
4050 const WORD *log_clust, const SCRIPT_VISATTR *sva,
4051 const int *advance, const SCRIPT_ANALYSIS *sa,
4052 ABC *abc, int *justify)
4053 {
4054 int i;
4055
4056 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
4057 dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
4058
4059 for (i = 0; i < num_chars; i++) justify[i] = advance[i];
4060 return S_OK;
4061 }
4062
ScriptJustify(const SCRIPT_VISATTR * sva,const int * advance,int num_glyphs,int dx,int min_kashida,int * justify)4063 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
4064 int num_glyphs, int dx, int min_kashida, int *justify)
4065 {
4066 int i;
4067
4068 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
4069
4070 for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
4071 return S_OK;
4072 }
4073
ScriptGetFontScriptTags(HDC hdc,SCRIPT_CACHE * psc,SCRIPT_ANALYSIS * psa,int cMaxTags,OPENTYPE_TAG * pScriptTags,int * pcTags)4074 HRESULT WINAPI ScriptGetFontScriptTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
4075 {
4076 HRESULT hr;
4077 if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4078 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4079
4080 return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
4081 }
4082
ScriptGetFontLanguageTags(HDC hdc,SCRIPT_CACHE * psc,SCRIPT_ANALYSIS * psa,OPENTYPE_TAG tagScript,int cMaxTags,OPENTYPE_TAG * pLangSysTags,int * pcTags)4083 HRESULT WINAPI ScriptGetFontLanguageTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
4084 {
4085 HRESULT hr;
4086 if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4087 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4088
4089 return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
4090 }
4091
ScriptGetFontFeatureTags(HDC hdc,SCRIPT_CACHE * psc,SCRIPT_ANALYSIS * psa,OPENTYPE_TAG tagScript,OPENTYPE_TAG tagLangSys,int cMaxTags,OPENTYPE_TAG * pFeatureTags,int * pcTags)4092 HRESULT WINAPI ScriptGetFontFeatureTags( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
4093 {
4094 HRESULT hr;
4095 if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4096 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4097
4098 return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);
4099 }
4100
4101 #ifdef __REACTOS__
4102 BOOL gbLpkPresent = FALSE;
LpkPresent()4103 VOID WINAPI LpkPresent()
4104 {
4105 gbLpkPresent = TRUE; /* Turn it on this way! Wine is out of control! */
4106 }
4107 #endif
4108