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