ReactOS  0.4.14-dev-1331-g167fa2c
usp10.c
Go to the documentation of this file.
1 /*
2  * Implementation of Uniscribe Script Processor (usp10.dll)
3  *
4  * Copyright 2005 Steven Edwards for CodeWeavers
5  * Copyright 2006 Hans Leidekker
6  * Copyright 2010 CodeWeavers, Aric Stewart
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21  *
22  * Notes:
23  * Uniscribe allows for processing of complex scripts such as joining
24  * and filtering characters and bi-directional text with custom line breaks.
25  */
26 
27 #include <stdarg.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #ifdef __REACTOS__
31 #include <wchar.h>
32 #endif
33 
34 #include "windef.h"
35 #include "winbase.h"
36 #include "wingdi.h"
37 #include "winuser.h"
38 #include "winnls.h"
39 #include "winreg.h"
40 #include "usp10.h"
41 
42 #include "usp10_internal.h"
43 
44 #include "wine/debug.h"
45 #include "wine/heap.h"
46 
48 
49 static const struct usp10_script_range
50 {
56 }
57 script_ranges[] =
58 {
59  /* Basic Latin: U+0000–U+007A */
61  /* Latin-1 Supplement: U+0080–U+00FF */
62  /* Latin Extended-A: U+0100–U+017F */
63  /* Latin Extended-B: U+0180–U+024F */
64  /* IPA Extensions: U+0250–U+02AF */
65  /* Spacing Modifier Letters:U+02B0–U+02FF */
67  /* Combining Diacritical Marks : U+0300–U+036F */
68  { Script_Diacritical,0x300, 0x36f, 0, 0},
69  /* Greek: U+0370–U+03FF */
70  { Script_Greek, 0x370, 0x3ff, 0, 0},
71  /* Cyrillic: U+0400–U+04FF */
72  /* Cyrillic Supplement: U+0500–U+052F */
73  { Script_Cyrillic, 0x400, 0x52f, 0, 0},
74  /* Armenian: U+0530–U+058F */
75  { Script_Armenian, 0x530, 0x58f, 0, 0},
76  /* Hebrew: U+0590–U+05FF */
77  { Script_Hebrew, 0x590, 0x5ff, 0, 0},
78  /* Arabic: U+0600–U+06FF */
79  { Script_Arabic, 0x600, 0x6ef, Script_Arabic_Numeric, 0},
80  /* Defined by Windows */
81  { Script_Persian, 0x6f0, 0x6f9, 0, 0},
82  /* Continue Arabic: U+0600–U+06FF */
83  { Script_Arabic, 0x6fa, 0x6ff, 0, 0},
84  /* Syriac: U+0700–U+074F*/
85  { Script_Syriac, 0x700, 0x74f, 0, 0},
86  /* Arabic Supplement: U+0750–U+077F */
87  { Script_Arabic, 0x750, 0x77f, 0, 0},
88  /* Thaana: U+0780–U+07BF */
89  { Script_Thaana, 0x780, 0x7bf, 0, 0},
90  /* N’Ko: U+07C0–U+07FF */
91  { Script_NKo, 0x7c0, 0x7ff, 0, 0},
92  /* Devanagari: U+0900–U+097F */
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 */
306  {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
307  {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
308  0x00000000,
309  {0}},
310  {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
311  {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
312  MS_MAKE_TAG('l','a','t','n'),
313  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
314  {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
315  {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
316  0x00000000,
317  {0}},
318  {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
319  {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
320  0x00000000,
321  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
322  {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
323  {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
324  0x00000000,
325  {0}},
326  {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
327  {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
328  0x00000000,
329  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
330  {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
331  {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
332  MS_MAKE_TAG('a','r','a','b'),
333  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
334  {{Script_Arabic_Numeric, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
335  {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
336  MS_MAKE_TAG('a','r','a','b'),
337  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
338  {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
339  {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
340  MS_MAKE_TAG('h','e','b','r'),
341  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
342  {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
343  {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
344  MS_MAKE_TAG('s','y','r','c'),
345  {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
346  {{Script_Persian, 0, 1, 0, 0, 0, 0, { 2,0,0,0,0,0,0,0,0,0,0}},
347  {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
348  MS_MAKE_TAG('a','r','a','b'),
349  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
350  {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
351  {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
352  MS_MAKE_TAG('t','h','a','a'),
353  {'M','V',' ','B','o','l','i',0}},
354  {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
355  {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
356  MS_MAKE_TAG('g','r','e','k'),
357  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
358  {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
359  {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
360  MS_MAKE_TAG('c','y','r','l'),
361  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
362  {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
363  {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
364  MS_MAKE_TAG('a','r','m','n'),
365  {'S','y','l','f','a','e','n',0}},
366  {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
367  {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
368  MS_MAKE_TAG('g','e','o','r'),
369  {'S','y','l','f','a','e','n',0}},
370  {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
371  {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
372  MS_MAKE_TAG('s','i','n','h'),
373  {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
374  {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
375  {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
376  MS_MAKE_TAG('t','i','b','t'),
377  {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
378  {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
379  {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
380  MS_MAKE_TAG('t','i','b','t'),
381  {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
382  {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
383  {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
384  MS_MAKE_TAG('p','h','a','g'),
385  {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
386  {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
387  {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
388  MS_MAKE_TAG('t','h','a','i'),
389  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
390  {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
391  {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
392  MS_MAKE_TAG('t','h','a','i'),
393  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
394  {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
395  {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
396  MS_MAKE_TAG('l','a','o',' '),
397  {'D','o','k','C','h','a','m','p','a',0}},
398  {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
399  {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
400  MS_MAKE_TAG('l','a','o',' '),
401  {'D','o','k','C','h','a','m','p','a',0}},
402  {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
403  {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
404  MS_MAKE_TAG('d','e','v','a'),
405  {'M','a','n','g','a','l',0}},
406  {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
407  {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
408  MS_MAKE_TAG('d','e','v','a'),
409  {'M','a','n','g','a','l',0}},
410  {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
411  {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
412  MS_MAKE_TAG('b','e','n','g'),
413  {'V','r','i','n','d','a',0}},
414  {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
415  {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
416  MS_MAKE_TAG('b','e','n','g'),
417  {'V','r','i','n','d','a',0}},
418  {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
419  {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
420  MS_MAKE_TAG('b','e','n','g'),
421  {'V','r','i','n','d','a',0}},
422  {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
423  {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
424  MS_MAKE_TAG('g','u','r','u'),
425  {'R','a','a','v','i',0}},
426  {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
427  {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
428  MS_MAKE_TAG('g','u','r','u'),
429  {'R','a','a','v','i',0}},
430  {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
431  {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
432  MS_MAKE_TAG('g','u','j','r'),
433  {'S','h','r','u','t','i',0}},
434  {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
435  {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
436  MS_MAKE_TAG('g','u','j','r'),
437  {'S','h','r','u','t','i',0}},
438  {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
439  {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
440  MS_MAKE_TAG('g','u','j','r'),
441  {'S','h','r','u','t','i',0}},
442  {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
443  {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
444  MS_MAKE_TAG('o','r','y','a'),
445  {'K','a','l','i','n','g','a',0}},
446  {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
447  {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
448  MS_MAKE_TAG('o','r','y','a'),
449  {'K','a','l','i','n','g','a',0}},
450  {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
451  {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
452  MS_MAKE_TAG('t','a','m','l'),
453  {'L','a','t','h','a',0}},
454  {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
455  {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
456  MS_MAKE_TAG('t','a','m','l'),
457  {'L','a','t','h','a',0}},
458  {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
459  {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
460  MS_MAKE_TAG('t','e','l','u'),
461  {'G','a','u','t','a','m','i',0}},
462  {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
463  {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
464  MS_MAKE_TAG('t','e','l','u'),
465  {'G','a','u','t','a','m','i',0}},
466  {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
467  {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
468  MS_MAKE_TAG('k','n','d','a'),
469  {'T','u','n','g','a',0}},
470  {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
471  {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
472  MS_MAKE_TAG('k','n','d','a'),
473  {'T','u','n','g','a',0}},
474  {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
475  {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
476  MS_MAKE_TAG('m','l','y','m'),
477  {'K','a','r','t','i','k','a',0}},
478  {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
479  {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
480  MS_MAKE_TAG('m','l','y','m'),
481  {'K','a','r','t','i','k','a',0}},
482  {{Script_Diacritical, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
483  {LANG_ENGLISH, 0, 1, 0, 1, ANSI_CHARSET, 0, 0, 0, 0, 0, 1, 1, 0, 0},
484  0x00000000,
485  {0}},
486  {{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
487  {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
488  MS_MAKE_TAG('l','a','t','n'),
489  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
490  {{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
491  {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
492  0x00000000,
493  {0}},
494  {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
495  {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
496  MS_MAKE_TAG('m','y','m','r'),
497  {'M','y','a','n','m','a','r',' ','T','e','x','t',0}},
498  {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
499  {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
500  MS_MAKE_TAG('m','y','m','r'),
501  {0}},
502  {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
503  {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
504  MS_MAKE_TAG('t','a','l','e'),
505  {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e',0}},
506  {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
507  {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
508  MS_MAKE_TAG('t','a','l','u'),
509  {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
510  {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
511  {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
512  MS_MAKE_TAG('t','a','l','u'),
513  {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e',0}},
514  {{Script_Khmer, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
515  {0x53, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
516  MS_MAKE_TAG('k','h','m','r'),
517  {'D','a','u','n','P','e','n','h',0}},
518  {{Script_Khmer_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
519  {0x53, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
520  MS_MAKE_TAG('k','h','m','r'),
521  {'D','a','u','n','P','e','n','h',0}},
522  {{Script_CJK_Han, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
523  {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
524  MS_MAKE_TAG('h','a','n','i'),
525  {0}},
526  {{Script_Ideograph, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
527  {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
528  MS_MAKE_TAG('h','a','n','i'),
529  {0}},
530  {{Script_Bopomofo, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
531  {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
532  MS_MAKE_TAG('b','o','p','o'),
533  {0}},
534  {{Script_Kana, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
535  {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
536  MS_MAKE_TAG('k','a','n','a'),
537  {0}},
538  {{Script_Hangul, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
539  {LANG_KOREAN, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
540  MS_MAKE_TAG('h','a','n','g'),
541  {0}},
542  {{Script_Yi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
543  {LANG_ENGLISH, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
544  MS_MAKE_TAG('y','i',' ',' '),
545  {'M','i','c','r','o','s','o','f','t',' ','Y','i',' ','B','a','i','t','i',0}},
546  {{Script_Ethiopic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
547  {0x5e, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
548  MS_MAKE_TAG('e','t','h','i'),
549  {'N','y','a','l','a',0}},
550  {{Script_Ethiopic_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
551  {0x5e, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
552  MS_MAKE_TAG('e','t','h','i'),
553  {'N','y','a','l','a',0}},
554  {{Script_Mongolian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
555  {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
556  MS_MAKE_TAG('m','o','n','g'),
557  {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
558  {{Script_Mongolian_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
559  {LANG_MONGOLIAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
560  MS_MAKE_TAG('m','o','n','g'),
561  {'M','o','n','g','o','l','i','a','n',' ','B','a','i','t','i',0}},
562  {{Script_Tifinagh, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
563  {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
564  MS_MAKE_TAG('t','f','n','g'),
565  {'E','b','r','i','m','a',0}},
566  {{Script_NKo, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
567  {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
568  MS_MAKE_TAG('n','k','o',' '),
569  {'E','b','r','i','m','a',0}},
570  {{Script_Vai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
571  {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
572  MS_MAKE_TAG('v','a','i',' '),
573  {'E','b','r','i','m','a',0}},
574  {{Script_Vai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
575  {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
576  MS_MAKE_TAG('v','a','i',' '),
577  {'E','b','r','i','m','a',0}},
578  {{Script_Cherokee, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
579  {0x5c, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
580  MS_MAKE_TAG('c','h','e','r'),
581  {'P','l','a','n','t','a','g','e','n','e','t',' ','C','h','e','r','o','k','e','e',0}},
582  {{Script_Canadian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
583  {0x5d, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
584  MS_MAKE_TAG('c','a','n','s'),
585  {'E','u','p','h','e','m','i','a',0}},
586  {{Script_Ogham, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
587  {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
588  MS_MAKE_TAG('o','g','a','m'),
589  {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
590  {{Script_Runic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
591  {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
592  MS_MAKE_TAG('r','u','n','r'),
593  {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
594  {{Script_Braille, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
595  {LANG_ENGLISH, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
596  MS_MAKE_TAG('b','r','a','i'),
597  {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
598  {{Script_Surrogates, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
599  {LANG_ENGLISH, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
600  0x00000000,
601  {0}},
602  {{Script_Private, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
603  {0, 0, 0, 0, 0, DEFAULT_CHARSET, 0, 1, 0, 0, 0, 0, 1, 0, 0},
604  0x00000000,
605  {0}},
606  {{Script_Deseret, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
607  {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
608  MS_MAKE_TAG('d','s','r','t'),
609  {'S','e','g','o','e',' ','U','I',' ','S','y','m','b','o','l',0}},
610  {{Script_Osmanya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
611  {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
612  MS_MAKE_TAG('o','s','m','a'),
613  {'E','b','r','i','m','a',0}},
614  {{Script_Osmanya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
615  {0, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
616  MS_MAKE_TAG('o','s','m','a'),
617  {'E','b','r','i','m','a',0}},
618  {{Script_MathAlpha, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
619  {0, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
620  MS_MAKE_TAG('m','a','t','h'),
621  {'C','a','m','b','r','i','a',' ','M','a','t','h',0}},
622  {{Script_Hebrew_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
623  {LANG_HEBREW, 0, 1, 0, 0, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
624  MS_MAKE_TAG('h','e','b','r'),
625  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
626  {{Script_Vietnamese_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
627  {LANG_VIETNAMESE, 0, 0, 0, 0, VIETNAMESE_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
628  MS_MAKE_TAG('l','a','t','n'),
629  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
630  {{Script_Thai_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
631  {LANG_THAI, 0, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
632  MS_MAKE_TAG('t','h','a','i'),
633  {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
634 };
635 
637 {
679 };
680 
683 {
684  0, 0, &cs_script_cache,
686  0, 0, { (DWORD_PTR)(__FILE__ ": script_cache") }
687 };
688 static CRITICAL_SECTION cs_script_cache = { &cs_script_cache_dbg, -1, 0, 0, 0, 0 };
690 
691 typedef struct {
696  int* piAdvance;
700  int iMaxPosX;
702 } StringGlyphs;
703 
705 {
708 };
709 
710 typedef struct {
714  int clip_len;
715  int cItems;
718  int numItems;
724 
725 typedef struct {
729 
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 */
762 {
763  sc->sfp.cBytes = sizeof(sc->sfp);
764 
765  if (!sc->sfnt)
766  {
767  sc->sfp.wgBlank = sc->tm.tmBreakChar;
768  sc->sfp.wgDefault = sc->tm.tmDefaultChar;
769  sc->sfp.wgInvalid = sc->sfp.wgBlank;
770  sc->sfp.wgKashida = 0xFFFF;
771  sc->sfp.iKashidaWidth = 0;
772  }
773  else
774  {
775  static const WCHAR chars[4] = {0x0020, 0x200B, 0xF71B, 0x0640};
776  /* U+0020: numeric space
777  U+200B: zero width space
778  U+F71B: unknown char found by black box testing
779  U+0640: kashida */
780  WORD gi[4];
781 
783  {
784  if(gi[0] != 0xFFFF) /* 0xFFFF: index of default non exist char */
785  sc->sfp.wgBlank = gi[0];
786  else
787  sc->sfp.wgBlank = 0;
788 
789  sc->sfp.wgDefault = 0;
790 
791  if (gi[2] != 0xFFFF)
792  sc->sfp.wgInvalid = gi[2];
793  else if (gi[1] != 0xFFFF)
794  sc->sfp.wgInvalid = gi[1];
795  else if (gi[0] != 0xFFFF)
796  sc->sfp.wgInvalid = gi[0];
797  else
798  sc->sfp.wgInvalid = 0;
799 
800  sc->sfp.wgKashida = gi[3];
801 
802  sc->sfp.iKashidaWidth = 0; /* TODO */
803  }
804  else
805  return FALSE;
806  }
807  return TRUE;
808 }
809 
811 {
812  *sfp = sc->sfp;
813 }
814 
816 {
817  return ((ScriptCache *)*psc)->tm.tmHeight;
818 }
819 
821 {
822  return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
823 }
824 
826 {
827  CacheGlyphPage *page = ((ScriptCache *)*psc)->page[c / 0x10000];
828  WORD *block;
829 
830  if (!page) return 0;
831  block = page->glyphs[(c % 0x10000) >> GLYPH_BLOCK_SHIFT];
832  if (!block) return 0;
833  return block[(c % 0x10000) & GLYPH_BLOCK_MASK];
834 }
835 
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 
848 {
849  static const ABC nil;
850  ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
851 
852  if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
853  memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
854  return TRUE;
855 }
856 
858 {
859  ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
860 
861  if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
862  memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
863  return TRUE;
864 }
865 
867 {
868  ScriptCache *sc;
869  unsigned size;
870  LOGFONTW lf;
871 
872  if (!psc) return E_INVALIDARG;
873  if (*psc) return S_OK;
874  if (!hdc) return E_PENDING;
875 
876  if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), &lf))
877  {
878  return E_INVALIDARG;
879  }
880  /* Ensure canonical result by zeroing extra space in lfFaceName */
881  size = lstrlenW(lf.lfFaceName);
882  memset(lf.lfFaceName + size, 0, sizeof(lf.lfFaceName) - size * sizeof(WCHAR));
883 
886  {
887  if (!memcmp(&sc->lf, &lf, sizeof(lf)))
888  {
889  sc->refcount++;
891  *psc = sc;
892  return S_OK;
893  }
894  }
896 
897  if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
898  if (!GetTextMetricsW(hdc, &sc->tm))
899  {
900  heap_free(sc);
901  return E_INVALIDARG;
902  }
904  if (size)
905  {
906  sc->otm = heap_alloc(size);
907  sc->otm->otmSize = size;
909  }
910  sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
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 
923  {
924  if (sc != *psc && !memcmp(&sc->lf, &lf, sizeof(lf)))
925  {
926  /* Another thread won the race. Use their cache instead of ours */
927  list_remove(&sc->entry);
928  sc->refcount++;
930  heap_free(*psc);
931  *psc = sc;
932  return S_OK;
933  }
934  }
936  TRACE("<- %p\n", sc);
937  return S_OK;
938 }
939 
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 
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 
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 
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 
1003  GetStringTypeW(CT_CTYPE2, &str[index], 1, &type2);
1004 
1005  if (type == 0)
1006  return SCRIPT_UNDEFINED;
1007 
1008  if (type & C1_CNTRL)
1009  return Script_Control;
1010 
1012  if (ch)
1013  *consumed = 2;
1014  else
1015  ch = str[index];
1016 
1019  return (*consumed == 2) ? Script_Surrogates : Script_Undefined;
1020 
1021  if (range->numericScript && (type & C1_DIGIT || type2 == C2_ARABICNUMBER))
1022  return range->numericScript;
1023  if (range->punctScript && type & C1_PUNCT)
1024  return range->punctScript;
1025  return range->script;
1026 }
1027 
1028 static int __cdecl compare_FindGlyph(const void *a, const void* b)
1029 {
1031  const WORD *idx= (WORD*)b;
1032  int rc = 0;
1033 
1034  if ( find->target > *idx)
1035  rc = 1;
1036  else if (find->target < *idx)
1037  rc = -1;
1038 
1039  if (!find->ascending)
1040  rc *= -1;
1041  return rc;
1042 }
1043 
1045 {
1046  FindGlyph_struct fgs;
1047  WORD *ptr;
1048  INT k;
1049 
1050  if (pwLogClust[0] < pwLogClust[cChars-1])
1051  fgs.ascending = TRUE;
1052  else
1053  fgs.ascending = FALSE;
1054 
1055  fgs.target = target;
1056  ptr = bsearch(&fgs, pwLogClust, cChars, sizeof(WORD), compare_FindGlyph);
1057 
1058  if (!ptr)
1059  return -1;
1060 
1061  for (k = (ptr - pwLogClust)-1; k >= 0 && pwLogClust[k] == target; k--)
1062  ;
1063  k++;
1064 
1065  return k;
1066 }
1067 
1068 /***********************************************************************
1069  * ScriptFreeCache (USP10.@)
1070  *
1071  * Free a script cache.
1072  *
1073  * PARAMS
1074  * psc [I/O] Script cache.
1075  *
1076  * RETURNS
1077  * Success: S_OK
1078  * Failure: Non-zero HRESULT value.
1079  */
1081 {
1082  TRACE("%p\n", psc);
1083 
1084  if (psc && *psc)
1085  {
1086  unsigned int i;
1087  INT n;
1088 
1090  if (--((ScriptCache *)*psc)->refcount > 0)
1091  {
1093  *psc = NULL;
1094  return S_OK;
1095  }
1096  list_remove(&((ScriptCache *)*psc)->entry);
1098 
1099  for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
1100  {
1101  heap_free(((ScriptCache *)*psc)->widths[i]);
1102  }
1103  for (i = 0; i < NUM_PAGES; i++)
1104  {
1105  unsigned int j;
1106  if (((ScriptCache *)*psc)->page[i])
1107  for (j = 0; j < GLYPH_MAX / GLYPH_BLOCK_SIZE; j++)
1108  heap_free(((ScriptCache *)*psc)->page[i]->glyphs[j]);
1109  heap_free(((ScriptCache *)*psc)->page[i]);
1110  }
1111  heap_free(((ScriptCache *)*psc)->GSUB_Table);
1112  heap_free(((ScriptCache *)*psc)->GDEF_Table);
1113  heap_free(((ScriptCache *)*psc)->CMAP_Table);
1114  heap_free(((ScriptCache *)*psc)->GPOS_Table);
1115  for (n = 0; n < ((ScriptCache *)*psc)->script_count; n++)
1116  {
1117  int j;
1118  for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].language_count; j++)
1119  {
1120  int k;
1121  for (k = 0; k < ((ScriptCache *)*psc)->scripts[n].languages[j].feature_count; k++)
1122  heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features[k].lookups);
1123  heap_free(((ScriptCache *)*psc)->scripts[n].languages[j].features);
1124  }
1125  for (j = 0; j < ((ScriptCache *)*psc)->scripts[n].default_language.feature_count; j++)
1126  heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features[j].lookups);
1127  heap_free(((ScriptCache *)*psc)->scripts[n].default_language.features);
1128  heap_free(((ScriptCache *)*psc)->scripts[n].languages);
1129  }
1130  heap_free(((ScriptCache *)*psc)->scripts);
1131  heap_free(((ScriptCache *)*psc)->otm);
1132  heap_free(*psc);
1133  *psc = NULL;
1134  }
1135  return S_OK;
1136 }
1137 
1138 /***********************************************************************
1139  * ScriptGetProperties (USP10.@)
1140  *
1141  * Retrieve a list of script properties.
1142  *
1143  * PARAMS
1144  * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
1145  * num [I] Pointer to the number of scripts.
1146  *
1147  * RETURNS
1148  * Success: S_OK
1149  * Failure: Non-zero HRESULT value.
1150  *
1151  * NOTES
1152  * Behaviour matches WinXP.
1153  */
1155 {
1156  TRACE("(%p,%p)\n", props, num);
1157 
1158  if (!props && !num) return E_INVALIDARG;
1159 
1160  if (num) *num = ARRAY_SIZE(script_props);
1161  if (props) *props = script_props;
1162 
1163  return S_OK;
1164 }
1165 
1166 /***********************************************************************
1167  * ScriptGetFontProperties (USP10.@)
1168  *
1169  * Get information on special glyphs.
1170  *
1171  * PARAMS
1172  * hdc [I] Device context.
1173  * psc [I/O] Opaque pointer to a script cache.
1174  * sfp [O] Font properties structure.
1175  */
1177 {
1178  HRESULT hr;
1179 
1180  TRACE("%p,%p,%p\n", hdc, psc, sfp);
1181 
1182  if (!sfp) return E_INVALIDARG;
1183  if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
1184 
1185  if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
1186  return E_INVALIDARG;
1187 
1189 
1190  return S_OK;
1191 }
1192 
1193 /***********************************************************************
1194  * ScriptRecordDigitSubstitution (USP10.@)
1195  *
1196  * Record digit substitution settings for a given locale.
1197  *
1198  * PARAMS
1199  * locale [I] Locale identifier.
1200  * sds [I] Structure to record substitution settings.
1201  *
1202  * RETURNS
1203  * Success: S_OK
1204  * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
1205  *
1206  * SEE ALSO
1207  * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
1208  */
1210 {
1211  DWORD plgid, sub;
1212 
1213  TRACE("0x%x, %p\n", locale, sds);
1214 
1215  /* This implementation appears to be correct for all languages, but it's
1216  * not clear if sds->DigitSubstitute is ever set to anything except
1217  * CONTEXT or NONE in reality */
1218 
1219  if (!sds) return E_POINTER;
1220 
1222 
1224  return E_INVALIDARG;
1225 
1227  sds->TraditionalDigitLanguage = plgid;
1228 
1229  if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1230  sds->NationalDigitLanguage = plgid;
1231  else
1233 
1234  if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
1235  (WCHAR *)&sub, sizeof(sub) / sizeof(WCHAR)))
1236  return E_INVALIDARG;
1237 
1238  switch (sub)
1239  {
1240  case 0:
1241  if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
1243  else
1245  break;
1246  case 1:
1248  break;
1249  case 2:
1251  break;
1252  default:
1254  break;
1255  }
1256 
1257  sds->dwReserved = 0;
1258  return S_OK;
1259 }
1260 
1261 /***********************************************************************
1262  * ScriptApplyDigitSubstitution (USP10.@)
1263  *
1264  * Apply digit substitution settings.
1265  *
1266  * PARAMS
1267  * sds [I] Structure with recorded substitution settings.
1268  * sc [I] Script control structure.
1269  * ss [I] Script state structure.
1270  *
1271  * RETURNS
1272  * Success: S_OK
1273  * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
1274  */
1277 {
1279 
1280  TRACE("%p, %p, %p\n", sds, sc, ss);
1281 
1282  if (!sc || !ss) return E_POINTER;
1283  if (!sds)
1284  {
1285  sds = &psds;
1287  return E_INVALIDARG;
1288  }
1289 
1291  sc->fContextDigits = 0;
1292  ss->fDigitSubstitute = 0;
1293 
1294  switch (sds->DigitSubstitute) {
1299  return S_OK;
1300  default:
1301  return E_INVALIDARG;
1302  }
1303 }
1304 
1305 static inline BOOL is_indic(enum usp10_script script)
1306 {
1308 }
1309 
1310 static inline enum usp10_script base_indic(enum usp10_script script)
1311 {
1312  switch (script)
1313  {
1314  case Script_Devanagari:
1316  case Script_Bengali:
1319  case Script_Gurmukhi:
1321  case Script_Gujarati:
1324  case Script_Oriya:
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:
1332  case Script_Malayalam:
1334  default:
1335  return Script_Undefined;
1336  };
1337 }
1338 
1340 {
1342 }
1343 
1344 static HRESULT _ItemizeInternal(const WCHAR *pwcInChars, int cInChars,
1345  int cMaxItems, const SCRIPT_CONTROL *psControl,
1348 {
1349 
1350 #define Numeric_space 0x0020
1351 #define ZWSP 0x200B
1352 #define ZWNJ 0x200C
1353 #define ZWJ 0x200D
1354 
1355  enum usp10_script last_indic = Script_Undefined;
1356  int cnt = 0, index = 0, str = 0;
1357  enum usp10_script New_Script = -1;
1358  int i;
1359  WORD *levels = NULL;
1360  WORD *layout_levels = NULL;
1361  WORD *overrides = NULL;
1362  WORD *strength = NULL;
1363  enum usp10_script *scripts;
1364  WORD baselevel = 0;
1365  WORD baselayout = 0;
1366  BOOL new_run;
1367  WORD layoutRTL = 0;
1368  BOOL forceLevels = FALSE;
1369  unsigned int consumed = 0;
1371 
1372  TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
1374 
1375  if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
1376  return E_INVALIDARG;
1377 
1378  if (!(scripts = heap_calloc(cInChars, sizeof(*scripts))))
1379  return E_OUTOFMEMORY;
1380 
1381  for (i = 0; i < cInChars; i++)
1382  {
1383  if (!consumed)
1384  {
1385  scripts[i] = get_char_script(pwcInChars,i,cInChars,&consumed);
1386  consumed --;
1387  }
1388  else
1389  {
1390  scripts[i] = scripts[i-1];
1391  consumed --;
1392  }
1393  /* Devanagari danda (U+0964) and double danda (U+0965) are used for
1394  all Indic scripts */
1395  if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic != Script_Undefined)
1396  scripts[i] = last_indic;
1397  else if (is_indic(scripts[i]))
1398  last_indic = base_indic(scripts[i]);
1399 
1400  /* Some unicode points :
1401  (Zero Width Space U+200B - Right-to-Left Mark U+200F)
1402  (Left Right Embed U+202A - Left Right Override U+202D)
1403  (Left Right Isolate U+2066 - Pop Directional Isolate U+2069)
1404  will force us into bidi mode */
1405  if (!forceLevels && ((pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F) ||
1406  (pwcInChars[i] >= 0x202A && pwcInChars[i] <= 0x202E) ||
1407  (pwcInChars[i] >= 0x2066 && pwcInChars[i] <= 0x2069)))
1408 
1409  forceLevels = TRUE;
1410 
1411  /* Diacritical marks merge with other scripts */
1412  if (scripts[i] == Script_Diacritical)
1413  {
1414  if (i > 0)
1415  {
1416  if (pScriptTags)
1417  scripts[i] = scripts[i-1];
1418  else
1419  {
1420  int j;
1421  BOOL asian = FALSE;
1422  enum usp10_script first_script = scripts[i-1];
1423  for (j = i-1; j >= 0 && scripts[j] == first_script && pwcInChars[j] != Numeric_space; j--)
1424  {
1425  enum usp10_script original = scripts[j];
1426  if (original == Script_Ideograph || original == Script_Kana || original == Script_Yi || original == Script_CJK_Han || original == Script_Bopomofo)
1427  {
1428  asian = TRUE;
1429  break;
1430  }
1431  if (original != Script_MathAlpha && scriptInformation[scripts[j]].props.fComplex)
1432  break;
1433  scripts[j] = scripts[i];
1434  if (original == Script_Punctuation2)
1435  break;
1436  }
1437  if (j >= 0 && (scriptInformation[scripts[j]].props.fComplex || asian))
1438  scripts[i] = scripts[j];
1439  }
1440  }
1441  }
1442  }
1443 
1444  for (i = 0; i < cInChars; i++)
1445  {
1446  /* Joiners get merged preferencially right */
1447  if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ || pwcInChars[i] == ZWSP))
1448  {
1449  int j;
1450  if (i+1 == cInChars)
1451  scripts[i] = scripts[i-1];
1452  else
1453  {
1454  for (j = i+1; j < cInChars; j++)
1455  {
1456  if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ
1457  && pwcInChars[j] != ZWSP && pwcInChars[j] != Numeric_space)
1458  {
1459  scripts[i] = scripts[j];
1460  break;
1461  }
1462  }
1463  }
1464  }
1465  }
1466 
1467  if (psState && psControl)
1468  {
1469  if (!(levels = heap_calloc(cInChars, sizeof(*levels))))
1470  goto nomemory;
1471 
1472  if (!(overrides = heap_calloc(cInChars, sizeof(*overrides))))
1473  goto nomemory;
1474 
1475  if (!(layout_levels = heap_calloc(cInChars, sizeof(*layout_levels))))
1476  goto nomemory;
1477 
1478  if (psState->fOverrideDirection)
1479  {
1480  if (!forceLevels)
1481  {
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  }
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)
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  */
1831 {
1833 }
1834 
1835 /***********************************************************************
1836  * ScriptItemize (USP10.@)
1837  *
1838  * Split a Unicode string into shapeable parts.
1839  *
1840  * PARAMS
1841  * pwcInChars [I] String to split.
1842  * cInChars [I] Number of characters in pwcInChars.
1843  * cMaxItems [I] Maximum number of items to return.
1844  * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1845  * psState [I] Pointer to a SCRIPT_STATE structure.
1846  * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1847  * pcItems [O] Number of script items returned.
1848  *
1849  * RETURNS
1850  * Success: S_OK
1851  * Failure: Non-zero HRESULT value.
1852  */
1853 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1855  SCRIPT_ITEM *pItems, int *pcItems)
1856 {
1858 }
1859 
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  */
1935  const WCHAR *pwcInChars, int cChars )
1936 {
1937  /* FIXME: When to properly fallback is still a bit of a mystery */
1938  WORD *glyphs;
1939 
1940  if (psa->fNoGlyphIndex)
1941  return FALSE;
1942 
1943  if (init_script_cache(hdc, psc) != S_OK)
1944  return FALSE;
1945 
1947  return TRUE;
1948 
1949  if (!(glyphs = heap_calloc(cChars, sizeof(*glyphs))))
1950  return FALSE;
1951  if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1952  {
1953  heap_free(glyphs);
1954  return TRUE;
1955  }
1956  heap_free(glyphs);
1957 
1958  return FALSE;
1959 }
1960 
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  */
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 {
1993  StringAnalysis *analysis = NULL;
1995  SCRIPT_STATE sState;
1996  int i, num_items = 255;
1997  BYTE *BidiLevel;
1998  WCHAR *iString = NULL;
1999 
2000  TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
2001  hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
2002  psControl, psState, piDx, pTabdef, pbInClass, pssa);
2003 
2004  if (iCharset != -1)
2005  {
2006  FIXME("Only Unicode strings are supported\n");
2007  return E_INVALIDARG;
2008  }
2009  if (cString < 1 || !pString) return E_INVALIDARG;
2010  if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
2011 
2012  if (!(analysis = heap_alloc_zero(sizeof(*analysis))))
2013  return E_OUTOFMEMORY;
2014  if (!(analysis->pItem = heap_calloc(num_items + 1, sizeof(*analysis->pItem))))
2015  goto error;
2016 
2017  /* FIXME: handle clipping */
2018  analysis->clip_len = cString;
2019  analysis->hdc = hdc;
2020  analysis->ssa_flags = dwFlags;
2021 
2022  if (psState)
2023  sState = *psState;
2024  else
2025  memset(&sState, 0, sizeof(SCRIPT_STATE));
2026 
2027  if (psControl)
2028  sControl = *psControl;
2029  else
2030  memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
2031 
2032  if (dwFlags & SSA_PASSWORD)
2033  {
2034  if (!(iString = heap_calloc(cString, sizeof(*iString))))
2035  {
2036  hr = E_OUTOFMEMORY;
2037  goto error;
2038  }
2039  for (i = 0; i < cString; i++)
2040  iString[i] = *((const WCHAR *)pString);
2041  pString = iString;
2042  }
2043 
2044  hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
2045  &analysis->numItems);
2046 
2047  if (FAILED(hr))
2048  {
2049  if (hr == E_OUTOFMEMORY)
2050  hr = E_INVALIDARG;
2051  goto error;
2052  }
2053 
2054  /* set back to out of memory for default goto error behaviour */
2055  hr = E_OUTOFMEMORY;
2056 
2057  if (dwFlags & SSA_BREAK)
2058  {
2059  if (!(analysis->logattrs = heap_calloc(cString, sizeof(*analysis->logattrs))))
2060  goto error;
2061 
2062  for (i = 0; i < analysis->numItems; ++i)
2063  ScriptBreak(&((const WCHAR *)pString)[analysis->pItem[i].iCharPos],
2064  analysis->pItem[i + 1].iCharPos - analysis->pItem[i].iCharPos,
2065  &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
2066  }
2067 
2068  if (!(analysis->logical2visual = heap_calloc(analysis->numItems, sizeof(*analysis->logical2visual))))
2069  goto error;
2070  if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
2071  goto error;
2072 
2073  if (dwFlags & SSA_GLYPHS)
2074  {
2075  int tab_x = 0;
2076 
2077  if (!(analysis->glyphs = heap_calloc(analysis->numItems, sizeof(*analysis->glyphs))))
2078  {
2079  heap_free(BidiLevel);
2080  goto error;
2081  }
2082 
2083  for (i = 0; i < analysis->numItems; i++)
2084  {
2085  SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
2086  int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2087  int numGlyphs = 1.5 * cChar + 16;
2088  WORD *glyphs = heap_calloc(numGlyphs, sizeof(*glyphs));
2089  WORD *pwLogClust = heap_calloc(cChar, sizeof(*pwLogClust));
2090  int *piAdvance = heap_calloc(numGlyphs, sizeof(*piAdvance));
2091  SCRIPT_VISATTR *psva = heap_calloc(numGlyphs, sizeof(*psva));
2092  GOFFSET *pGoffset = heap_calloc(numGlyphs, sizeof(*pGoffset));
2093  int numGlyphsReturned;
2094  HFONT originalFont = 0x0;
2095 
2096  /* FIXME: non unicode strings */
2097  const WCHAR* pStr = (const WCHAR*)pString;
2098  analysis->glyphs[i].fallbackFont = NULL;
2099 
2100  if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset)
2101  {
2102  heap_free (BidiLevel);
2103  heap_free (glyphs);
2105  heap_free (piAdvance);
2106  heap_free (psva);
2107  heap_free (pGoffset);
2108  hr = E_OUTOFMEMORY;
2109  goto error;
2110  }
2111 
2112  if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
2113  {
2114  LOGFONTW lf;
2115  GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
2117  lf.lfFaceName[0] = 0;
2118  find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
2119  if (lf.lfFaceName[0])
2120  {
2121  analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
2122  if (analysis->glyphs[i].fallbackFont)
2123  {
2124  ScriptFreeCache(sc);
2125  originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
2126  }
2127  }
2128  }
2129 
2130  /* FIXME: When we properly shape Hangul remove this check */
2131  if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && analysis->pItem[i].a.eScript == Script_Hangul)
2132  analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2133 
2134  if ((dwFlags & SSA_LINK) && !analysis->glyphs[i].fallbackFont && !scriptInformation[analysis->pItem[i].a.eScript].props.fComplex && !analysis->pItem[i].a.fRTL)
2135  analysis->pItem[i].a.fNoGlyphIndex = TRUE;
2136 
2137  ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos], cChar, numGlyphs,
2138  &analysis->pItem[i].a, glyphs, pwLogClust, psva, &numGlyphsReturned);
2139  hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
2140  piAdvance, pGoffset, &analysis->glyphs[i].abc);
2141  if (originalFont)
2142  SelectObject(hdc,originalFont);
2143 
2144  if (dwFlags & SSA_TAB)
2145  {
2146  int tabi = 0;
2147  for (tabi = 0; tabi < cChar; tabi++)
2148  {
2149  if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
2150  piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
2151  tab_x+=piAdvance[tabi];
2152  }
2153  }
2154 
2155  analysis->glyphs[i].numGlyphs = numGlyphsReturned;
2156  analysis->glyphs[i].glyphs = glyphs;
2157  analysis->glyphs[i].pwLogClust = pwLogClust;
2158  analysis->glyphs[i].piAdvance = piAdvance;
2159  analysis->glyphs[i].psva = psva;
2160  analysis->glyphs[i].pGoffset = pGoffset;
2161  analysis->glyphs[i].iMaxPosX= -1;
2162 
2163  BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2164  }
2165  }
2166  else
2167  {
2168  for (i = 0; i < analysis->numItems; i++)
2169  BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
2170  }
2171 
2172  ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
2173  heap_free(BidiLevel);
2174 
2175  *pssa = analysis;
2176  heap_free(iString);
2177  return S_OK;
2178 
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 
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 
2201  int iX,
2202  int iY,
2203  int iItem,
2204  int cStart,
2205  int cEnd,
2206  UINT uOptions,
2207  const RECT *prc,
2208  BOOL fSelected,
2209  BOOL fDisabled)
2210 {
2211  StringAnalysis *analysis;
2212  int off_x = 0;
2213  HRESULT hr;
2214  COLORREF BkColor = 0x0;
2215  COLORREF TextColor = 0x0;
2216  INT BkMode = 0;
2217  INT runStart, runEnd;
2218  INT iGlyph, cGlyphs;
2219  HFONT oldFont = 0x0;
2220  RECT crc;
2221  int i;
2222 
2223  TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
2224  ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
2225 
2226  if (!(analysis = ssa)) return E_INVALIDARG;
2227 
2228  if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
2229  (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
2230  return S_OK;
2231 
2232  CopyRect(&crc,prc);
2233  if (fSelected)
2234  {
2235  BkMode = GetBkMode(analysis->hdc);
2236  SetBkMode( analysis->hdc, OPAQUE);
2237  BkColor = GetBkColor(analysis->hdc);
2239  if (!fDisabled)
2240  {
2241  TextColor = GetTextColor(analysis->hdc);
2243  }
2244  }
2245  if (analysis->glyphs[iItem].fallbackFont)
2246  oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
2247 
2248  if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
2249  runStart = cStart - analysis->pItem[iItem].iCharPos;
2250  else
2251  runStart = 0;
2252  if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
2253  runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
2254  else
2255  runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
2256 
2257  if (analysis->pItem[iItem].a.fRTL)
2258  {
2259  if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
2260  ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
2261  else
2262  ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
2263  crc.left = iX + off_x;
2264  }
2265  else
2266  {
2267  if (cStart >=0 && runStart)
2268  ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
2269  else
2270  ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
2271  crc.left = iX + off_x;
2272  }
2273 
2274  if (analysis->pItem[iItem].a.fRTL)
2275  iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
2276  else
2277  iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
2278 
2279  if (analysis->pItem[iItem].a.fRTL)
2280  cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
2281  else
2282  cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
2283 
2284  cGlyphs++;
2285 
2286  /* adjust for cluster glyphs when starting */
2287  if (analysis->pItem[iItem].a.fRTL)
2288  i = analysis->pItem[iItem+1].iCharPos - 1;
2289  else
2290  i = analysis->pItem[iItem].iCharPos;
2291 
2292  for (; i >=analysis->pItem[iItem].iCharPos && i < analysis->pItem[iItem+1].iCharPos; (analysis->pItem[iItem].a.fRTL)?i--:i++)
2293  {
2294  if (analysis->glyphs[iItem].pwLogClust[i - analysis->pItem[iItem].iCharPos] == iGlyph)
2295  {
2296  if (analysis->pItem[iItem].a.fRTL)
2297  ScriptStringCPtoX(ssa, i, TRUE, &off_x);
2298  else
2299  ScriptStringCPtoX(ssa, i, FALSE, &off_x);
2300  break;
2301  }
2302  }
2303 
2304  if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
2305  {
2306  INT direction;
2307  INT clust_glyph;
2308 
2309  clust_glyph = iGlyph + cGlyphs;
2310  if (analysis->pItem[iItem].a.fRTL)
2311  direction = -1;
2312  else
2313  direction = 1;
2314 
2315  while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
2316  !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
2317  {
2318  cGlyphs++;
2319  clust_glyph++;
2320  }
2321  }
2322 
2323  hr = ScriptTextOut(analysis->hdc,
2324  (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
2325  iY, uOptions, &crc, &analysis->pItem[iItem].a, NULL, 0,
2326  &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
2327  &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
2328  &analysis->glyphs[iItem].pGoffset[iGlyph]);
2329 
2330  TRACE("ScriptTextOut hr=%08x\n", hr);
2331 
2332  if (fSelected)
2333  {
2334  SetBkColor(analysis->hdc, BkColor);
2335  SetBkMode( analysis->hdc, BkMode);
2336  if (!fDisabled)
2337  SetTextColor(analysis->hdc, TextColor);
2338  }
2339  if (analysis->glyphs[iItem].fallbackFont)
2340  SelectObject(analysis->hdc, oldFont);
2341 
2342  return hr;
2343 }
2344 
2345 /***********************************************************************
2346  * ScriptStringOut (USP10.@)
2347  *
2348  * This function takes the output of ScriptStringAnalyse and joins the segments
2349  * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
2350  * only processes glyphs.
2351  *
2352  * Parameters:
2353  * ssa [I] buffer to hold the analysed string components
2354  * iX [I] X axis displacement for output
2355  * iY [I] Y axis displacement for output
2356  * uOptions [I] flags controlling output processing
2357  * prc [I] rectangle coordinates
2358  * iMinSel [I] starting pos for substringing output string
2359  * iMaxSel [I] ending pos for substringing output string
2360  * fDisabled [I] controls text highlighting
2361  *
2362  * RETURNS
2363  * Success: S_OK
2364  * Failure: is the value returned by ScriptTextOut
2365  */
2367  int iX,
2368  int iY,
2369  UINT uOptions,
2370  const RECT *prc,
2371  int iMinSel,
2372  int iMaxSel,
2373  BOOL fDisabled)
2374 {
2375  StringAnalysis *analysis;
2376  int item;
2377  HRESULT hr;
2378 
2379  TRACE("(%p,%d,%d,0x%08x,%s,%d,%d,%d)\n",
2380  ssa, iX, iY, uOptions, wine_dbgstr_rect(prc), iMinSel, iMaxSel, fDisabled);
2381 
2382  if (!(analysis = ssa)) return E_INVALIDARG;
2383  if (!(analysis->ssa_flags & SSA_GLYPHS)) return E_INVALIDARG;
2384 
2385  for (item = 0; item < analysis->numItems; item++)
2386  {
2387  hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
2388  if (FAILED(hr))
2389  return hr;
2390  }
2391 
2392  if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
2393  {
2394  if (iMaxSel > 0 && iMinSel < 0)
2395  iMinSel = 0;
2396  for (item = 0; item < analysis->numItems; item++)
2397  {
2398  hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
2399  if (FAILED(hr))
2400  return hr;
2401  }
2402  }
2403 
2404  return S_OK;
2405 }
2406 
2407 /***********************************************************************
2408  * ScriptStringCPtoX (USP10.@)
2409  *
2410  */
2412 {
2413  int item;
2414  int runningX = 0;
2415  StringAnalysis* analysis = ssa;
2416 
2417  TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
2418 
2419  if (!ssa || !pX) return S_FALSE;
2420  if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
2421 
2422  /* icp out of range */
2423  if(icp < 0)
2424  {
2426  return E_INVALIDARG;
2427  }
2428 
2429  for(item=0; item<analysis->numItems; item++)
2430  {
2431  int CP, i;
2432  int offset;
2433 
2434  i = analysis->logical2visual[item];
2435  CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2436  /* initialize max extents for uninitialized runs */
2437  if (analysis->glyphs[i].iMaxPosX == -1)
2438  {
2439  if (analysis->pItem[i].a.fRTL)
2440  ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2441  analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2442  &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2443  else
2444  ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2445  analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2446  &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
2447  }
2448 
2449  if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
2450  {
2451  runningX += analysis->glyphs[i].iMaxPosX;
2452  continue;
2453  }
2454 
2455  icp -= analysis->pItem[i].iCharPos;
2456  ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
2457  analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
2458  &analysis->pItem[i].a, &offset);
2459  runningX += offset;
2460 
2461  *pX = runningX;
2462  return S_OK;
2463  }
2464 
2465  /* icp out of range */
2467  return E_INVALIDARG;
2468 }
2469 
2470 /***********************************************************************
2471  * ScriptStringXtoCP (USP10.@)
2472  *
2473  */
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  */
2557 {
2558  StringAnalysis* analysis;
2559  BOOL invalid;
2560  int i;
2561 
2562  TRACE("(%p)\n", pssa);
2563 
2564  if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
2565 
2567 
2568  if (analysis->glyphs)
2569  {
2570  for (i = 0; i < analysis->numItems; i++)
2571  {
2572  heap_free(analysis->glyphs[i].glyphs);
2573  heap_free(analysis->glyphs[i].pwLogClust);
2574  heap_free(analysis->glyphs[i].piAdvance);
2575  heap_free(analysis->glyphs[i].psva);
2576  heap_free(analysis->glyphs[i].pGoffset);
2577  if (analysis->glyphs[i].fallbackFont)
2578  DeleteObject(analysis->glyphs[i].fallbackFont);
2579  ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
2580  heap_free(analysis->glyphs[i].sc);
2581  }
2582  heap_free(analysis->glyphs);
2583  }
2584 
2585  heap_free(analysis->pItem);
2586  heap_free(analysis->logattrs);
2587  heap_free(analysis->logical2visual);
2588  heap_free(analysis);
2589 
2590  if (invalid) return E_INVALIDARG;
2591  return S_OK;
2592 }
2593 
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 
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  */
2651  BOOL fTrailing,
2652  int cChars,
2653  int cGlyphs,
2654  const WORD *pwLogClust,
2655  const SCRIPT_VISATTR *psva,
2656  const int *piAdvance,
2657  const SCRIPT_ANALYSIS *psa,
2658  int *piX)
2659 {
2660  int item;
2661  float iPosX;
2662  int iSpecial = -1;
2663  int iCluster = -1;
2664  int clust_size = 1;
2665  float special_size = 0.0;
2666  int iMaxPos = 0;
2667  int advance = 0;
2668  BOOL rtl = FALSE;
2669 
2670  TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2671  iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2672  psa, piX);
2673 
2674  if (psa->fRTL && ! psa->fLogicalOrder)
2675  rtl = TRUE;
2676 
2677  if (fTrailing)
2678  iCP++;
2679 
2680  if (rtl)
2681  {
2682  int max_clust = pwLogClust[0];
2683 
2684  for (item=0; item < cGlyphs; item++)
2685  if (pwLogClust[item] > max_clust)
2686  {
2687  ERR("We do not handle non reversed clusters properly\n");
2688  break;
2689  }
2690 
2691  iMaxPos = 0;
2692  for (item = max_clust; item >=0; item --)
2693  iMaxPos += piAdvance[item];
2694  }
2695 
2696  iPosX = 0.0;
2697  for (item=0; item < iCP && item < cChars; item++)
2698  {
2699  if (iSpecial == -1 && (iCluster == -1 || iCluster+clust_size <= item))
2700  {
2701  int check;
2702  int clust = pwLogClust[item];
2703 
2704  iCluster = -1;
2705  clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2706  &check);
2707 
2708  advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2709 
2710  if (check >= cChars && !iMaxPos)
2711  {
2712  int glyph;
2713  for (glyph = clust; glyph < cGlyphs; glyph++)
2714  special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, glyph, 1);
2715  iSpecial = item;
2716  special_size /= (cChars - item);
2717  iPosX += special_size;
2718  }
2719  else
2720  {
2722  {
2723  clust_size --;
2724  if (clust_size == 0)
2725  iPosX += advance;
2726  }
2727  else
2728  iPosX += advance / (float)clust_size;
2729  }
2730  }
2731  else if (iSpecial != -1)
2732  iPosX += special_size;
2733  else /* (iCluster != -1) */
2734  {
2735  int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2737  {
2738  clust_size --;
2739  if (clust_size == 0)
2740  iPosX += adv;
2741  }
2742  else
2743  iPosX += adv / (float)clust_size;
2744  }
2745  }
2746 
2747  if (iMaxPos > 0)
2748  {
2749  iPosX = iMaxPos - iPosX;
2750  if (iPosX < 0)
2751  iPosX = 0;
2752  }
2753 
2754  *piX = iPosX;
2755  TRACE("*piX=%d\n", *piX);
2756  return S_OK;
2757 }
2758 
2759 /* Count the number of characters in a cluster and its starting index*/
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 */
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  */
2855  int cChars,
2856  int cGlyphs,
2857  const WORD *pwLogClust,
2858  const SCRIPT_VISATTR *psva,
2859  const int *piAdvance,
2860  const SCRIPT_ANALYSIS *psa,
2861  int *piCP,
2862  int *piTrailing)
2863 {
2864  int direction = 1;
2865  int iPosX;
2866  int i;
2867  int glyph_index, cluster_index;
2868  int cluster_size;
2869 
2870  TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2871  iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2872  psa, piCP, piTrailing);
2873 
2874  if (psa->fRTL && ! psa->fLogicalOrder)
2875  direction = -1;
2876 
2877  /* Handle an iX < 0 */
2878  if (iX < 0)
2879  {
2880  if (direction < 0)
2881  {
2882  *piCP = cChars;
2883  *piTrailing = 0;
2884  }
2885  else
2886  {
2887  *piCP = -1;
2888  *piTrailing = 1;
2889  }
2890  return S_OK;
2891  }
2892 
2893  /* Looking for non-reversed clusters in a reversed string */
2894  if (direction < 0)
2895  {
2896  int max_clust = pwLogClust[0];
2897  for (i=0; i< cChars; i++)
2898  if (pwLogClust[i] > max_clust)
2899  {
2900  FIXME("We do not handle non reversed clusters properly\n");
2901  break;
2902  }
2903  }
2904 
2905  /* find the glyph_index based in iX */
2906  if (direction > 0)
2907  {
2908  for (glyph_index = -1, iPosX = iX; iPosX >=0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2909  ;
2910  }
2911  else
2912  {
2913  for (glyph_index = -1, iPosX = iX; iPosX > 0 && glyph_index < cGlyphs; iPosX -= piAdvance[glyph_index+1], glyph_index++)
2914  ;
2915  }
2916 
2917  TRACE("iPosX %i -> glyph_index %i (%i)\n", iPosX, glyph_index, cGlyphs);
2918 
2919  *piTrailing = 0;
2920  if (glyph_index >= 0 && glyph_index < cGlyphs)
2921  {
2922  /* find the cluster */
2923  if (direction > 0 )
2924  for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] <= glyph_index; cluster_index=pwLogClust[i++])
2925  ;
2926  else
2927  for (i = 0, cluster_index = pwLogClust[0]; i < cChars && pwLogClust[i] >= glyph_index; cluster_index=pwLogClust[i++])
2928  ;
2929 
2930  TRACE("cluster_index %i\n", cluster_index);
2931 
2932  if (direction < 0 && iPosX >= 0 && glyph_index != cluster_index)
2933  {
2934  /* We are off the end of the string */
2935  *piCP = -1;
2936  *piTrailing = 1;
2937  return S_OK;
2938  }
2939 
2940  get_cluster_data(pwLogClust, cChars, cluster_index, &cluster_size, &i);
2941 
2942  TRACE("first char index %i\n",i);
2944  {
2945  /* Check trailing */
2946  if (glyph_index != cluster_index ||
2947  (direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
2948  (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
2949  *piTrailing = cluster_size;
2950  }
2951  else
2952  {
2953  if (cluster_size > 1)
2954  {
2955  /* Be part way through the glyph cluster based on size and position */
2956  int cluster_advance = get_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, cluster_index, direction);
2957  double cluster_part_width = cluster_advance / (float)cluster_size;
2958  double adv;
2959  int part_index;
2960 
2961  /* back up to the beginning of the cluster */
2962  for (adv = iPosX, part_index = cluster_index; part_index <= glyph_index; part_index++)
2963  adv += piAdvance[part_index];
2964  if (adv > iX) adv = iX;
2965 
2966  TRACE("Multi-char cluster, no snap\n");
2967  TRACE("cluster size %i, pre-cluster iPosX %f\n",cluster_size, adv);
2968  TRACE("advance %i divides into %f per char\n", cluster_advance, cluster_part_width);
2969  if (direction > 0)
2970  {
2971  for (part_index = 0; adv >= 0; adv-=cluster_part_width, part_index++)
2972  ;
2973  if (part_index) part_index--;
2974  }
2975  else
2976  {
2977  for (part_index = 0; adv > 0; adv-=cluster_part_width, part_index++)
2978  ;
2979  if (part_index > cluster_size)
2980  {
2981  adv += cluster_part_width;
2982  part_index=cluster_size;
2983  }
2984  }
2985 
2986  TRACE("base_char %i part_index %i, leftover advance %f\n",i, part_index, adv);
2987 
2988  if (direction > 0)
2989  i += part_index;
2990  else
2991  i += (cluster_size - part_index);
2992 
2993  /* Check trailing */
2994  if ((direction > 0 && fabs(adv) <= (cluster_part_width / 2.0)) ||
2995  (direction < 0 && adv && fabs(adv) >= (cluster_part_width / 2.0)))
2996  *piTrailing = 1;
2997  }
2998  else
2999  {
3000  /* Check trailing */
3001  if ((direction > 0 && abs(iPosX) <= (piAdvance[glyph_index] / 2)) ||
3002  (direction < 0 && abs(iPosX) >= (piAdvance[glyph_index] / 2)))
3003  *piTrailing = 1;
3004  }
3005  }
3006  }
3007  else
3008  {
3009  TRACE("Point falls outside of string\n");
3010  if (glyph_index < 0)
3011  i = cChars-1;
3012  else /* (glyph_index >= cGlyphs) */
3013  i = cChars;
3014 
3015  /* If not snaping in the reverse direction (such as Hebrew) Then 0
3016  point flow to the next character */
3017  if (direction < 0)
3018  {
3019  if (!scriptInformation[psa->eScript].props.fNeedsCaretInfo && abs(iPosX) == piAdvance[glyph_index])
3020  i++;
3021  else
3022  *piTrailing = 1;
3023  }
3024  }
3025 
3026  *piCP = i;
3027 
3028  TRACE("*piCP=%d\n", *piCP);
3029  TRACE("*piTrailing=%d\n", *piTrailing);
3030  return S_OK;
3031 }
3032 
3033 /***********************************************************************
3034  * ScriptBreak (USP10.@)
3035  *
3036  * Retrieve line break information.
3037  *
3038  * PARAMS
3039  * chars [I] Array of characters.
3040  * sa [I] Script analysis.
3041  * la [I] Array of logical attribute structures.
3042  *
3043  * RETURNS
3044  * Success: S_OK
3045  * Failure: S_FALSE
3046  */
3048 {
3049  TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
3050 
3051  if (count < 0 || !la) return E_INVALIDARG;
3052  if (count == 0) return E_FAIL;
3053 
3054  BREAK_line(chars, count, sa, la);
3055 
3056  return S_OK;
3057 }
3058 
3059 /***********************************************************************
3060  * ScriptIsComplex (USP10.@)
3061  *
3062  * Determine if a string is complex.
3063  *
3064  * PARAMS
3065  * chars [I] Array of characters to test.
3066  * len [I] Length in characters.
3067  * flag [I] Flag.
3068  *
3069  * RETURNS
3070  * Success: S_OK
3071  * Failure: S_FALSE
3072  *
3073  */
3075 {
3076  enum usp10_script script;
3077  unsigned int i, consumed;
3078 
3079  TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
3080 
3081  if (!chars || len < 0)
3082  return E_INVALIDARG;
3083 
3084  for (i = 0; i < len; i+=consumed)
3085  {
3086  if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
3087  return S_OK;
3088 
3089  script = get_char_script(chars,i,len, &consumed);
3090  if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
3092  return S_OK;
3093  }
3094  return S_FALSE;
3095 }
3096 
3097 /***********************************************************************
3098  * ScriptShapeOpenType (USP10.@)
3099  *
3100  * Produce glyphs and visual attributes for a run.
3101  *
3102  * PARAMS
3103  * hdc [I] Device context.
3104  * psc [I/O] Opaque pointer to a script cache.
3105  * psa [I/O] Script analysis.
3106  * tagScript [I] The OpenType tag for the Script
3107  * tagLangSys [I] The OpenType tag for the Language
3108  * rcRangeChars[I] Array of Character counts in each range
3109  * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3110  * cRanges [I] Count of ranges
3111  * pwcChars [I] Array of characters specifying the run.
3112  * cChars [I] Number of characters in pwcChars.
3113  * cMaxGlyphs [I] Length of pwOutGlyphs.
3114  * pwLogClust [O] Array of logical cluster info.
3115  * pCharProps [O] Array of character property values
3116  * pwOutGlyphs [O] Array of glyphs.
3117  * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
3118  * pcGlyphs [O] Number of glyphs returned.
3119  *
3120  * RETURNS
3121  * Success: S_OK
3122  * Failure: Non-zero HRESULT value.
3123  */
3128  int cRanges, const WCHAR *pwcChars, int cChars,
3129  int cMaxGlyphs, WORD *pwLogClust,
3132 {
3133  HRESULT hr;
3134  int i;
3135  unsigned int g;
3136  BOOL rtl;
3137  int cluster;
3138  static int once = 0;
3139 
3140  TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
3141  hdc, psc, psa,
3142  debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3145 
3146  if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
3147  psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
3148 
3149  if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
3150  if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3151 
3152  if (cRanges)
3153  if(!once++) FIXME("Ranges not supported yet\n");
3154 
3155  rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
3156 
3157  *pcGlyphs = cChars;
3158  if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3159  if (!pwLogClust) return E_FAIL;
3160 
3161  ((ScriptCache *)*psc)->userScript = tagScript;
3162  ((ScriptCache *)*psc)->userLang = tagLangSys;
3163 
3164  /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
3165  for (i = 0; i < cChars; i++)
3166  {
3167  int idx = i;
3168  if (rtl) idx = cChars - 1 - i;
3169  /* FIXME: set to better values */
3170  pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
3171  pOutGlyphProps[i].sva.fClusterStart = 1;
3172  pOutGlyphProps[i].sva.fDiacritic = 0;
3173  pOutGlyphProps[i].sva.fZeroWidth = 0;
3174  pOutGlyphProps[i].sva.fReserved = 0;
3175  pOutGlyphProps[i].sva.fShapeReserved = 0;
3176 
3177  /* FIXME: have the shaping engine set this */
3178  pCharProps[i].fCanGlyphAlone = 0;
3179 
3180  pwLogClust[i] = idx;
3181  }
3182 
3183  if (psa && !psa->fNoGlyphIndex && ((ScriptCache *)*psc)->sfnt)
3184  {
3185  WCHAR *rChars;
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  {
3200  if (!chInput)
3201  {
3202  if (psa->fRTL)
3203  chInput = mirror_char(pwcChars[idx]);
3204  else
3205  chInput = pwcChars[idx];
3206  rChars[i] = chInput;
3207  }
3208  else
3209  {
3210  rChars[i] = pwcChars[idx];
3211  rChars[i+1] = pwcChars[(rtl)?idx-1:idx+1];
3212  cluster = 1;
3213  }
3214  if (!(pwOutGlyphs[g] = get_cache_glyph(psc, chInput)))
3215  {
3216  WORD glyph;
3217  if (!hdc)
3218  {
3219  heap_free(rChars);
3220  return E_PENDING;
3221  }
3222  if (OpenType_CMAP_GetGlyphIndex(hdc, (ScriptCache *)*psc, chInput, &glyph, 0) == GDI_ERROR)
3223  {
3224  heap_free(rChars);
3225  return S_FALSE;
3226  }
3227  pwOutGlyphs[g] = set_cache_glyph(psc, chInput, glyph);
3228  }
3229  g++;
3230  }
3231  else
3232  {
3233  int k;
3234  cluster--;
3236  for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3237  pwLogClust[k]--;
3238  }
3239  }
3240  *pcGlyphs = g;
3241 
3245 
3246  for (i = 0; i < cChars; ++i)
3247  {
3248  /* Special case for tabs and joiners. As control characters, ZWNJ
3249  * and ZWJ would in principle get handled by the corresponding
3250  * shaping functions. However, since ZWNJ and ZWJ can get merged
3251  * into adjoining runs during itemisation, these don't generally
3252  * get classified as Script_Control. */
3253  if (pwcChars[i] == 0x0009 || pwcChars[i] == ZWSP || pwcChars[i] == ZWNJ || pwcChars[i] == ZWJ)
3254  {
3255  pwOutGlyphs[pwLogClust[i]] = ((ScriptCache *)*psc)->sfp.wgBlank;
3256  pOutGlyphProps[pwLogClust[i]].sva.fZeroWidth = 1;
3257  }
3258  }
3259  heap_free(rChars);
3260  }
3261  else
3262  {
3263  TRACE("no glyph translation\n");
3264  for (i = 0; i < cChars; i++)
3265  {
3266  int idx = i;
3267  /* No mirroring done here */
3268  if (rtl) idx = cChars - 1 - i;
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  */
3322  int cChars, int cMaxGlyphs,
3324  SCRIPT_VISATTR *psva, int *pcGlyphs)
3325 {
3326  HRESULT hr;
3327  int i;
3328  SCRIPT_CHARPROP *charProps;
3329  SCRIPT_GLYPHPROP *glyphProps;
3330 
3331  if (!psva || !pcGlyphs) return E_INVALIDARG;
3332  if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
3333 
3334  if (!(charProps = heap_calloc(cChars, sizeof(*charProps))))
3335  return E_OUTOFMEMORY;
3336 
3337  if (!(glyphProps = heap_calloc(cMaxGlyphs, sizeof(*glyphProps))))
3338  {
3339  heap_free(charProps);
3340  return E_OUTOFMEMORY;
3341  }
3342 
3344 
3345  if (SUCCEEDED(hr))
3346  {
3347  for (i = 0; i < *pcGlyphs; i++)
3348  psva[i] = glyphProps[i].sva;
3349  }
3350 
3351  heap_free(charProps);
3352  heap_free(glyphProps);
3353 
3354  return hr;
3355 }
3356 
3357 /***********************************************************************
3358  * ScriptPlaceOpenType (USP10.@)
3359  *
3360  * Produce advance widths for a run.
3361  *
3362  * PARAMS
3363  * hdc [I] Device context.
3364  * psc [I/O] Opaque pointer to a script cache.
3365  * psa [I/O] Script analysis.
3366  * tagScript [I] The OpenType tag for the Script
3367  * tagLangSys [I] The OpenType tag for the Language
3368  * rcRangeChars[I] Array of Character counts in each range
3369  * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
3370  * cRanges [I] Count of ranges
3371  * pwcChars [I] Array of characters specifying the run.
3372  * pwLogClust [I] Array of logical cluster info
3373  * pCharProps [I] Array of character property values
3374  * cChars [I] Number of characters in pwcChars.
3375  * pwGlyphs [I] Array of glyphs.
3376  * pGlyphProps [I] Array of attributes for the retrieved glyphs
3377  * cGlyphs [I] Count of Glyphs
3378  * piAdvance [O] Array of advance widths.
3379  * pGoffset [O] Glyph offsets.
3380  * pABC [O] Combined ABC width.
3381  *
3382  * RETURNS
3383  * Success: S_OK
3384  * Failure: Non-zero HRESULT value.
3385  */
3386 
3390  int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
3392  const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
3393  int cGlyphs, int *piAdvance,
3394  GOFFSET *pGoffset, ABC *pABC
3395 )
3396 {
3397  HRESULT hr;
3398  int i;
3399  static int once = 0;
3400 
3401  TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
3402  hdc, psc, psa,
3403  debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
3405  pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
3406  pGoffset, pABC);
3407 
3408  if (!pGlyphProps) return E_INVALIDARG;
3409  if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3410  if (!pGoffset) return E_FAIL;
3411 
3412  if (cRanges)
3413  if (!once++) FIXME("Ranges not supported yet\n");
3414 
3415  ((ScriptCache *)*psc)->userScript = tagScript;
3416  ((ScriptCache *)*psc)->userLang = tagLangSys;
3417 
3418  if (pABC) memset(pABC, 0, sizeof(ABC));
3419  for (i = 0; i < cGlyphs; i++)
3420  {
3421  WORD glyph;
3422  ABC abc;
3423 
3424  /* FIXME: set to more reasonable values */
3425  pGoffset[i].du = pGoffset[i].dv = 0;
3426 
3427  if (pGlyphProps[i].sva.fZeroWidth)
3428  {
3429  abc.abcA = abc.abcB = abc.abcC = 0;
3430  if (piAdvance) piAdvance[i] = 0;
3431  continue;
3432  }
3433 
3434  if (psa->fNoGlyphIndex)
3435  {
3436  if (FAILED(hr = ScriptGetCMap(hdc, psc, &pwGlyphs[i], 1, 0, &glyph))) return hr;
3437  }
3438  else
3439  {
3440  hr = S_OK;
3441  glyph = pwGlyphs[i];
3442  }
3443 
3444  if (hr == S_FALSE)
3445  {
3446  if (!hdc) return E_PENDING;
3448  {
3449  if (!GetCharABCWidthsW(hdc, pwGlyphs[i], pwGlyphs[i], &abc)) return S_FALSE;
3450  }
3451  else
3452  {
3453  INT width;
3454  if (!GetCharWidthW(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
3455  abc.abcB = width;
3456  abc.abcA = abc.abcC = 0;
3457  }
3458  }
3459  else if (!get_cache_glyph_widths(psc, glyph, &abc))
3460  {
3461  if (!hdc) return E_PENDING;
3463  {
3464  if (!GetCharABCWidthsI(hdc, glyph, 1, NULL, &abc)) return S_FALSE;
3465  }
3466  else
3467  {
3468  INT width;
3469  if (!GetCharWidthI(hdc, glyph, 1, NULL, &width)) return S_FALSE;
3470  abc.abcB = width;
3471  abc.abcA = abc.abcC = 0;
3472  }
3473  set_cache_glyph_widths(psc, glyph, &abc);
3474  }
3475  if (pABC)
3476  {
3477  pABC->abcA += abc.abcA;
3478  pABC->abcB += abc.abcB;
3479  pABC->abcC += abc.abcC;
3480  }
3481  if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
3482  }
3483 
3484  SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset);
3485 
3486  if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
3487  return S_OK;
3488 }
3489 
3490 /***********************************************************************
3491  * ScriptPlace (USP10.@)
3492  *
3493  * Produce advance widths for a run.
3494  *
3495  * PARAMS
3496  * hdc [I] Device context.
3497  * psc [I/O] Opaque pointer to a script cache.
3498  * pwGlyphs [I] Array of glyphs.
3499  * cGlyphs [I] Number of glyphs in pwGlyphs.
3500  * psva [I] Array of visual attributes.
3501  * psa [I/O] String analysis.
3502  * piAdvance [O] Array of advance widths.
3503  * pGoffset [O] Glyph offsets.
3504  * pABC [O] Combined ABC width.
3505  *
3506  * RETURNS
3507  * Success: S_OK
3508  * Failure: Non-zero HRESULT value.
3509  */
3511  int cGlyphs, const SCRIPT_VISATTR *psva,
3512  SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
3513 {
3514  HRESULT hr;
3515  SCRIPT_GLYPHPROP *glyphProps;
3516  int i;
3517 
3518  TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
3519  piAdvance, pGoffset, pABC);
3520 
3521  if (!psva) return E_INVALIDARG;
3522  if (!pGoffset) return E_FAIL;
3523 
3524  if (!(glyphProps = heap_calloc(cGlyphs, sizeof(*glyphProps))))
3525  return E_OUTOFMEMORY;
3526 
3527  for (i = 0; i < cGlyphs; i++)
3528  glyphProps[i].sva = psva[i];
3529 
3530  hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
3531 
3532  heap_free(glyphProps);
3533 
3534  return hr;
3535 }
3536 
3537 /***********************************************************************
3538  * ScriptGetCMap (USP10.@)
3539  *
3540  * Retrieve glyph indices.
3541  *
3542  * PARAMS
3543  * hdc [I] Device context.
3544  * psc [I/O] Opaque pointer to a script cache.
3545  * pwcInChars [I] Array of Unicode characters.
3546  * cChars [I] Number of characters in pwcInChars.
3547  * dwFlags [I] Flags.
3548  * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3549  *
3550  * RETURNS
3551  * Success: S_OK
3552  * Failure: Non-zero HRESULT value.
3553  */
3556 {
3557  HRESULT hr;
3558  int i;
3559 
3560  TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
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  */
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  */
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 
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  */
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;
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  */
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  */
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  */
3855 {
3856  StringAnalysis *analysis = ssa;
3857 
3858  TRACE("(%p)\n", ssa);
3859 
3860  if (!analysis) return E_INVALIDARG;