usp10: Pay attention to script changes for bidi run itemization.
[wine] / dlls / usp10 / usp10.c
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
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "usp10.h"
36
37 #include "usp10_internal.h"
38
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
43
44 typedef struct _scriptRange
45 {
46     WORD script;
47     WORD rangeFirst;
48     WORD rangeLast;
49     WORD numericScript;
50     WORD punctScript;
51 } scriptRange;
52
53 static const scriptRange scriptRanges[] = {
54     /* Basic Latin: U+0000–U+007A */
55     /* Latin-1 Supplement: U+0080–U+00FF */
56     /* Latin Extended-A: U+0100–U+017F */
57     /* Latin Extended-B: U+0180–U+024F */
58     /* IPA Extensions: U+0250–U+02AF */
59     { Script_Latin,      0x00,   0x2af ,  Script_Numeric, Script_Punctuation},
60     /* Greek: U+0370–U+03FF */
61     { Script_Greek,      0x370,  0x3ff,  0, 0},
62     /* Cyrillic: U+0400–U+04FF */
63     /* Cyrillic Supplement: U+0500–U+052F */
64     { Script_Cyrillic,   0x400,  0x52f,  0, 0},
65     /* Armenian: U+0530–U+058F */
66     { Script_Armenian,   0x530,  0x58f,  0, 0},
67     /* Hebrew: U+0590–U+05FF */
68     { Script_Hebrew,     0x590,  0x5ff,  0, 0},
69     /* Arabic: U+0600–U+06FF */
70     { Script_Arabic,     0x600,  0x6ef,  Script_Arabic_Numeric, 0},
71     /* Defined by Windows */
72     { Script_Persian,    0x6f0,  0x6f9,  0, 0},
73     /* Continue Arabic: U+0600–U+06FF */
74     { Script_Arabic,     0x6fa,  0x6ff,  0, 0},
75     /* Syriac: U+0700–U+074F*/
76     { Script_Syriac,     0x700,  0x74f,  0, 0},
77     /* Arabic Supplement: U+0750–U+077F */
78     { Script_Arabic,     0x750,  0x77f,  0, 0},
79     /* Thaana: U+0780–U+07BF */
80     { Script_Thaana,     0x780,  0x7bf,  0, 0},
81     /* Devanagari: U+0900–U+097F */
82     { Script_Devanagari, 0x900,  0x97f,  Script_Devanagari_Numeric, 0},
83     /* Bengali: U+0980–U+09FF */
84     { Script_Bengali,    0x980,  0x9ff,  Script_Bengali_Numeric, 0},
85     /* Gurmukhi: U+0A00–U+0A7F*/
86     { Script_Gurmukhi,   0xa00,  0xa7f,  Script_Gurmukhi_Numeric, 0},
87     /* Gujarati: U+0A80–U+0AFF*/
88     { Script_Gujarati,   0xa80,  0xaff,  Script_Gujarati_Numeric, 0},
89     /* Oriya: U+0B00–U+0B7F */
90     { Script_Oriya,      0xb00,  0xb7f,  Script_Oriya_Numeric, 0},
91     /* Tamil: U+0B80–U+0BFF */
92     { Script_Tamil,      0xb80,  0xbff,  Script_Tamil_Numeric, 0},
93     /* Telugu: U+0C00–U+0C7F */
94     { Script_Telugu,     0xc00,  0xc7f,  Script_Telugu_Numeric, 0},
95     /* Kannada: U+0C80–U+0CFF */
96     { Script_Kannada,    0xc80,  0xcff,  Script_Kannada_Numeric, 0},
97     /* Malayalam: U+0D00–U+0D7F */
98     { Script_Malayalam,  0xd00,  0xd7f,  Script_Malayalam_Numeric, 0},
99     /* Sinhala: U+0D80–U+0DFF */
100     { Script_Sinhala,   0xd80,  0xdff,  0, 0},
101     /* Thai: U+0E00–U+0E7F */
102     { Script_Thai,      0xe00,  0xe7f,  Script_Thai_Numeric, 0},
103     /* Lao: U+0E80–U+0EFF */
104     { Script_Lao,       0xe80,  0xeff,  Script_Lao_Numeric, 0},
105     /* Tibetan: U+0F00–U+0FFF */
106     { Script_Tibetan,   0xf00,  0xfff,  Script_Tibetan_Numeric, 0},
107     /* Georgian: U+10A0–U+10FF */
108     { Script_Georgian,   0x10a0,  0x10ff,  0, 0},
109     /* Vedic Extensions: U+1CD0-U+1CFF */
110     { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
111     /* Phonetic Extensions: U+1D00–U+1DBF */
112     { Script_Latin,      0x1d00, 0x1dbf, 0, 0},
113     /* Latin Extended Additional: U+1E00–U+1EFF */
114     { Script_Latin,      0x1e00, 0x1eff, 0, 0},
115     /* Greek Extended: U+1F00–U+1FFF */
116     { Script_Greek,      0x1f00, 0x1fff, 0, 0},
117     /* General Punctuation: U+2000 –U+206f */
118     /* Superscripts and Subscripts : U+2070 –U+209f */
119     /* Currency Symbols : U+20a0 –U+20cf */
120     { Script_Latin,      0x2000, 0x20cf, 0, 0},
121     /* Letterlike Symbols : U+2100 –U+214f */
122     /* Number Forms : U+2150 –U+218f */
123     /* Arrows : U+2190 –U+21ff */
124     /* Mathematical Operators : U+2200 –U+22ff */
125     /* Miscellaneous Technical : U+2300 –U+23ff */
126     /* Control Pictures : U+2400 –U+243f */
127     /* Optical Character Recognition : U+2440 –U+245f */
128     /* Enclosed Alphanumerics : U+2460 –U+24ff */
129     /* Box Drawing : U+2500 –U+25ff */
130     /* Block Elements : U+2580 –U+259f */
131     /* Geometric Shapes : U+25a0 –U+25ff */
132     /* Miscellaneous Symbols : U+2600 –U+26ff */
133     /* Dingbats : U+2700 –U+27bf */
134     /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
135     /* Supplemental Arrows-A : U+27f0 –U+27ff */
136     { Script_Latin,      0x2100, 0x27ff, 0, 0},
137     /* Supplemental Arrows-B : U+2900 –U+297f */
138     /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
139     /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
140     /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
141     { Script_Latin,      0x2900, 0x2bff, 0, 0},
142     /* Latin Extended-C: U+2C60–U+2C7F */
143     { Script_Latin,      0x2c60, 0x2c7f, 0, 0},
144     /* Georgian: U+2D00–U+2D2F */
145     { Script_Georgian,   0x2d00,  0x2d2f,  0, 0},
146     /* Cyrillic Extended-A: U+2DE0–U+2DFF */
147     { Script_Cyrillic,   0x2de0, 0x2dff,  0, 0},
148     /* Cyrillic Extended-B: U+A640–U+A69F */
149     { Script_Cyrillic,   0xa640, 0xa69f,  0, 0},
150     /* Modifier Tone Letters: U+A700–U+A71F */
151     /* Latin Extended-D: U+A720–U+A7FF */
152     { Script_Latin,      0xa700, 0xa7ff, 0, 0},
153     /* Phags-pa: U+A840–U+A87F */
154     { Script_Phags_pa,   0xa840, 0xa87f, 0, 0},
155     /* Devanagari Extended: U+A8E0-U+A8FF */
156     { Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
157     /* Latin Ligatures: U+FB00–U+FB06 */
158     { Script_Latin,      0xfb00, 0xfb06, 0, 0},
159     /* Armenian ligatures U+FB13..U+FB17 */
160     { Script_Armenian,   0xfb13, 0xfb17,  0, 0},
161     /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
162     { Script_Hebrew,     0xfb1d, 0xfb4f, 0, 0},
163     /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
164     { Script_Arabic,     0xfb50, 0xfdff, 0, 0},
165     /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
166     { Script_Arabic,     0xfe70, 0xfeff, 0, 0},
167     /* END */
168     { SCRIPT_UNDEFINED,  0, 0, 0}
169 };
170
171 typedef struct _scriptData
172 {
173     SCRIPT_ANALYSIS a;
174     SCRIPT_PROPERTIES props;
175     OPENTYPE_TAG scriptTag;
176     WCHAR fallbackFont[LF_FACESIZE];
177 } scriptData;
178
179 /* the must be in order so that the index matches the Script value */
180 static const scriptData scriptInformation[] = {
181     {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
182      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
183      0x00000000,
184      {0}},
185     {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
186      {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
187      MS_MAKE_TAG('l','a','t','n'),
188      {0}},
189     {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
190      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
191      0x00000000,
192      {0}},
193     {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
194      {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
195      0x00000000,
196      {0}},
197     {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
198      {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
199      0x00000000,
200      {0}},
201     {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
202      {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
203      0x00000000,
204      {0}},
205     {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
206      {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
207      MS_MAKE_TAG('a','r','a','b'),
208      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
209     {{Script_Arabic_Numeric, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
210      {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
211      MS_MAKE_TAG('a','r','a','b'),
212      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
213     {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
214      {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
215      MS_MAKE_TAG('h','e','b','r'),
216      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
217     {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
218      {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
219      MS_MAKE_TAG('s','y','r','c'),
220      {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
221     {{Script_Persian, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
222      {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
223      MS_MAKE_TAG('s','y','r','c'),
224      {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
225     {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
226      {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
227      MS_MAKE_TAG('t','h','a','a'),
228      {'M','V',' ','B','o','l','i',0}},
229     {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
230      {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
231      MS_MAKE_TAG('g','r','e','k'),
232      {0}},
233     {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
234      {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
235      MS_MAKE_TAG('c','y','r','l'),
236      {0}},
237     {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
238      {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
239      MS_MAKE_TAG('a','r','m','n'),
240      {'S','y','l','f','a','e','n',0}},
241     {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
242      {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
243      MS_MAKE_TAG('g','e','o','r'),
244      {'S','y','l','f','a','e','n',0}},
245     {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
246      {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
247      MS_MAKE_TAG('s','i','n','h'),
248      {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
249     {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
250      {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
251      MS_MAKE_TAG('t','i','b','t'),
252      {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
253     {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
254      {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
255      MS_MAKE_TAG('t','i','b','t'),
256      {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
257     {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
258      {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
259      MS_MAKE_TAG('p','h','a','g'),
260      {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
261     {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
262      {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
263      MS_MAKE_TAG('t','h','a','i'),
264      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
265     {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
266      {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
267      MS_MAKE_TAG('t','h','a','i'),
268      {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
269     {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
270      {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
271      MS_MAKE_TAG('l','a','o',' '),
272      {'D','o','k','C','h','a','m','p','a',0}},
273     {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
274      {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
275      MS_MAKE_TAG('l','a','o',' '),
276      {'D','o','k','C','h','a','m','p','a',0}},
277     {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
278      {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
279      MS_MAKE_TAG('d','e','v','a'),
280      {'M','a','n','g','a','l',0}},
281     {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
282      {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
283      MS_MAKE_TAG('d','e','v','a'),
284      {'M','a','n','g','a','l',0}},
285     {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
286      {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
287      MS_MAKE_TAG('b','e','n','g'),
288      {'V','r','i','n','d','a',0}},
289     {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
290      {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
291      MS_MAKE_TAG('b','e','n','g'),
292      {'V','r','i','n','d','a',0}},
293     {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
294      {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
295      MS_MAKE_TAG('b','e','n','g'),
296      {'V','r','i','n','d','a',0}},
297     {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
298      {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
299      MS_MAKE_TAG('g','u','r','u'),
300      {'R','a','a','v','i',0}},
301     {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
302      {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
303      MS_MAKE_TAG('g','u','r','u'),
304      {'R','a','a','v','i',0}},
305     {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
306      {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
307      MS_MAKE_TAG('g','u','j','r'),
308      {'S','h','r','u','t','i',0}},
309     {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
310      {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
311      MS_MAKE_TAG('g','u','j','r'),
312      {'S','h','r','u','t','i',0}},
313     {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
314      {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
315      MS_MAKE_TAG('g','u','j','r'),
316      {'S','h','r','u','t','i',0}},
317     {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
318      {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
319      MS_MAKE_TAG('o','r','y','a'),
320      {'K','a','l','i','n','g','a',0}},
321     {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
322      {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
323      MS_MAKE_TAG('o','r','y','a'),
324      {'K','a','l','i','n','g','a',0}},
325     {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
326      {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
327      MS_MAKE_TAG('t','a','m','l'),
328      {'L','a','t','h','a',0}},
329     {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
330      {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
331      MS_MAKE_TAG('t','a','m','l'),
332      {'L','a','t','h','a',0}},
333     {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
334      {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
335      MS_MAKE_TAG('t','e','l','u'),
336      {'G','a','u','t','a','m','i',0}},
337     {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
338      {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
339      MS_MAKE_TAG('t','e','l','u'),
340      {'G','a','u','t','a','m','i',0}},
341     {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
342      {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
343      MS_MAKE_TAG('k','n','d','a'),
344      {'T','u','n','g','a',0}},
345     {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
346      {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
347      MS_MAKE_TAG('k','n','d','a'),
348      {'T','u','n','g','a',0}},
349     {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
350      {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
351      MS_MAKE_TAG('m','l','y','m'),
352      {'K','a','r','t','i','k','a',0}},
353     {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
354      {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
355      MS_MAKE_TAG('m','l','y','m'),
356      {'K','a','r','t','i','k','a',0}},
357 };
358
359 static const SCRIPT_PROPERTIES *script_props[] =
360 {
361     &scriptInformation[0].props, &scriptInformation[1].props,
362     &scriptInformation[2].props, &scriptInformation[3].props,
363     &scriptInformation[4].props, &scriptInformation[5].props,
364     &scriptInformation[6].props, &scriptInformation[7].props,
365     &scriptInformation[8].props, &scriptInformation[9].props,
366     &scriptInformation[10].props, &scriptInformation[11].props,
367     &scriptInformation[12].props, &scriptInformation[13].props,
368     &scriptInformation[14].props, &scriptInformation[15].props,
369     &scriptInformation[16].props, &scriptInformation[17].props,
370     &scriptInformation[18].props, &scriptInformation[19].props,
371     &scriptInformation[20].props, &scriptInformation[21].props,
372     &scriptInformation[22].props, &scriptInformation[23].props,
373     &scriptInformation[24].props, &scriptInformation[25].props,
374     &scriptInformation[26].props, &scriptInformation[27].props,
375     &scriptInformation[28].props, &scriptInformation[29].props,
376     &scriptInformation[30].props, &scriptInformation[31].props,
377     &scriptInformation[32].props, &scriptInformation[33].props,
378     &scriptInformation[34].props, &scriptInformation[35].props,
379     &scriptInformation[36].props, &scriptInformation[37].props,
380     &scriptInformation[38].props, &scriptInformation[39].props,
381     &scriptInformation[40].props, &scriptInformation[41].props,
382     &scriptInformation[42].props, &scriptInformation[43].props
383 };
384
385 typedef struct {
386     ScriptCache *sc;
387     int numGlyphs;
388     WORD* glyphs;
389     WORD* pwLogClust;
390     int* piAdvance;
391     SCRIPT_VISATTR* psva;
392     GOFFSET* pGoffset;
393     ABC* abc;
394     int iMaxPosX;
395     HFONT fallbackFont;
396 } StringGlyphs;
397
398 typedef struct {
399     HDC hdc;
400     DWORD dwFlags;
401     BOOL invalid;
402     int clip_len;
403     int cItems;
404     int cMaxGlyphs;
405     SCRIPT_ITEM* pItem;
406     int numItems;
407     StringGlyphs* glyphs;
408     SCRIPT_LOGATTR* logattrs;
409     SIZE* sz;
410     int* logical2visual;
411 } StringAnalysis;
412
413 static inline void *heap_alloc(SIZE_T size)
414 {
415     return HeapAlloc(GetProcessHeap(), 0, size);
416 }
417
418 static inline void *heap_alloc_zero(SIZE_T size)
419 {
420     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
421 }
422
423 static inline void *heap_realloc_zero(LPVOID mem, SIZE_T size)
424 {
425     return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
426 }
427
428 static inline BOOL heap_free(LPVOID mem)
429 {
430     return HeapFree(GetProcessHeap(), 0, mem);
431 }
432
433 static inline WCHAR get_cache_default_char(SCRIPT_CACHE *psc)
434 {
435     return ((ScriptCache *)*psc)->tm.tmDefaultChar;
436 }
437
438 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
439 {
440     return ((ScriptCache *)*psc)->tm.tmHeight;
441 }
442
443 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
444 {
445     return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
446 }
447
448 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, WCHAR c)
449 {
450     WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
451
452     if (!block) return 0;
453     return block[c & GLYPH_BLOCK_MASK];
454 }
455
456 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
457 {
458     WORD **block = &((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
459
460     if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
461     return ((*block)[c & GLYPH_BLOCK_MASK] = glyph);
462 }
463
464 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
465 {
466     static const ABC nil;
467     ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
468
469     if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
470     memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
471     return TRUE;
472 }
473
474 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
475 {
476     ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
477
478     if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
479     memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
480     return TRUE;
481 }
482
483 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
484 {
485     ScriptCache *sc;
486
487     if (!psc) return E_INVALIDARG;
488     if (*psc) return S_OK;
489     if (!hdc) return E_PENDING;
490
491     if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
492     if (!GetTextMetricsW(hdc, &sc->tm))
493     {
494         heap_free(sc);
495         return E_INVALIDARG;
496     }
497     if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
498     {
499         heap_free(sc);
500         return E_INVALIDARG;
501     }
502     sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
503     *psc = sc;
504     TRACE("<- %p\n", sc);
505     return S_OK;
506 }
507
508 static WCHAR mirror_char( WCHAR ch )
509 {
510     extern const WCHAR wine_mirror_map[];
511     return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
512 }
513
514 static WORD get_char_script( WCHAR ch)
515 {
516     WORD type = 0;
517     int i;
518
519     if (ch == 0xc || ch == 0x20 || ch == 0x202f)
520         return Script_CR;
521
522     /* These chars are itemized as Punctuation by Windows */
523     if (ch == 0x2212 || ch == 0x2044 || ch == 0x00a0)
524         return Script_Punctuation;
525
526     GetStringTypeW(CT_CTYPE1, &ch, 1, &type);
527
528     if (type == 0)
529         return SCRIPT_UNDEFINED;
530
531     if (type & C1_CNTRL)
532         return Script_Control;
533
534     i = 0;
535     do
536     {
537         if (ch < scriptRanges[i].rangeFirst || scriptRanges[i].script == SCRIPT_UNDEFINED)
538             break;
539
540         if (ch >= scriptRanges[i].rangeFirst && ch <= scriptRanges[i].rangeLast)
541         {
542             if (scriptRanges[i].numericScript && type & C1_DIGIT)
543                 return scriptRanges[i].numericScript;
544             if (scriptRanges[i].punctScript && type & C1_PUNCT)
545                 return scriptRanges[i].punctScript;
546             return scriptRanges[i].script;
547         }
548         i++;
549     } while (1);
550
551     return SCRIPT_UNDEFINED;
552 }
553
554 /***********************************************************************
555  *      DllMain
556  *
557  */
558 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
559 {
560     switch(fdwReason)
561     {
562     case DLL_PROCESS_ATTACH:
563         DisableThreadLibraryCalls(hInstDLL);
564         break;
565     case DLL_PROCESS_DETACH:
566         break;
567     }
568     return TRUE;
569 }
570
571 /***********************************************************************
572  *      ScriptFreeCache (USP10.@)
573  *
574  * Free a script cache.
575  *
576  * PARAMS
577  *   psc [I/O] Script cache.
578  *
579  * RETURNS
580  *  Success: S_OK
581  *  Failure: Non-zero HRESULT value.
582  */
583 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
584 {
585     TRACE("%p\n", psc);
586
587     if (psc && *psc)
588     {
589         unsigned int i;
590         for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
591         {
592             heap_free(((ScriptCache *)*psc)->glyphs[i]);
593             heap_free(((ScriptCache *)*psc)->widths[i]);
594         }
595         heap_free(((ScriptCache *)*psc)->GSUB_Table);
596         heap_free(((ScriptCache *)*psc)->GDEF_Table);
597         heap_free(((ScriptCache *)*psc)->features);
598         heap_free(*psc);
599         *psc = NULL;
600     }
601     return S_OK;
602 }
603
604 /***********************************************************************
605  *      ScriptGetProperties (USP10.@)
606  *
607  * Retrieve a list of script properties.
608  *
609  * PARAMS
610  *  props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
611  *  num   [I] Pointer to the number of scripts.
612  *
613  * RETURNS
614  *  Success: S_OK
615  *  Failure: Non-zero HRESULT value.
616  *
617  * NOTES
618  *  Behaviour matches WinXP.
619  */
620 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
621 {
622     TRACE("(%p,%p)\n", props, num);
623
624     if (!props && !num) return E_INVALIDARG;
625
626     if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
627     if (props) *props = script_props;
628
629     return S_OK;
630 }
631
632 /***********************************************************************
633  *      ScriptGetFontProperties (USP10.@)
634  *
635  * Get information on special glyphs.
636  *
637  * PARAMS
638  *  hdc [I]   Device context.
639  *  psc [I/O] Opaque pointer to a script cache.
640  *  sfp [O]   Font properties structure.
641  */
642 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
643 {
644     HRESULT hr;
645
646     TRACE("%p,%p,%p\n", hdc, psc, sfp);
647
648     if (!sfp) return E_INVALIDARG;
649     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
650
651     if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
652         return E_INVALIDARG;
653
654     /* return something sensible? */
655     sfp->wgBlank = 0;
656     sfp->wgDefault = get_cache_default_char(psc);
657     sfp->wgInvalid = 0;
658     sfp->wgKashida = 0xffff;
659     sfp->iKashidaWidth = 0;
660
661     return S_OK;
662 }
663
664 /***********************************************************************
665  *      ScriptRecordDigitSubstitution (USP10.@)
666  *
667  *  Record digit substitution settings for a given locale.
668  *
669  *  PARAMS
670  *   locale [I] Locale identifier.
671  *   sds    [I] Structure to record substitution settings.
672  *
673  *  RETURNS
674  *   Success: S_OK
675  *   Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
676  *
677  *  SEE ALSO
678  *   http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
679  */
680 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
681 {
682     DWORD plgid, sub;
683
684     TRACE("0x%x, %p\n", locale, sds);
685
686     /* This implementation appears to be correct for all languages, but it's
687      * not clear if sds->DigitSubstitute is ever set to anything except 
688      * CONTEXT or NONE in reality */
689
690     if (!sds) return E_POINTER;
691
692     locale = ConvertDefaultLocale(locale);
693
694     if (!IsValidLocale(locale, LCID_INSTALLED))
695         return E_INVALIDARG;
696
697     plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
698     sds->TraditionalDigitLanguage = plgid;
699
700     if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
701         sds->NationalDigitLanguage = plgid;
702     else
703         sds->NationalDigitLanguage = LANG_ENGLISH;
704
705     if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
706                         (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
707
708     switch (sub)
709     {
710     case 0: 
711         if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
712             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
713         else
714             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
715         break;
716     case 1:
717         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
718         break;
719     case 2:
720         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
721         break;
722     default:
723         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
724         break;
725     }
726
727     sds->dwReserved = 0;
728     return S_OK;
729 }
730
731 /***********************************************************************
732  *      ScriptApplyDigitSubstitution (USP10.@)
733  *
734  *  Apply digit substitution settings.
735  *
736  *  PARAMS
737  *   sds [I] Structure with recorded substitution settings.
738  *   sc  [I] Script control structure.
739  *   ss  [I] Script state structure.
740  *
741  *  RETURNS
742  *   Success: S_OK
743  *   Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
744  */
745 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds, 
746                                             SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
747 {
748     SCRIPT_DIGITSUBSTITUTE psds;
749
750     TRACE("%p, %p, %p\n", sds, sc, ss);
751
752     if (!sc || !ss) return E_POINTER;
753     if (!sds)
754     {
755         sds = &psds;
756         if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
757             return E_INVALIDARG;
758     }
759
760     sc->uDefaultLanguage = LANG_ENGLISH;
761     sc->fContextDigits = 0;
762     ss->fDigitSubstitute = 0;
763
764     switch (sds->DigitSubstitute) {
765         case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
766         case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
767         case SCRIPT_DIGITSUBSTITUTE_NONE:
768         case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
769             return S_OK;
770         default:
771             return E_INVALIDARG;
772     }
773 }
774
775 /***********************************************************************
776  *      ScriptItemizeOpenType (USP10.@)
777  *
778  * Split a Unicode string into shapeable parts.
779  *
780  * PARAMS
781  *  pwcInChars  [I] String to split.
782  *  cInChars    [I] Number of characters in pwcInChars.
783  *  cMaxItems   [I] Maximum number of items to return.
784  *  psControl   [I] Pointer to a SCRIPT_CONTROL structure.
785  *  psState     [I] Pointer to a SCRIPT_STATE structure.
786  *  pItems      [O] Buffer to receive SCRIPT_ITEM structures.
787  *  pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
788  *  pcItems     [O] Number of script items returned.
789  *
790  * RETURNS
791  *  Success: S_OK
792  *  Failure: Non-zero HRESULT value.
793  */
794 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
795                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
796                              SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
797 {
798
799 #define Numeric_space 0x0020
800 #define ZWNJ 0x200C
801 #define ZWJ  0x200D
802
803     int   cnt = 0, index = 0, str = 0;
804     int   New_Script = -1;
805     int   i;
806     WORD  *levels = NULL;
807     WORD  *strength = NULL;
808     WORD  *scripts = NULL;
809     WORD  baselevel = 0;
810     BOOL  new_run;
811
812     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
813           psControl, psState, pItems, pcItems);
814
815     if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
816         return E_INVALIDARG;
817
818     scripts = heap_alloc(cInChars * sizeof(WORD));
819     if (!scripts)
820         return E_OUTOFMEMORY;
821
822     for (i = 0; i < cInChars; i++)
823         scripts[i] = get_char_script(pwcInChars[i]);
824
825     if (psState && psControl)
826     {
827         levels = heap_alloc_zero(cInChars * sizeof(WORD));
828         if (!levels)
829         {
830             heap_free(scripts);
831             return E_OUTOFMEMORY;
832         }
833
834         BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
835         baselevel = levels[0];
836         for (i = 0; i < cInChars; i++)
837             if (levels[i]!=levels[0])
838                 break;
839         if (i >= cInChars && !odd(baselevel))
840         {
841             heap_free(levels);
842             levels = NULL;
843         }
844         else
845         {
846             BOOL inNumber = FALSE;
847             static WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
848
849             strength = heap_alloc_zero(cInChars * sizeof(WORD));
850             if (!strength)
851             {
852                 heap_free(scripts);
853                 heap_free(levels);
854                 return E_OUTOFMEMORY;
855             }
856             BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
857
858             /* Script_Numeric and select puncuation at level 0 get bumped to level 2 */
859             for (i = 0; i < cInChars; i++)
860             {
861                 if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && inNumber && strchrW(math_punc,pwcInChars[i]))
862                 {
863                     scripts[i] = Script_Numeric;
864                     levels[i] = 2;
865                 }
866                 else if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && scripts[i] == Script_Numeric)
867                 {
868                     levels[i] = 2;
869                     inNumber = TRUE;
870                 }
871                 else
872                     inNumber = FALSE;
873             }
874             if (psControl->fMergeNeutralItems)
875             {
876                 /* Merge the neutrals */
877                 for (i = 0; i < cInChars; i++)
878                 {
879                     if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
880                     {
881                         int j;
882                         for (j = i; j > 0; j--)
883                         {
884                             if (levels[i] != levels[j])
885                                 break;
886                             if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
887                             {
888                                 scripts[i] = scripts[j];
889                                 strength[i] = strength[j];
890                                 break;
891                             }
892                         }
893                     }
894                     /* Try going the other way */
895                     if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
896                     {
897                         int j;
898                         for (j = i; j < cInChars; j++)
899                         {
900                             if (levels[i] != levels[j])
901                                 break;
902                             if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
903                             {
904                                 scripts[i] = scripts[j];
905                                 strength[i] = strength[j];
906                                 break;
907                             }
908                         }
909                     }
910                 }
911             }
912         }
913     }
914
915     while ((!levels || (levels && levels[cnt+1] == levels[0])) && (pwcInChars[cnt] == Numeric_space || pwcInChars[cnt] == ZWJ || pwcInChars[cnt] == ZWNJ) && cnt < cInChars)
916         cnt++;
917
918     if (cnt == cInChars) /* All Spaces */
919     {
920         cnt = 0;
921         New_Script = scripts[cnt];
922     }
923
924     pItems[index].iCharPos = 0;
925     pItems[index].a = scriptInformation[scripts[cnt]].a;
926     pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
927
928     if (strength && strength[cnt] == BIDI_STRONG)
929         str = strength[cnt];
930     else if (strength)
931         str = strength[0];
932
933     cnt = 0;
934
935     if (levels)
936     {
937         pItems[index].a.fRTL = odd(levels[cnt]);
938         pItems[index].a.fLayoutRTL = odd(levels[cnt]);
939         pItems[index].a.s.uBidiLevel = levels[cnt];
940     }
941     else if (!pItems[index].a.s.uBidiLevel)
942     {
943         pItems[index].a.s.uBidiLevel = baselevel;
944         pItems[index].a.fLayoutRTL = odd(baselevel);
945         pItems[index].a.fRTL = odd(baselevel);
946     }
947
948     TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
949           levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
950           pItems[index].iCharPos);
951
952     for (cnt=1; cnt < cInChars; cnt++)
953     {
954         if(pwcInChars[cnt] != Numeric_space && pwcInChars[cnt] != ZWJ && pwcInChars[cnt] != ZWNJ)
955             New_Script = scripts[cnt];
956         else if (levels)
957         {
958             int j = 1;
959             while (cnt + j < cInChars - 1 && (pwcInChars[cnt+j] == Numeric_space || pwcInChars[cnt+j] == ZWJ || pwcInChars[cnt+j] == ZWNJ) && levels[cnt] == levels[cnt+j])
960                 j++;
961             if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
962                 New_Script = scripts[cnt+j];
963             else
964                 New_Script = scripts[cnt];
965         }
966
967         new_run = FALSE;
968         /* merge space strengths*/
969         if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
970             str = BIDI_STRONG;
971
972         if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
973             str = BIDI_NEUTRAL;
974
975         /* changes in level */
976         if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
977         {
978             TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
979             new_run = TRUE;
980         }
981         /* changes in strength */
982         else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
983         {
984             TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
985             new_run = TRUE;
986         }
987         /* changes in script */
988         else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
989         {
990             TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
991             new_run = TRUE;
992         }
993
994         if (new_run)
995         {
996             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);
997
998             index++;
999             if  (index+1 > cMaxItems)
1000                 return E_OUTOFMEMORY;
1001
1002             if (strength)
1003                 str = strength[cnt];
1004
1005             pItems[index].iCharPos = cnt;
1006             memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1007
1008             pItems[index].a = scriptInformation[New_Script].a;
1009             pScriptTags[index] = scriptInformation[New_Script].scriptTag;
1010             if (levels)
1011             {
1012                 pItems[index].a.fRTL = odd(levels[cnt]);
1013                 pItems[index].a.fLayoutRTL = odd(levels[cnt]);
1014                 pItems[index].a.s.uBidiLevel = levels[cnt];
1015             }
1016             else if (!pItems[index].a.s.uBidiLevel)
1017             {
1018                 pItems[index].a.s.uBidiLevel = baselevel;
1019                 pItems[index].a.fLayoutRTL = odd(baselevel);
1020                 pItems[index].a.fRTL = odd(baselevel);
1021             }
1022
1023             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1024         }
1025     }
1026
1027     /* While not strictly necessary according to the spec, make sure the n+1
1028      * item is set up to prevent random behaviour if the caller erroneously
1029      * checks the n+1 structure                                              */
1030     index++;
1031     memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1032
1033     TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1034
1035     /*  Set one SCRIPT_STATE item being returned  */
1036     if  (index + 1 > cMaxItems) return E_OUTOFMEMORY;
1037     if (pcItems) *pcItems = index;
1038
1039     /*  Set SCRIPT_ITEM                                     */
1040     pItems[index].iCharPos = cnt;         /* the last item contains the ptr to the lastchar */
1041     heap_free(levels);
1042     heap_free(strength);
1043     heap_free(scripts);
1044     return S_OK;
1045 }
1046
1047 /***********************************************************************
1048  *      ScriptItemize (USP10.@)
1049  *
1050  * Split a Unicode string into shapeable parts.
1051  *
1052  * PARAMS
1053  *  pwcInChars [I] String to split.
1054  *  cInChars   [I] Number of characters in pwcInChars.
1055  *  cMaxItems  [I] Maximum number of items to return.
1056  *  psControl  [I] Pointer to a SCRIPT_CONTROL structure.
1057  *  psState    [I] Pointer to a SCRIPT_STATE structure.
1058  *  pItems     [O] Buffer to receive SCRIPT_ITEM structures.
1059  *  pcItems    [O] Number of script items returned.
1060  *
1061  * RETURNS
1062  *  Success: S_OK
1063  *  Failure: Non-zero HRESULT value.
1064  */
1065 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1066                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1067                              SCRIPT_ITEM *pItems, int *pcItems)
1068 {
1069     OPENTYPE_TAG *discarded_tags;
1070     HRESULT res;
1071
1072     discarded_tags = heap_alloc(cMaxItems * sizeof(OPENTYPE_TAG));
1073     if (!discarded_tags)
1074         return E_OUTOFMEMORY;
1075     res = ScriptItemizeOpenType(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, discarded_tags, pcItems);
1076     heap_free(discarded_tags);
1077     return res;
1078 }
1079
1080 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1081 {
1082     int defWidth;
1083     int cTabStops=0;
1084     INT *lpTabPos = NULL;
1085     INT nTabOrg = 0;
1086     INT x = 0;
1087
1088     if (pTabdef)
1089         lpTabPos = pTabdef->pTabStops;
1090
1091     if (pTabdef && pTabdef->iTabOrigin)
1092     {
1093         if (pTabdef->iScale)
1094             nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1095         else
1096             nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1097     }
1098
1099     if (pTabdef)
1100         cTabStops = pTabdef->cTabStops;
1101
1102     if (cTabStops == 1)
1103     {
1104         if (pTabdef->iScale)
1105             defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1106         else
1107             defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1108         cTabStops = 0;
1109     }
1110     else
1111         defWidth = 8 * psc->tm.tmAveCharWidth;
1112
1113     for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1114     {
1115         int position = *lpTabPos;
1116         if (position < 0)
1117             position = -1 * position;
1118         if (pTabdef->iScale)
1119             position = (position * pTabdef->iScale) / 4;
1120         else
1121             position = position * psc->tm.tmAveCharWidth;
1122
1123         if( nTabOrg + position > current_x)
1124         {
1125             if( *lpTabPos >= 0)
1126             {
1127                 /* a left aligned tab */
1128                 x = (nTabOrg + *lpTabPos) - current_x;
1129                 break;
1130             }
1131             else
1132             {
1133                 FIXME("Negative tabstop\n");
1134                 break;
1135             }
1136         }
1137     }
1138     if ((!cTabStops) && (defWidth > 0))
1139         x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1140     else if ((!cTabStops) && (defWidth < 0))
1141         FIXME("TODO: Negative defWidth\n");
1142
1143     return x;
1144 }
1145
1146 /***********************************************************************
1147  * Helper function for ScriptStringAnalyse
1148  */
1149 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1150                               const WCHAR *pwcInChars, int cChars )
1151 {
1152     /* FIXME: When to properly fallback is still a bit of a mystery */
1153     WORD *glyphs;
1154
1155     if (psa->fNoGlyphIndex)
1156         return FALSE;
1157
1158     if (init_script_cache(hdc, psc) != S_OK)
1159         return FALSE;
1160
1161     if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1162         return TRUE;
1163
1164     glyphs = heap_alloc(sizeof(WORD) * cChars);
1165     if (!glyphs)
1166         return FALSE;
1167     if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1168     {
1169         heap_free(glyphs);
1170         return TRUE;
1171     }
1172     heap_free(glyphs);
1173
1174     return FALSE;
1175 }
1176
1177 static void find_fallback_font(DWORD scriptid, LPWSTR FaceName)
1178 {
1179     HKEY hkey;
1180
1181     if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1182     {
1183         static const WCHAR szFmt[] = {'%','x',0};
1184         WCHAR value[10];
1185         DWORD count = LF_FACESIZE * sizeof(WCHAR);
1186         DWORD type;
1187
1188         sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1189         if (RegQueryValueExW(hkey, value, 0, &type, (LPBYTE)FaceName, &count))
1190             lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1191         RegCloseKey(hkey);
1192     }
1193     else
1194         lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1195 }
1196
1197 /***********************************************************************
1198  *      ScriptStringAnalyse (USP10.@)
1199  *
1200  */
1201 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1202                                    int cGlyphs, int iCharset, DWORD dwFlags,
1203                                    int iReqWidth, SCRIPT_CONTROL *psControl,
1204                                    SCRIPT_STATE *psState, const int *piDx,
1205                                    SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1206                                    SCRIPT_STRING_ANALYSIS *pssa)
1207 {
1208     HRESULT hr = E_OUTOFMEMORY;
1209     StringAnalysis *analysis = NULL;
1210     SCRIPT_CONTROL sControl;
1211     SCRIPT_STATE sState;
1212     int i, num_items = 255;
1213     BYTE   *BidiLevel;
1214     WCHAR *iString = NULL;
1215
1216     TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1217           hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1218           psControl, psState, piDx, pTabdef, pbInClass, pssa);
1219
1220     if (iCharset != -1)
1221     {
1222         FIXME("Only Unicode strings are supported\n");
1223         return E_INVALIDARG;
1224     }
1225     if (cString < 1 || !pString) return E_INVALIDARG;
1226     if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1227
1228     if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1229     if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1230
1231     /* FIXME: handle clipping */
1232     analysis->clip_len = cString;
1233     analysis->hdc = hdc;
1234     analysis->dwFlags = dwFlags;
1235
1236     if (psState)
1237         sState = *psState;
1238     else
1239         memset(&sState, 0, sizeof(SCRIPT_STATE));
1240
1241     if (psControl)
1242         sControl = *psControl;
1243     else
1244         memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1245
1246     if (dwFlags & SSA_PASSWORD)
1247     {
1248         iString = heap_alloc(sizeof(WCHAR)*cString);
1249         if (!iString)
1250         {
1251             hr = E_OUTOFMEMORY;
1252             goto error;
1253         }
1254         for (i = 0; i < cString; i++)
1255             iString[i] = *((const WCHAR *)pString);
1256         pString = iString;
1257     }
1258
1259     hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1260                        &analysis->numItems);
1261
1262     while (hr == E_OUTOFMEMORY)
1263     {
1264         SCRIPT_ITEM *tmp;
1265
1266         num_items *= 2;
1267         if (!(tmp = heap_realloc_zero(analysis->pItem, num_items * sizeof(SCRIPT_ITEM) + 1)))
1268             goto error;
1269
1270         analysis->pItem = tmp;
1271         hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
1272                            &analysis->numItems);
1273     }
1274     if (hr != S_OK) goto error;
1275
1276     /* set back to out of memory for default goto error behaviour */
1277     hr = E_OUTOFMEMORY;
1278
1279     if (dwFlags & SSA_BREAK)
1280     {
1281         if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
1282         {
1283             for (i = 0; i < analysis->numItems; i++)
1284                 ScriptBreak(&((LPWSTR)pString)[analysis->pItem[i].iCharPos], analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos, &analysis->pItem[i].a, &analysis->logattrs[analysis->pItem[i].iCharPos]);
1285         }
1286         else
1287             goto error;
1288     }
1289
1290     if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
1291         goto error;
1292     if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
1293         goto error;
1294
1295     if (dwFlags & SSA_GLYPHS)
1296     {
1297         int tab_x = 0;
1298         if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
1299             goto error;
1300
1301         for (i = 0; i < analysis->numItems; i++)
1302         {
1303             SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
1304             int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1305             int numGlyphs = 1.5 * cChar + 16;
1306             WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
1307             WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
1308             int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
1309             SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
1310             GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
1311             ABC *abc = heap_alloc_zero(sizeof(ABC));
1312             int numGlyphsReturned;
1313             HFONT originalFont = 0x0;
1314
1315             /* FIXME: non unicode strings */
1316             const WCHAR* pStr = (const WCHAR*)pString;
1317             analysis->glyphs[i].fallbackFont = NULL;
1318
1319             if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
1320             {
1321                 heap_free (glyphs);
1322                 heap_free (pwLogClust);
1323                 heap_free (piAdvance);
1324                 heap_free (psva);
1325                 heap_free (pGoffset);
1326                 heap_free (abc);
1327                 hr = E_OUTOFMEMORY;
1328                 goto error;
1329             }
1330
1331             if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
1332             {
1333                 LOGFONTW lf;
1334                 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
1335                 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
1336                 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
1337                 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
1338                 if (analysis->glyphs[i].fallbackFont)
1339                 {
1340                     ScriptFreeCache(sc);
1341                     originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
1342                 }
1343             }
1344
1345             hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
1346                              cChar, numGlyphs, &analysis->pItem[i].a,
1347                              glyphs, pwLogClust, psva, &numGlyphsReturned);
1348             hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
1349                              piAdvance, pGoffset, abc);
1350             if (originalFont)
1351                 SelectObject(hdc,originalFont);
1352
1353             if (dwFlags & SSA_TAB)
1354             {
1355                 int tabi = 0;
1356                 for (tabi = 0; tabi < cChar; tabi++)
1357                 {
1358                     if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
1359                         piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
1360                     tab_x+=piAdvance[tabi];
1361                 }
1362             }
1363
1364             analysis->glyphs[i].numGlyphs = numGlyphsReturned;
1365             analysis->glyphs[i].glyphs = glyphs;
1366             analysis->glyphs[i].pwLogClust = pwLogClust;
1367             analysis->glyphs[i].piAdvance = piAdvance;
1368             analysis->glyphs[i].psva = psva;
1369             analysis->glyphs[i].pGoffset = pGoffset;
1370             analysis->glyphs[i].abc = abc;
1371             analysis->glyphs[i].iMaxPosX= -1;
1372
1373             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1374         }
1375     }
1376     else
1377     {
1378         for (i = 0; i < analysis->numItems; i++)
1379             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1380     }
1381
1382     ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
1383     heap_free(BidiLevel);
1384
1385     *pssa = analysis;
1386     heap_free(iString);
1387     return S_OK;
1388
1389 error:
1390     heap_free(iString);
1391     heap_free(analysis->glyphs);
1392     heap_free(analysis->logattrs);
1393     heap_free(analysis->pItem);
1394     heap_free(analysis->logical2visual);
1395     heap_free(analysis);
1396     return hr;
1397 }
1398
1399 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
1400 {
1401     int i;
1402
1403     if (pva[glyph].fClusterStart)
1404         return TRUE;
1405     for (i = 0; i < cChars; i++)
1406         if (pwLogClust[i] == glyph) break;
1407     if (i != cChars)
1408         return TRUE;
1409
1410     return FALSE;
1411 }
1412
1413
1414 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
1415                            int iX,
1416                            int iY,
1417                            int iItem,
1418                            int cStart,
1419                            int cEnd,
1420                            UINT uOptions,
1421                            const RECT *prc,
1422                            BOOL fSelected,
1423                            BOOL fDisabled)
1424 {
1425     StringAnalysis *analysis;
1426     int off_x = 0;
1427     HRESULT hr;
1428     COLORREF BkColor = 0x0;
1429     COLORREF TextColor = 0x0;
1430     INT BkMode = 0;
1431     INT runStart, runEnd;
1432     INT iGlyph, cGlyphs;
1433     HFONT oldFont = 0x0;
1434
1435     TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
1436          ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
1437
1438     if (!(analysis = ssa)) return E_INVALIDARG;
1439
1440     if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
1441          (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
1442             return S_OK;
1443
1444     if (fSelected)
1445     {
1446         BkMode = GetBkMode(analysis->hdc);
1447         SetBkMode( analysis->hdc, OPAQUE);
1448         BkColor = GetBkColor(analysis->hdc);
1449         SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
1450         if (!fDisabled)
1451         {
1452             TextColor = GetTextColor(analysis->hdc);
1453             SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1454         }
1455     }
1456     if (analysis->glyphs[iItem].fallbackFont)
1457         oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
1458
1459     if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
1460         runStart = cStart - analysis->pItem[iItem].iCharPos;
1461     else
1462         runStart =  0;
1463     if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
1464         runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
1465     else
1466         runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
1467
1468     if (analysis->pItem[iItem].a.fRTL)
1469     {
1470         if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
1471             ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
1472         else
1473             ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
1474     }
1475     else
1476     {
1477         if (cStart >=0 && runStart)
1478             ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
1479         else
1480             ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
1481     }
1482
1483     if (analysis->pItem[iItem].a.fRTL)
1484         iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
1485     else
1486         iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
1487
1488     if (analysis->pItem[iItem].a.fRTL)
1489         cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
1490     else
1491         cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
1492
1493     cGlyphs++;
1494
1495     if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
1496     {
1497         INT direction;
1498         INT clust_glyph;
1499
1500         clust_glyph = iGlyph + cGlyphs;
1501         if (analysis->pItem[iItem].a.fRTL)
1502             direction = -1;
1503         else
1504             direction = 1;
1505
1506         while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
1507               !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
1508         {
1509             cGlyphs++;
1510             clust_glyph++;
1511         }
1512     }
1513
1514     hr = ScriptTextOut(analysis->hdc,
1515                        (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
1516                        iY, uOptions, prc, &analysis->pItem[iItem].a, NULL, 0,
1517                        &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
1518                        &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
1519                        &analysis->glyphs[iItem].pGoffset[iGlyph]);
1520
1521     TRACE("ScriptTextOut hr=%08x\n", hr);
1522
1523     if (fSelected)
1524     {
1525         SetBkColor(analysis->hdc, BkColor);
1526         SetBkMode( analysis->hdc, BkMode);
1527         if (!fDisabled)
1528             SetTextColor(analysis->hdc, TextColor);
1529     }
1530     if (analysis->glyphs[iItem].fallbackFont)
1531         SelectObject(analysis->hdc, oldFont);
1532
1533     return hr;
1534 }
1535
1536 /***********************************************************************
1537  *      ScriptStringOut (USP10.@)
1538  *
1539  * This function takes the output of ScriptStringAnalyse and joins the segments
1540  * of glyphs and passes the resulting string to ScriptTextOut.  ScriptStringOut
1541  * only processes glyphs.
1542  *
1543  * Parameters:
1544  *  ssa       [I] buffer to hold the analysed string components
1545  *  iX        [I] X axis displacement for output
1546  *  iY        [I] Y axis displacement for output
1547  *  uOptions  [I] flags controling output processing
1548  *  prc       [I] rectangle coordinates
1549  *  iMinSel   [I] starting pos for substringing output string
1550  *  iMaxSel   [I] ending pos for substringing output string
1551  *  fDisabled [I] controls text highlighting
1552  *
1553  *  RETURNS
1554  *   Success: S_OK
1555  *   Failure: is the value returned by ScriptTextOut
1556  */
1557 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
1558                                int iX,
1559                                int iY, 
1560                                UINT uOptions, 
1561                                const RECT *prc, 
1562                                int iMinSel, 
1563                                int iMaxSel,
1564                                BOOL fDisabled)
1565 {
1566     StringAnalysis *analysis;
1567     int   item;
1568     HRESULT hr;
1569
1570     TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
1571          ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
1572
1573     if (!(analysis = ssa)) return E_INVALIDARG;
1574     if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
1575
1576     for (item = 0; item < analysis->numItems; item++)
1577     {
1578         hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
1579         if (FAILED(hr))
1580             return hr;
1581     }
1582
1583     if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
1584     {
1585         if (iMaxSel > 0 &&  iMinSel < 0)
1586             iMinSel = 0;
1587         for (item = 0; item < analysis->numItems; item++)
1588         {
1589             hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
1590             if (FAILED(hr))
1591                 return hr;
1592         }
1593     }
1594
1595     return S_OK;
1596 }
1597
1598 /***********************************************************************
1599  *      ScriptStringCPtoX (USP10.@)
1600  *
1601  */
1602 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
1603 {
1604     int item;
1605     int runningX = 0;
1606     StringAnalysis* analysis = ssa;
1607
1608     TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
1609
1610     if (!ssa || !pX) return S_FALSE;
1611     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1612
1613     /* icp out of range */
1614     if(icp < 0)
1615     {
1616         analysis->invalid = TRUE;
1617         return E_INVALIDARG;
1618     }
1619
1620     for(item=0; item<analysis->numItems; item++)
1621     {
1622         int CP, i;
1623         int offset;
1624
1625         i = analysis->logical2visual[item];
1626         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1627         /* initialize max extents for uninitialized runs */
1628         if (analysis->glyphs[i].iMaxPosX == -1)
1629         {
1630             if (analysis->pItem[i].a.fRTL)
1631                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1632                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1633                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1634             else
1635                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1636                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1637                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1638         }
1639
1640         if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
1641         {
1642             runningX += analysis->glyphs[i].iMaxPosX;
1643             continue;
1644         }
1645
1646         icp -= analysis->pItem[i].iCharPos;
1647         ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1648                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1649                     &analysis->pItem[i].a, &offset);
1650         runningX += offset;
1651
1652         *pX = runningX;
1653         return S_OK;
1654     }
1655
1656     /* icp out of range */
1657     analysis->invalid = TRUE;
1658     return E_INVALIDARG;
1659 }
1660
1661 /***********************************************************************
1662  *      ScriptStringXtoCP (USP10.@)
1663  *
1664  */
1665 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
1666 {
1667     StringAnalysis* analysis = ssa;
1668     int item;
1669
1670     TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
1671
1672     if (!ssa || !piCh || !piTrailing) return S_FALSE;
1673     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1674
1675     /* out of range */
1676     if(iX < 0)
1677     {
1678         if (analysis->pItem[0].a.fRTL)
1679         {
1680             *piCh = 1;
1681             *piTrailing = FALSE;
1682         }
1683         else
1684         {
1685             *piCh = -1;
1686             *piTrailing = TRUE;
1687         }
1688         return S_OK;
1689     }
1690
1691     for(item=0; item<analysis->numItems; item++)
1692     {
1693         int i;
1694         int CP;
1695
1696         for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
1697         /* nothing */;
1698
1699         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1700         /* initialize max extents for uninitialized runs */
1701         if (analysis->glyphs[i].iMaxPosX == -1)
1702         {
1703             if (analysis->pItem[i].a.fRTL)
1704                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1705                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1706                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1707             else
1708                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1709                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1710                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1711         }
1712
1713         if (iX > analysis->glyphs[i].iMaxPosX)
1714         {
1715             iX -= analysis->glyphs[i].iMaxPosX;
1716             continue;
1717         }
1718
1719         ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1720                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1721                     &analysis->pItem[i].a, piCh, piTrailing);
1722         *piCh += analysis->pItem[i].iCharPos;
1723
1724         return S_OK;
1725     }
1726
1727     /* out of range */
1728     *piCh = analysis->pItem[analysis->numItems].iCharPos;
1729     *piTrailing = FALSE;
1730
1731     return S_OK;
1732 }
1733
1734
1735 /***********************************************************************
1736  *      ScriptStringFree (USP10.@)
1737  *
1738  * Free a string analysis.
1739  *
1740  * PARAMS
1741  *  pssa [I] string analysis.
1742  *
1743  * RETURNS
1744  *  Success: S_OK
1745  *  Failure: Non-zero HRESULT value.
1746  */
1747 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
1748 {
1749     StringAnalysis* analysis;
1750     BOOL invalid;
1751     int i;
1752
1753     TRACE("(%p)\n", pssa);
1754
1755     if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
1756
1757     invalid = analysis->invalid;
1758
1759     if (analysis->glyphs)
1760     {
1761         for (i = 0; i < analysis->numItems; i++)
1762         {
1763             heap_free(analysis->glyphs[i].glyphs);
1764             heap_free(analysis->glyphs[i].pwLogClust);
1765             heap_free(analysis->glyphs[i].piAdvance);
1766             heap_free(analysis->glyphs[i].psva);
1767             heap_free(analysis->glyphs[i].pGoffset);
1768             heap_free(analysis->glyphs[i].abc);
1769             if (analysis->glyphs[i].fallbackFont)
1770                 DeleteObject(analysis->glyphs[i].fallbackFont);
1771             ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
1772             heap_free(analysis->glyphs[i].sc);
1773         }
1774         heap_free(analysis->glyphs);
1775     }
1776
1777     heap_free(analysis->pItem);
1778     heap_free(analysis->logattrs);
1779     heap_free(analysis->sz);
1780     heap_free(analysis->logical2visual);
1781     heap_free(analysis);
1782
1783     if (invalid) return E_INVALIDARG;
1784     return S_OK;
1785 }
1786
1787 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
1788                                    int direction, int* iCluster, int *check_out)
1789 {
1790     int clust_size = 1;
1791     int check;
1792     WORD clust = pwLogClust[item];
1793
1794     for (check = item+direction; check < cChars && check >= 0; check+=direction)
1795     {
1796         if (pwLogClust[check] == clust)
1797         {
1798             clust_size ++;
1799             if (iCluster && *iCluster == -1)
1800                 *iCluster = item;
1801         }
1802         else break;
1803     }
1804
1805     if (check_out)
1806         *check_out = check;
1807
1808     return clust_size;
1809 }
1810
1811 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)
1812 {
1813     int advance;
1814     int log_clust_max = 0;
1815     int i;
1816
1817     advance = piAdvance[glyph];
1818
1819     for (i = 0; i < cChars; i++)
1820     {
1821         if (pwLogClust[i] > log_clust_max)
1822             log_clust_max = pwLogClust[i];
1823     }
1824
1825     if (glyph > log_clust_max)
1826         return advance;
1827
1828     for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
1829     {
1830
1831         if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
1832             break;
1833         if (glyph > log_clust_max)
1834             break;
1835         advance += piAdvance[glyph];
1836     }
1837
1838     return advance;
1839 }
1840
1841 /***********************************************************************
1842  *      ScriptCPtoX (USP10.@)
1843  *
1844  */
1845 HRESULT WINAPI ScriptCPtoX(int iCP,
1846                            BOOL fTrailing,
1847                            int cChars,
1848                            int cGlyphs,
1849                            const WORD *pwLogClust,
1850                            const SCRIPT_VISATTR *psva,
1851                            const int *piAdvance,
1852                            const SCRIPT_ANALYSIS *psa,
1853                            int *piX)
1854 {
1855     int item;
1856     float iPosX;
1857     int iSpecial = -1;
1858     int iCluster = -1;
1859     int clust_size = 1;
1860     float special_size = 0.0;
1861     int iMaxPos = 0;
1862     int advance = 0;
1863     BOOL rtl = FALSE;
1864
1865     TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
1866           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1867           psa, piX);
1868
1869     if (psa->fRTL && ! psa->fLogicalOrder)
1870         rtl = TRUE;
1871
1872     if (fTrailing)
1873         iCP++;
1874
1875     if (rtl)
1876     {
1877         int max_clust = pwLogClust[0];
1878
1879         for (item=0; item < cGlyphs; item++)
1880             if (pwLogClust[item] > max_clust)
1881             {
1882                 ERR("We do not handle non reversed clusters properly\n");
1883                 break;
1884             }
1885
1886         iMaxPos = 0;
1887         for (item = max_clust; item >=0; item --)
1888             iMaxPos += piAdvance[item];
1889     }
1890
1891     iPosX = 0.0;
1892     for (item=0; item < iCP && item < cChars; item++)
1893     {
1894         if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
1895         {
1896             int check;
1897             int clust = pwLogClust[item];
1898
1899             iCluster = -1;
1900             clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
1901                                           &check);
1902
1903             advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
1904
1905             if (check >= cChars && !iMaxPos)
1906             {
1907                 for (check = clust; check < cChars; check++)
1908                     special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, 1);
1909                 iSpecial = item;
1910                 special_size /= (cChars - item);
1911                 iPosX += special_size;
1912             }
1913             else
1914             {
1915                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1916                 {
1917                     clust_size --;
1918                     if (clust_size == 0)
1919                         iPosX += advance;
1920                 }
1921                 else
1922                     iPosX += advance / (float)clust_size;
1923             }
1924         }
1925         else if (iSpecial != -1)
1926             iPosX += special_size;
1927         else /* (iCluster != -1) */
1928         {
1929             int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
1930             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1931             {
1932                 clust_size --;
1933                 if (clust_size == 0)
1934                     iPosX += adv;
1935             }
1936             else
1937                 iPosX += adv / (float)clust_size;
1938         }
1939     }
1940
1941     if (iMaxPos > 0)
1942     {
1943         iPosX = iMaxPos - iPosX;
1944         if (iPosX < 0)
1945             iPosX = 0;
1946     }
1947
1948     *piX = iPosX;
1949     TRACE("*piX=%d\n", *piX);
1950     return S_OK;
1951 }
1952
1953 /***********************************************************************
1954  *      ScriptXtoCP (USP10.@)
1955  *
1956  */
1957 HRESULT WINAPI ScriptXtoCP(int iX,
1958                            int cChars,
1959                            int cGlyphs,
1960                            const WORD *pwLogClust,
1961                            const SCRIPT_VISATTR *psva,
1962                            const int *piAdvance,
1963                            const SCRIPT_ANALYSIS *psa,
1964                            int *piCP,
1965                            int *piTrailing)
1966 {
1967     int item;
1968     float iPosX;
1969     float iLastPosX;
1970     int iSpecial = -1;
1971     int iCluster = -1;
1972     int clust_size = 1;
1973     int cjump = 0;
1974     int advance;
1975     float special_size = 0.0;
1976     int direction = 1;
1977
1978     TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
1979           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1980           psa, piCP, piTrailing);
1981
1982     if (psa->fRTL && ! psa->fLogicalOrder)
1983         direction = -1;
1984
1985     if (direction<0)
1986     {
1987         int max_clust = pwLogClust[0];
1988
1989         if (iX < 0)
1990         {
1991             *piCP = cChars;
1992             *piTrailing = 0;
1993             return S_OK;
1994         }
1995
1996         for (item=0; item < cChars; item++)
1997             if (pwLogClust[item] > max_clust)
1998             {
1999                 ERR("We do not handle non reversed clusters properly\n");
2000                 break;
2001             }
2002     }
2003
2004     if (iX < 0)
2005     {
2006         *piCP = -1;
2007         *piTrailing = 1;
2008         return S_OK;
2009     }
2010
2011     iPosX = iLastPosX = 0;
2012     if (direction > 0)
2013         item = 0;
2014     else
2015         item = cChars - 1;
2016     for (; iPosX <= iX && item < cChars && item >= 0; item+=direction)
2017     {
2018         iLastPosX = iPosX;
2019         if (iSpecial == -1 &&
2020              (iCluster == -1 ||
2021               (iCluster != -1 &&
2022                  ((direction > 0 && iCluster+clust_size <= item) ||
2023                   (direction < 0 && iCluster-clust_size >= item))
2024               )
2025              )
2026             )
2027         {
2028             int check;
2029             int clust = pwLogClust[item];
2030
2031             iCluster = -1;
2032             cjump = 0;
2033             clust_size = get_cluster_size(pwLogClust, cChars, item, direction,
2034                                           &iCluster, &check);
2035             advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, direction);
2036
2037             if (check >= cChars && direction > 0)
2038             {
2039                 for (check = clust; check < cChars; check++)
2040                     special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, direction);
2041                 iSpecial = item;
2042                 special_size /= (cChars - item);
2043                 iPosX += special_size;
2044             }
2045             else
2046             {
2047                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2048                 {
2049                     if (!cjump)
2050                         iPosX += advance;
2051                     cjump++;
2052                 }
2053                 else
2054                     iPosX += advance / (float)clust_size;
2055             }
2056         }
2057         else if (iSpecial != -1)
2058             iPosX += special_size;
2059         else /* (iCluster != -1) */
2060         {
2061             int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], direction);
2062             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2063             {
2064                 if (!cjump)
2065                     iPosX += adv;
2066                 cjump++;
2067             }
2068             else
2069                 iPosX += adv / (float)clust_size;
2070         }
2071     }
2072
2073     if (direction > 0)
2074     {
2075         if (iPosX > iX)
2076             item--;
2077         if (item < cChars && ((iPosX - iLastPosX) / 2.0) + iX >= iPosX)
2078         {
2079             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
2080                 item+=(clust_size-1);
2081             *piTrailing = 1;
2082         }
2083         else
2084             *piTrailing = 0;
2085     }
2086     else
2087     {
2088         if (iX == iLastPosX)
2089             item++;
2090         if (iX >= iLastPosX && iX <= iPosX)
2091             item++;
2092
2093         if (iLastPosX == iX)
2094             *piTrailing = 0;
2095         else if (item < 0 || ((iLastPosX - iPosX) / 2.0) + iX <= iLastPosX)
2096         {
2097             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
2098                 item-=(clust_size-1);
2099             *piTrailing = 1;
2100         }
2101         else
2102             *piTrailing = 0;
2103     }
2104
2105     *piCP = item;
2106
2107     TRACE("*piCP=%d\n", *piCP);
2108     TRACE("*piTrailing=%d\n", *piTrailing);
2109     return S_OK;
2110 }
2111
2112 /***********************************************************************
2113  *      ScriptBreak (USP10.@)
2114  *
2115  *  Retrieve line break information.
2116  *
2117  *  PARAMS
2118  *   chars [I] Array of characters.
2119  *   sa    [I] String analysis.
2120  *   la    [I] Array of logical attribute structures.
2121  *
2122  *  RETURNS
2123  *   Success: S_OK
2124  *   Failure: S_FALSE
2125  */
2126 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2127 {
2128     TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2129
2130     if (!la) return S_FALSE;
2131
2132     BREAK_line(chars, count, sa, la);
2133
2134     return S_OK;
2135 }
2136
2137 /***********************************************************************
2138  *      ScriptIsComplex (USP10.@)
2139  *
2140  *  Determine if a string is complex.
2141  *
2142  *  PARAMS
2143  *   chars [I] Array of characters to test.
2144  *   len   [I] Length in characters.
2145  *   flag  [I] Flag.
2146  *
2147  *  RETURNS
2148  *   Success: S_OK
2149  *   Failure: S_FALSE
2150  *
2151  */
2152 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
2153 {
2154     int i;
2155
2156     TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
2157
2158     for (i = 0; i < len; i++)
2159     {
2160         int script;
2161
2162         if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
2163             return S_OK;
2164
2165         script = get_char_script(chars[i]);
2166         if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
2167             (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
2168             return S_OK;
2169     }
2170     return S_FALSE;
2171 }
2172
2173 /***********************************************************************
2174  *      ScriptShapeOpenType (USP10.@)
2175  *
2176  * Produce glyphs and visual attributes for a run.
2177  *
2178  * PARAMS
2179  *  hdc         [I]   Device context.
2180  *  psc         [I/O] Opaque pointer to a script cache.
2181  *  psa         [I/O] Script analysis.
2182  *  tagScript   [I]   The OpenType tag for the Script
2183  *  tagLangSys  [I]   The OpenType tag for the Language
2184  *  rcRangeChars[I]   Array of Character counts in each range
2185  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2186  *  cRanges     [I]   Count of ranges
2187  *  pwcChars    [I]   Array of characters specifying the run.
2188  *  cChars      [I]   Number of characters in pwcChars.
2189  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
2190  *  pwLogClust  [O]   Array of logical cluster info.
2191  *  pCharProps  [O]   Array of character property values
2192  *  pwOutGlyphs [O]   Array of glyphs.
2193  *  pOutGlyphProps [O]  Array of attributes for the retrieved glyphs
2194  *  pcGlyphs    [O]   Number of glyphs returned.
2195  *
2196  * RETURNS
2197  *  Success: S_OK
2198  *  Failure: Non-zero HRESULT value.
2199  */
2200 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
2201                                     SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2202                                     OPENTYPE_TAG tagLangSys, int *rcRangeChars,
2203                                     TEXTRANGE_PROPERTIES **rpRangeProperties,
2204                                     int cRanges, const WCHAR *pwcChars, int cChars,
2205                                     int cMaxGlyphs, WORD *pwLogClust,
2206                                     SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
2207                                     SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
2208 {
2209     HRESULT hr;
2210     unsigned int i;
2211     BOOL rtl;
2212
2213     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
2214      hdc, psc, psa,
2215      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2216      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2217      cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
2218
2219     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
2220                    psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
2221
2222     if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
2223     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2224
2225     if (cRanges)
2226         FIXME("Ranges not supported yet\n");
2227
2228     rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
2229
2230     *pcGlyphs = cChars;
2231     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2232     if (!pwLogClust) return E_FAIL;
2233
2234     ((ScriptCache *)*psc)->userScript = tagScript;
2235     ((ScriptCache *)*psc)->userLang = tagLangSys;
2236
2237     /* set fNoGlyphIndex non truetype/opentype fonts */
2238     if (!psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
2239         psa->fNoGlyphIndex = TRUE;
2240
2241     /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
2242     for (i = 0; i < cChars; i++)
2243     {
2244         int idx = i;
2245         if (rtl) idx = cChars - 1 - i;
2246         /* FIXME: set to better values */
2247         pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
2248         pOutGlyphProps[i].sva.fClusterStart  = 1;
2249         pOutGlyphProps[i].sva.fDiacritic     = 0;
2250         pOutGlyphProps[i].sva.fZeroWidth     = 0;
2251         pOutGlyphProps[i].sva.fReserved      = 0;
2252         pOutGlyphProps[i].sva.fShapeReserved = 0;
2253
2254         /* FIXME: have the shaping engine set this */
2255         pCharProps[i].fCanGlyphAlone = 0;
2256
2257         pwLogClust[i] = idx;
2258     }
2259
2260     if (psa && !psa->fNoGlyphIndex)
2261     {
2262         WCHAR *rChars;
2263         if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
2264
2265         rChars = heap_alloc(sizeof(WCHAR) * cChars);
2266         if (!rChars) return E_OUTOFMEMORY;
2267         for (i = 0; i < cChars; i++)
2268         {
2269             int idx = i;
2270             WCHAR chInput;
2271             if (rtl) idx = cChars - 1 - i;
2272             if (psa->fRTL)
2273                 chInput = mirror_char(pwcChars[idx]);
2274             else
2275                 chInput = pwcChars[idx];
2276             /* special case for tabs */
2277             if (chInput == 0x0009)
2278                 chInput = 0x0020;
2279             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, chInput)))
2280             {
2281                 WORD glyph;
2282                 if (!hdc) return E_PENDING;
2283                 if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR) return S_FALSE;
2284                 pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph);
2285             }
2286             rChars[i] = chInput;
2287         }
2288
2289         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2290         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
2291         SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
2292         heap_free(rChars);
2293     }
2294     else
2295     {
2296         TRACE("no glyph translation\n");
2297         for (i = 0; i < cChars; i++)
2298         {
2299             int idx = i;
2300             /* No mirroring done here */
2301             if (rtl) idx = cChars - 1 - i;
2302             pwOutGlyphs[i] = pwcChars[idx];
2303         }
2304     }
2305
2306     return S_OK;
2307 }
2308
2309
2310 /***********************************************************************
2311  *      ScriptShape (USP10.@)
2312  *
2313  * Produce glyphs and visual attributes for a run.
2314  *
2315  * PARAMS
2316  *  hdc         [I]   Device context.
2317  *  psc         [I/O] Opaque pointer to a script cache.
2318  *  pwcChars    [I]   Array of characters specifying the run.
2319  *  cChars      [I]   Number of characters in pwcChars.
2320  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
2321  *  psa         [I/O] Script analysis.
2322  *  pwOutGlyphs [O]   Array of glyphs.
2323  *  pwLogClust  [O]   Array of logical cluster info.
2324  *  psva        [O]   Array of visual attributes.
2325  *  pcGlyphs    [O]   Number of glyphs returned.
2326  *
2327  * RETURNS
2328  *  Success: S_OK
2329  *  Failure: Non-zero HRESULT value.
2330  */
2331 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
2332                            int cChars, int cMaxGlyphs,
2333                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
2334                            SCRIPT_VISATTR *psva, int *pcGlyphs)
2335 {
2336     HRESULT hr;
2337     int i;
2338     SCRIPT_CHARPROP *charProps;
2339     SCRIPT_GLYPHPROP *glyphProps;
2340
2341     if (!psva || !pcGlyphs) return E_INVALIDARG;
2342     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2343
2344     charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
2345     if (!charProps) return E_OUTOFMEMORY;
2346     glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
2347     if (!glyphProps) return E_OUTOFMEMORY;
2348
2349     hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
2350
2351     if (SUCCEEDED(hr))
2352     {
2353         for (i = 0; i < *pcGlyphs; i++)
2354             psva[i] = glyphProps[i].sva;
2355     }
2356
2357     heap_free(charProps);
2358     heap_free(glyphProps);
2359
2360     return hr;
2361 }
2362
2363 /***********************************************************************
2364  *      ScriptPlaceOpenType (USP10.@)
2365  *
2366  * Produce advance widths for a run.
2367  *
2368  * PARAMS
2369  *  hdc       [I]   Device context.
2370  *  psc       [I/O] Opaque pointer to a script cache.
2371  *  psa       [I/O] String analysis.
2372  *  tagScript   [I]   The OpenType tag for the Script
2373  *  tagLangSys  [I]   The OpenType tag for the Language
2374  *  rcRangeChars[I]   Array of Character counts in each range
2375  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2376  *  cRanges     [I]   Count of ranges
2377  *  pwcChars    [I]   Array of characters specifying the run.
2378  *  pwLogClust  [I]   Array of logical cluster info
2379  *  pCharProps  [I]   Array of character property values
2380  *  cChars      [I]   Number of characters in pwcChars.
2381  *  pwGlyphs  [I]   Array of glyphs.
2382  *  pGlyphProps [I]  Array of attributes for the retrieved glyphs
2383  *  cGlyphs [I] Count of Glyphs
2384  *  piAdvance [O]   Array of advance widths.
2385  *  pGoffset  [O]   Glyph offsets.
2386  *  pABC      [O]   Combined ABC width.
2387  *
2388  * RETURNS
2389  *  Success: S_OK
2390  *  Failure: Non-zero HRESULT value.
2391  */
2392
2393 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
2394                                     OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
2395                                     int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
2396                                     int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
2397                                     SCRIPT_CHARPROP *pCharProps, int cChars,
2398                                     const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
2399                                     int cGlyphs, int *piAdvance,
2400                                     GOFFSET *pGoffset, ABC *pABC
2401 )
2402 {
2403     HRESULT hr;
2404     int i;
2405
2406     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
2407      hdc, psc, psa,
2408      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2409      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2410      pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
2411      pGoffset, pABC);
2412
2413     if (!pGlyphProps) return E_INVALIDARG;
2414     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2415     if (!pGoffset) return E_FAIL;
2416
2417     if (cRanges)
2418         FIXME("Ranges not supported yet\n");
2419
2420     ((ScriptCache *)*psc)->userScript = tagScript;
2421     ((ScriptCache *)*psc)->userLang = tagLangSys;
2422
2423     if (pABC) memset(pABC, 0, sizeof(ABC));
2424     for (i = 0; i < cGlyphs; i++)
2425     {
2426         ABC abc;
2427         if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
2428         {
2429             if (!hdc) return E_PENDING;
2430             if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
2431             {
2432                 if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
2433             }
2434             else
2435             {
2436                 INT width;
2437                 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
2438                 abc.abcB = width;
2439                 abc.abcA = abc.abcC = 0;
2440             }
2441             set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
2442         }
2443         if (pABC)
2444         {
2445             pABC->abcA += abc.abcA;
2446             pABC->abcB += abc.abcB;
2447             pABC->abcC += abc.abcC;
2448         }
2449         /* FIXME: set to more reasonable values */
2450         pGoffset[i].du = pGoffset[i].dv = 0;
2451         if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
2452     }
2453
2454     if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
2455     return S_OK;
2456 }
2457
2458 /***********************************************************************
2459  *      ScriptPlace (USP10.@)
2460  *
2461  * Produce advance widths for a run.
2462  *
2463  * PARAMS
2464  *  hdc       [I]   Device context.
2465  *  psc       [I/O] Opaque pointer to a script cache.
2466  *  pwGlyphs  [I]   Array of glyphs.
2467  *  cGlyphs   [I]   Number of glyphs in pwGlyphs.
2468  *  psva      [I]   Array of visual attributes.
2469  *  psa       [I/O] String analysis.
2470  *  piAdvance [O]   Array of advance widths.
2471  *  pGoffset  [O]   Glyph offsets.
2472  *  pABC      [O]   Combined ABC width.
2473  *
2474  * RETURNS
2475  *  Success: S_OK
2476  *  Failure: Non-zero HRESULT value.
2477  */
2478 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
2479                            int cGlyphs, const SCRIPT_VISATTR *psva,
2480                            SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
2481 {
2482     HRESULT hr;
2483     SCRIPT_GLYPHPROP *glyphProps;
2484     int i;
2485
2486     TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n",  hdc, psc, pwGlyphs, cGlyphs, psva, psa,
2487           piAdvance, pGoffset, pABC);
2488
2489     if (!psva) return E_INVALIDARG;
2490     if (!pGoffset) return E_FAIL;
2491
2492     glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
2493     if (!glyphProps) return E_OUTOFMEMORY;
2494
2495     for (i = 0; i < cGlyphs; i++)
2496         glyphProps[i].sva = psva[i];
2497
2498     hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
2499
2500     heap_free(glyphProps);
2501
2502     return hr;
2503 }
2504
2505 /***********************************************************************
2506  *      ScriptGetCMap (USP10.@)
2507  *
2508  * Retrieve glyph indices.
2509  *
2510  * PARAMS
2511  *  hdc         [I]   Device context.
2512  *  psc         [I/O] Opaque pointer to a script cache.
2513  *  pwcInChars  [I]   Array of Unicode characters.
2514  *  cChars      [I]   Number of characters in pwcInChars.
2515  *  dwFlags     [I]   Flags.
2516  *  pwOutGlyphs [O]   Buffer to receive the array of glyph indices.
2517  *
2518  * RETURNS
2519  *  Success: S_OK
2520  *  Failure: Non-zero HRESULT value.
2521  */
2522 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
2523                              int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
2524 {
2525     HRESULT hr;
2526     int i;
2527
2528     TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
2529           cChars, dwFlags, pwOutGlyphs);
2530
2531     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2532
2533     hr = S_OK;
2534
2535     if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2536     {
2537         for (i = 0; i < cChars; i++)
2538         {
2539             WCHAR inChar;
2540             if (dwFlags == SGCM_RTL)
2541                 inChar = mirror_char(pwcInChars[i]);
2542             else
2543                 inChar = pwcInChars[i];
2544             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
2545             {
2546                 WORD glyph;
2547                 if (!hdc) return E_PENDING;
2548                 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
2549                 if (glyph == 0xffff)
2550                 {
2551                     hr = S_FALSE;
2552                     glyph = 0x0;
2553                 }
2554                 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
2555             }
2556         }
2557     }
2558     else
2559     {
2560         TRACE("no glyph translation\n");
2561         for (i = 0; i < cChars; i++)
2562         {
2563             WCHAR inChar;
2564             if (dwFlags == SGCM_RTL)
2565                 inChar = mirror_char(pwcInChars[i]);
2566             else
2567                 inChar = pwcInChars[i];
2568             pwOutGlyphs[i] = inChar;
2569         }
2570     }
2571     return hr;
2572 }
2573
2574 /***********************************************************************
2575  *      ScriptTextOut (USP10.@)
2576  *
2577  */
2578 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
2579                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
2580                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
2581                              const int *piJustify, const GOFFSET *pGoffset)
2582 {
2583     HRESULT hr = S_OK;
2584
2585     TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
2586          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
2587          piAdvance, piJustify, pGoffset);
2588
2589     if (!hdc || !psc) return E_INVALIDARG;
2590     if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
2591
2592     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
2593     fuOptions |= ETO_IGNORELANGUAGE;
2594     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
2595         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do translation to glyph */
2596
2597     if (psa->fRTL && psa->fLogicalOrder)
2598     {
2599         int i;
2600         WORD *rtlGlyphs;
2601
2602         rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD));
2603         if (!rtlGlyphs)
2604             return E_OUTOFMEMORY;
2605
2606         for (i = 0; i < cGlyphs; i++)
2607             rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i];
2608
2609         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL))
2610             hr = S_FALSE;
2611         heap_free(rtlGlyphs);
2612     }
2613     else
2614         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
2615             hr = S_FALSE;
2616
2617     return hr;
2618 }
2619
2620 /***********************************************************************
2621  *      ScriptCacheGetHeight (USP10.@)
2622  *
2623  * Retrieve the height of the font in the cache.
2624  *
2625  * PARAMS
2626  *  hdc    [I]    Device context.
2627  *  psc    [I/O]  Opaque pointer to a script cache.
2628  *  height [O]    Receives font height.
2629  *
2630  * RETURNS
2631  *  Success: S_OK
2632  *  Failure: Non-zero HRESULT value.
2633  */
2634 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
2635 {
2636     HRESULT hr;
2637
2638     TRACE("(%p, %p, %p)\n", hdc, psc, height);
2639
2640     if (!height) return E_INVALIDARG;
2641     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2642
2643     *height = get_cache_height(psc);
2644     return S_OK;
2645 }
2646
2647 /***********************************************************************
2648  *      ScriptGetGlyphABCWidth (USP10.@)
2649  *
2650  * Retrieve the width of a glyph.
2651  *
2652  * PARAMS
2653  *  hdc    [I]    Device context.
2654  *  psc    [I/O]  Opaque pointer to a script cache.
2655  *  glyph  [I]    Glyph to retrieve the width for.
2656  *  abc    [O]    ABC widths of the glyph.
2657  *
2658  * RETURNS
2659  *  Success: S_OK
2660  *  Failure: Non-zero HRESULT value.
2661  */
2662 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
2663 {
2664     HRESULT hr;
2665
2666     TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
2667
2668     if (!abc) return E_INVALIDARG;
2669     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2670
2671     if (!get_cache_glyph_widths(psc, glyph, abc))
2672     {
2673         if (!hdc) return E_PENDING;
2674         if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2675         {
2676             if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
2677         }
2678         else
2679         {
2680             INT width;
2681             if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
2682             abc->abcB = width;
2683             abc->abcA = abc->abcC = 0;
2684         }
2685         set_cache_glyph_widths(psc, glyph, abc);
2686     }
2687     return S_OK;
2688 }
2689
2690 /***********************************************************************
2691  *      ScriptLayout (USP10.@)
2692  *
2693  * Map embedding levels to visual and/or logical order.
2694  *
2695  * PARAMS
2696  *  runs     [I] Size of level array.
2697  *  level    [I] Array of embedding levels.
2698  *  vistolog [O] Map of embedding levels from visual to logical order.
2699  *  logtovis [O] Map of embedding levels from logical to visual order.
2700  *
2701  * RETURNS
2702  *  Success: S_OK
2703  *  Failure: Non-zero HRESULT value.
2704  *
2705  * BUGS
2706  *  This stub works correctly for any sequence of a single
2707  *  embedding level but not for sequences of different
2708  *  embedding levels, i.e. mixtures of RTL and LTR scripts.
2709  */
2710 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
2711 {
2712     int* indexs;
2713     int ich;
2714
2715     TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
2716
2717     if (!level || (!vistolog && !logtovis))
2718         return E_INVALIDARG;
2719
2720     indexs = heap_alloc(sizeof(int) * runs);
2721     if (!indexs)
2722         return E_OUTOFMEMORY;
2723
2724
2725     if (vistolog)
2726     {
2727         for( ich = 0; ich < runs; ich++)
2728             indexs[ich] = ich;
2729
2730         ich = 0;
2731         while (ich < runs)
2732             ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2733         for (ich = 0; ich < runs; ich++)
2734             vistolog[ich] = indexs[ich];
2735     }
2736
2737
2738     if (logtovis)
2739     {
2740         for( ich = 0; ich < runs; ich++)
2741             indexs[ich] = ich;
2742
2743         ich = 0;
2744         while (ich < runs)
2745             ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2746         for (ich = 0; ich < runs; ich++)
2747             logtovis[ich] = indexs[ich];
2748     }
2749     heap_free(indexs);
2750
2751     return S_OK;
2752 }
2753
2754 /***********************************************************************
2755  *      ScriptStringGetLogicalWidths (USP10.@)
2756  *
2757  * Returns logical widths from a string analysis.
2758  *
2759  * PARAMS
2760  *  ssa  [I] string analysis.
2761  *  piDx [O] logical widths returned.
2762  *
2763  * RETURNS
2764  *  Success: S_OK
2765  *  Failure: a non-zero HRESULT.
2766  */
2767 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
2768 {
2769     int i, j, next = 0;
2770     StringAnalysis *analysis = ssa;
2771
2772     TRACE("%p, %p\n", ssa, piDx);
2773
2774     if (!analysis) return S_FALSE;
2775     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2776
2777     for (i = 0; i < analysis->numItems; i++)
2778     {
2779         int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2780         int direction = 1;
2781
2782         if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
2783             direction = -1;
2784
2785         for (j = 0; j < cChar; j++)
2786         {
2787             int k;
2788             int glyph = analysis->glyphs[i].pwLogClust[j];
2789             int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
2790                                               cChar, j, direction, NULL, NULL);
2791             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);
2792
2793             for (k = 0; k < clust_size; k++)
2794             {
2795                 piDx[next] = advance / clust_size;
2796                 next++;
2797                 if (k) j++;
2798             }
2799         }
2800     }
2801     return S_OK;
2802 }
2803
2804 /***********************************************************************
2805  *      ScriptStringValidate (USP10.@)
2806  *
2807  * Validate a string analysis.
2808  *
2809  * PARAMS
2810  *  ssa [I] string analysis.
2811  *
2812  * RETURNS
2813  *  Success: S_OK
2814  *  Failure: S_FALSE if invalid sequences are found
2815  *           or a non-zero HRESULT if it fails.
2816  */
2817 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
2818 {
2819     StringAnalysis *analysis = ssa;
2820
2821     TRACE("(%p)\n", ssa);
2822
2823     if (!analysis) return E_INVALIDARG;
2824     return (analysis->invalid) ? S_FALSE : S_OK;
2825 }
2826
2827 /***********************************************************************
2828  *      ScriptString_pSize (USP10.@)
2829  *
2830  * Retrieve width and height of an analysed string.
2831  *
2832  * PARAMS
2833  *  ssa [I] string analysis.
2834  *
2835  * RETURNS
2836  *  Success: Pointer to a SIZE structure.
2837  *  Failure: NULL
2838  */
2839 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
2840 {
2841     int i, j;
2842     StringAnalysis *analysis = ssa;
2843
2844     TRACE("(%p)\n", ssa);
2845
2846     if (!analysis) return NULL;
2847     if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
2848
2849     if (!analysis->sz)
2850     {
2851         if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
2852         analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
2853
2854         analysis->sz->cx = 0;
2855         for (i = 0; i < analysis->numItems; i++)
2856         {
2857             if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
2858                 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
2859             for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
2860                 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
2861         }
2862     }
2863     return analysis->sz;
2864 }
2865
2866 /***********************************************************************
2867  *      ScriptString_pLogAttr (USP10.@)
2868  *
2869  * Retrieve logical attributes of an analysed string.
2870  *
2871  * PARAMS
2872  *  ssa [I] string analysis.
2873  *
2874  * RETURNS
2875  *  Success: Pointer to an array of SCRIPT_LOGATTR structures.
2876  *  Failure: NULL
2877  */
2878 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
2879 {
2880     StringAnalysis *analysis = ssa;
2881
2882     TRACE("(%p)\n", ssa);
2883
2884     if (!analysis) return NULL;
2885     if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
2886     return analysis->logattrs;
2887 }
2888
2889 /***********************************************************************
2890  *      ScriptString_pcOutChars (USP10.@)
2891  *
2892  * Retrieve the length of a string after clipping.
2893  *
2894  * PARAMS
2895  *  ssa [I] String analysis.
2896  *
2897  * RETURNS
2898  *  Success: Pointer to the length.
2899  *  Failure: NULL
2900  */
2901 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
2902 {
2903     StringAnalysis *analysis = ssa;
2904
2905     TRACE("(%p)\n", ssa);
2906
2907     if (!analysis) return NULL;
2908     return &analysis->clip_len;
2909 }
2910
2911 /***********************************************************************
2912  *      ScriptStringGetOrder (USP10.@)
2913  *
2914  * Retrieve a glyph order map.
2915  *
2916  * PARAMS
2917  *  ssa   [I]   String analysis.
2918  *  order [I/O] Array of glyph positions.
2919  *
2920  * RETURNS
2921  *  Success: S_OK
2922  *  Failure: a non-zero HRESULT.
2923  */
2924 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
2925 {
2926     int i, j;
2927     unsigned int k;
2928     StringAnalysis *analysis = ssa;
2929
2930     TRACE("(%p)\n", ssa);
2931
2932     if (!analysis) return S_FALSE;
2933     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2934
2935     /* FIXME: handle RTL scripts */
2936     for (i = 0, k = 0; i < analysis->numItems; i++)
2937         for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
2938             order[k] = k;
2939
2940     return S_OK;
2941 }
2942
2943 /***********************************************************************
2944  *      ScriptGetLogicalWidths (USP10.@)
2945  *
2946  * Convert advance widths to logical widths.
2947  *
2948  * PARAMS
2949  *  sa          [I] Script analysis.
2950  *  nbchars     [I] Number of characters.
2951  *  nbglyphs    [I] Number of glyphs.
2952  *  glyph_width [I] Array of glyph widths.
2953  *  log_clust   [I] Array of logical clusters.
2954  *  sva         [I] Visual attributes.
2955  *  widths      [O] Array of logical widths.
2956  *
2957  * RETURNS
2958  *  Success: S_OK
2959  *  Failure: a non-zero HRESULT.
2960  */
2961 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
2962                                       const int *glyph_width, const WORD *log_clust,
2963                                       const SCRIPT_VISATTR *sva, int *widths)
2964 {
2965     int i;
2966
2967     TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
2968           sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);
2969
2970     /* FIXME */
2971     for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
2972     return S_OK;
2973 }
2974
2975 /***********************************************************************
2976  *      ScriptApplyLogicalWidth (USP10.@)
2977  *
2978  * Generate glyph advance widths.
2979  *
2980  * PARAMS
2981  *  dx          [I]   Array of logical advance widths.
2982  *  num_chars   [I]   Number of characters.
2983  *  num_glyphs  [I]   Number of glyphs.
2984  *  log_clust   [I]   Array of logical clusters.
2985  *  sva         [I]   Visual attributes.
2986  *  advance     [I]   Array of glyph advance widths.
2987  *  sa          [I]   Script analysis.
2988  *  abc         [I/O] Summed ABC widths.
2989  *  justify     [O]   Array of glyph advance widths.
2990  *
2991  * RETURNS
2992  *  Success: S_OK
2993  *  Failure: a non-zero HRESULT.
2994  */
2995 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
2996                                        const WORD *log_clust, const SCRIPT_VISATTR *sva,
2997                                        const int *advance, const SCRIPT_ANALYSIS *sa,
2998                                        ABC *abc, int *justify)
2999 {
3000     int i;
3001
3002     FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3003           dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
3004
3005     for (i = 0; i < num_chars; i++) justify[i] = advance[i];
3006     return S_OK;
3007 }
3008
3009 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
3010                              int num_glyphs, int dx, int min_kashida, int *justify)
3011 {
3012     int i;
3013
3014     FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
3015
3016     for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
3017     return S_OK;
3018 }