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