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