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