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