ReactOS  0.4.11-dev-195-gef016bf
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 {
636  &scriptInformation[0].props, &scriptInformation[1].props,
637  &scriptInformation[2].props, &scriptInformation[3].props,
638  &scriptInformation[4].props, &scriptInformation[5].props,
639  &scriptInformation[6].props, &scriptInformation[7].props,
640  &scriptInformation[8].props, &scriptInformation[9].props,
641  &scriptInformation[10].props, &scriptInformation[11].props,
642  &scriptInformation[12].props, &scriptInformation[13].props,
643  &scriptInformation[14].props, &scriptInformation[15].props,
644  &scriptInformation[16].props, &scriptInformation[17].props,
645  &scriptInformation[18].props, &scriptInformation[19].props,
646  &scriptInformation[20].props, &scriptInformation[21].props,
647  &scriptInformation[22].props, &scriptInformation[23].props,
648  &scriptInformation[24].props, &scriptInformation[25].props,
649  &scriptInformation[26].props, &scriptInformation[27].props,
650  &scriptInformation[28].props, &scriptInformation[29].props,
651  &scriptInformation[30].props, &scriptInformation[31].props,
652  &scriptInformation[32].props, &scriptInformation[33].props,
653  &scriptInformation[34].props, &scriptInformation[35].props,
654  &scriptInformation[36].props, &scriptInformation[37].props,
655  &scriptInformation[38].props, &scriptInformation[39].props,
656  &scriptInformation[40].props, &scriptInformation[41].props,
657  &scriptInformation[42].props, &scriptInformation[43].props,
658  &scriptInformation[44].props, &scriptInformation[45].props,
659  &scriptInformation[46].props, &scriptInformation[47].props,
660  &scriptInformation[48].props, &scriptInformation[49].props,
661  &scriptInformation[50].props, &scriptInformation[51].props,
662  &scriptInformation[52].props, &scriptInformation[53].props,
663  &scriptInformation[54].props, &scriptInformation[55].props,
664  &scriptInformation[56].props, &scriptInformation[57].props,
665  &scriptInformation[58].props, &scriptInformation[59].props,
666  &scriptInformation[60].props, &scriptInformation[61].props,
667  &scriptInformation[62].props, &scriptInformation[63].props,
668  &scriptInformation[64].props, &scriptInformation[65].props,
669  &scriptInformation[66].props, &scriptInformation[67].props,
670  &scriptInformation[68].props, &scriptInformation[69].props,
671  &scriptInformation[70].props, &scriptInformation[71].props,
672  &scriptInformation[72].props, &scriptInformation[73].props,
673  &scriptInformation[74].props, &scriptInformation[75].props,
674  &scriptInformation[76].props, &scriptInformation[77].props,
675  &scriptInformation[78].props, &scriptInformation[79].props,
676  &scriptInformation[80].props, &scriptInformation[81].props
677 };
678 
681 {
682  0, 0, &cs_script_cache,
683  { &cs_script_cache_dbg.ProcessLocksList, &cs_script_cache_dbg.ProcessLocksList },
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 };
687 static struct list script_cache_list = LIST_INIT(script_cache_list);
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 
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 
780  if (GetGlyphIndicesW(hdc, chars, 4, gi, GGI_MARK_NONEXISTING_GLYPHS) != GDI_ERROR)
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 
882  EnterCriticalSection(&cs_script_cache);
883  LIST_FOR_EACH_ENTRY(sc, &script_cache_list, ScriptCache, entry)
884  {
885  if (!memcmp(&sc->lf, &lf, sizeof(lf)))
886  {
887  sc->refcount++;
888  LeaveCriticalSection(&cs_script_cache);
889  *psc = sc;
890  return S_OK;
891  }
892  }
893  LeaveCriticalSection(&cs_script_cache);
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  }
901  size = GetOutlineTextMetricsW(hdc, 0, NULL);
902  if (size)
903  {
904  sc->otm = heap_alloc(size);
905  sc->otm->otmSize = size;
906  GetOutlineTextMetricsW(hdc, size, sc->otm);
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 
918  EnterCriticalSection(&cs_script_cache);
919  list_add_head(&script_cache_list, &sc->entry);
920  LIST_FOR_EACH_ENTRY(sc, &script_cache_list, ScriptCache, entry)
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++;
927  LeaveCriticalSection(&cs_script_cache);
928  heap_free(*psc);
929  *psc = sc;
930  return S_OK;
931  }
932  }
933  LeaveCriticalSection(&cs_script_cache);
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 
1000  GetStringTypeW(CT_CTYPE1, &str[index], 1, &type);
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 
1009  ch = decode_surrogate_pair(str, index, end);
1010  if (ch)
1011  *consumed = 2;
1012  else
1013  ch = str[index];
1014 
1015  if (!(range = bsearch(&ch, script_ranges, ARRAY_SIZE(script_ranges),
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 {
1028  const FindGlyph_struct *find = (FindGlyph_struct*)a;
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 
1087  EnterCriticalSection(&cs_script_cache);
1088  if (--((ScriptCache *)*psc)->refcount > 0)
1089  {
1090  LeaveCriticalSection(&cs_script_cache);
1091  *psc = NULL;
1092  return S_OK;
1093  }
1094  list_remove(&((ScriptCache *)*psc)->entry);
1095  LeaveCriticalSection(&cs_script_cache);
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 
1186  get_cache_font_properties(sfp, *psc);
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 
1219  locale = ConvertDefaultLocale(locale);
1220 
1221  if (!IsValidLocale(locale, LCID_INSTALLED))
1222  return E_INVALIDARG;
1223 
1224  plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
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 {
1305  return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
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 {
1339  return scriptInformation[script].props.fNumeric;
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,
1371  psControl, psState, pItems, pcItems);
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;
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  }
1591  if (psControl->fMergeNeutralItems)
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)
1751  pScriptTags[index] = scriptInformation[New_Script].scriptTag;
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 {
1830  return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, pScriptTags, pcItems);
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 {
1855  return _ItemizeInternal(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, NULL, pcItems);
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 
1944  if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
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 {
1990  HRESULT hr = E_OUTOFMEMORY;
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);
2102  heap_free (pwLogClust);
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);
2114  lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
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 
2564  invalid = analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID;
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  {
2719  if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
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);
2734  if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
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);
2941  if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
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))||
3089  (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
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),
3141  rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
3142  cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
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  {
3197  chInput = decode_surrogate_pair(pwcChars, idx, cChars);
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--;
3233  pwLogClust[idx] = (rtl)?pwLogClust[idx+1]:pwLogClust[idx-1];
3234  for (k = (rtl)?idx-1:idx+1; k >= 0 && k < cChars; (rtl)?k--:k++)
3235  pwLogClust[k]--;
3236  }
3237  }
3238  *pcGlyphs = g;
3239 
3240  SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3241  SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
3242  SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
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 
3341  hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
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),
3402  rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
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  ABC abc;
3420  if (pGlyphProps[i].sva.fZeroWidth)
3421  {
3422  abc.abcA = abc.abcB = abc.abcC = 0;
3423  }
3424  else if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
3425  {
3426  BOOL ret;
3427  if (!hdc) return E_PENDING;
3429  {
3430  if (psa->fNoGlyphIndex)
3431  ret = GetCharABCWidthsW(hdc, pwGlyphs[i], pwGlyphs[i], &abc);
3432  else
3433  ret = GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc);
3434  if (!ret) return S_FALSE;
3435  }
3436  else
3437  {
3438  INT width;
3439  if (psa->fNoGlyphIndex)
3440  ret = GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width);
3441  else
3442  ret = GetCharWidthI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &width);
3443  if (!ret) return S_FALSE;
3444  abc.abcB = width;
3445  abc.abcA = abc.abcC = 0;
3446  }
3447  set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
3448  }
3449  if (pABC)
3450  {
3451  pABC->abcA += abc.abcA;
3452  pABC->abcB += abc.abcB;
3453  pABC->abcC += abc.abcC;
3454  }
3455  /* FIXME: set to more reasonable values */
3456  pGoffset[i].du = pGoffset[i].dv = 0;
3457  if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
3458  }
3459 
3460  SHAPE_ApplyOpenTypePositions(hdc, (ScriptCache *)*psc, psa, pwGlyphs, cGlyphs, piAdvance, pGoffset);
3461 
3462  if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
3463  return S_OK;
3464 }
3465 
3466 /***********************************************************************
3467  * ScriptPlace (USP10.@)
3468  *
3469  * Produce advance widths for a run.
3470  *
3471  * PARAMS
3472  * hdc [I] Device context.
3473  * psc [I/O] Opaque pointer to a script cache.
3474  * pwGlyphs [I] Array of glyphs.
3475  * cGlyphs [I] Number of glyphs in pwGlyphs.
3476  * psva [I] Array of visual attributes.
3477  * psa [I/O] String analysis.
3478  * piAdvance [O] Array of advance widths.
3479  * pGoffset [O] Glyph offsets.
3480  * pABC [O] Combined ABC width.
3481  *
3482  * RETURNS
3483  * Success: S_OK
3484  * Failure: Non-zero HRESULT value.
3485  */
3487  int cGlyphs, const SCRIPT_VISATTR *psva,
3488  SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
3489 {
3490  HRESULT hr;
3491  SCRIPT_GLYPHPROP *glyphProps;
3492  int i;
3493 
3494  TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
3495  piAdvance, pGoffset, pABC);
3496 
3497  if (!psva) return E_INVALIDARG;
3498  if (!pGoffset) return E_FAIL;
3499 
3500  if (!(glyphProps = heap_calloc(cGlyphs, sizeof(*glyphProps))))
3501  return E_OUTOFMEMORY;
3502 
3503  for (i = 0; i < cGlyphs; i++)
3504  glyphProps[i].sva = psva[i];
3505 
3506  hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
3507 
3508  heap_free(glyphProps);
3509 
3510  return hr;
3511 }
3512 
3513 /***********************************************************************
3514  * ScriptGetCMap (USP10.@)
3515  *
3516  * Retrieve glyph indices.
3517  *
3518  * PARAMS
3519  * hdc [I] Device context.
3520  * psc [I/O] Opaque pointer to a script cache.
3521  * pwcInChars [I] Array of Unicode characters.
3522  * cChars [I] Number of characters in pwcInChars.
3523  * dwFlags [I] Flags.
3524  * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
3525  *
3526  * RETURNS
3527  * Success: S_OK
3528  * Failure: Non-zero HRESULT value.
3529  */
3532 {
3533  HRESULT hr;
3534  int i;
3535 
3536  TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
3537  cChars, dwFlags, pwOutGlyphs);
3538 
3539  if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3540 
3541  hr = S_OK;
3542 
3544  {
3545  for (i = 0; i < cChars; i++)
3546  {
3547  WCHAR inChar;
3548  if (dwFlags == SGCM_RTL)
3549  inChar = mirror_char(pwcInChars[i]);
3550  else
3551  inChar = pwcInChars[i];
3552  if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
3553  {
3554  WORD glyph;
3555  if (!hdc) return E_PENDING;
3556  if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
3557  if (glyph == 0xffff)
3558  {
3559  hr = S_FALSE;
3560  glyph = 0x0;
3561  }
3562  pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
3563  }
3564  }
3565  }
3566  else
3567  {
3568  TRACE("no glyph translation\n");
3569  for (i = 0; i < cChars; i++)
3570  {
3571  WCHAR inChar;
3572  if (dwFlags == SGCM_RTL)
3573  inChar = mirror_char(pwcInChars[i]);
3574  else
3575  inChar = pwcInChars[i];
3576  pwOutGlyphs[i] = inChar;
3577  }
3578  }
3579  return hr;
3580 }
3581 
3582 /***********************************************************************
3583  * ScriptTextOut (USP10.@)
3584  *
3585  */
3586 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
3587  const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
3588  int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
3589  const int *piJustify, const GOFFSET *pGoffset)
3590 {
3591  HRESULT hr = S_OK;
3592  INT i, dir = 1;
3593  INT *lpDx;
3594  WORD *reordered_glyphs = (WORD *)pwGlyphs;
3595 
3596  TRACE("(%p, %p, %d, %d, %08x, %s, %p, %p, %d, %p, %d, %p, %p, %p)\n",
3597  hdc, psc, x, y, fuOptions, wine_dbgstr_rect(lprc), psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
3598  piAdvance, piJustify, pGoffset);
3599 
3600  if (!hdc || !psc) return E_INVALIDARG;
3601  if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
3602 
3603  fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
3604  fuOptions |= ETO_IGNORELANGUAGE;
3605  if (!psa->fNoGlyphIndex) /* Have Glyphs? */
3606  fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */
3607 
3608  if (!(lpDx = heap_calloc(cGlyphs, 2 * sizeof(*lpDx))))
3609  return E_OUTOFMEMORY;
3610  fuOptions |= ETO_PDY;
3611 
3612  if (psa->fRTL && psa->fLogicalOrder)
3613  {
3614  if (!(reordered_glyphs = heap_calloc(cGlyphs, sizeof(*reordered_glyphs))))
3615  {
3616  heap_free( lpDx );
3617  return E_OUTOFMEMORY;
3618  }
3619 
3620  for (i = 0; i < cGlyphs; i++)
3621  reordered_glyphs[i] = pwGlyphs[cGlyphs - 1 - i];
3622  dir = -1;
3623  }
3624 
3625  for (i = 0; i < cGlyphs; i++)
3626  {
3627  int orig_index = (dir > 0) ? i : cGlyphs - 1 - i;
3628  lpDx[i * 2] = piAdvance[orig_index];
3629  lpDx[i * 2 + 1] = 0;
3630 
3631  if (pGoffset)
3632  {
3633  if (i == 0)
3634  {
3635  x += pGoffset[orig_index].du * dir;
3636  y += pGoffset[orig_index].dv;
3637  }
3638  else
3639  {
3640  lpDx[(i - 1) * 2] += pGoffset[orig_index].du * dir;
3641  lpDx[(i - 1) * 2 + 1] += pGoffset[orig_index].dv;
3642  }
3643  lpDx[i * 2] -= pGoffset[orig_index].du * dir;
3644  lpDx[i * 2 + 1] -= pGoffset[orig_index].dv;
3645  }
3646  }
3647 
3648  if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, reordered_glyphs, cGlyphs, lpDx))
3649  hr = S_FALSE;
3650 
3651  if (reordered_glyphs != pwGlyphs) heap_free( reordered_glyphs );
3652  heap_free(lpDx);
3653 
3654  return hr;
3655 }
3656 
3657 /***********************************************************************
3658  * ScriptCacheGetHeight (USP10.@)
3659  *
3660  * Retrieve the height of the font in the cache.
3661  *
3662  * PARAMS
3663  * hdc [I] Device context.
3664  * psc [I/O] Opaque pointer to a script cache.
3665  * height [O] Receives font height.
3666  *
3667  * RETURNS
3668  * Success: S_OK
3669  * Failure: Non-zero HRESULT value.
3670  */
3672 {
3673  HRESULT hr;
3674 
3675  TRACE("(%p, %p, %p)\n", hdc, psc, height);
3676 
3677  if (!height) return E_INVALIDARG;
3678  if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3679 
3680  *height = get_cache_height(psc);
3681  return S_OK;
3682 }
3683 
3684 /***********************************************************************
3685  * ScriptGetGlyphABCWidth (USP10.@)
3686  *
3687  * Retrieve the width of a glyph.
3688  *
3689  * PARAMS
3690  * hdc [I] Device context.
3691  * psc [I/O] Opaque pointer to a script cache.
3692  * glyph [I] Glyph to retrieve the width for.
3693  * abc [O] ABC widths of the glyph.
3694  *
3695  * RETURNS
3696  * Success: S_OK
3697  * Failure: Non-zero HRESULT value.
3698  */
3700 {
3701  HRESULT hr;
3702 
3703  TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
3704 
3705  if (!abc) return E_INVALIDARG;
3706  if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
3707 
3708  if (!get_cache_glyph_widths(psc, glyph, abc))
3709  {
3710  if (!hdc) return E_PENDING;
3712  {
3713  if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
3714  }
3715  else
3716  {
3717  INT width;
3718  if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
3719  abc->abcB = width;
3720  abc->abcA = abc->abcC = 0;
3721  }
3722  set_cache_glyph_widths(psc, glyph, abc);
3723  }
3724  return S_OK;
3725 }
3726 
3727 /***********************************************************************
3728  * ScriptLayout (USP10.@)
3729  *
3730  * Map embedding levels to visual and/or logical order.
3731  *
3732  * PARAMS
3733  * runs [I] Size of level array.
3734  * level [I] Array of embedding levels.
3735  * vistolog [O] Map of embedding levels from visual to logical order.
3736  * logtovis [O] Map of embedding levels from logical to visual order.
3737  *
3738  * RETURNS
3739  * Success: S_OK
3740  * Failure: Non-zero HRESULT value.
3741  *
3742  */
3743 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
3744 {
3745  int* indexs;
3746  int ich;
3747 
3748  TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
3749 
3750  if (!level || (!vistolog && !logtovis))
3751  return E_INVALIDARG;
3752 
3753  if (!(indexs = heap_calloc(runs, sizeof(*indexs))))
3754  return E_OUTOFMEMORY;
3755 
3756  if (vistolog)
3757  {
3758  for( ich = 0; ich < runs; ich++)
3759  indexs[ich] = ich;
3760 
3761  ich = 0;
3762  while (ich < runs)
3763  ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3764  memcpy(vistolog, indexs, runs * sizeof(*vistolog));
3765  }
3766 
3767  if (logtovis)
3768  {
3769  for( ich = 0; ich < runs; ich++)
3770  indexs[ich] = ich;
3771 
3772  ich = 0;
3773  while (ich < runs)
3774  ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
3775  memcpy(logtovis, indexs, runs * sizeof(*logtovis));
3776  }
3777  heap_free(indexs);
3778 
3779  return S_OK;
3780 }
3781 
3782 /***********************************************************************
3783  * ScriptStringGetLogicalWidths (USP10.@)
3784  *
3785  * Returns logical widths from a string analysis.
3786  *
3787  * PARAMS
3788  * ssa [I] string analysis.
3789  * piDx [O] logical widths returned.
3790  *
3791  * RETURNS
3792  * Success: S_OK
3793  * Failure: a non-zero HRESULT.
3794  */
3796 {
3797  int i, j, next = 0;
3798  StringAnalysis *analysis = ssa;
3799 
3800  TRACE("%p, %p\n", ssa, piDx);
3801 
3802  if (!analysis) return S_FALSE;
3803  if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3804 
3805  for (i = 0; i < analysis->numItems; i++)
3806  {
3807  int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
3808  int direction = 1;
3809 
3810  if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
3811  direction = -1;
3812 
3813  for (j = 0; j < cChar; j++)
3814  {
3815  int k;
3816  int glyph = analysis->glyphs[i].pwLogClust[j];
3817  int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
3818  cChar, j, direction, NULL, NULL);
3819  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);
3820 
3821  for (k = 0; k < clust_size; k++)
3822  {
3823  piDx[next] = advance / clust_size;
3824  next++;
3825  if (k) j++;
3826  }
3827  }
3828  }
3829  return S_OK;
3830 }
3831 
3832 /***********************************************************************
3833  * ScriptStringValidate (USP10.@)
3834  *
3835  * Validate a string analysis.
3836  *
3837  * PARAMS
3838  * ssa [I] string analysis.
3839  *
3840  * RETURNS
3841  * Success: S_OK
3842  * Failure: S_FALSE if invalid sequences are found
3843  * or a non-zero HRESULT if it fails.
3844  */
3846 {
3847  StringAnalysis *analysis = ssa;
3848 
3849  TRACE("(%p)\n", ssa);
3850 
3851  if (!analysis) return E_INVALIDARG;
3852  return analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_INVALID ? S_FALSE : S_OK;
3853 }
3854 
3855 /***********************************************************************
3856  * ScriptString_pSize (USP10.@)
3857  *
3858  * Retrieve width and height of an analysed string.
3859  *
3860  * PARAMS
3861  * ssa [I] string analysis.
3862  *
3863  * RETURNS
3864  * Success: Pointer to a SIZE structure.
3865  * Failure: NULL
3866  */
3868 {
3869  int i, j;
3870  StringAnalysis *analysis = ssa;
3871 
3872  TRACE("(%p)\n", ssa);
3873 
3874  if (!analysis) return NULL;
3875  if (!(analysis->ssa_flags & SSA_GLYPHS)) return NULL;
3876 
3877  if (!(analysis->flags & SCRIPT_STRING_ANALYSIS_FLAGS_SIZE))
3878  {
3879  analysis->sz.cy = analysis->glyphs[0].sc->tm.tmHeight;
3880 
3881  analysis->sz.cx = 0;
3882  for (i = 0; i < analysis->numItems; i++)
3883  {
3884  if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz.cy)
3885  analysis->sz.cy = analysis->glyphs[i].sc->tm.tmHeight;
3886  for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3887  analysis->sz.cx += analysis->glyphs[i].piAdvance[j];
3888  }
3889  }
3890  return &analysis->sz;
3891 }
3892 
3893 /***********************************************************************
3894  * ScriptString_pLogAttr (USP10.@)
3895  *
3896  * Retrieve logical attributes of an analysed string.
3897  *
3898  * PARAMS
3899  * ssa [I] string analysis.
3900  *
3901  * RETURNS
3902  * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3903  * Failure: NULL
3904  */
3906 {
3907  StringAnalysis *analysis = ssa;
3908 
3909  TRACE("(%p)\n", ssa);
3910 
3911  if (!analysis) return NULL;
3912  if (!(analysis->ssa_flags & SSA_BREAK)) return NULL;
3913  return analysis->logattrs;
3914 }
3915 
3916 /***********************************************************************
3917  * ScriptString_pcOutChars (USP10.@)
3918  *
3919  * Retrieve the length of a string after clipping.
3920  *
3921  * PARAMS
3922  * ssa [I] String analysis.
3923  *
3924  * RETURNS
3925  * Success: Pointer to the length.
3926  * Failure: NULL
3927  */
3929 {
3930  StringAnalysis *analysis = ssa;
3931 
3932  TRACE("(%p)\n", ssa);
3933 
3934  if (!analysis) return NULL;
3935  return &analysis->clip_len;
3936 }
3937 
3938 /***********************************************************************
3939  * ScriptStringGetOrder (USP10.@)
3940  *
3941  * Retrieve a glyph order map.
3942  *
3943  * PARAMS
3944  * ssa [I] String analysis.
3945  * order [I/O] Array of glyph positions.
3946  *
3947  * RETURNS
3948  * Success: S_OK
3949  * Failure: a non-zero HRESULT.
3950  */
3952 {
3953  int i, j;
3954  unsigned int k;
3955  StringAnalysis *analysis = ssa;
3956 
3957  TRACE("(%p)\n", ssa);
3958 
3959  if (!analysis) return S_FALSE;
3960  if (!(analysis->ssa_flags & SSA_GLYPHS)) return S_FALSE;
3961 
3962  /* FIXME: handle RTL scripts */
3963  for (i = 0, k = 0; i < analysis->numItems; i++)
3964  for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3965  order[k] = k;
3966 
3967  return S_OK;
3968 }
3969 
3970 /***********************************************************************
3971  * ScriptGetLogicalWidths (USP10.@)
3972  *
3973  * Convert advance widths to logical widths.
3974  *
3975  * PARAMS
3976  * sa [I] Script analysis.
3977  * nbchars [I] Number of characters.
3978  * nbglyphs [I] Number of glyphs.
3979  * glyph_width [I] Array of glyph widths.
3980  * log_clust [I] Array of logical clusters.
3981  * sva [I] Visual attributes.
3982  * widths [O] Array of logical widths.
3983  *
3984  * RETURNS
3985  * Success: S_OK
3986  * Failure: a non-zero HRESULT.
3987  */
3988 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3989  const int *advances, const WORD *log_clust,
3990  const SCRIPT_VISATTR *sva, int *widths)
3991 {
3992  int i, next = 0, direction;
3993 
3994  TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3995  sa, nbchars, nbglyphs, advances, log_clust, sva, widths);
3996 
3997  if (sa->fRTL && !sa->fLogicalOrder)
3998  direction = -1;
3999  else
4000  direction = 1;
4001 
4002  for (i = 0; i < nbchars; i++)
4003  {
4004  int clust_size = get_cluster_size(log_clust, nbchars, i, direction, NULL, NULL);
4005  int advance = get_glyph_cluster_advance(advances, sva, log_clust, nbglyphs, nbchars, log_clust[i], direction);
4006  int j;
4007 
4008  for (j = 0; j < clust_size; j++)
4009  {
4010  widths[next] = advance / clust_size;
4011  next++;
4012  if (j) i++;
4013  }
4014  }
4015 
4016  return S_OK;
4017 }
4018 
4019 /***********************************************************************
4020  * ScriptApplyLogicalWidth (USP10.@)
4021  *
4022  * Generate glyph advance widths.
4023  *
4024  * PARAMS
4025  * dx [I] Array of logical advance widths.
4026  * num_chars [I] Number of characters.
4027  * num_glyphs [I] Number of glyphs.
4028  * log_clust [I] Array of logical clusters.
4029  * sva [I] Visual attributes.
4030  * advance [I] Array of glyph advance widths.
4031  * sa [I] Script analysis.
4032  * abc [I/O] Summed ABC widths.
4033  * justify [O] Array of glyph advance widths.
4034  *
4035  * RETURNS
4036  * Success: S_OK
4037  * Failure: a non-zero HRESULT.
4038  */
4039 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
4040  const WORD *log_clust, const SCRIPT_VISATTR *sva,
4041  const int *advance, const SCRIPT_ANALYSIS *sa,
4042  ABC *abc, int *justify)
4043 {
4044  int i;
4045 
4046  FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
4047  dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
4048 
4049  for (i = 0; i < num_chars; i++) justify[i] = advance[i];
4050  return S_OK;
4051 }
4052 
4054  int num_glyphs, int dx, int min_kashida, int *justify)
4055 {
4056  int i;
4057 
4058  FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
4059 
4060  for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
4061  return S_OK;
4062 }
4063 
4065 {
4066  HRESULT hr;
4067  if (!pScriptTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4068  if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4069 
4070  return SHAPE_GetFontScriptTags(hdc, (ScriptCache *)*psc, psa, cMaxTags, pScriptTags, pcTags);
4071 }
4072 
4074 {
4075  HRESULT hr;
4076  if (!pLangSysTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4077  if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4078 
4079  return SHAPE_GetFontLanguageTags(hdc, (ScriptCache *)*psc, psa, tagScript, cMaxTags, pLangSysTags, pcTags);
4080 }
4081 
4083 {
4084  HRESULT hr;
4085  if (!pFeatureTags || !pcTags || cMaxTags == 0) return E_INVALIDARG;
4086  if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
4087 
4088  return SHAPE_GetFontFeatureTags(hdc, (ScriptCache *)*psc, psa, tagScript, tagLangSys, cMaxTags, pFeatureTags, pcTags);
4089 }
4090 
4091 #ifdef __REACTOS__
4092 BOOL gbLpkPresent = FALSE;
4094 {
4095  gbLpkPresent = TRUE; /* Turn it on this way! Wine is out of control! */
4096 }
4097 #endif
BOOL WINAPI GetCharABCWidthsW(_In_ HDC hdc, _In_ UINT wFirst, _In_ UINT wLast, _Out_writes_(wLast-wFirst+1) LPABC lpABC)
HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance, int num_glyphs, int dx, int min_kashida, int *justify)
Definition: usp10.c:4053
static unsigned int block
Definition: xmlmemory.c:118
HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs, const WORD *log_clust, const SCRIPT_VISATTR *sva, const int *advance, const SCRIPT_ANALYSIS *sa, ABC *abc, int *justify)
Definition: usp10.c:4039
BOOL WINAPI ExtTextOutW(_In_ HDC hdc, _In_ int x, _In_ int y, _In_ UINT options, _In_opt_ const RECT *lprect, _In_reads_opt_(c) LPCWSTR lpString, _In_ UINT c, _In_reads_opt_(c) const INT *lpDx)
#define HDC
Definition: msvc.h:22
LONG WINAPI RegOpenKeyA(HKEY hKey, LPCSTR lpSubKey, PHKEY phkResult)
Definition: reg.c:3272
static const WCHAR invalid[]
Definition: assoc.c:39
#define abs(i)
Definition: fconv.c:206
SCRIPT_PROPERTIES props
GLint level
Definition: gl.h:1546
COLORREF WINAPI GetBkColor(_In_ HDC)
Definition: dc.c:954
#define CT_CTYPE2
Definition: winnls.h:226
GLuint GLdouble GLdouble GLint GLint order
Definition: glext.h:11194
#define max(a, b)
Definition: svc.c:63
#define LANG_SYRIAC
Definition: nls.h:126
int * piAdvance
Definition: usp10.c:694
GLenum GLclampf GLint GLenum GLuint GLenum GLenum GLsizei GLenum const GLvoid GLfloat GLfloat GLfloat GLfloat GLclampd GLint GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean GLboolean GLboolean GLboolean GLint GLenum GLsizei const GLvoid GLenum GLint GLenum GLint GLint GLsizei GLint GLenum GLint GLint GLint GLint GLsizei GLenum GLsizei const GLuint GLboolean GLenum GLenum GLint GLsizei GLenum GLsizei GLenum const GLvoid GLboolean const GLboolean GLenum const GLdouble const GLfloat const GLdouble const GLfloat GLenum GLint GLint GLint GLint GLint GLint j
Definition: glfuncs.h:98
unsigned short WORD
Definition: ntddk_ex.h:93
Definition: get.c:139
#define TRUE
Definition: types.h:120
#define LANG_LAO
Definition: nls.h:86
int BIDI_ReorderL2vLevel(int level, int *pIndexs, const BYTE *plevel, int cch, BOOL fReverse)
Definition: bidi.c:1259
SCRIPT_VISATTR sva
Definition: usp10.h:215
static BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
Definition: usp10.c:845
DWORD rangeFirst
Definition: usp10.c:50
#define COLOR_HIGHLIGHT
Definition: winuser.h:916
#define LF_FACESIZE
Definition: dimm.idl:39
HRESULT WINAPI ScriptGetFontFeatureTags(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys, int cMaxTags, OPENTYPE_TAG *pFeatureTags, int *pcTags)
Definition: usp10.c:4082
#define C1_CNTRL
Definition: unicode.h:36
BOOL BIDI_DetermineLevels(const WCHAR *lpString, unsigned int uCount, const SCRIPT_STATE *s, const SCRIPT_CONTROL *c, WORD *lpOutLevels, WORD *lpOutOverrides)
Definition: bidi.c:1132
BOOL WINAPI GetTextMetricsW(_In_ HDC, _Out_ LPTEXTMETRICW)
Definition: text.c:221
Definition: wingdi.h:1387
struct list entry
_In_ int _Inout_ LPRECT lprc
Definition: winuser.h:4334
static int get_cluster_advance(const int *piAdvance, const SCRIPT_VISATTR *psva, const WORD *pwLogClust, int cGlyphs, int cChars, int cluster, int direction)
Definition: usp10.c:2791
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
WINE_UNICODE_INLINE unsigned int strlenW(const WCHAR *str)
Definition: unicode.h:212
static BOOL rtl
Definition: propsheet.c:36
stringanalysis_flags
Definition: usp10.c:702
WORD uJustification
Definition: usp10.h:178
DWORD fContextDigits
Definition: usp10.h:94
HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds, SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
Definition: usp10.c:1273
static SCRIPT_CACHE SCRIPT_ANALYSIS OPENTYPE_TAG OPENTYPE_TAG int TEXTRANGE_PROPERTIES int const WCHAR int int WORD SCRIPT_CHARPROP * pCharProps
Definition: usp10.c:64
HRESULT WINAPI ScriptGetFontLanguageTags(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript, int cMaxTags, OPENTYPE_TAG *pLangSysTags, int *pcTags)
Definition: usp10.c:4073
#define error(str)
Definition: mkdosfs.c:1605
static SCRIPT_CACHE SCRIPT_ANALYSIS OPENTYPE_TAG OPENTYPE_TAG int TEXTRANGE_PROPERTIES int const WCHAR int int WORD * pwLogClust
Definition: usp10.c:64
static CRITICAL_SECTION cs_script_cache
Definition: usp10.c:679
int abcC
Definition: wingdi.h:1390
HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
Definition: usp10.c:3072
static int cInChars
Definition: usp10.c:62
GLsizei levels
Definition: glext.h:7884
#define LANG_PERSIAN
Definition: nls.h:106
HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance, const int *piJustify, const GOFFSET *pGoffset)
Definition: usp10.c:3586
static WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
Definition: usp10.c:834
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define LANG_THAI
Definition: nls.h:132
#define LANG_HINDI
Definition: nls.h:68
WINE_UNICODE_INLINE WCHAR * strchrW(const WCHAR *str, WCHAR ch)
Definition: unicode.h:248
static void get_cache_font_properties(SCRIPT_FONTPROPERTIES *sfp, ScriptCache *sc)
Definition: usp10.c:808
#define BIDI_NEUTRAL
#define LANG_NEUTRAL
Definition: nls.h:22
SFNT_Service sfnt
Definition: ttdriver.c:206
#define LOCALE_USER_DEFAULT
#define HKEY_CURRENT_USER
Definition: winreg.h:11
_In_ FONTOBJ _In_ ULONG _In_ ULONG cGlyphs
Definition: winddi.h:3799
uint8_t entry
Definition: isohybrid.c:63
HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
Definition: usp10.c:1152
LONG tmAveCharWidth
Definition: wingdi.h:2365
static int int const SCRIPT_CONTROL const SCRIPT_STATE SCRIPT_ITEM ULONG * pScriptTags
Definition: usp10.c:62
HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString, int cGlyphs, int iCharset, DWORD dwFlags, int iReqWidth, SCRIPT_CONTROL *psControl, SCRIPT_STATE *psState, const int *piDx, SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass, SCRIPT_STRING_ANALYSIS *pssa)
Definition: usp10.c:1983
BYTE lfCharSet
Definition: dimm.idl:67
HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int *piCh, int *piTrailing)
Definition: usp10.c:2472
static HRESULT SS_ItemOut(SCRIPT_STRING_ANALYSIS ssa, int iX, int iY, int iItem, int cStart, int cEnd, UINT uOptions, const RECT *prc, BOOL fSelected, BOOL fDisabled)
Definition: usp10.c:2198
WORD uBidiLevel
Definition: usp10.h:125
HFONT fallbackFont
Definition: usp10.c:699
GLintptr offset
Definition: glext.h:5920
#define LANG_DIVEHI
Definition: nls.h:50
HRESULT WINAPI ScriptCPtoX(int iCP, BOOL fTrailing, int cChars, int cGlyphs, const WORD *pwLogClust, const SCRIPT_VISATTR *psva, const int *piAdvance, const SCRIPT_ANALYSIS *psa, int *piX)
Definition: usp10.c:2648
__WINE_SERVER_LIST_INLINE void list_add_head(struct list *list, struct list *elem)
Definition: list.h:96
int iCharPos
Definition: usp10.h:150
HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
Definition: usp10.c:1174
DWORD fMergeNeutralItems
Definition: usp10.h:102
static BOOL get_cluster_data(const WORD *pwLogClust, int cChars, int cluster_index, int *cluster_size, int *start_index)
Definition: usp10.c:2758
HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs, const int *advances, const WORD *log_clust, const SCRIPT_VISATTR *sva, int *widths)
Definition: usp10.c:3988
HGDIOBJ WINAPI SelectObject(_In_ HDC, _In_ HGDIOBJ)
Definition: dc.c:1497
GLuint GLuint GLsizei GLenum type
Definition: gl.h:1545
HRESULT SHAPE_GetFontScriptTags(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, int cMaxTags, OPENTYPE_TAG *pScriptTags, int *pcTags)
Definition: shape.c:3477
HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
Definition: usp10.c:3743
BOOL WINAPI DeleteObject(_In_ HGDIOBJ)
#define SIC_ASCIIDIGIT
Definition: usp10.h:57
StringGlyphs * glyphs
Definition: usp10.c:717
#define LANG_ARABIC
Definition: nls.h:29
#define LANG_MALAYALAM
Definition: nls.h:93
static int int const SCRIPT_CONTROL const SCRIPT_STATE SCRIPT_ITEM ULONG int * pcItems
Definition: usp10.c:62
#define LANG_ORIYA
Definition: nls.h:104
DWORD LCID
Definition: nls.h:13
DWORD fNeedsCaretInfo
Definition: usp10.h:111
GLuint GLuint end
Definition: gl.h:1545
LONG du
Definition: usp10.h:200
#define BIDI_WEAK
LONG left
Definition: windef.h:296
static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
Definition: usp10.c:864
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define LANG_BENGALI
Definition: nls.h:36
#define Numeric_space
static void * heap_calloc(SIZE_T count, SIZE_T size)
Definition: heap.h:49
#define WCHAR
Definition: msvc.h:43
#define DEFAULT_CHARSET
Definition: wingdi.h:382
static UINT UINT LPWORD glyphs
Definition: font.c:44
HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
Definition: shape.c:3454
BOOL usp10_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
Definition: usp10.c:728
#define E_FAIL
Definition: ddrawi.h:102
static SCRIPT_CACHE SCRIPT_ANALYSIS OPENTYPE_TAG OPENTYPE_TAG int * rcRangeChars
Definition: usp10.c:64
int32_t INT
Definition: typedefs.h:56
#define LANG_HEBREW
Definition: nls.h:67
DWORD WINAPI GetSysColor(_In_ int)
DWORD DWORD
Definition: winlogon.h:84
char * sControl[8]
static void * heap_alloc(size_t len)
Definition: appwiz.h:65
#define LCID_INSTALLED
Definition: winnls.h:198
SCRIPT_ANALYSIS a
Definition: usp10.h:151
void SHAPE_ApplyOpenTypePositions(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WORD *pwGlyphs, INT cGlyphs, int *piAdvance, GOFFSET *pGoffset)
Definition: shape.c:3429
int USP10_FindGlyphInLogClust(const WORD *pwLogClust, int cChars, WORD target)
Definition: usp10.c:1042
WORD fNoGlyphIndex
Definition: usp10.h:145
INT WINAPI GetLocaleInfoW(LCID lcid, LCTYPE lctype, LPWSTR buffer, INT len)
Definition: lang.c:807
COLORREF WINAPI SetBkColor(_In_ HDC, _In_ COLORREF)
Definition: dc.c:975
BOOL WINAPI GetCharWidth32W(_In_ HDC hdc, _In_ UINT iFirst, _In_ UINT iLast, _Out_writes_(iLast+1-iFirst) LPINT lpBuffer)
GLuint n
Definition: s_context.h:57
#define LIST_FOR_EACH_ENTRY(elem, list, type, field)
Definition: list.h:198
int WINAPI SetBkMode(_In_ HDC, _In_ int)
Definition: dc.c:1032
GLenum GLclampf GLint i
Definition: glfuncs.h:14
HRESULT WINAPI ScriptXtoCP(int iX, int cChars, int cGlyphs, const WORD *pwLogClust, const SCRIPT_VISATTR *psva, const int *piAdvance, const SCRIPT_ANALYSIS *psa, int *piCP, int *piTrailing)
Definition: usp10.c:2852
LONG WINAPI RegCloseKey(HKEY hKey)
Definition: reg.c:423
OPENTYPE_TAG scriptTag
DWORD WINAPI GetFontData(HDC hdc, DWORD dwTable, DWORD dwOffset, LPVOID lpvBuffer, DWORD cbData)
Definition: font.c:2444
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
BOOL WINAPI GetCharABCWidthsI(_In_ HDC hdc, _In_ UINT giFirst, _In_ UINT cgi, _In_reads_opt_(cgi) LPWORD pgi, _Out_writes_(cgi) LPABC pabc)
#define SIC_NEUTRAL
Definition: usp10.h:58
#define FALSE
Definition: types.h:117
#define ETO_OPAQUE
Definition: wingdi.h:645
LCID WINAPI ConvertDefaultLocale(LCID lcid)
Definition: lang.c:1176
Definition: _locale.h:75
long LONG
Definition: pedump.c:60
#define TMPF_TRUETYPE
Definition: wingdi.h:1294
#define FIXME(fmt,...)
Definition: debug.h:110
PIN_DIRECTION dir
Definition: strmbase.h:230
static PVOID ptr
Definition: dispmode.c:27
HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
Definition: usp10.c:3951
#define GLYPH_BLOCK_SIZE
unsigned int idx
Definition: utils.c:41
#define ZWSP
HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs, int cGlyphs, const SCRIPT_VISATTR *psva, SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC)
Definition: usp10.c:3486
#define S_FALSE
Definition: winerror.h:2357
__u8 cluster_size
Definition: mkdosfs.c:362
COLORREF WINAPI GetTextColor(_In_ HDC)
Definition: text.c:727
#define E_INVALIDARG
Definition: ddrawi.h:101
HDC hdc
Definition: msvc.h:53
const WCHAR * str
#define LANG_MONGOLIAN
Definition: nls.h:100
#define LANG_SINHALESE
Definition: nls.h:119
void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, INT *pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
Definition: shape.c:3421
static BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
Definition: usp10.c:2187
smooth NULL
Definition: ftsmooth.c:416
HFONT WINAPI CreateFontIndirectW(_In_ const LOGFONTW *)