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