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