usp10: Add a few chars that Windows itemizes as punctuation.
[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     /* These chars are itemized as Punctuation by Windows */
498     if (ch == 0x2212 || ch == 0x2044 || ch == 0x00a0)
499         return Script_Punctuation;
500
501     GetStringTypeW(CT_CTYPE1, &ch, 1, &type);
502
503     if (type == 0)
504         return SCRIPT_UNDEFINED;
505
506     if (type & C1_CNTRL)
507         return Script_Control;
508
509     i = 0;
510     do
511     {
512         if (ch < scriptRanges[i].rangeFirst || scriptRanges[i].script == SCRIPT_UNDEFINED)
513             break;
514
515         if (ch >= scriptRanges[i].rangeFirst && ch <= scriptRanges[i].rangeLast)
516         {
517             if (scriptRanges[i].numericScript && type & C1_DIGIT)
518                 return scriptRanges[i].numericScript;
519             if (scriptRanges[i].punctScript && type & C1_PUNCT)
520                 return scriptRanges[i].punctScript;
521             return scriptRanges[i].script;
522         }
523         i++;
524     } while (1);
525
526     return SCRIPT_UNDEFINED;
527 }
528
529 /***********************************************************************
530  *      DllMain
531  *
532  */
533 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
534 {
535     switch(fdwReason)
536     {
537     case DLL_PROCESS_ATTACH:
538         DisableThreadLibraryCalls(hInstDLL);
539         break;
540     case DLL_PROCESS_DETACH:
541         break;
542     }
543     return TRUE;
544 }
545
546 /***********************************************************************
547  *      ScriptFreeCache (USP10.@)
548  *
549  * Free a script cache.
550  *
551  * PARAMS
552  *   psc [I/O] Script cache.
553  *
554  * RETURNS
555  *  Success: S_OK
556  *  Failure: Non-zero HRESULT value.
557  */
558 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
559 {
560     TRACE("%p\n", psc);
561
562     if (psc && *psc)
563     {
564         unsigned int i;
565         for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
566         {
567             heap_free(((ScriptCache *)*psc)->glyphs[i]);
568             heap_free(((ScriptCache *)*psc)->widths[i]);
569         }
570         heap_free(((ScriptCache *)*psc)->GSUB_Table);
571         heap_free(((ScriptCache *)*psc)->GDEF_Table);
572         heap_free(((ScriptCache *)*psc)->features);
573         heap_free(*psc);
574         *psc = NULL;
575     }
576     return S_OK;
577 }
578
579 /***********************************************************************
580  *      ScriptGetProperties (USP10.@)
581  *
582  * Retrieve a list of script properties.
583  *
584  * PARAMS
585  *  props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
586  *  num   [I] Pointer to the number of scripts.
587  *
588  * RETURNS
589  *  Success: S_OK
590  *  Failure: Non-zero HRESULT value.
591  *
592  * NOTES
593  *  Behaviour matches WinXP.
594  */
595 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
596 {
597     TRACE("(%p,%p)\n", props, num);
598
599     if (!props && !num) return E_INVALIDARG;
600
601     if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
602     if (props) *props = script_props;
603
604     return S_OK;
605 }
606
607 /***********************************************************************
608  *      ScriptGetFontProperties (USP10.@)
609  *
610  * Get information on special glyphs.
611  *
612  * PARAMS
613  *  hdc [I]   Device context.
614  *  psc [I/O] Opaque pointer to a script cache.
615  *  sfp [O]   Font properties structure.
616  */
617 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
618 {
619     HRESULT hr;
620
621     TRACE("%p,%p,%p\n", hdc, psc, sfp);
622
623     if (!sfp) return E_INVALIDARG;
624     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
625
626     if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
627         return E_INVALIDARG;
628
629     /* return something sensible? */
630     sfp->wgBlank = 0;
631     sfp->wgDefault = get_cache_default_char(psc);
632     sfp->wgInvalid = 0;
633     sfp->wgKashida = 0xffff;
634     sfp->iKashidaWidth = 0;
635
636     return S_OK;
637 }
638
639 /***********************************************************************
640  *      ScriptRecordDigitSubstitution (USP10.@)
641  *
642  *  Record digit substitution settings for a given locale.
643  *
644  *  PARAMS
645  *   locale [I] Locale identifier.
646  *   sds    [I] Structure to record substitution settings.
647  *
648  *  RETURNS
649  *   Success: S_OK
650  *   Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
651  *
652  *  SEE ALSO
653  *   http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
654  */
655 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
656 {
657     DWORD plgid, sub;
658
659     TRACE("0x%x, %p\n", locale, sds);
660
661     /* This implementation appears to be correct for all languages, but it's
662      * not clear if sds->DigitSubstitute is ever set to anything except 
663      * CONTEXT or NONE in reality */
664
665     if (!sds) return E_POINTER;
666
667     locale = ConvertDefaultLocale(locale);
668
669     if (!IsValidLocale(locale, LCID_INSTALLED))
670         return E_INVALIDARG;
671
672     plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
673     sds->TraditionalDigitLanguage = plgid;
674
675     if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
676         sds->NationalDigitLanguage = plgid;
677     else
678         sds->NationalDigitLanguage = LANG_ENGLISH;
679
680     if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
681                         (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
682
683     switch (sub)
684     {
685     case 0: 
686         if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
687             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
688         else
689             sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
690         break;
691     case 1:
692         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
693         break;
694     case 2:
695         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
696         break;
697     default:
698         sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
699         break;
700     }
701
702     sds->dwReserved = 0;
703     return S_OK;
704 }
705
706 /***********************************************************************
707  *      ScriptApplyDigitSubstitution (USP10.@)
708  *
709  *  Apply digit substitution settings.
710  *
711  *  PARAMS
712  *   sds [I] Structure with recorded substitution settings.
713  *   sc  [I] Script control structure.
714  *   ss  [I] Script state structure.
715  *
716  *  RETURNS
717  *   Success: S_OK
718  *   Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
719  */
720 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds, 
721                                             SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
722 {
723     SCRIPT_DIGITSUBSTITUTE psds;
724
725     TRACE("%p, %p, %p\n", sds, sc, ss);
726
727     if (!sc || !ss) return E_POINTER;
728     if (!sds)
729     {
730         sds = &psds;
731         if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
732             return E_INVALIDARG;
733     }
734
735     sc->uDefaultLanguage = LANG_ENGLISH;
736     sc->fContextDigits = 0;
737     ss->fDigitSubstitute = 0;
738
739     switch (sds->DigitSubstitute) {
740         case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
741         case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
742         case SCRIPT_DIGITSUBSTITUTE_NONE:
743         case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
744             return S_OK;
745         default:
746             return E_INVALIDARG;
747     }
748 }
749
750 /***********************************************************************
751  *      ScriptItemizeOpenType (USP10.@)
752  *
753  * Split a Unicode string into shapeable parts.
754  *
755  * PARAMS
756  *  pwcInChars  [I] String to split.
757  *  cInChars    [I] Number of characters in pwcInChars.
758  *  cMaxItems   [I] Maximum number of items to return.
759  *  psControl   [I] Pointer to a SCRIPT_CONTROL structure.
760  *  psState     [I] Pointer to a SCRIPT_STATE structure.
761  *  pItems      [O] Buffer to receive SCRIPT_ITEM structures.
762  *  pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
763  *  pcItems     [O] Number of script items returned.
764  *
765  * RETURNS
766  *  Success: S_OK
767  *  Failure: Non-zero HRESULT value.
768  */
769 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
770                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
771                              SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
772 {
773
774 #define Numeric_space 0x0020
775 #define ZWNJ 0x200C
776 #define ZWJ  0x200D
777
778     int   cnt = 0, index = 0, str = 0;
779     int   New_Script = -1;
780     WORD  *levels = NULL;
781     WORD  *strength = NULL;
782     WORD  baselevel = 0;
783
784     TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems, 
785           psControl, psState, pItems, pcItems);
786
787     if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
788         return E_INVALIDARG;
789
790     if (psState && psControl)
791     {
792         int i;
793         levels = heap_alloc_zero(cInChars * sizeof(WORD));
794         if (!levels)
795             return E_OUTOFMEMORY;
796
797         BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
798         baselevel = levels[0];
799         for (i = 0; i < cInChars; i++)
800             if (levels[i]!=levels[0])
801                 break;
802         if (i >= cInChars && !odd(baselevel))
803         {
804             heap_free(levels);
805             levels = NULL;
806         }
807         else
808         {
809             if (!psControl->fMergeNeutralItems)
810             {
811                 strength = heap_alloc_zero(cInChars * sizeof(WORD));
812                 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
813             }
814         }
815     }
816
817     while ((pwcInChars[cnt] == Numeric_space || pwcInChars[cnt] == ZWJ || pwcInChars[cnt] == ZWNJ) && cnt < cInChars)
818         cnt++;
819
820     if (cnt == cInChars) /* All Spaces */
821     {
822         cnt = 0;
823         New_Script = get_char_script(pwcInChars[cnt]);
824     }
825
826     pItems[index].iCharPos = 0;
827     pItems[index].a = scriptInformation[get_char_script(pwcInChars[cnt])].a;
828     pScriptTags[index] = scriptInformation[get_char_script(pwcInChars[cnt])].scriptTag;
829
830     if (strength)
831         str = strength[cnt];
832
833     cnt = 0;
834     if (levels)
835     {
836         pItems[index].a.fRTL = odd(levels[cnt]);
837         pItems[index].a.fLayoutRTL = odd(levels[cnt]);
838         pItems[index].a.s.uBidiLevel = levels[cnt];
839     }
840     else if (!pItems[index].a.s.uBidiLevel)
841     {
842         pItems[index].a.s.uBidiLevel = baselevel;
843         pItems[index].a.fLayoutRTL = odd(baselevel);
844         pItems[index].a.fRTL = odd(baselevel);
845     }
846
847     TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
848           levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
849           pItems[index].iCharPos);
850
851     for (cnt=1; cnt < cInChars; cnt++)
852     {
853         if (levels && (levels[cnt] == pItems[index].a.s.uBidiLevel && (!strength || (strength[cnt] == 0 || strength[cnt] == str))))
854             continue;
855
856         if(pwcInChars[cnt] != Numeric_space && pwcInChars[cnt] != ZWJ && pwcInChars[cnt] != ZWNJ)
857             New_Script = get_char_script(pwcInChars[cnt]);
858         else if (levels)
859         {
860             int j = 1;
861             while (cnt + j < cInChars - 1 && (pwcInChars[cnt+j] == Numeric_space || pwcInChars[cnt+j] == ZWJ || pwcInChars[cnt+j] == ZWNJ))
862                 j++;
863             if (cnt + j < cInChars)
864                 New_Script = get_char_script(pwcInChars[cnt+j]);
865             else
866                 New_Script = get_char_script(pwcInChars[cnt]);
867         }
868
869         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)
870         {
871             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);
872
873             if (strength && strength[cnt] != 0)
874                 str = strength[cnt];
875
876             index++;
877             if  (index+1 > cMaxItems)
878                 return E_OUTOFMEMORY;
879
880             pItems[index].iCharPos = cnt;
881             memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
882
883             pItems[index].a = scriptInformation[New_Script].a;
884             pScriptTags[index] = scriptInformation[New_Script].scriptTag;
885             if (levels)
886             {
887                 pItems[index].a.fRTL = odd(levels[cnt]);
888                 pItems[index].a.fLayoutRTL = odd(levels[cnt]);
889                 pItems[index].a.s.uBidiLevel = levels[cnt];
890             }
891             else if (!pItems[index].a.s.uBidiLevel)
892             {
893                 pItems[index].a.s.uBidiLevel = baselevel;
894                 pItems[index].a.fLayoutRTL = odd(baselevel);
895                 pItems[index].a.fRTL = odd(baselevel);
896             }
897
898             TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
899         }
900     }
901
902     /* While not strictly necessary according to the spec, make sure the n+1
903      * item is set up to prevent random behaviour if the caller erroneously
904      * checks the n+1 structure                                              */
905     index++;
906     memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
907
908     TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
909
910     /*  Set one SCRIPT_STATE item being returned  */
911     if  (index + 1 > cMaxItems) return E_OUTOFMEMORY;
912     if (pcItems) *pcItems = index;
913
914     /*  Set SCRIPT_ITEM                                     */
915     pItems[index].iCharPos = cnt;         /* the last item contains the ptr to the lastchar */
916     heap_free(levels);
917     heap_free(strength);
918     return S_OK;
919 }
920
921 /***********************************************************************
922  *      ScriptItemize (USP10.@)
923  *
924  * Split a Unicode string into shapeable parts.
925  *
926  * PARAMS
927  *  pwcInChars [I] String to split.
928  *  cInChars   [I] Number of characters in pwcInChars.
929  *  cMaxItems  [I] Maximum number of items to return.
930  *  psControl  [I] Pointer to a SCRIPT_CONTROL structure.
931  *  psState    [I] Pointer to a SCRIPT_STATE structure.
932  *  pItems     [O] Buffer to receive SCRIPT_ITEM structures.
933  *  pcItems    [O] Number of script items returned.
934  *
935  * RETURNS
936  *  Success: S_OK
937  *  Failure: Non-zero HRESULT value.
938  */
939 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
940                              const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
941                              SCRIPT_ITEM *pItems, int *pcItems)
942 {
943     OPENTYPE_TAG *discarded_tags;
944     HRESULT res;
945
946     discarded_tags = heap_alloc(cMaxItems * sizeof(OPENTYPE_TAG));
947     if (!discarded_tags)
948         return E_OUTOFMEMORY;
949     res = ScriptItemizeOpenType(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, discarded_tags, pcItems);
950     heap_free(discarded_tags);
951     return res;
952 }
953
954 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
955 {
956     int defWidth;
957     int cTabStops=0;
958     INT *lpTabPos = NULL;
959     INT nTabOrg = 0;
960     INT x = 0;
961
962     if (pTabdef)
963         lpTabPos = pTabdef->pTabStops;
964
965     if (pTabdef && pTabdef->iTabOrigin)
966     {
967         if (pTabdef->iScale)
968             nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
969         else
970             nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
971     }
972
973     if (pTabdef)
974         cTabStops = pTabdef->cTabStops;
975
976     if (cTabStops == 1)
977     {
978         if (pTabdef->iScale)
979             defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
980         else
981             defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
982         cTabStops = 0;
983     }
984     else
985         defWidth = 8 * psc->tm.tmAveCharWidth;
986
987     for (; cTabStops>0 ; lpTabPos++, cTabStops--)
988     {
989         int position = *lpTabPos;
990         if (position < 0)
991             position = -1 * position;
992         if (pTabdef->iScale)
993             position = (position * pTabdef->iScale) / 4;
994         else
995             position = position * psc->tm.tmAveCharWidth;
996
997         if( nTabOrg + position > current_x)
998         {
999             if( *lpTabPos >= 0)
1000             {
1001                 /* a left aligned tab */
1002                 x = (nTabOrg + *lpTabPos) - current_x;
1003                 break;
1004             }
1005             else
1006             {
1007                 FIXME("Negative tabstop\n");
1008                 break;
1009             }
1010         }
1011     }
1012     if ((!cTabStops) && (defWidth > 0))
1013         x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1014     else if ((!cTabStops) && (defWidth < 0))
1015         FIXME("TODO: Negative defWidth\n");
1016
1017     return x;
1018 }
1019
1020 /***********************************************************************
1021  * Helper function for ScriptStringAnalyse
1022  */
1023 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1024                               const WCHAR *pwcInChars, int cChars )
1025 {
1026     /* FIXME: When to properly fallback is still a bit of a mystery */
1027     WORD *glyphs;
1028
1029     if (psa->fNoGlyphIndex)
1030         return FALSE;
1031
1032     if (init_script_cache(hdc, psc) != S_OK)
1033         return FALSE;
1034
1035     if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1036         return TRUE;
1037
1038     glyphs = heap_alloc(sizeof(WORD) * cChars);
1039     if (!glyphs)
1040         return FALSE;
1041     if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1042     {
1043         heap_free(glyphs);
1044         return TRUE;
1045     }
1046     heap_free(glyphs);
1047
1048     return FALSE;
1049 }
1050
1051 static void find_fallback_font(DWORD scriptid, LPWSTR FaceName)
1052 {
1053     HKEY hkey;
1054
1055     if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1056     {
1057         static const WCHAR szFmt[] = {'%','x',0};
1058         WCHAR value[10];
1059         DWORD count = LF_FACESIZE * sizeof(WCHAR);
1060         DWORD type;
1061
1062         sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1063         if (RegQueryValueExW(hkey, value, 0, &type, (LPBYTE)FaceName, &count))
1064             lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1065         RegCloseKey(hkey);
1066     }
1067     else
1068         lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1069 }
1070
1071 /***********************************************************************
1072  *      ScriptStringAnalyse (USP10.@)
1073  *
1074  */
1075 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1076                                    int cGlyphs, int iCharset, DWORD dwFlags,
1077                                    int iReqWidth, SCRIPT_CONTROL *psControl,
1078                                    SCRIPT_STATE *psState, const int *piDx,
1079                                    SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1080                                    SCRIPT_STRING_ANALYSIS *pssa)
1081 {
1082     HRESULT hr = E_OUTOFMEMORY;
1083     StringAnalysis *analysis = NULL;
1084     SCRIPT_CONTROL sControl;
1085     SCRIPT_STATE sState;
1086     int i, num_items = 255;
1087     BYTE   *BidiLevel;
1088     WCHAR *iString = NULL;
1089
1090     TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1091           hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1092           psControl, psState, piDx, pTabdef, pbInClass, pssa);
1093
1094     if (iCharset != -1)
1095     {
1096         FIXME("Only Unicode strings are supported\n");
1097         return E_INVALIDARG;
1098     }
1099     if (cString < 1 || !pString) return E_INVALIDARG;
1100     if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1101
1102     if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1103     if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1104
1105     /* FIXME: handle clipping */
1106     analysis->clip_len = cString;
1107     analysis->hdc = hdc;
1108     analysis->dwFlags = dwFlags;
1109
1110     if (psState)
1111         sState = *psState;
1112     else
1113         memset(&sState, 0, sizeof(SCRIPT_STATE));
1114
1115     if (psControl)
1116         sControl = *psControl;
1117     else
1118         memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1119
1120     if (dwFlags & SSA_PASSWORD)
1121     {
1122         iString = heap_alloc(sizeof(WCHAR)*cString);
1123         if (!iString)
1124         {
1125             hr = E_OUTOFMEMORY;
1126             goto error;
1127         }
1128         for (i = 0; i < cString; i++)
1129             iString[i] = *((const WCHAR *)pString);
1130         pString = iString;
1131     }
1132
1133     hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1134                        &analysis->numItems);
1135
1136     while (hr == E_OUTOFMEMORY)
1137     {
1138         SCRIPT_ITEM *tmp;
1139
1140         num_items *= 2;
1141         if (!(tmp = heap_realloc_zero(analysis->pItem, num_items * sizeof(SCRIPT_ITEM) + 1)))
1142             goto error;
1143
1144         analysis->pItem = tmp;
1145         hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
1146                            &analysis->numItems);
1147     }
1148     if (hr != S_OK) goto error;
1149
1150     /* set back to out of memory for default goto error behaviour */
1151     hr = E_OUTOFMEMORY;
1152
1153     if (dwFlags & SSA_BREAK)
1154     {
1155         if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
1156         {
1157             for (i = 0; i < analysis->numItems; i++)
1158                 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]);
1159         }
1160         else
1161             goto error;
1162     }
1163
1164     if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
1165         goto error;
1166     if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
1167         goto error;
1168
1169     if (dwFlags & SSA_GLYPHS)
1170     {
1171         int tab_x = 0;
1172         if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
1173             goto error;
1174
1175         for (i = 0; i < analysis->numItems; i++)
1176         {
1177             SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
1178             int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1179             int numGlyphs = 1.5 * cChar + 16;
1180             WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
1181             WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
1182             int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
1183             SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
1184             GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
1185             ABC *abc = heap_alloc_zero(sizeof(ABC));
1186             int numGlyphsReturned;
1187             HFONT originalFont = 0x0;
1188
1189             /* FIXME: non unicode strings */
1190             const WCHAR* pStr = (const WCHAR*)pString;
1191             analysis->glyphs[i].fallbackFont = NULL;
1192
1193             if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
1194             {
1195                 heap_free (glyphs);
1196                 heap_free (pwLogClust);
1197                 heap_free (piAdvance);
1198                 heap_free (psva);
1199                 heap_free (pGoffset);
1200                 heap_free (abc);
1201                 hr = E_OUTOFMEMORY;
1202                 goto error;
1203             }
1204
1205             if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
1206             {
1207                 LOGFONTW lf;
1208                 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
1209                 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
1210                 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
1211                 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
1212                 if (analysis->glyphs[i].fallbackFont)
1213                 {
1214                     ScriptFreeCache(sc);
1215                     originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
1216                 }
1217             }
1218
1219             hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
1220                              cChar, numGlyphs, &analysis->pItem[i].a,
1221                              glyphs, pwLogClust, psva, &numGlyphsReturned);
1222             hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
1223                              piAdvance, pGoffset, abc);
1224             if (originalFont)
1225                 SelectObject(hdc,originalFont);
1226
1227             if (dwFlags & SSA_TAB)
1228             {
1229                 int tabi = 0;
1230                 for (tabi = 0; tabi < cChar; tabi++)
1231                 {
1232                     if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
1233                         piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
1234                     tab_x+=piAdvance[tabi];
1235                 }
1236             }
1237
1238             analysis->glyphs[i].numGlyphs = numGlyphsReturned;
1239             analysis->glyphs[i].glyphs = glyphs;
1240             analysis->glyphs[i].pwLogClust = pwLogClust;
1241             analysis->glyphs[i].piAdvance = piAdvance;
1242             analysis->glyphs[i].psva = psva;
1243             analysis->glyphs[i].pGoffset = pGoffset;
1244             analysis->glyphs[i].abc = abc;
1245             analysis->glyphs[i].iMaxPosX= -1;
1246
1247             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1248         }
1249     }
1250     else
1251     {
1252         for (i = 0; i < analysis->numItems; i++)
1253             BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1254     }
1255
1256     ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
1257     heap_free(BidiLevel);
1258
1259     *pssa = analysis;
1260     heap_free(iString);
1261     return S_OK;
1262
1263 error:
1264     heap_free(iString);
1265     heap_free(analysis->glyphs);
1266     heap_free(analysis->logattrs);
1267     heap_free(analysis->pItem);
1268     heap_free(analysis->logical2visual);
1269     heap_free(analysis);
1270     return hr;
1271 }
1272
1273 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
1274 {
1275     int i;
1276
1277     if (pva[glyph].fClusterStart)
1278         return TRUE;
1279     for (i = 0; i < cChars; i++)
1280         if (pwLogClust[i] == glyph) break;
1281     if (i != cChars)
1282         return TRUE;
1283
1284     return FALSE;
1285 }
1286
1287
1288 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
1289                            int iX,
1290                            int iY,
1291                            int iItem,
1292                            int cStart,
1293                            int cEnd,
1294                            UINT uOptions,
1295                            const RECT *prc,
1296                            BOOL fSelected,
1297                            BOOL fDisabled)
1298 {
1299     StringAnalysis *analysis;
1300     int off_x = 0;
1301     HRESULT hr;
1302     COLORREF BkColor = 0x0;
1303     COLORREF TextColor = 0x0;
1304     INT BkMode = 0;
1305     INT runStart, runEnd;
1306     INT iGlyph, cGlyphs;
1307     HFONT oldFont = 0x0;
1308
1309     TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
1310          ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
1311
1312     if (!(analysis = ssa)) return E_INVALIDARG;
1313
1314     if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
1315          (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
1316             return S_OK;
1317
1318     if (fSelected)
1319     {
1320         BkMode = GetBkMode(analysis->hdc);
1321         SetBkMode( analysis->hdc, OPAQUE);
1322         BkColor = GetBkColor(analysis->hdc);
1323         SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
1324         if (!fDisabled)
1325         {
1326             TextColor = GetTextColor(analysis->hdc);
1327             SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1328         }
1329     }
1330     if (analysis->glyphs[iItem].fallbackFont)
1331         oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
1332
1333     if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
1334         runStart = cStart - analysis->pItem[iItem].iCharPos;
1335     else
1336         runStart =  0;
1337     if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
1338         runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
1339     else
1340         runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
1341
1342     if (analysis->pItem[iItem].a.fRTL)
1343     {
1344         if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
1345             ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
1346         else
1347             ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
1348     }
1349     else
1350     {
1351         if (cStart >=0 && runStart)
1352             ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
1353         else
1354             ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
1355     }
1356
1357     if (analysis->pItem[iItem].a.fRTL)
1358         iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
1359     else
1360         iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
1361
1362     if (analysis->pItem[iItem].a.fRTL)
1363         cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
1364     else
1365         cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
1366
1367     cGlyphs++;
1368
1369     if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
1370     {
1371         INT direction;
1372         INT clust_glyph;
1373
1374         clust_glyph = iGlyph + cGlyphs;
1375         if (analysis->pItem[iItem].a.fRTL)
1376             direction = -1;
1377         else
1378             direction = 1;
1379
1380         while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
1381               !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
1382         {
1383             cGlyphs++;
1384             clust_glyph++;
1385         }
1386     }
1387
1388     hr = ScriptTextOut(analysis->hdc,
1389                        (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
1390                        iY, uOptions, prc, &analysis->pItem[iItem].a, NULL, 0,
1391                        &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
1392                        &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
1393                        &analysis->glyphs[iItem].pGoffset[iGlyph]);
1394
1395     TRACE("ScriptTextOut hr=%08x\n", hr);
1396
1397     if (fSelected)
1398     {
1399         SetBkColor(analysis->hdc, BkColor);
1400         SetBkMode( analysis->hdc, BkMode);
1401         if (!fDisabled)
1402             SetTextColor(analysis->hdc, TextColor);
1403     }
1404     if (analysis->glyphs[iItem].fallbackFont)
1405         SelectObject(analysis->hdc, oldFont);
1406
1407     return hr;
1408 }
1409
1410 /***********************************************************************
1411  *      ScriptStringOut (USP10.@)
1412  *
1413  * This function takes the output of ScriptStringAnalyse and joins the segments
1414  * of glyphs and passes the resulting string to ScriptTextOut.  ScriptStringOut
1415  * only processes glyphs.
1416  *
1417  * Parameters:
1418  *  ssa       [I] buffer to hold the analysed string components
1419  *  iX        [I] X axis displacement for output
1420  *  iY        [I] Y axis displacement for output
1421  *  uOptions  [I] flags controling output processing
1422  *  prc       [I] rectangle coordinates
1423  *  iMinSel   [I] starting pos for substringing output string
1424  *  iMaxSel   [I] ending pos for substringing output string
1425  *  fDisabled [I] controls text highlighting
1426  *
1427  *  RETURNS
1428  *   Success: S_OK
1429  *   Failure: is the value returned by ScriptTextOut
1430  */
1431 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
1432                                int iX,
1433                                int iY, 
1434                                UINT uOptions, 
1435                                const RECT *prc, 
1436                                int iMinSel, 
1437                                int iMaxSel,
1438                                BOOL fDisabled)
1439 {
1440     StringAnalysis *analysis;
1441     int   item;
1442     HRESULT hr;
1443
1444     TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
1445          ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
1446
1447     if (!(analysis = ssa)) return E_INVALIDARG;
1448     if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
1449
1450     for (item = 0; item < analysis->numItems; item++)
1451     {
1452         hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
1453         if (FAILED(hr))
1454             return hr;
1455     }
1456
1457     if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
1458     {
1459         if (iMaxSel > 0 &&  iMinSel < 0)
1460             iMinSel = 0;
1461         for (item = 0; item < analysis->numItems; item++)
1462         {
1463             hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
1464             if (FAILED(hr))
1465                 return hr;
1466         }
1467     }
1468
1469     return S_OK;
1470 }
1471
1472 /***********************************************************************
1473  *      ScriptStringCPtoX (USP10.@)
1474  *
1475  */
1476 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
1477 {
1478     int item;
1479     int runningX = 0;
1480     StringAnalysis* analysis = ssa;
1481
1482     TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
1483
1484     if (!ssa || !pX) return S_FALSE;
1485     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1486
1487     /* icp out of range */
1488     if(icp < 0)
1489     {
1490         analysis->invalid = TRUE;
1491         return E_INVALIDARG;
1492     }
1493
1494     for(item=0; item<analysis->numItems; item++)
1495     {
1496         int CP, i;
1497         int offset;
1498
1499         i = analysis->logical2visual[item];
1500         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1501         /* initialize max extents for uninitialized runs */
1502         if (analysis->glyphs[i].iMaxPosX == -1)
1503         {
1504             if (analysis->pItem[i].a.fRTL)
1505                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1506                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1507                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1508             else
1509                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1510                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1511                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1512         }
1513
1514         if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
1515         {
1516             runningX += analysis->glyphs[i].iMaxPosX;
1517             continue;
1518         }
1519
1520         icp -= analysis->pItem[i].iCharPos;
1521         ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1522                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1523                     &analysis->pItem[i].a, &offset);
1524         runningX += offset;
1525
1526         *pX = runningX;
1527         return S_OK;
1528     }
1529
1530     /* icp out of range */
1531     analysis->invalid = TRUE;
1532     return E_INVALIDARG;
1533 }
1534
1535 /***********************************************************************
1536  *      ScriptStringXtoCP (USP10.@)
1537  *
1538  */
1539 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
1540 {
1541     StringAnalysis* analysis = ssa;
1542     int item;
1543
1544     TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
1545
1546     if (!ssa || !piCh || !piTrailing) return S_FALSE;
1547     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1548
1549     /* out of range */
1550     if(iX < 0)
1551     {
1552         if (analysis->pItem[0].a.fRTL)
1553         {
1554             *piCh = 1;
1555             *piTrailing = FALSE;
1556         }
1557         else
1558         {
1559             *piCh = -1;
1560             *piTrailing = TRUE;
1561         }
1562         return S_OK;
1563     }
1564
1565     for(item=0; item<analysis->numItems; item++)
1566     {
1567         int i;
1568         int CP;
1569
1570         for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
1571         /* nothing */;
1572
1573         CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1574         /* initialize max extents for uninitialized runs */
1575         if (analysis->glyphs[i].iMaxPosX == -1)
1576         {
1577             if (analysis->pItem[i].a.fRTL)
1578                 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1579                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1580                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1581             else
1582                 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1583                             analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1584                             &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1585         }
1586
1587         if (iX > analysis->glyphs[i].iMaxPosX)
1588         {
1589             iX -= analysis->glyphs[i].iMaxPosX;
1590             continue;
1591         }
1592
1593         ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1594                     analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1595                     &analysis->pItem[i].a, piCh, piTrailing);
1596         *piCh += analysis->pItem[i].iCharPos;
1597
1598         return S_OK;
1599     }
1600
1601     /* out of range */
1602     *piCh = analysis->pItem[analysis->numItems].iCharPos;
1603     *piTrailing = FALSE;
1604
1605     return S_OK;
1606 }
1607
1608
1609 /***********************************************************************
1610  *      ScriptStringFree (USP10.@)
1611  *
1612  * Free a string analysis.
1613  *
1614  * PARAMS
1615  *  pssa [I] string analysis.
1616  *
1617  * RETURNS
1618  *  Success: S_OK
1619  *  Failure: Non-zero HRESULT value.
1620  */
1621 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
1622 {
1623     StringAnalysis* analysis;
1624     BOOL invalid;
1625     int i;
1626
1627     TRACE("(%p)\n", pssa);
1628
1629     if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
1630
1631     invalid = analysis->invalid;
1632
1633     if (analysis->glyphs)
1634     {
1635         for (i = 0; i < analysis->numItems; i++)
1636         {
1637             heap_free(analysis->glyphs[i].glyphs);
1638             heap_free(analysis->glyphs[i].pwLogClust);
1639             heap_free(analysis->glyphs[i].piAdvance);
1640             heap_free(analysis->glyphs[i].psva);
1641             heap_free(analysis->glyphs[i].pGoffset);
1642             heap_free(analysis->glyphs[i].abc);
1643             if (analysis->glyphs[i].fallbackFont)
1644                 DeleteObject(analysis->glyphs[i].fallbackFont);
1645             ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
1646             heap_free(analysis->glyphs[i].sc);
1647         }
1648         heap_free(analysis->glyphs);
1649     }
1650
1651     heap_free(analysis->pItem);
1652     heap_free(analysis->logattrs);
1653     heap_free(analysis->sz);
1654     heap_free(analysis->logical2visual);
1655     heap_free(analysis);
1656
1657     if (invalid) return E_INVALIDARG;
1658     return S_OK;
1659 }
1660
1661 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
1662                                    int direction, int* iCluster, int *check_out)
1663 {
1664     int clust_size = 1;
1665     int check;
1666     WORD clust = pwLogClust[item];
1667
1668     for (check = item+direction; check < cChars && check >= 0; check+=direction)
1669     {
1670         if (pwLogClust[check] == clust)
1671         {
1672             clust_size ++;
1673             if (iCluster && *iCluster == -1)
1674                 *iCluster = item;
1675         }
1676         else break;
1677     }
1678
1679     if (check_out)
1680         *check_out = check;
1681
1682     return clust_size;
1683 }
1684
1685 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)
1686 {
1687     int advance;
1688     int log_clust_max = 0;
1689     int i;
1690
1691     advance = piAdvance[glyph];
1692
1693     for (i = 0; i < cChars; i++)
1694     {
1695         if (pwLogClust[i] > log_clust_max)
1696             log_clust_max = pwLogClust[i];
1697     }
1698
1699     if (glyph > log_clust_max)
1700         return advance;
1701
1702     for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
1703     {
1704
1705         if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
1706             break;
1707         if (glyph > log_clust_max)
1708             break;
1709         advance += piAdvance[glyph];
1710     }
1711
1712     return advance;
1713 }
1714
1715 /***********************************************************************
1716  *      ScriptCPtoX (USP10.@)
1717  *
1718  */
1719 HRESULT WINAPI ScriptCPtoX(int iCP,
1720                            BOOL fTrailing,
1721                            int cChars,
1722                            int cGlyphs,
1723                            const WORD *pwLogClust,
1724                            const SCRIPT_VISATTR *psva,
1725                            const int *piAdvance,
1726                            const SCRIPT_ANALYSIS *psa,
1727                            int *piX)
1728 {
1729     int item;
1730     float iPosX;
1731     int iSpecial = -1;
1732     int iCluster = -1;
1733     int clust_size = 1;
1734     float special_size = 0.0;
1735     int iMaxPos = 0;
1736     int advance = 0;
1737     BOOL rtl = FALSE;
1738
1739     TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
1740           iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1741           psa, piX);
1742
1743     if (psa->fRTL && ! psa->fLogicalOrder)
1744         rtl = TRUE;
1745
1746     if (fTrailing)
1747         iCP++;
1748
1749     if (rtl)
1750     {
1751         int max_clust = pwLogClust[0];
1752
1753         for (item=0; item < cGlyphs; item++)
1754             if (pwLogClust[item] > max_clust)
1755             {
1756                 ERR("We do not handle non reversed clusters properly\n");
1757                 break;
1758             }
1759
1760         iMaxPos = 0;
1761         for (item = max_clust; item >=0; item --)
1762             iMaxPos += piAdvance[item];
1763     }
1764
1765     iPosX = 0.0;
1766     for (item=0; item < iCP && item < cChars; item++)
1767     {
1768         if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
1769         {
1770             int check;
1771             int clust = pwLogClust[item];
1772
1773             iCluster = -1;
1774             clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
1775                                           &check);
1776
1777             advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
1778
1779             if (check >= cChars && !iMaxPos)
1780             {
1781                 for (check = clust; check < cChars; check++)
1782                     special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, 1);
1783                 iSpecial = item;
1784                 special_size /= (cChars - item);
1785                 iPosX += special_size;
1786             }
1787             else
1788             {
1789                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1790                 {
1791                     clust_size --;
1792                     if (clust_size == 0)
1793                         iPosX += advance;
1794                 }
1795                 else
1796                     iPosX += advance / (float)clust_size;
1797             }
1798         }
1799         else if (iSpecial != -1)
1800             iPosX += special_size;
1801         else /* (iCluster != -1) */
1802         {
1803             int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
1804             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1805             {
1806                 clust_size --;
1807                 if (clust_size == 0)
1808                     iPosX += adv;
1809             }
1810             else
1811                 iPosX += adv / (float)clust_size;
1812         }
1813     }
1814
1815     if (iMaxPos > 0)
1816     {
1817         iPosX = iMaxPos - iPosX;
1818         if (iPosX < 0)
1819             iPosX = 0;
1820     }
1821
1822     *piX = iPosX;
1823     TRACE("*piX=%d\n", *piX);
1824     return S_OK;
1825 }
1826
1827 /***********************************************************************
1828  *      ScriptXtoCP (USP10.@)
1829  *
1830  */
1831 HRESULT WINAPI ScriptXtoCP(int iX,
1832                            int cChars,
1833                            int cGlyphs,
1834                            const WORD *pwLogClust,
1835                            const SCRIPT_VISATTR *psva,
1836                            const int *piAdvance,
1837                            const SCRIPT_ANALYSIS *psa,
1838                            int *piCP,
1839                            int *piTrailing)
1840 {
1841     int item;
1842     float iPosX;
1843     float iLastPosX;
1844     int iSpecial = -1;
1845     int iCluster = -1;
1846     int clust_size = 1;
1847     int cjump = 0;
1848     int advance;
1849     float special_size = 0.0;
1850     int direction = 1;
1851
1852     TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
1853           iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
1854           psa, piCP, piTrailing);
1855
1856     if (psa->fRTL && ! psa->fLogicalOrder)
1857         direction = -1;
1858
1859     if (direction<0)
1860     {
1861         int max_clust = pwLogClust[0];
1862
1863         if (iX < 0)
1864         {
1865             *piCP = cChars;
1866             *piTrailing = 0;
1867             return S_OK;
1868         }
1869
1870         for (item=0; item < cChars; item++)
1871             if (pwLogClust[item] > max_clust)
1872             {
1873                 ERR("We do not handle non reversed clusters properly\n");
1874                 break;
1875             }
1876     }
1877
1878     if (iX < 0)
1879     {
1880         *piCP = -1;
1881         *piTrailing = 1;
1882         return S_OK;
1883     }
1884
1885     iPosX = iLastPosX = 0;
1886     if (direction > 0)
1887         item = 0;
1888     else
1889         item = cChars - 1;
1890     for (; iPosX <= iX && item < cChars && item >= 0; item+=direction)
1891     {
1892         iLastPosX = iPosX;
1893         if (iSpecial == -1 &&
1894              (iCluster == -1 ||
1895               (iCluster != -1 &&
1896                  ((direction > 0 && iCluster+clust_size <= item) ||
1897                   (direction < 0 && iCluster-clust_size >= item))
1898               )
1899              )
1900             )
1901         {
1902             int check;
1903             int clust = pwLogClust[item];
1904
1905             iCluster = -1;
1906             cjump = 0;
1907             clust_size = get_cluster_size(pwLogClust, cChars, item, direction,
1908                                           &iCluster, &check);
1909             advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, direction);
1910
1911             if (check >= cChars && direction > 0)
1912             {
1913                 for (check = clust; check < cChars; check++)
1914                     special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, direction);
1915                 iSpecial = item;
1916                 special_size /= (cChars - item);
1917                 iPosX += special_size;
1918             }
1919             else
1920             {
1921                 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1922                 {
1923                     if (!cjump)
1924                         iPosX += advance;
1925                     cjump++;
1926                 }
1927                 else
1928                     iPosX += advance / (float)clust_size;
1929             }
1930         }
1931         else if (iSpecial != -1)
1932             iPosX += special_size;
1933         else /* (iCluster != -1) */
1934         {
1935             int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], direction);
1936             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
1937             {
1938                 if (!cjump)
1939                     iPosX += adv;
1940                 cjump++;
1941             }
1942             else
1943                 iPosX += adv / (float)clust_size;
1944         }
1945     }
1946
1947     if (direction > 0)
1948     {
1949         if (iPosX > iX)
1950             item--;
1951         if (item < cChars && ((iPosX - iLastPosX) / 2.0) + iX >= iPosX)
1952         {
1953             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
1954                 item+=(clust_size-1);
1955             *piTrailing = 1;
1956         }
1957         else
1958             *piTrailing = 0;
1959     }
1960     else
1961     {
1962         if (iX == iLastPosX)
1963             item++;
1964         if (iX >= iLastPosX && iX <= iPosX)
1965             item++;
1966
1967         if (iLastPosX == iX)
1968             *piTrailing = 0;
1969         else if (item < 0 || ((iLastPosX - iPosX) / 2.0) + iX <= iLastPosX)
1970         {
1971             if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
1972                 item-=(clust_size-1);
1973             *piTrailing = 1;
1974         }
1975         else
1976             *piTrailing = 0;
1977     }
1978
1979     *piCP = item;
1980
1981     TRACE("*piCP=%d\n", *piCP);
1982     TRACE("*piTrailing=%d\n", *piTrailing);
1983     return S_OK;
1984 }
1985
1986 /***********************************************************************
1987  *      ScriptBreak (USP10.@)
1988  *
1989  *  Retrieve line break information.
1990  *
1991  *  PARAMS
1992  *   chars [I] Array of characters.
1993  *   sa    [I] String analysis.
1994  *   la    [I] Array of logical attribute structures.
1995  *
1996  *  RETURNS
1997  *   Success: S_OK
1998  *   Failure: S_FALSE
1999  */
2000 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2001 {
2002     TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2003
2004     if (!la) return S_FALSE;
2005
2006     BREAK_line(chars, count, sa, la);
2007
2008     return S_OK;
2009 }
2010
2011 /***********************************************************************
2012  *      ScriptIsComplex (USP10.@)
2013  *
2014  *  Determine if a string is complex.
2015  *
2016  *  PARAMS
2017  *   chars [I] Array of characters to test.
2018  *   len   [I] Length in characters.
2019  *   flag  [I] Flag.
2020  *
2021  *  RETURNS
2022  *   Success: S_OK
2023  *   Failure: S_FALSE
2024  *
2025  */
2026 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
2027 {
2028     int i;
2029
2030     TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
2031
2032     for (i = 0; i < len; i++)
2033     {
2034         int script;
2035
2036         if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
2037             return S_OK;
2038
2039         script = get_char_script(chars[i]);
2040         if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
2041             (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
2042             return S_OK;
2043     }
2044     return S_FALSE;
2045 }
2046
2047 /***********************************************************************
2048  *      ScriptShapeOpenType (USP10.@)
2049  *
2050  * Produce glyphs and visual attributes for a run.
2051  *
2052  * PARAMS
2053  *  hdc         [I]   Device context.
2054  *  psc         [I/O] Opaque pointer to a script cache.
2055  *  psa         [I/O] Script analysis.
2056  *  tagScript   [I]   The OpenType tag for the Script
2057  *  tagLangSys  [I]   The OpenType tag for the Language
2058  *  rcRangeChars[I]   Array of Character counts in each range
2059  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2060  *  cRanges     [I]   Count of ranges
2061  *  pwcChars    [I]   Array of characters specifying the run.
2062  *  cChars      [I]   Number of characters in pwcChars.
2063  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
2064  *  pwLogClust  [O]   Array of logical cluster info.
2065  *  pCharProps  [O]   Array of character property values
2066  *  pwOutGlyphs [O]   Array of glyphs.
2067  *  pOutGlyphProps [O]  Array of attributes for the retrieved glyphs
2068  *  pcGlyphs    [O]   Number of glyphs returned.
2069  *
2070  * RETURNS
2071  *  Success: S_OK
2072  *  Failure: Non-zero HRESULT value.
2073  */
2074 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
2075                                     SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2076                                     OPENTYPE_TAG tagLangSys, int *rcRangeChars,
2077                                     TEXTRANGE_PROPERTIES **rpRangeProperties,
2078                                     int cRanges, const WCHAR *pwcChars, int cChars,
2079                                     int cMaxGlyphs, WORD *pwLogClust,
2080                                     SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
2081                                     SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
2082 {
2083     HRESULT hr;
2084     unsigned int i;
2085     BOOL rtl;
2086
2087     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
2088      hdc, psc, psa,
2089      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2090      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2091      cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
2092
2093     if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
2094                    psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
2095
2096     if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
2097     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2098
2099     if (cRanges)
2100         FIXME("Ranges not supported yet\n");
2101
2102     rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
2103
2104     *pcGlyphs = cChars;
2105     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2106     if (!pwLogClust) return E_FAIL;
2107
2108     ((ScriptCache *)*psc)->userScript = tagScript;
2109     ((ScriptCache *)*psc)->userLang = tagLangSys;
2110
2111     /* set fNoGlyphIndex non truetype/opentype fonts */
2112     if (!psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
2113         psa->fNoGlyphIndex = TRUE;
2114
2115     /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
2116     for (i = 0; i < cChars; i++)
2117     {
2118         int idx = i;
2119         if (rtl) idx = cChars - 1 - i;
2120         /* FIXME: set to better values */
2121         pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
2122         pOutGlyphProps[i].sva.fClusterStart  = 1;
2123         pOutGlyphProps[i].sva.fDiacritic     = 0;
2124         pOutGlyphProps[i].sva.fZeroWidth     = 0;
2125         pOutGlyphProps[i].sva.fReserved      = 0;
2126         pOutGlyphProps[i].sva.fShapeReserved = 0;
2127
2128         /* FIXME: have the shaping engine set this */
2129         pCharProps[i].fCanGlyphAlone = 0;
2130
2131         pwLogClust[i] = idx;
2132     }
2133
2134     if (psa && !psa->fNoGlyphIndex)
2135     {
2136         WCHAR *rChars;
2137         if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
2138
2139         rChars = heap_alloc(sizeof(WCHAR) * cChars);
2140         if (!rChars) return E_OUTOFMEMORY;
2141         for (i = 0; i < cChars; i++)
2142         {
2143             int idx = i;
2144             WCHAR chInput;
2145             if (rtl) idx = cChars - 1 - i;
2146             if (psa->fRTL)
2147                 chInput = mirror_char(pwcChars[idx]);
2148             else
2149                 chInput = pwcChars[idx];
2150             /* special case for tabs */
2151             if (chInput == 0x0009)
2152                 chInput = 0x0020;
2153             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, chInput)))
2154             {
2155                 WORD glyph;
2156                 if (!hdc) return E_PENDING;
2157                 if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR) return S_FALSE;
2158                 pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph);
2159             }
2160             rChars[i] = chInput;
2161         }
2162
2163         SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2164         SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
2165         SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
2166         heap_free(rChars);
2167     }
2168     else
2169     {
2170         TRACE("no glyph translation\n");
2171         for (i = 0; i < cChars; i++)
2172         {
2173             int idx = i;
2174             /* No mirroring done here */
2175             if (rtl) idx = cChars - 1 - i;
2176             pwOutGlyphs[i] = pwcChars[idx];
2177         }
2178     }
2179
2180     return S_OK;
2181 }
2182
2183
2184 /***********************************************************************
2185  *      ScriptShape (USP10.@)
2186  *
2187  * Produce glyphs and visual attributes for a run.
2188  *
2189  * PARAMS
2190  *  hdc         [I]   Device context.
2191  *  psc         [I/O] Opaque pointer to a script cache.
2192  *  pwcChars    [I]   Array of characters specifying the run.
2193  *  cChars      [I]   Number of characters in pwcChars.
2194  *  cMaxGlyphs  [I]   Length of pwOutGlyphs.
2195  *  psa         [I/O] Script analysis.
2196  *  pwOutGlyphs [O]   Array of glyphs.
2197  *  pwLogClust  [O]   Array of logical cluster info.
2198  *  psva        [O]   Array of visual attributes.
2199  *  pcGlyphs    [O]   Number of glyphs returned.
2200  *
2201  * RETURNS
2202  *  Success: S_OK
2203  *  Failure: Non-zero HRESULT value.
2204  */
2205 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
2206                            int cChars, int cMaxGlyphs,
2207                            SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
2208                            SCRIPT_VISATTR *psva, int *pcGlyphs)
2209 {
2210     HRESULT hr;
2211     int i;
2212     SCRIPT_CHARPROP *charProps;
2213     SCRIPT_GLYPHPROP *glyphProps;
2214
2215     if (!psva || !pcGlyphs) return E_INVALIDARG;
2216     if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2217
2218     charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
2219     if (!charProps) return E_OUTOFMEMORY;
2220     glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
2221     if (!glyphProps) return E_OUTOFMEMORY;
2222
2223     hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
2224
2225     if (SUCCEEDED(hr))
2226     {
2227         for (i = 0; i < *pcGlyphs; i++)
2228             psva[i] = glyphProps[i].sva;
2229     }
2230
2231     heap_free(charProps);
2232     heap_free(glyphProps);
2233
2234     return hr;
2235 }
2236
2237 /***********************************************************************
2238  *      ScriptPlaceOpenType (USP10.@)
2239  *
2240  * Produce advance widths for a run.
2241  *
2242  * PARAMS
2243  *  hdc       [I]   Device context.
2244  *  psc       [I/O] Opaque pointer to a script cache.
2245  *  psa       [I/O] String analysis.
2246  *  tagScript   [I]   The OpenType tag for the Script
2247  *  tagLangSys  [I]   The OpenType tag for the Language
2248  *  rcRangeChars[I]   Array of Character counts in each range
2249  *  rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2250  *  cRanges     [I]   Count of ranges
2251  *  pwcChars    [I]   Array of characters specifying the run.
2252  *  pwLogClust  [I]   Array of logical cluster info
2253  *  pCharProps  [I]   Array of character property values
2254  *  cChars      [I]   Number of characters in pwcChars.
2255  *  pwGlyphs  [I]   Array of glyphs.
2256  *  pGlyphProps [I]  Array of attributes for the retrieved glyphs
2257  *  cGlyphs [I] Count of Glyphs
2258  *  piAdvance [O]   Array of advance widths.
2259  *  pGoffset  [O]   Glyph offsets.
2260  *  pABC      [O]   Combined ABC width.
2261  *
2262  * RETURNS
2263  *  Success: S_OK
2264  *  Failure: Non-zero HRESULT value.
2265  */
2266
2267 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
2268                                     OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
2269                                     int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
2270                                     int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
2271                                     SCRIPT_CHARPROP *pCharProps, int cChars,
2272                                     const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
2273                                     int cGlyphs, int *piAdvance,
2274                                     GOFFSET *pGoffset, ABC *pABC
2275 )
2276 {
2277     HRESULT hr;
2278     int i;
2279
2280     TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
2281      hdc, psc, psa,
2282      debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2283      rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2284      pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
2285      pGoffset, pABC);
2286
2287     if (!pGlyphProps) return E_INVALIDARG;
2288     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2289     if (!pGoffset) return E_FAIL;
2290
2291     if (cRanges)
2292         FIXME("Ranges not supported yet\n");
2293
2294     ((ScriptCache *)*psc)->userScript = tagScript;
2295     ((ScriptCache *)*psc)->userLang = tagLangSys;
2296
2297     if (pABC) memset(pABC, 0, sizeof(ABC));
2298     for (i = 0; i < cGlyphs; i++)
2299     {
2300         ABC abc;
2301         if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
2302         {
2303             if (!hdc) return E_PENDING;
2304             if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
2305             {
2306                 if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
2307             }
2308             else
2309             {
2310                 INT width;
2311                 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
2312                 abc.abcB = width;
2313                 abc.abcA = abc.abcC = 0;
2314             }
2315             set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
2316         }
2317         if (pABC)
2318         {
2319             pABC->abcA += abc.abcA;
2320             pABC->abcB += abc.abcB;
2321             pABC->abcC += abc.abcC;
2322         }
2323         /* FIXME: set to more reasonable values */
2324         pGoffset[i].du = pGoffset[i].dv = 0;
2325         if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
2326     }
2327
2328     if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
2329     return S_OK;
2330 }
2331
2332 /***********************************************************************
2333  *      ScriptPlace (USP10.@)
2334  *
2335  * Produce advance widths for a run.
2336  *
2337  * PARAMS
2338  *  hdc       [I]   Device context.
2339  *  psc       [I/O] Opaque pointer to a script cache.
2340  *  pwGlyphs  [I]   Array of glyphs.
2341  *  cGlyphs   [I]   Number of glyphs in pwGlyphs.
2342  *  psva      [I]   Array of visual attributes.
2343  *  psa       [I/O] String analysis.
2344  *  piAdvance [O]   Array of advance widths.
2345  *  pGoffset  [O]   Glyph offsets.
2346  *  pABC      [O]   Combined ABC width.
2347  *
2348  * RETURNS
2349  *  Success: S_OK
2350  *  Failure: Non-zero HRESULT value.
2351  */
2352 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
2353                            int cGlyphs, const SCRIPT_VISATTR *psva,
2354                            SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
2355 {
2356     HRESULT hr;
2357     SCRIPT_GLYPHPROP *glyphProps;
2358     int i;
2359
2360     TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n",  hdc, psc, pwGlyphs, cGlyphs, psva, psa,
2361           piAdvance, pGoffset, pABC);
2362
2363     if (!psva) return E_INVALIDARG;
2364     if (!pGoffset) return E_FAIL;
2365
2366     glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
2367     if (!glyphProps) return E_OUTOFMEMORY;
2368
2369     for (i = 0; i < cGlyphs; i++)
2370         glyphProps[i].sva = psva[i];
2371
2372     hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
2373
2374     heap_free(glyphProps);
2375
2376     return hr;
2377 }
2378
2379 /***********************************************************************
2380  *      ScriptGetCMap (USP10.@)
2381  *
2382  * Retrieve glyph indices.
2383  *
2384  * PARAMS
2385  *  hdc         [I]   Device context.
2386  *  psc         [I/O] Opaque pointer to a script cache.
2387  *  pwcInChars  [I]   Array of Unicode characters.
2388  *  cChars      [I]   Number of characters in pwcInChars.
2389  *  dwFlags     [I]   Flags.
2390  *  pwOutGlyphs [O]   Buffer to receive the array of glyph indices.
2391  *
2392  * RETURNS
2393  *  Success: S_OK
2394  *  Failure: Non-zero HRESULT value.
2395  */
2396 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
2397                              int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
2398 {
2399     HRESULT hr;
2400     int i;
2401
2402     TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
2403           cChars, dwFlags, pwOutGlyphs);
2404
2405     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2406
2407     hr = S_OK;
2408
2409     if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2410     {
2411         for (i = 0; i < cChars; i++)
2412         {
2413             WCHAR inChar;
2414             if (dwFlags == SGCM_RTL)
2415                 inChar = mirror_char(pwcInChars[i]);
2416             else
2417                 inChar = pwcInChars[i];
2418             if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
2419             {
2420                 WORD glyph;
2421                 if (!hdc) return E_PENDING;
2422                 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
2423                 if (glyph == 0xffff)
2424                 {
2425                     hr = S_FALSE;
2426                     glyph = 0x0;
2427                 }
2428                 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
2429             }
2430         }
2431     }
2432     else
2433     {
2434         TRACE("no glyph translation\n");
2435         for (i = 0; i < cChars; i++)
2436         {
2437             WCHAR inChar;
2438             if (dwFlags == SGCM_RTL)
2439                 inChar = mirror_char(pwcInChars[i]);
2440             else
2441                 inChar = pwcInChars[i];
2442             pwOutGlyphs[i] = inChar;
2443         }
2444     }
2445     return hr;
2446 }
2447
2448 /***********************************************************************
2449  *      ScriptTextOut (USP10.@)
2450  *
2451  */
2452 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions, 
2453                              const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved, 
2454                              int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
2455                              const int *piJustify, const GOFFSET *pGoffset)
2456 {
2457     HRESULT hr = S_OK;
2458
2459     TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
2460          hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
2461          piAdvance, piJustify, pGoffset);
2462
2463     if (!hdc || !psc) return E_INVALIDARG;
2464     if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
2465
2466     fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
2467     fuOptions |= ETO_IGNORELANGUAGE;
2468     if  (!psa->fNoGlyphIndex)                                     /* Have Glyphs?                      */
2469         fuOptions |= ETO_GLYPH_INDEX;                             /* Say don't do translation to glyph */
2470
2471     if (psa->fRTL && psa->fLogicalOrder)
2472     {
2473         int i;
2474         WORD *rtlGlyphs;
2475
2476         rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD));
2477         if (!rtlGlyphs)
2478             return E_OUTOFMEMORY;
2479
2480         for (i = 0; i < cGlyphs; i++)
2481             rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i];
2482
2483         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL))
2484             hr = S_FALSE;
2485         heap_free(rtlGlyphs);
2486     }
2487     else
2488         if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
2489             hr = S_FALSE;
2490
2491     return hr;
2492 }
2493
2494 /***********************************************************************
2495  *      ScriptCacheGetHeight (USP10.@)
2496  *
2497  * Retrieve the height of the font in the cache.
2498  *
2499  * PARAMS
2500  *  hdc    [I]    Device context.
2501  *  psc    [I/O]  Opaque pointer to a script cache.
2502  *  height [O]    Receives font height.
2503  *
2504  * RETURNS
2505  *  Success: S_OK
2506  *  Failure: Non-zero HRESULT value.
2507  */
2508 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
2509 {
2510     HRESULT hr;
2511
2512     TRACE("(%p, %p, %p)\n", hdc, psc, height);
2513
2514     if (!height) return E_INVALIDARG;
2515     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2516
2517     *height = get_cache_height(psc);
2518     return S_OK;
2519 }
2520
2521 /***********************************************************************
2522  *      ScriptGetGlyphABCWidth (USP10.@)
2523  *
2524  * Retrieve the width of a glyph.
2525  *
2526  * PARAMS
2527  *  hdc    [I]    Device context.
2528  *  psc    [I/O]  Opaque pointer to a script cache.
2529  *  glyph  [I]    Glyph to retrieve the width for.
2530  *  abc    [O]    ABC widths of the glyph.
2531  *
2532  * RETURNS
2533  *  Success: S_OK
2534  *  Failure: Non-zero HRESULT value.
2535  */
2536 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
2537 {
2538     HRESULT hr;
2539
2540     TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
2541
2542     if (!abc) return E_INVALIDARG;
2543     if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2544
2545     if (!get_cache_glyph_widths(psc, glyph, abc))
2546     {
2547         if (!hdc) return E_PENDING;
2548         if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2549         {
2550             if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
2551         }
2552         else
2553         {
2554             INT width;
2555             if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
2556             abc->abcB = width;
2557             abc->abcA = abc->abcC = 0;
2558         }
2559         set_cache_glyph_widths(psc, glyph, abc);
2560     }
2561     return S_OK;
2562 }
2563
2564 /***********************************************************************
2565  *      ScriptLayout (USP10.@)
2566  *
2567  * Map embedding levels to visual and/or logical order.
2568  *
2569  * PARAMS
2570  *  runs     [I] Size of level array.
2571  *  level    [I] Array of embedding levels.
2572  *  vistolog [O] Map of embedding levels from visual to logical order.
2573  *  logtovis [O] Map of embedding levels from logical to visual order.
2574  *
2575  * RETURNS
2576  *  Success: S_OK
2577  *  Failure: Non-zero HRESULT value.
2578  *
2579  * BUGS
2580  *  This stub works correctly for any sequence of a single
2581  *  embedding level but not for sequences of different
2582  *  embedding levels, i.e. mixtures of RTL and LTR scripts.
2583  */
2584 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
2585 {
2586     int* indexs;
2587     int ich;
2588
2589     TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
2590
2591     if (!level || (!vistolog && !logtovis))
2592         return E_INVALIDARG;
2593
2594     indexs = heap_alloc(sizeof(int) * runs);
2595     if (!indexs)
2596         return E_OUTOFMEMORY;
2597
2598
2599     if (vistolog)
2600     {
2601         for( ich = 0; ich < runs; ich++)
2602             indexs[ich] = ich;
2603
2604         ich = 0;
2605         while (ich < runs)
2606             ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2607         for (ich = 0; ich < runs; ich++)
2608             vistolog[ich] = indexs[ich];
2609     }
2610
2611
2612     if (logtovis)
2613     {
2614         for( ich = 0; ich < runs; ich++)
2615             indexs[ich] = ich;
2616
2617         ich = 0;
2618         while (ich < runs)
2619             ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2620         for (ich = 0; ich < runs; ich++)
2621             logtovis[ich] = indexs[ich];
2622     }
2623     heap_free(indexs);
2624
2625     return S_OK;
2626 }
2627
2628 /***********************************************************************
2629  *      ScriptStringGetLogicalWidths (USP10.@)
2630  *
2631  * Returns logical widths from a string analysis.
2632  *
2633  * PARAMS
2634  *  ssa  [I] string analysis.
2635  *  piDx [O] logical widths returned.
2636  *
2637  * RETURNS
2638  *  Success: S_OK
2639  *  Failure: a non-zero HRESULT.
2640  */
2641 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
2642 {
2643     int i, j, next = 0;
2644     StringAnalysis *analysis = ssa;
2645
2646     TRACE("%p, %p\n", ssa, piDx);
2647
2648     if (!analysis) return S_FALSE;
2649     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2650
2651     for (i = 0; i < analysis->numItems; i++)
2652     {
2653         int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2654         int direction = 1;
2655
2656         if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
2657             direction = -1;
2658
2659         for (j = 0; j < cChar; j++)
2660         {
2661             int k;
2662             int glyph = analysis->glyphs[i].pwLogClust[j];
2663             int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
2664                                               cChar, j, direction, NULL, NULL);
2665             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);
2666
2667             for (k = 0; k < clust_size; k++)
2668             {
2669                 piDx[next] = advance / clust_size;
2670                 next++;
2671                 if (k) j++;
2672             }
2673         }
2674     }
2675     return S_OK;
2676 }
2677
2678 /***********************************************************************
2679  *      ScriptStringValidate (USP10.@)
2680  *
2681  * Validate a string analysis.
2682  *
2683  * PARAMS
2684  *  ssa [I] string analysis.
2685  *
2686  * RETURNS
2687  *  Success: S_OK
2688  *  Failure: S_FALSE if invalid sequences are found
2689  *           or a non-zero HRESULT if it fails.
2690  */
2691 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
2692 {
2693     StringAnalysis *analysis = ssa;
2694
2695     TRACE("(%p)\n", ssa);
2696
2697     if (!analysis) return E_INVALIDARG;
2698     return (analysis->invalid) ? S_FALSE : S_OK;
2699 }
2700
2701 /***********************************************************************
2702  *      ScriptString_pSize (USP10.@)
2703  *
2704  * Retrieve width and height of an analysed string.
2705  *
2706  * PARAMS
2707  *  ssa [I] string analysis.
2708  *
2709  * RETURNS
2710  *  Success: Pointer to a SIZE structure.
2711  *  Failure: NULL
2712  */
2713 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
2714 {
2715     int i, j;
2716     StringAnalysis *analysis = ssa;
2717
2718     TRACE("(%p)\n", ssa);
2719
2720     if (!analysis) return NULL;
2721     if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
2722
2723     if (!analysis->sz)
2724     {
2725         if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
2726         analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
2727
2728         analysis->sz->cx = 0;
2729         for (i = 0; i < analysis->numItems; i++)
2730         {
2731             if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
2732                 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
2733             for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
2734                 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
2735         }
2736     }
2737     return analysis->sz;
2738 }
2739
2740 /***********************************************************************
2741  *      ScriptString_pLogAttr (USP10.@)
2742  *
2743  * Retrieve logical attributes of an analysed string.
2744  *
2745  * PARAMS
2746  *  ssa [I] string analysis.
2747  *
2748  * RETURNS
2749  *  Success: Pointer to an array of SCRIPT_LOGATTR structures.
2750  *  Failure: NULL
2751  */
2752 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
2753 {
2754     StringAnalysis *analysis = ssa;
2755
2756     TRACE("(%p)\n", ssa);
2757
2758     if (!analysis) return NULL;
2759     if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
2760     return analysis->logattrs;
2761 }
2762
2763 /***********************************************************************
2764  *      ScriptString_pcOutChars (USP10.@)
2765  *
2766  * Retrieve the length of a string after clipping.
2767  *
2768  * PARAMS
2769  *  ssa [I] String analysis.
2770  *
2771  * RETURNS
2772  *  Success: Pointer to the length.
2773  *  Failure: NULL
2774  */
2775 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
2776 {
2777     StringAnalysis *analysis = ssa;
2778
2779     TRACE("(%p)\n", ssa);
2780
2781     if (!analysis) return NULL;
2782     return &analysis->clip_len;
2783 }
2784
2785 /***********************************************************************
2786  *      ScriptStringGetOrder (USP10.@)
2787  *
2788  * Retrieve a glyph order map.
2789  *
2790  * PARAMS
2791  *  ssa   [I]   String analysis.
2792  *  order [I/O] Array of glyph positions.
2793  *
2794  * RETURNS
2795  *  Success: S_OK
2796  *  Failure: a non-zero HRESULT.
2797  */
2798 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
2799 {
2800     int i, j;
2801     unsigned int k;
2802     StringAnalysis *analysis = ssa;
2803
2804     TRACE("(%p)\n", ssa);
2805
2806     if (!analysis) return S_FALSE;
2807     if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2808
2809     /* FIXME: handle RTL scripts */
2810     for (i = 0, k = 0; i < analysis->numItems; i++)
2811         for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
2812             order[k] = k;
2813
2814     return S_OK;
2815 }
2816
2817 /***********************************************************************
2818  *      ScriptGetLogicalWidths (USP10.@)
2819  *
2820  * Convert advance widths to logical widths.
2821  *
2822  * PARAMS
2823  *  sa          [I] Script analysis.
2824  *  nbchars     [I] Number of characters.
2825  *  nbglyphs    [I] Number of glyphs.
2826  *  glyph_width [I] Array of glyph widths.
2827  *  log_clust   [I] Array of logical clusters.
2828  *  sva         [I] Visual attributes.
2829  *  widths      [O] Array of logical widths.
2830  *
2831  * RETURNS
2832  *  Success: S_OK
2833  *  Failure: a non-zero HRESULT.
2834  */
2835 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
2836                                       const int *glyph_width, const WORD *log_clust,
2837                                       const SCRIPT_VISATTR *sva, int *widths)
2838 {
2839     int i;
2840
2841     TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
2842           sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);
2843
2844     /* FIXME */
2845     for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
2846     return S_OK;
2847 }
2848
2849 /***********************************************************************
2850  *      ScriptApplyLogicalWidth (USP10.@)
2851  *
2852  * Generate glyph advance widths.
2853  *
2854  * PARAMS
2855  *  dx          [I]   Array of logical advance widths.
2856  *  num_chars   [I]   Number of characters.
2857  *  num_glyphs  [I]   Number of glyphs.
2858  *  log_clust   [I]   Array of logical clusters.
2859  *  sva         [I]   Visual attributes.
2860  *  advance     [I]   Array of glyph advance widths.
2861  *  sa          [I]   Script analysis.
2862  *  abc         [I/O] Summed ABC widths.
2863  *  justify     [O]   Array of glyph advance widths.
2864  *
2865  * RETURNS
2866  *  Success: S_OK
2867  *  Failure: a non-zero HRESULT.
2868  */
2869 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
2870                                        const WORD *log_clust, const SCRIPT_VISATTR *sva,
2871                                        const int *advance, const SCRIPT_ANALYSIS *sa,
2872                                        ABC *abc, int *justify)
2873 {
2874     int i;
2875
2876     FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
2877           dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
2878
2879     for (i = 0; i < num_chars; i++) justify[i] = advance[i];
2880     return S_OK;
2881 }
2882
2883 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
2884                              int num_glyphs, int dx, int min_kashida, int *justify)
2885 {
2886     int i;
2887
2888     FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
2889
2890     for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
2891     return S_OK;
2892 }