usp10: Add New Tai Lue script.
[wine/multimedia.git] / dlls / usp10 / usp10.c
blob846d03c300a03d8b0f62b5b30506bc69ad7bc06e
1 /*
2 * Implementation of Uniscribe Script Processor (usp10.dll)
4 * Copyright 2005 Steven Edwards for CodeWeavers
5 * Copyright 2006 Hans Leidekker
6 * Copyright 2010 CodeWeavers, Aric Stewart
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.
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.
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
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.
27 #include <stdarg.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winnls.h"
34 #include "winreg.h"
35 #include "usp10.h"
37 #include "usp10_internal.h"
39 #include "wine/debug.h"
40 #include "wine/unicode.h"
42 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
44 typedef struct _scriptRange
46 WORD script;
47 WORD rangeFirst;
48 WORD rangeLast;
49 WORD numericScript;
50 WORD punctScript;
51 } scriptRange;
53 static const scriptRange scriptRanges[] = {
54 /* Basic Latin: U+0000–U+007A */
55 { Script_Latin, 0x00, 0x07a , Script_Numeric, Script_Punctuation},
56 /* Latin-1 Supplement: U+0080–U+00FF */
57 /* Latin Extended-A: U+0100–U+017F */
58 /* Latin Extended-B: U+0180–U+024F */
59 /* IPA Extensions: U+0250–U+02AF */
60 { Script_Latin, 0x80, 0x2af , Script_Numeric2, Script_Punctuation},
61 /* Combining Diacritical Marks : U+0300–U+036F */
62 { Script_Diacritical,0x300, 0x36f, 0, 0},
63 /* Greek: U+0370–U+03FF */
64 { Script_Greek, 0x370, 0x3ff, 0, 0},
65 /* Cyrillic: U+0400–U+04FF */
66 /* Cyrillic Supplement: U+0500–U+052F */
67 { Script_Cyrillic, 0x400, 0x52f, 0, 0},
68 /* Armenian: U+0530–U+058F */
69 { Script_Armenian, 0x530, 0x58f, 0, 0},
70 /* Hebrew: U+0590–U+05FF */
71 { Script_Hebrew, 0x590, 0x5ff, 0, 0},
72 /* Arabic: U+0600–U+06FF */
73 { Script_Arabic, 0x600, 0x6ef, Script_Arabic_Numeric, 0},
74 /* Defined by Windows */
75 { Script_Persian, 0x6f0, 0x6f9, 0, 0},
76 /* Continue Arabic: U+0600–U+06FF */
77 { Script_Arabic, 0x6fa, 0x6ff, 0, 0},
78 /* Syriac: U+0700–U+074F*/
79 { Script_Syriac, 0x700, 0x74f, 0, 0},
80 /* Arabic Supplement: U+0750–U+077F */
81 { Script_Arabic, 0x750, 0x77f, 0, 0},
82 /* Thaana: U+0780–U+07BF */
83 { Script_Thaana, 0x780, 0x7bf, 0, 0},
84 /* Devanagari: U+0900–U+097F */
85 { Script_Devanagari, 0x900, 0x97f, Script_Devanagari_Numeric, 0},
86 /* Bengali: U+0980–U+09FF */
87 { Script_Bengali, 0x980, 0x9ff, Script_Bengali_Numeric, 0},
88 /* Gurmukhi: U+0A00–U+0A7F*/
89 { Script_Gurmukhi, 0xa00, 0xa7f, Script_Gurmukhi_Numeric, 0},
90 /* Gujarati: U+0A80–U+0AFF*/
91 { Script_Gujarati, 0xa80, 0xaff, Script_Gujarati_Numeric, 0},
92 /* Oriya: U+0B00–U+0B7F */
93 { Script_Oriya, 0xb00, 0xb7f, Script_Oriya_Numeric, 0},
94 /* Tamil: U+0B80–U+0BFF */
95 { Script_Tamil, 0xb80, 0xbff, Script_Tamil_Numeric, 0},
96 /* Telugu: U+0C00–U+0C7F */
97 { Script_Telugu, 0xc00, 0xc7f, Script_Telugu_Numeric, 0},
98 /* Kannada: U+0C80–U+0CFF */
99 { Script_Kannada, 0xc80, 0xcff, Script_Kannada_Numeric, 0},
100 /* Malayalam: U+0D00–U+0D7F */
101 { Script_Malayalam, 0xd00, 0xd7f, Script_Malayalam_Numeric, 0},
102 /* Sinhala: U+0D80–U+0DFF */
103 { Script_Sinhala, 0xd80, 0xdff, 0, 0},
104 /* Thai: U+0E00–U+0E7F */
105 { Script_Thai, 0xe00, 0xe7f, Script_Thai_Numeric, 0},
106 /* Lao: U+0E80–U+0EFF */
107 { Script_Lao, 0xe80, 0xeff, Script_Lao_Numeric, 0},
108 /* Tibetan: U+0F00–U+0FFF */
109 { Script_Tibetan, 0xf00, 0xfff, 0, 0},
110 /* Myanmar: U+1000–U+109F */
111 { Script_Myanmar, 0x1000, 0x109f, Script_Myanmar_Numeric, 0},
112 /* Georgian: U+10A0–U+10FF */
113 { Script_Georgian, 0x10a0, 0x10ff, 0, 0},
114 /* Tai Le: U+1950–U+197F */
115 { Script_Tai_Le, 0x1950, 0x197f, 0, 0},
116 /* New Tai Lue: U+1980–U+19DF */
117 { Script_New_Tai_Lue,0x1980, 0x19df, Script_New_Tai_Lue_Numeric, 0},
118 /* Vedic Extensions: U+1CD0-U+1CFF */
119 { Script_Devanagari, 0x1cd0, 0x1cff, Script_Devanagari_Numeric, 0},
120 /* Phonetic Extensions: U+1D00–U+1DBF */
121 { Script_Latin, 0x1d00, 0x1dbf, 0, 0},
122 /* Combining Diacritical Marks Supplement: U+1DC0–U+1DFF */
123 { Script_Diacritical,0x1dc0, 0x1dff, 0, 0},
124 /* Latin Extended Additional: U+1E00–U+1EFF */
125 { Script_Latin, 0x1e00, 0x1eff, 0, 0},
126 /* Greek Extended: U+1F00–U+1FFF */
127 { Script_Greek, 0x1f00, 0x1fff, 0, 0},
128 /* General Punctuation: U+2000 –U+206f */
129 { Script_Latin, 0x2000, 0x206f, 0, 0},
130 /* Superscripts and Subscripts : U+2070 –U+209f */
131 /* Currency Symbols : U+20a0 –U+20cf */
132 { Script_Numeric2, 0x2070, 0x2070, 0, 0},
133 { Script_Latin, 0x2071, 0x2073, 0, 0},
134 { Script_Numeric2, 0x2074, 0x2079, 0, 0},
135 { Script_Latin, 0x207a, 0x207f, 0, 0},
136 { Script_Numeric2, 0x2080, 0x2089, 0, 0},
137 { Script_Latin, 0x208a, 0x20cf, 0, 0},
138 /* Letterlike Symbols : U+2100 –U+214f */
139 /* Number Forms : U+2150 –U+218f */
140 /* Arrows : U+2190 –U+21ff */
141 /* Mathematical Operators : U+2200 –U+22ff */
142 /* Miscellaneous Technical : U+2300 –U+23ff */
143 /* Control Pictures : U+2400 –U+243f */
144 /* Optical Character Recognition : U+2440 –U+245f */
145 /* Enclosed Alphanumerics : U+2460 –U+24ff */
146 /* Box Drawing : U+2500 –U+25ff */
147 /* Block Elements : U+2580 –U+259f */
148 /* Geometric Shapes : U+25a0 –U+25ff */
149 /* Miscellaneous Symbols : U+2600 –U+26ff */
150 /* Dingbats : U+2700 –U+27bf */
151 /* Miscellaneous Mathematical Symbols-A : U+27c0 –U+27ef */
152 /* Supplemental Arrows-A : U+27f0 –U+27ff */
153 { Script_Latin, 0x2100, 0x27ff, 0, 0},
154 /* Supplemental Arrows-B : U+2900 –U+297f */
155 /* Miscellaneous Mathematical Symbols-B : U+2980 –U+29ff */
156 /* Supplemental Mathematical Operators : U+2a00 –U+2aff */
157 /* Miscellaneous Symbols and Arrows : U+2b00 –U+2bff */
158 { Script_Latin, 0x2900, 0x2bff, 0, 0},
159 /* Latin Extended-C: U+2C60–U+2C7F */
160 { Script_Latin, 0x2c60, 0x2c7f, 0, 0},
161 /* Georgian: U+2D00–U+2D2F */
162 { Script_Georgian, 0x2d00, 0x2d2f, 0, 0},
163 /* Cyrillic Extended-A: U+2DE0–U+2DFF */
164 { Script_Cyrillic, 0x2de0, 0x2dff, 0, 0},
165 /* Cyrillic Extended-B: U+A640–U+A69F */
166 { Script_Cyrillic, 0xa640, 0xa69f, 0, 0},
167 /* Modifier Tone Letters: U+A700–U+A71F */
168 /* Latin Extended-D: U+A720–U+A7FF */
169 { Script_Latin, 0xa700, 0xa7ff, 0, 0},
170 /* Phags-pa: U+A840–U+A87F */
171 { Script_Phags_pa, 0xa840, 0xa87f, 0, 0},
172 /* Devanagari Extended: U+A8E0-U+A8FF */
173 { Script_Devanagari, 0xa8e0, 0xa8ff, Script_Devanagari_Numeric, 0},
174 /* Myanmar Extended-A: U+AA60–U+AA7F */
175 { Script_Myanmar, 0xaa60, 0xaa7f, Script_Myanmar_Numeric, 0},
176 /* Latin Ligatures: U+FB00–U+FB06 */
177 { Script_Latin, 0xfb00, 0xfb06, 0, 0},
178 /* Armenian ligatures U+FB13..U+FB17 */
179 { Script_Armenian, 0xfb13, 0xfb17, 0, 0},
180 /* Alphabetic Presentation Forms: U+FB1D–U+FB4F */
181 { Script_Hebrew, 0xfb1d, 0xfb4f, 0, 0},
182 /* Arabic Presentation Forms-A: U+FB50–U+FDFF*/
183 { Script_Arabic, 0xfb50, 0xfdff, 0, 0},
184 /* Arabic Presentation Forms-B: U+FE70–U+FEFF*/
185 { Script_Arabic, 0xfe70, 0xfeff, 0, 0},
186 /* END */
187 { SCRIPT_UNDEFINED, 0, 0, 0}
190 typedef struct _scriptData
192 SCRIPT_ANALYSIS a;
193 SCRIPT_PROPERTIES props;
194 OPENTYPE_TAG scriptTag;
195 WCHAR fallbackFont[LF_FACESIZE];
196 } scriptData;
198 /* the must be in order so that the index matches the Script value */
199 static const scriptData scriptInformation[] = {
200 {{SCRIPT_UNDEFINED, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
201 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
202 0x00000000,
203 {0}},
204 {{Script_Latin, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
205 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
206 MS_MAKE_TAG('l','a','t','n'),
207 {0}},
208 {{Script_CR, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
209 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
210 0x00000000,
211 {0}},
212 {{Script_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
213 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
214 0x00000000,
215 {0}},
216 {{Script_Control, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
217 {LANG_ENGLISH, 0, 1, 0, 0, ANSI_CHARSET, 1, 0, 0, 0, 0, 0, 1, 0, 0},
218 0x00000000,
219 {0}},
220 {{Script_Punctuation, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
221 {LANG_NEUTRAL, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
222 0x00000000,
223 {0}},
224 {{Script_Arabic, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
225 {LANG_ARABIC, 0, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 1, 0},
226 MS_MAKE_TAG('a','r','a','b'),
227 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
228 {{Script_Arabic_Numeric, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
229 {LANG_ARABIC, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
230 MS_MAKE_TAG('a','r','a','b'),
231 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
232 {{Script_Hebrew, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
233 {LANG_HEBREW, 0, 1, 0, 1, HEBREW_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
234 MS_MAKE_TAG('h','e','b','r'),
235 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
236 {{Script_Syriac, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
237 {LANG_SYRIAC, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 1, 0},
238 MS_MAKE_TAG('s','y','r','c'),
239 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
240 {{Script_Persian, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
241 {LANG_PERSIAN, 1, 1, 0, 0, ARABIC_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
242 MS_MAKE_TAG('s','y','r','c'),
243 {'E','s','t','r','a','n','g','e','l','o',' ','E','d','e','s','s','a',0}},
244 {{Script_Thaana, 1, 1, 0, 0, 0, 0, { 1,0,0,0,0,0,0,0,0,0,0}},
245 {LANG_DIVEHI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
246 MS_MAKE_TAG('t','h','a','a'),
247 {'M','V',' ','B','o','l','i',0}},
248 {{Script_Greek, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
249 {LANG_GREEK, 0, 0, 0, 0, GREEK_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
250 MS_MAKE_TAG('g','r','e','k'),
251 {0}},
252 {{Script_Cyrillic, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
253 {LANG_RUSSIAN, 0, 0, 0, 0, RUSSIAN_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
254 MS_MAKE_TAG('c','y','r','l'),
255 {0}},
256 {{Script_Armenian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
257 {LANG_ARMENIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
258 MS_MAKE_TAG('a','r','m','n'),
259 {'S','y','l','f','a','e','n',0}},
260 {{Script_Georgian, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
261 {LANG_GEORGIAN, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
262 MS_MAKE_TAG('g','e','o','r'),
263 {'S','y','l','f','a','e','n',0}},
264 {{Script_Sinhala, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
265 {LANG_SINHALESE, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
266 MS_MAKE_TAG('s','i','n','h'),
267 {'I','s','k','o','o','l','a',' ','P','o','t','a',0}},
268 {{Script_Tibetan, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
269 {LANG_TIBETAN, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
270 MS_MAKE_TAG('t','i','b','t'),
271 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
272 {{Script_Tibetan_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
273 {LANG_TIBETAN, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
274 MS_MAKE_TAG('t','i','b','t'),
275 {'M','i','c','r','o','s','o','f','t',' ','H','i','m','a','l','a','y','a',0}},
276 {{Script_Phags_pa, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
277 {LANG_MONGOLIAN, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
278 MS_MAKE_TAG('p','h','a','g'),
279 {'M','i','c','r','o','s','o','f','t',' ','P','h','a','g','s','P','a',0}},
280 {{Script_Thai, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
281 {LANG_THAI, 0, 1, 1, 1, THAI_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 1},
282 MS_MAKE_TAG('t','h','a','i'),
283 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
284 {{Script_Thai_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
285 {LANG_THAI, 1, 1, 0, 0, THAI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
286 MS_MAKE_TAG('t','h','a','i'),
287 {'M','i','c','r','o','s','o','f','t',' ','S','a','n','s',' ','S','e','r','i','f',0}},
288 {{Script_Lao, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
289 {LANG_LAO, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 1, 0, 1, 0, 0, 0, 0},
290 MS_MAKE_TAG('l','a','o',' '),
291 {'D','o','k','C','h','a','m','p','a',0}},
292 {{Script_Lao_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
293 {LANG_LAO, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
294 MS_MAKE_TAG('l','a','o',' '),
295 {'D','o','k','C','h','a','m','p','a',0}},
296 {{Script_Devanagari, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
297 {LANG_HINDI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
298 MS_MAKE_TAG('d','e','v','a'),
299 {'M','a','n','g','a','l',0}},
300 {{Script_Devanagari_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
301 {LANG_HINDI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
302 MS_MAKE_TAG('d','e','v','a'),
303 {'M','a','n','g','a','l',0}},
304 {{Script_Bengali, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
305 {LANG_BENGALI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
306 MS_MAKE_TAG('b','e','n','g'),
307 {'V','r','i','n','d','a',0}},
308 {{Script_Bengali_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
309 {LANG_BENGALI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
310 MS_MAKE_TAG('b','e','n','g'),
311 {'V','r','i','n','d','a',0}},
312 {{Script_Bengali_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
313 {LANG_BENGALI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
314 MS_MAKE_TAG('b','e','n','g'),
315 {'V','r','i','n','d','a',0}},
316 {{Script_Gurmukhi, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
317 {LANG_PUNJABI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
318 MS_MAKE_TAG('g','u','r','u'),
319 {'R','a','a','v','i',0}},
320 {{Script_Gurmukhi_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
321 {LANG_PUNJABI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
322 MS_MAKE_TAG('g','u','r','u'),
323 {'R','a','a','v','i',0}},
324 {{Script_Gujarati, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
325 {LANG_GUJARATI, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
326 MS_MAKE_TAG('g','u','j','r'),
327 {'S','h','r','u','t','i',0}},
328 {{Script_Gujarati_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
329 {LANG_GUJARATI, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
330 MS_MAKE_TAG('g','u','j','r'),
331 {'S','h','r','u','t','i',0}},
332 {{Script_Gujarati_Currency, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
333 {LANG_GUJARATI, 0, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
334 MS_MAKE_TAG('g','u','j','r'),
335 {'S','h','r','u','t','i',0}},
336 {{Script_Oriya, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
337 {LANG_ORIYA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
338 MS_MAKE_TAG('o','r','y','a'),
339 {'K','a','l','i','n','g','a',0}},
340 {{Script_Oriya_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
341 {LANG_ORIYA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
342 MS_MAKE_TAG('o','r','y','a'),
343 {'K','a','l','i','n','g','a',0}},
344 {{Script_Tamil, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
345 {LANG_TAMIL, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
346 MS_MAKE_TAG('t','a','m','l'),
347 {'L','a','t','h','a',0}},
348 {{Script_Tamil_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
349 {LANG_TAMIL, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
350 MS_MAKE_TAG('t','a','m','l'),
351 {'L','a','t','h','a',0}},
352 {{Script_Telugu, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
353 {LANG_TELUGU, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
354 MS_MAKE_TAG('t','e','l','u'),
355 {'G','a','u','t','a','m','i',0}},
356 {{Script_Telugu_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
357 {LANG_TELUGU, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
358 MS_MAKE_TAG('t','e','l','u'),
359 {'G','a','u','t','a','m','i',0}},
360 {{Script_Kannada, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
361 {LANG_KANNADA, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
362 MS_MAKE_TAG('k','n','d','a'),
363 {'T','u','n','g','a',0}},
364 {{Script_Kannada_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
365 {LANG_KANNADA, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
366 MS_MAKE_TAG('k','n','d','a'),
367 {'T','u','n','g','a',0}},
368 {{Script_Malayalam, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
369 {LANG_MALAYALAM, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
370 MS_MAKE_TAG('m','l','y','m'),
371 {'K','a','r','t','i','k','a',0}},
372 {{Script_Malayalam_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
373 {LANG_MALAYALAM, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
374 MS_MAKE_TAG('m','l','y','m'),
375 {'K','a','r','t','i','k','a',0}},
376 {{Script_Diacritical, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
377 {LANG_ENGLISH, 0, 1, 0, 1, ANSI_CHARSET, 0, 0, 0, 0, 0, 1, 1, 0, 0},
378 0x00000000,
379 {0}},
380 {{Script_Punctuation2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
381 {LANG_ENGLISH, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
382 MS_MAKE_TAG('l','a','t','n'),
383 {0}},
384 {{Script_Numeric2, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
385 {LANG_ENGLISH, 1, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, 0, 0, 1, 0, 0},
386 0x00000000,
387 {0}},
388 {{Script_Myanmar, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
389 {0x55, 0, 1, 1, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 1, 0, 0, 0, 0},
390 MS_MAKE_TAG('m','y','m','r'),
391 {0}},
392 {{Script_Myanmar_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
393 {0x55, 1, 1, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
394 MS_MAKE_TAG('m','y','m','r'),
395 {0}},
396 {{Script_Tai_Le, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
397 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
398 MS_MAKE_TAG('t','a','l','e'),
399 {'M','i','c','r','o','s','o','f','t',' ','T','a','i',' ','L','e'}},
400 {{Script_New_Tai_Lue, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
401 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
402 MS_MAKE_TAG('t','a','l','u'),
403 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
404 {{Script_New_Tai_Lue_Numeric, 0, 0, 0, 0, 0, 0, { 0,0,0,0,0,0,0,0,0,0,0}},
405 {0, 0, 1, 0, 1, DEFAULT_CHARSET, 0, 0, 0, 0, 0, 0, 0, 0, 0},
406 MS_MAKE_TAG('t','a','l','u'),
407 {'M','i','c','r','o','s','o','f','t',' ','N','e','w',' ','T','a','i',' ','L','u','e'}},
410 static const SCRIPT_PROPERTIES *script_props[] =
412 &scriptInformation[0].props, &scriptInformation[1].props,
413 &scriptInformation[2].props, &scriptInformation[3].props,
414 &scriptInformation[4].props, &scriptInformation[5].props,
415 &scriptInformation[6].props, &scriptInformation[7].props,
416 &scriptInformation[8].props, &scriptInformation[9].props,
417 &scriptInformation[10].props, &scriptInformation[11].props,
418 &scriptInformation[12].props, &scriptInformation[13].props,
419 &scriptInformation[14].props, &scriptInformation[15].props,
420 &scriptInformation[16].props, &scriptInformation[17].props,
421 &scriptInformation[18].props, &scriptInformation[19].props,
422 &scriptInformation[20].props, &scriptInformation[21].props,
423 &scriptInformation[22].props, &scriptInformation[23].props,
424 &scriptInformation[24].props, &scriptInformation[25].props,
425 &scriptInformation[26].props, &scriptInformation[27].props,
426 &scriptInformation[28].props, &scriptInformation[29].props,
427 &scriptInformation[30].props, &scriptInformation[31].props,
428 &scriptInformation[32].props, &scriptInformation[33].props,
429 &scriptInformation[34].props, &scriptInformation[35].props,
430 &scriptInformation[36].props, &scriptInformation[37].props,
431 &scriptInformation[38].props, &scriptInformation[39].props,
432 &scriptInformation[40].props, &scriptInformation[41].props,
433 &scriptInformation[42].props, &scriptInformation[43].props,
434 &scriptInformation[44].props, &scriptInformation[45].props,
435 &scriptInformation[46].props, &scriptInformation[47].props,
436 &scriptInformation[48].props, &scriptInformation[49].props,
437 &scriptInformation[50].props, &scriptInformation[51].props
440 typedef struct {
441 ScriptCache *sc;
442 int numGlyphs;
443 WORD* glyphs;
444 WORD* pwLogClust;
445 int* piAdvance;
446 SCRIPT_VISATTR* psva;
447 GOFFSET* pGoffset;
448 ABC* abc;
449 int iMaxPosX;
450 HFONT fallbackFont;
451 } StringGlyphs;
453 typedef struct {
454 HDC hdc;
455 DWORD dwFlags;
456 BOOL invalid;
457 int clip_len;
458 int cItems;
459 int cMaxGlyphs;
460 SCRIPT_ITEM* pItem;
461 int numItems;
462 StringGlyphs* glyphs;
463 SCRIPT_LOGATTR* logattrs;
464 SIZE* sz;
465 int* logical2visual;
466 } StringAnalysis;
468 static inline void *heap_alloc(SIZE_T size)
470 return HeapAlloc(GetProcessHeap(), 0, size);
473 static inline void *heap_alloc_zero(SIZE_T size)
475 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
478 static inline void *heap_realloc_zero(LPVOID mem, SIZE_T size)
480 return HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, mem, size);
483 static inline BOOL heap_free(LPVOID mem)
485 return HeapFree(GetProcessHeap(), 0, mem);
488 static inline WCHAR get_cache_default_char(SCRIPT_CACHE *psc)
490 return ((ScriptCache *)*psc)->tm.tmDefaultChar;
493 static inline LONG get_cache_height(SCRIPT_CACHE *psc)
495 return ((ScriptCache *)*psc)->tm.tmHeight;
498 static inline BYTE get_cache_pitch_family(SCRIPT_CACHE *psc)
500 return ((ScriptCache *)*psc)->tm.tmPitchAndFamily;
503 static inline WORD get_cache_glyph(SCRIPT_CACHE *psc, WCHAR c)
505 WORD *block = ((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
507 if (!block) return 0;
508 return block[c & GLYPH_BLOCK_MASK];
511 static inline WORD set_cache_glyph(SCRIPT_CACHE *psc, WCHAR c, WORD glyph)
513 WORD **block = &((ScriptCache *)*psc)->glyphs[c >> GLYPH_BLOCK_SHIFT];
515 if (!*block && !(*block = heap_alloc_zero(sizeof(WORD) * GLYPH_BLOCK_SIZE))) return 0;
516 return ((*block)[c & GLYPH_BLOCK_MASK] = glyph);
519 static inline BOOL get_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
521 static const ABC nil;
522 ABC *block = ((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
524 if (!block || !memcmp(&block[glyph & GLYPH_BLOCK_MASK], &nil, sizeof(ABC))) return FALSE;
525 memcpy(abc, &block[glyph & GLYPH_BLOCK_MASK], sizeof(ABC));
526 return TRUE;
529 static inline BOOL set_cache_glyph_widths(SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
531 ABC **block = &((ScriptCache *)*psc)->widths[glyph >> GLYPH_BLOCK_SHIFT];
533 if (!*block && !(*block = heap_alloc_zero(sizeof(ABC) * GLYPH_BLOCK_SIZE))) return FALSE;
534 memcpy(&(*block)[glyph & GLYPH_BLOCK_MASK], abc, sizeof(ABC));
535 return TRUE;
538 static HRESULT init_script_cache(const HDC hdc, SCRIPT_CACHE *psc)
540 ScriptCache *sc;
542 if (!psc) return E_INVALIDARG;
543 if (*psc) return S_OK;
544 if (!hdc) return E_PENDING;
546 if (!(sc = heap_alloc_zero(sizeof(ScriptCache)))) return E_OUTOFMEMORY;
547 if (!GetTextMetricsW(hdc, &sc->tm))
549 heap_free(sc);
550 return E_INVALIDARG;
552 if (!GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(LOGFONTW), &sc->lf))
554 heap_free(sc);
555 return E_INVALIDARG;
557 sc->sfnt = (GetFontData(hdc, MS_MAKE_TAG('h','e','a','d'), 0, NULL, 0)!=GDI_ERROR);
558 *psc = sc;
559 TRACE("<- %p\n", sc);
560 return S_OK;
563 static WCHAR mirror_char( WCHAR ch )
565 extern const WCHAR wine_mirror_map[];
566 return ch + wine_mirror_map[wine_mirror_map[ch >> 8] + (ch & 0xff)];
569 static WORD get_char_script( WCHAR ch)
571 static const WCHAR latin_punc[] = {'#','$','&','\'',',',';','<','>','?','@','\\','^','_','`','{','|','}','~', 0x00a0, 0};
572 WORD type = 0;
573 int i;
575 if (ch == 0xc || ch == 0x20 || ch == 0x202f)
576 return Script_CR;
578 /* These punctuation are separated out as Latin punctuation */
579 if (strchrW(latin_punc,ch))
580 return Script_Punctuation2;
582 /* These chars are itemized as Punctuation by Windows */
583 if (ch == 0x2212 || ch == 0x2044)
584 return Script_Punctuation;
586 GetStringTypeW(CT_CTYPE1, &ch, 1, &type);
588 if (type == 0)
589 return SCRIPT_UNDEFINED;
591 if (type & C1_CNTRL)
592 return Script_Control;
594 i = 0;
597 if (ch < scriptRanges[i].rangeFirst || scriptRanges[i].script == SCRIPT_UNDEFINED)
598 break;
600 if (ch >= scriptRanges[i].rangeFirst && ch <= scriptRanges[i].rangeLast)
602 if (scriptRanges[i].numericScript && type & C1_DIGIT)
603 return scriptRanges[i].numericScript;
604 if (scriptRanges[i].punctScript && type & C1_PUNCT)
605 return scriptRanges[i].punctScript;
606 return scriptRanges[i].script;
608 i++;
609 } while (1);
611 return SCRIPT_UNDEFINED;
614 /***********************************************************************
615 * DllMain
618 BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv)
620 switch(fdwReason)
622 case DLL_PROCESS_ATTACH:
623 DisableThreadLibraryCalls(hInstDLL);
624 break;
625 case DLL_PROCESS_DETACH:
626 break;
628 return TRUE;
631 /***********************************************************************
632 * ScriptFreeCache (USP10.@)
634 * Free a script cache.
636 * PARAMS
637 * psc [I/O] Script cache.
639 * RETURNS
640 * Success: S_OK
641 * Failure: Non-zero HRESULT value.
643 HRESULT WINAPI ScriptFreeCache(SCRIPT_CACHE *psc)
645 TRACE("%p\n", psc);
647 if (psc && *psc)
649 unsigned int i;
650 for (i = 0; i < GLYPH_MAX / GLYPH_BLOCK_SIZE; i++)
652 heap_free(((ScriptCache *)*psc)->glyphs[i]);
653 heap_free(((ScriptCache *)*psc)->widths[i]);
655 heap_free(((ScriptCache *)*psc)->GSUB_Table);
656 heap_free(((ScriptCache *)*psc)->GDEF_Table);
657 heap_free(((ScriptCache *)*psc)->features);
658 heap_free(*psc);
659 *psc = NULL;
661 return S_OK;
664 /***********************************************************************
665 * ScriptGetProperties (USP10.@)
667 * Retrieve a list of script properties.
669 * PARAMS
670 * props [I] Pointer to an array of SCRIPT_PROPERTIES pointers.
671 * num [I] Pointer to the number of scripts.
673 * RETURNS
674 * Success: S_OK
675 * Failure: Non-zero HRESULT value.
677 * NOTES
678 * Behaviour matches WinXP.
680 HRESULT WINAPI ScriptGetProperties(const SCRIPT_PROPERTIES ***props, int *num)
682 TRACE("(%p,%p)\n", props, num);
684 if (!props && !num) return E_INVALIDARG;
686 if (num) *num = sizeof(script_props)/sizeof(script_props[0]);
687 if (props) *props = script_props;
689 return S_OK;
692 /***********************************************************************
693 * ScriptGetFontProperties (USP10.@)
695 * Get information on special glyphs.
697 * PARAMS
698 * hdc [I] Device context.
699 * psc [I/O] Opaque pointer to a script cache.
700 * sfp [O] Font properties structure.
702 HRESULT WINAPI ScriptGetFontProperties(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_FONTPROPERTIES *sfp)
704 HRESULT hr;
706 TRACE("%p,%p,%p\n", hdc, psc, sfp);
708 if (!sfp) return E_INVALIDARG;
709 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
711 if (sfp->cBytes != sizeof(SCRIPT_FONTPROPERTIES))
712 return E_INVALIDARG;
714 /* return something sensible? */
715 sfp->wgBlank = 0;
716 sfp->wgDefault = get_cache_default_char(psc);
717 sfp->wgInvalid = 0;
718 sfp->wgKashida = 0xffff;
719 sfp->iKashidaWidth = 0;
721 return S_OK;
724 /***********************************************************************
725 * ScriptRecordDigitSubstitution (USP10.@)
727 * Record digit substitution settings for a given locale.
729 * PARAMS
730 * locale [I] Locale identifier.
731 * sds [I] Structure to record substitution settings.
733 * RETURNS
734 * Success: S_OK
735 * Failure: E_POINTER if sds is NULL, E_INVALIDARG otherwise.
737 * SEE ALSO
738 * http://blogs.msdn.com/michkap/archive/2006/02/22/536877.aspx
740 HRESULT WINAPI ScriptRecordDigitSubstitution(LCID locale, SCRIPT_DIGITSUBSTITUTE *sds)
742 DWORD plgid, sub;
744 TRACE("0x%x, %p\n", locale, sds);
746 /* This implementation appears to be correct for all languages, but it's
747 * not clear if sds->DigitSubstitute is ever set to anything except
748 * CONTEXT or NONE in reality */
750 if (!sds) return E_POINTER;
752 locale = ConvertDefaultLocale(locale);
754 if (!IsValidLocale(locale, LCID_INSTALLED))
755 return E_INVALIDARG;
757 plgid = PRIMARYLANGID(LANGIDFROMLCID(locale));
758 sds->TraditionalDigitLanguage = plgid;
760 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
761 sds->NationalDigitLanguage = plgid;
762 else
763 sds->NationalDigitLanguage = LANG_ENGLISH;
765 if (!GetLocaleInfoW(locale, LOCALE_IDIGITSUBSTITUTION | LOCALE_RETURN_NUMBER,
766 (LPWSTR)&sub, sizeof(sub)/sizeof(WCHAR))) return E_INVALIDARG;
768 switch (sub)
770 case 0:
771 if (plgid == LANG_ARABIC || plgid == LANG_FARSI)
772 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_CONTEXT;
773 else
774 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
775 break;
776 case 1:
777 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NONE;
778 break;
779 case 2:
780 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_NATIONAL;
781 break;
782 default:
783 sds->DigitSubstitute = SCRIPT_DIGITSUBSTITUTE_TRADITIONAL;
784 break;
787 sds->dwReserved = 0;
788 return S_OK;
791 /***********************************************************************
792 * ScriptApplyDigitSubstitution (USP10.@)
794 * Apply digit substitution settings.
796 * PARAMS
797 * sds [I] Structure with recorded substitution settings.
798 * sc [I] Script control structure.
799 * ss [I] Script state structure.
801 * RETURNS
802 * Success: S_OK
803 * Failure: E_INVALIDARG if sds is invalid. Otherwise an HRESULT.
805 HRESULT WINAPI ScriptApplyDigitSubstitution(const SCRIPT_DIGITSUBSTITUTE *sds,
806 SCRIPT_CONTROL *sc, SCRIPT_STATE *ss)
808 SCRIPT_DIGITSUBSTITUTE psds;
810 TRACE("%p, %p, %p\n", sds, sc, ss);
812 if (!sc || !ss) return E_POINTER;
813 if (!sds)
815 sds = &psds;
816 if (ScriptRecordDigitSubstitution(LOCALE_USER_DEFAULT, &psds) != S_OK)
817 return E_INVALIDARG;
820 sc->uDefaultLanguage = LANG_ENGLISH;
821 sc->fContextDigits = 0;
822 ss->fDigitSubstitute = 0;
824 switch (sds->DigitSubstitute) {
825 case SCRIPT_DIGITSUBSTITUTE_CONTEXT:
826 case SCRIPT_DIGITSUBSTITUTE_NATIONAL:
827 case SCRIPT_DIGITSUBSTITUTE_NONE:
828 case SCRIPT_DIGITSUBSTITUTE_TRADITIONAL:
829 return S_OK;
830 default:
831 return E_INVALIDARG;
835 static inline BOOL is_indic(WORD script)
837 return (script >= Script_Devanagari && script <= Script_Malayalam_Numeric);
840 static inline WORD base_indic(WORD script)
842 switch (script)
844 case Script_Devanagari:
845 case Script_Devanagari_Numeric: return Script_Devanagari;
846 case Script_Bengali:
847 case Script_Bengali_Numeric:
848 case Script_Bengali_Currency: return Script_Bengali;
849 case Script_Gurmukhi:
850 case Script_Gurmukhi_Numeric: return Script_Gurmukhi;
851 case Script_Gujarati:
852 case Script_Gujarati_Numeric:
853 case Script_Gujarati_Currency: return Script_Gujarati;
854 case Script_Oriya:
855 case Script_Oriya_Numeric: return Script_Oriya;
856 case Script_Tamil:
857 case Script_Tamil_Numeric: return Script_Tamil;
858 case Script_Telugu:
859 case Script_Telugu_Numeric: return Script_Telugu;
860 case Script_Kannada:
861 case Script_Kannada_Numeric: return Script_Kannada;
862 case Script_Malayalam:
863 case Script_Malayalam_Numeric: return Script_Malayalam;
864 default:
865 return -1;
869 /***********************************************************************
870 * ScriptItemizeOpenType (USP10.@)
872 * Split a Unicode string into shapeable parts.
874 * PARAMS
875 * pwcInChars [I] String to split.
876 * cInChars [I] Number of characters in pwcInChars.
877 * cMaxItems [I] Maximum number of items to return.
878 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
879 * psState [I] Pointer to a SCRIPT_STATE structure.
880 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
881 * pScriptTags [O] Buffer to receive OPENTYPE_TAGs.
882 * pcItems [O] Number of script items returned.
884 * RETURNS
885 * Success: S_OK
886 * Failure: Non-zero HRESULT value.
888 HRESULT WINAPI ScriptItemizeOpenType(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
889 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
890 SCRIPT_ITEM *pItems, OPENTYPE_TAG *pScriptTags, int *pcItems)
893 #define Numeric_space 0x0020
894 #define ZWNJ 0x200C
895 #define ZWJ 0x200D
897 int cnt = 0, index = 0, str = 0;
898 int New_Script = -1;
899 int i;
900 WORD *levels = NULL;
901 WORD *strength = NULL;
902 WORD *scripts = NULL;
903 WORD baselevel = 0;
904 BOOL new_run;
905 WORD last_indic = -1;
906 WORD layoutRTL = 0;
907 BOOL forceLevels = FALSE;
909 TRACE("%s,%d,%d,%p,%p,%p,%p\n", debugstr_wn(pwcInChars, cInChars), cInChars, cMaxItems,
910 psControl, psState, pItems, pcItems);
912 if (!pwcInChars || !cInChars || !pItems || cMaxItems < 2)
913 return E_INVALIDARG;
915 scripts = heap_alloc(cInChars * sizeof(WORD));
916 if (!scripts)
917 return E_OUTOFMEMORY;
919 for (i = 0; i < cInChars; i++)
921 scripts[i] = get_char_script(pwcInChars[i]);
922 /* Devanagari danda (U+0964) and double danda (U+0965) are used for
923 all Indic scripts */
924 if ((pwcInChars[i] == 0x964 || pwcInChars[i] ==0x965) && last_indic > 0)
925 scripts[i] = last_indic;
926 else if (is_indic(scripts[i]))
927 last_indic = base_indic(scripts[i]);
929 /* Some unicode points (Zero Width Space U+200B -
930 Right-to-Left Mark U+200F) will force us into bidi mode */
931 if (!forceLevels && pwcInChars[i] >= 0x200B && pwcInChars[i] <= 0x200F)
932 forceLevels = TRUE;
934 /* Diacritical marks merge with other scripts */
935 if (scripts[i] == Script_Diacritical && i > 0)
936 scripts[i] = scripts[i-1];
939 for (i = 0; i < cInChars; i++)
941 /* Joiners get merged preferencially right */
942 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
944 int j;
945 if (i+1 == cInChars)
946 scripts[i] = scripts[i-1];
947 else
949 for (j = i+1; j < cInChars; j++)
951 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
953 scripts[i] = scripts[j];
954 break;
961 if (psState && psControl)
963 levels = heap_alloc_zero(cInChars * sizeof(WORD));
964 if (!levels)
966 heap_free(scripts);
967 return E_OUTOFMEMORY;
970 BIDI_DetermineLevels(pwcInChars, cInChars, psState, psControl, levels);
971 baselevel = levels[0];
972 for (i = 0; i < cInChars; i++)
973 if (levels[i]!=levels[0])
974 break;
975 if (i >= cInChars && !odd(baselevel) && !odd(psState->uBidiLevel) && !forceLevels)
977 heap_free(levels);
978 levels = NULL;
980 else
982 BOOL inNumber = FALSE;
983 static WCHAR math_punc[] = {'#','$','%','+',',','-','.','/',':',0x2212, 0x2044, 0x00a0,0};
985 strength = heap_alloc_zero(cInChars * sizeof(WORD));
986 if (!strength)
988 heap_free(scripts);
989 heap_free(levels);
990 return E_OUTOFMEMORY;
992 BIDI_GetStrengths(pwcInChars, cInChars, psControl, strength);
994 /* We currently mis-level leading Diacriticals */
995 if (scripts[0] == Script_Diacritical)
996 for (i = 0; i < cInChars && scripts[0] == Script_Diacritical; i++)
998 levels[i] = odd(levels[i])?levels[i]+1:levels[i];
999 strength[i] = BIDI_STRONG;
1002 for (i = 0; i < cInChars; i++)
1004 /* Script_Numeric and select puncuation at level 0 get bumped to level 2 */
1005 if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && inNumber && strchrW(math_punc,pwcInChars[i]))
1007 scripts[i] = Script_Numeric;
1008 levels[i] = 2;
1010 else if ((levels[i] == 0 || (odd(psState->uBidiLevel) && levels[i] == psState->uBidiLevel+1)) && scripts[i] == Script_Numeric)
1012 levels[i] = 2;
1013 inNumber = TRUE;
1015 else
1016 inNumber = FALSE;
1018 /* Joiners get merged preferencially right */
1019 if (i > 0 && (pwcInChars[i] == ZWJ || pwcInChars[i] == ZWNJ))
1021 int j;
1022 if (i+1 == cInChars && levels[i-1] == levels[i])
1023 strength[i] = strength[i-1];
1024 else
1025 for (j = i+1; j < cInChars && levels[i] == levels[j]; j++)
1026 if (pwcInChars[j] != ZWJ && pwcInChars[j] != ZWNJ && pwcInChars[j] != Numeric_space)
1028 strength[i] = strength[j];
1029 break;
1033 if (psControl->fMergeNeutralItems)
1035 /* Merge the neutrals */
1036 for (i = 0; i < cInChars; i++)
1038 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1040 int j;
1041 for (j = i; j > 0; j--)
1043 if (levels[i] != levels[j])
1044 break;
1045 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1047 scripts[i] = scripts[j];
1048 strength[i] = strength[j];
1049 break;
1053 /* Try going the other way */
1054 if (strength[i] == BIDI_NEUTRAL || strength[i] == BIDI_WEAK)
1056 int j;
1057 for (j = i; j < cInChars; j++)
1059 if (levels[i] != levels[j])
1060 break;
1061 if ((strength[j] == BIDI_STRONG) || (strength[i] == BIDI_NEUTRAL && strength[j] == BIDI_WEAK))
1063 scripts[i] = scripts[j];
1064 strength[i] = strength[j];
1065 break;
1074 while ((!levels || (levels && levels[cnt+1] == levels[0])) && (pwcInChars[cnt] == Numeric_space) && cnt < cInChars)
1075 cnt++;
1077 if (cnt == cInChars) /* All Spaces */
1079 cnt = 0;
1080 New_Script = scripts[cnt];
1083 pItems[index].iCharPos = 0;
1084 pItems[index].a = scriptInformation[scripts[cnt]].a;
1085 pScriptTags[index] = scriptInformation[scripts[cnt]].scriptTag;
1087 if (strength && strength[cnt] == BIDI_STRONG)
1088 str = strength[cnt];
1089 else if (strength)
1090 str = strength[0];
1092 cnt = 0;
1094 if (levels)
1096 if (strength[cnt] == BIDI_STRONG)
1097 layoutRTL = (odd(levels[cnt]))?1:0;
1098 else
1099 layoutRTL = (psState->uBidiLevel || odd(levels[cnt]))?1:0;
1100 pItems[index].a.fRTL = odd(levels[cnt]);
1101 pItems[index].a.fLayoutRTL = layoutRTL;
1102 pItems[index].a.s.uBidiLevel = levels[cnt];
1104 else if (!pItems[index].a.s.uBidiLevel)
1106 layoutRTL = (odd(baselevel))?1:0;
1107 pItems[index].a.s.uBidiLevel = baselevel;
1108 pItems[index].a.fLayoutRTL = odd(baselevel);
1109 pItems[index].a.fRTL = odd(baselevel);
1112 TRACE("New_Level=%i New_Strength=%i New_Script=%d, eScript=%d index=%d cnt=%d iCharPos=%d\n",
1113 levels?levels[cnt]:-1, str, New_Script, pItems[index].a.eScript, index, cnt,
1114 pItems[index].iCharPos);
1116 for (cnt=1; cnt < cInChars; cnt++)
1118 if(pwcInChars[cnt] != Numeric_space)
1119 New_Script = scripts[cnt];
1120 else if (levels)
1122 int j = 1;
1123 while (cnt + j < cInChars - 1 && pwcInChars[cnt+j] == Numeric_space && levels[cnt] == levels[cnt+j])
1124 j++;
1125 if (cnt + j < cInChars && levels[cnt] == levels[cnt+j])
1126 New_Script = scripts[cnt+j];
1127 else
1128 New_Script = scripts[cnt];
1131 new_run = FALSE;
1132 /* merge space strengths*/
1133 if (strength && strength[cnt] == BIDI_STRONG && str != BIDI_STRONG && New_Script == pItems[index].a.eScript)
1134 str = BIDI_STRONG;
1136 if (strength && strength[cnt] == BIDI_NEUTRAL && str == BIDI_STRONG && pwcInChars[cnt] != Numeric_space && New_Script == pItems[index].a.eScript)
1137 str = BIDI_NEUTRAL;
1139 /* changes in level */
1140 if (levels && (levels[cnt] != pItems[index].a.s.uBidiLevel))
1142 TRACE("Level break(%i/%i)\n",pItems[index].a.s.uBidiLevel,levels[cnt]);
1143 new_run = TRUE;
1145 /* changes in strength */
1146 else if (strength && pwcInChars[cnt] != Numeric_space && str != strength[cnt])
1148 TRACE("Strength break (%i/%i)\n",str,strength[cnt]);
1149 new_run = TRUE;
1151 /* changes in script */
1152 else if (((pwcInChars[cnt] != Numeric_space) && (New_Script != -1) && (New_Script != pItems[index].a.eScript)) || (New_Script == Script_Control))
1154 TRACE("Script break(%i/%i)\n",pItems[index].a.eScript,New_Script);
1155 new_run = TRUE;
1158 if (!new_run && strength && str == BIDI_STRONG)
1160 layoutRTL = odd(levels[cnt])?1:0;
1161 pItems[index].a.fLayoutRTL = layoutRTL;
1164 if (new_run)
1166 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);
1168 index++;
1169 if (index+1 > cMaxItems)
1170 return E_OUTOFMEMORY;
1172 if (strength)
1173 str = strength[cnt];
1175 pItems[index].iCharPos = cnt;
1176 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1178 pItems[index].a = scriptInformation[New_Script].a;
1179 pScriptTags[index] = scriptInformation[New_Script].scriptTag;
1180 if (levels)
1182 if (levels[cnt] == 0)
1183 layoutRTL = 0;
1184 else
1185 layoutRTL = (layoutRTL || odd(levels[cnt]))?1:0;
1186 pItems[index].a.fRTL = odd(levels[cnt]);
1187 pItems[index].a.fLayoutRTL = layoutRTL;
1188 pItems[index].a.s.uBidiLevel = levels[cnt];
1190 else if (!pItems[index].a.s.uBidiLevel)
1192 pItems[index].a.s.uBidiLevel = baselevel;
1193 pItems[index].a.fLayoutRTL = layoutRTL;
1194 pItems[index].a.fRTL = odd(baselevel);
1197 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1201 /* While not strictly necessary according to the spec, make sure the n+1
1202 * item is set up to prevent random behaviour if the caller erroneously
1203 * checks the n+1 structure */
1204 index++;
1205 memset(&pItems[index].a, 0, sizeof(SCRIPT_ANALYSIS));
1207 TRACE("index=%d cnt=%d iCharPos=%d\n", index, cnt, pItems[index].iCharPos);
1209 /* Set one SCRIPT_STATE item being returned */
1210 if (index + 1 > cMaxItems) return E_OUTOFMEMORY;
1211 if (pcItems) *pcItems = index;
1213 /* Set SCRIPT_ITEM */
1214 pItems[index].iCharPos = cnt; /* the last item contains the ptr to the lastchar */
1215 heap_free(levels);
1216 heap_free(strength);
1217 heap_free(scripts);
1218 return S_OK;
1221 /***********************************************************************
1222 * ScriptItemize (USP10.@)
1224 * Split a Unicode string into shapeable parts.
1226 * PARAMS
1227 * pwcInChars [I] String to split.
1228 * cInChars [I] Number of characters in pwcInChars.
1229 * cMaxItems [I] Maximum number of items to return.
1230 * psControl [I] Pointer to a SCRIPT_CONTROL structure.
1231 * psState [I] Pointer to a SCRIPT_STATE structure.
1232 * pItems [O] Buffer to receive SCRIPT_ITEM structures.
1233 * pcItems [O] Number of script items returned.
1235 * RETURNS
1236 * Success: S_OK
1237 * Failure: Non-zero HRESULT value.
1239 HRESULT WINAPI ScriptItemize(const WCHAR *pwcInChars, int cInChars, int cMaxItems,
1240 const SCRIPT_CONTROL *psControl, const SCRIPT_STATE *psState,
1241 SCRIPT_ITEM *pItems, int *pcItems)
1243 OPENTYPE_TAG *discarded_tags;
1244 HRESULT res;
1246 discarded_tags = heap_alloc(cMaxItems * sizeof(OPENTYPE_TAG));
1247 if (!discarded_tags)
1248 return E_OUTOFMEMORY;
1249 res = ScriptItemizeOpenType(pwcInChars, cInChars, cMaxItems, psControl, psState, pItems, discarded_tags, pcItems);
1250 heap_free(discarded_tags);
1251 return res;
1254 static inline int getGivenTabWidth(ScriptCache *psc, SCRIPT_TABDEF *pTabdef, int charPos, int current_x)
1256 int defWidth;
1257 int cTabStops=0;
1258 INT *lpTabPos = NULL;
1259 INT nTabOrg = 0;
1260 INT x = 0;
1262 if (pTabdef)
1263 lpTabPos = pTabdef->pTabStops;
1265 if (pTabdef && pTabdef->iTabOrigin)
1267 if (pTabdef->iScale)
1268 nTabOrg = (pTabdef->iTabOrigin * pTabdef->iScale)/4;
1269 else
1270 nTabOrg = pTabdef->iTabOrigin * psc->tm.tmAveCharWidth;
1273 if (pTabdef)
1274 cTabStops = pTabdef->cTabStops;
1276 if (cTabStops == 1)
1278 if (pTabdef->iScale)
1279 defWidth = ((pTabdef->pTabStops[0])*pTabdef->iScale) / 4;
1280 else
1281 defWidth = (pTabdef->pTabStops[0])*psc->tm.tmAveCharWidth;
1282 cTabStops = 0;
1284 else
1285 defWidth = 8 * psc->tm.tmAveCharWidth;
1287 for (; cTabStops>0 ; lpTabPos++, cTabStops--)
1289 int position = *lpTabPos;
1290 if (position < 0)
1291 position = -1 * position;
1292 if (pTabdef->iScale)
1293 position = (position * pTabdef->iScale) / 4;
1294 else
1295 position = position * psc->tm.tmAveCharWidth;
1297 if( nTabOrg + position > current_x)
1299 if( *lpTabPos >= 0)
1301 /* a left aligned tab */
1302 x = (nTabOrg + *lpTabPos) - current_x;
1303 break;
1305 else
1307 FIXME("Negative tabstop\n");
1308 break;
1312 if ((!cTabStops) && (defWidth > 0))
1313 x =((((current_x - nTabOrg) / defWidth)+1) * defWidth) - current_x;
1314 else if ((!cTabStops) && (defWidth < 0))
1315 FIXME("TODO: Negative defWidth\n");
1317 return x;
1320 /***********************************************************************
1321 * Helper function for ScriptStringAnalyse
1323 static BOOL requires_fallback(HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
1324 const WCHAR *pwcInChars, int cChars )
1326 /* FIXME: When to properly fallback is still a bit of a mystery */
1327 WORD *glyphs;
1329 if (psa->fNoGlyphIndex)
1330 return FALSE;
1332 if (init_script_cache(hdc, psc) != S_OK)
1333 return FALSE;
1335 if (SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa) != S_OK)
1336 return TRUE;
1338 glyphs = heap_alloc(sizeof(WORD) * cChars);
1339 if (!glyphs)
1340 return FALSE;
1341 if (ScriptGetCMap(hdc, psc, pwcInChars, cChars, 0, glyphs) != S_OK)
1343 heap_free(glyphs);
1344 return TRUE;
1346 heap_free(glyphs);
1348 return FALSE;
1351 static void find_fallback_font(DWORD scriptid, LPWSTR FaceName)
1353 HKEY hkey;
1355 if (!RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\Uniscribe\\Fallback", &hkey))
1357 static const WCHAR szFmt[] = {'%','x',0};
1358 WCHAR value[10];
1359 DWORD count = LF_FACESIZE * sizeof(WCHAR);
1360 DWORD type;
1362 sprintfW(value, szFmt, scriptInformation[scriptid].scriptTag);
1363 if (RegQueryValueExW(hkey, value, 0, &type, (LPBYTE)FaceName, &count))
1364 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1365 RegCloseKey(hkey);
1367 else
1368 lstrcpyW(FaceName,scriptInformation[scriptid].fallbackFont);
1371 /***********************************************************************
1372 * ScriptStringAnalyse (USP10.@)
1375 HRESULT WINAPI ScriptStringAnalyse(HDC hdc, const void *pString, int cString,
1376 int cGlyphs, int iCharset, DWORD dwFlags,
1377 int iReqWidth, SCRIPT_CONTROL *psControl,
1378 SCRIPT_STATE *psState, const int *piDx,
1379 SCRIPT_TABDEF *pTabdef, const BYTE *pbInClass,
1380 SCRIPT_STRING_ANALYSIS *pssa)
1382 HRESULT hr = E_OUTOFMEMORY;
1383 StringAnalysis *analysis = NULL;
1384 SCRIPT_CONTROL sControl;
1385 SCRIPT_STATE sState;
1386 int i, num_items = 255;
1387 BYTE *BidiLevel;
1388 WCHAR *iString = NULL;
1390 TRACE("(%p,%p,%d,%d,%d,0x%x,%d,%p,%p,%p,%p,%p,%p)\n",
1391 hdc, pString, cString, cGlyphs, iCharset, dwFlags, iReqWidth,
1392 psControl, psState, piDx, pTabdef, pbInClass, pssa);
1394 if (iCharset != -1)
1396 FIXME("Only Unicode strings are supported\n");
1397 return E_INVALIDARG;
1399 if (cString < 1 || !pString) return E_INVALIDARG;
1400 if ((dwFlags & SSA_GLYPHS) && !hdc) return E_PENDING;
1402 if (!(analysis = heap_alloc_zero(sizeof(StringAnalysis)))) return E_OUTOFMEMORY;
1403 if (!(analysis->pItem = heap_alloc_zero(num_items * sizeof(SCRIPT_ITEM) + 1))) goto error;
1405 /* FIXME: handle clipping */
1406 analysis->clip_len = cString;
1407 analysis->hdc = hdc;
1408 analysis->dwFlags = dwFlags;
1410 if (psState)
1411 sState = *psState;
1412 else
1413 memset(&sState, 0, sizeof(SCRIPT_STATE));
1415 if (psControl)
1416 sControl = *psControl;
1417 else
1418 memset(&sControl, 0, sizeof(SCRIPT_CONTROL));
1420 if (dwFlags & SSA_PASSWORD)
1422 iString = heap_alloc(sizeof(WCHAR)*cString);
1423 if (!iString)
1425 hr = E_OUTOFMEMORY;
1426 goto error;
1428 for (i = 0; i < cString; i++)
1429 iString[i] = *((const WCHAR *)pString);
1430 pString = iString;
1433 hr = ScriptItemize(pString, cString, num_items, &sControl, &sState, analysis->pItem,
1434 &analysis->numItems);
1436 while (hr == E_OUTOFMEMORY)
1438 SCRIPT_ITEM *tmp;
1440 num_items *= 2;
1441 if (!(tmp = heap_realloc_zero(analysis->pItem, num_items * sizeof(SCRIPT_ITEM) + 1)))
1442 goto error;
1444 analysis->pItem = tmp;
1445 hr = ScriptItemize(pString, cString, num_items, psControl, psState, analysis->pItem,
1446 &analysis->numItems);
1448 if (hr != S_OK) goto error;
1450 /* set back to out of memory for default goto error behaviour */
1451 hr = E_OUTOFMEMORY;
1453 if (dwFlags & SSA_BREAK)
1455 if ((analysis->logattrs = heap_alloc(sizeof(SCRIPT_LOGATTR) * cString)))
1457 for (i = 0; i < analysis->numItems; i++)
1458 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]);
1460 else
1461 goto error;
1464 if (!(analysis->logical2visual = heap_alloc_zero(sizeof(int) * analysis->numItems)))
1465 goto error;
1466 if (!(BidiLevel = heap_alloc_zero(analysis->numItems)))
1467 goto error;
1469 if (dwFlags & SSA_GLYPHS)
1471 int tab_x = 0;
1472 if (!(analysis->glyphs = heap_alloc_zero(sizeof(StringGlyphs) * analysis->numItems)))
1474 heap_free(BidiLevel);
1475 goto error;
1478 for (i = 0; i < analysis->numItems; i++)
1480 SCRIPT_CACHE *sc = (SCRIPT_CACHE*)&analysis->glyphs[i].sc;
1481 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1482 int numGlyphs = 1.5 * cChar + 16;
1483 WORD *glyphs = heap_alloc_zero(sizeof(WORD) * numGlyphs);
1484 WORD *pwLogClust = heap_alloc_zero(sizeof(WORD) * cChar);
1485 int *piAdvance = heap_alloc_zero(sizeof(int) * numGlyphs);
1486 SCRIPT_VISATTR *psva = heap_alloc_zero(sizeof(SCRIPT_VISATTR) * numGlyphs);
1487 GOFFSET *pGoffset = heap_alloc_zero(sizeof(GOFFSET) * numGlyphs);
1488 ABC *abc = heap_alloc_zero(sizeof(ABC));
1489 int numGlyphsReturned;
1490 HFONT originalFont = 0x0;
1492 /* FIXME: non unicode strings */
1493 const WCHAR* pStr = (const WCHAR*)pString;
1494 analysis->glyphs[i].fallbackFont = NULL;
1496 if (!glyphs || !pwLogClust || !piAdvance || !psva || !pGoffset || !abc)
1498 heap_free (BidiLevel);
1499 heap_free (glyphs);
1500 heap_free (pwLogClust);
1501 heap_free (piAdvance);
1502 heap_free (psva);
1503 heap_free (pGoffset);
1504 heap_free (abc);
1505 hr = E_OUTOFMEMORY;
1506 goto error;
1509 if ((dwFlags & SSA_FALLBACK) && requires_fallback(hdc, sc, &analysis->pItem[i].a, &pStr[analysis->pItem[i].iCharPos], cChar))
1511 LOGFONTW lf;
1512 GetObjectW(GetCurrentObject(hdc, OBJ_FONT), sizeof(lf), & lf);
1513 lf.lfCharSet = scriptInformation[analysis->pItem[i].a.eScript].props.bCharSet;
1514 find_fallback_font(analysis->pItem[i].a.eScript, lf.lfFaceName);
1515 analysis->glyphs[i].fallbackFont = CreateFontIndirectW(&lf);
1516 if (analysis->glyphs[i].fallbackFont)
1518 ScriptFreeCache(sc);
1519 originalFont = SelectObject(hdc, analysis->glyphs[i].fallbackFont);
1523 hr = ScriptShape(hdc, sc, &pStr[analysis->pItem[i].iCharPos],
1524 cChar, numGlyphs, &analysis->pItem[i].a,
1525 glyphs, pwLogClust, psva, &numGlyphsReturned);
1526 hr = ScriptPlace(hdc, sc, glyphs, numGlyphsReturned, psva, &analysis->pItem[i].a,
1527 piAdvance, pGoffset, abc);
1528 if (originalFont)
1529 SelectObject(hdc,originalFont);
1531 if (dwFlags & SSA_TAB)
1533 int tabi = 0;
1534 for (tabi = 0; tabi < cChar; tabi++)
1536 if (pStr[analysis->pItem[i].iCharPos+tabi] == 0x0009)
1537 piAdvance[tabi] = getGivenTabWidth(analysis->glyphs[i].sc, pTabdef, analysis->pItem[i].iCharPos+tabi, tab_x);
1538 tab_x+=piAdvance[tabi];
1542 analysis->glyphs[i].numGlyphs = numGlyphsReturned;
1543 analysis->glyphs[i].glyphs = glyphs;
1544 analysis->glyphs[i].pwLogClust = pwLogClust;
1545 analysis->glyphs[i].piAdvance = piAdvance;
1546 analysis->glyphs[i].psva = psva;
1547 analysis->glyphs[i].pGoffset = pGoffset;
1548 analysis->glyphs[i].abc = abc;
1549 analysis->glyphs[i].iMaxPosX= -1;
1551 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1554 else
1556 for (i = 0; i < analysis->numItems; i++)
1557 BidiLevel[i] = analysis->pItem[i].a.s.uBidiLevel;
1560 ScriptLayout(analysis->numItems, BidiLevel, NULL, analysis->logical2visual);
1561 heap_free(BidiLevel);
1563 *pssa = analysis;
1564 heap_free(iString);
1565 return S_OK;
1567 error:
1568 heap_free(iString);
1569 heap_free(analysis->glyphs);
1570 heap_free(analysis->logattrs);
1571 heap_free(analysis->pItem);
1572 heap_free(analysis->logical2visual);
1573 heap_free(analysis);
1574 return hr;
1577 static inline BOOL does_glyph_start_cluster(const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cChars, int glyph, int direction)
1579 int i;
1581 if (pva[glyph].fClusterStart)
1582 return TRUE;
1583 for (i = 0; i < cChars; i++)
1584 if (pwLogClust[i] == glyph) break;
1585 if (i != cChars)
1586 return TRUE;
1588 return FALSE;
1592 static HRESULT SS_ItemOut( SCRIPT_STRING_ANALYSIS ssa,
1593 int iX,
1594 int iY,
1595 int iItem,
1596 int cStart,
1597 int cEnd,
1598 UINT uOptions,
1599 const RECT *prc,
1600 BOOL fSelected,
1601 BOOL fDisabled)
1603 StringAnalysis *analysis;
1604 int off_x = 0;
1605 HRESULT hr;
1606 COLORREF BkColor = 0x0;
1607 COLORREF TextColor = 0x0;
1608 INT BkMode = 0;
1609 INT runStart, runEnd;
1610 INT iGlyph, cGlyphs;
1611 HFONT oldFont = 0x0;
1613 TRACE("(%p,%d,%d,%d,%d,%d, 0x%1x, %d, %d)\n",
1614 ssa, iX, iY, iItem, cStart, cEnd, uOptions, fSelected, fDisabled);
1616 if (!(analysis = ssa)) return E_INVALIDARG;
1618 if ((cStart >= 0 && analysis->pItem[iItem+1].iCharPos <= cStart) ||
1619 (cEnd >= 0 && analysis->pItem[iItem].iCharPos >= cEnd))
1620 return S_OK;
1622 if (fSelected)
1624 BkMode = GetBkMode(analysis->hdc);
1625 SetBkMode( analysis->hdc, OPAQUE);
1626 BkColor = GetBkColor(analysis->hdc);
1627 SetBkColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHT));
1628 if (!fDisabled)
1630 TextColor = GetTextColor(analysis->hdc);
1631 SetTextColor(analysis->hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
1634 if (analysis->glyphs[iItem].fallbackFont)
1635 oldFont = SelectObject(analysis->hdc, analysis->glyphs[iItem].fallbackFont);
1637 if (cStart >= 0 && analysis->pItem[iItem+1].iCharPos > cStart && analysis->pItem[iItem].iCharPos <= cStart)
1638 runStart = cStart - analysis->pItem[iItem].iCharPos;
1639 else
1640 runStart = 0;
1641 if (cEnd >= 0 && analysis->pItem[iItem+1].iCharPos > cEnd && analysis->pItem[iItem].iCharPos <= cEnd)
1642 runEnd = (cEnd-1) - analysis->pItem[iItem].iCharPos;
1643 else
1644 runEnd = (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos) - 1;
1646 if (analysis->pItem[iItem].a.fRTL)
1648 if (cEnd >= 0 && cEnd < analysis->pItem[iItem+1].iCharPos)
1649 ScriptStringCPtoX(ssa, cEnd, FALSE, &off_x);
1650 else
1651 ScriptStringCPtoX(ssa, analysis->pItem[iItem+1].iCharPos-1, TRUE, &off_x);
1653 else
1655 if (cStart >=0 && runStart)
1656 ScriptStringCPtoX(ssa, cStart, FALSE, &off_x);
1657 else
1658 ScriptStringCPtoX(ssa, analysis->pItem[iItem].iCharPos, FALSE, &off_x);
1661 if (analysis->pItem[iItem].a.fRTL)
1662 iGlyph = analysis->glyphs[iItem].pwLogClust[runEnd];
1663 else
1664 iGlyph = analysis->glyphs[iItem].pwLogClust[runStart];
1666 if (analysis->pItem[iItem].a.fRTL)
1667 cGlyphs = analysis->glyphs[iItem].pwLogClust[runStart] - iGlyph;
1668 else
1669 cGlyphs = analysis->glyphs[iItem].pwLogClust[runEnd] - iGlyph;
1671 cGlyphs++;
1673 if (cEnd < 0 || scriptInformation[analysis->pItem[iItem].a.eScript].props.fNeedsCaretInfo)
1675 INT direction;
1676 INT clust_glyph;
1678 clust_glyph = iGlyph + cGlyphs;
1679 if (analysis->pItem[iItem].a.fRTL)
1680 direction = -1;
1681 else
1682 direction = 1;
1684 while(clust_glyph < analysis->glyphs[iItem].numGlyphs &&
1685 !does_glyph_start_cluster(analysis->glyphs[iItem].psva, analysis->glyphs[iItem].pwLogClust, (analysis->pItem[iItem+1].iCharPos - analysis->pItem[iItem].iCharPos), clust_glyph, direction))
1687 cGlyphs++;
1688 clust_glyph++;
1692 hr = ScriptTextOut(analysis->hdc,
1693 (SCRIPT_CACHE *)&analysis->glyphs[iItem].sc, iX + off_x,
1694 iY, uOptions, prc, &analysis->pItem[iItem].a, NULL, 0,
1695 &analysis->glyphs[iItem].glyphs[iGlyph], cGlyphs,
1696 &analysis->glyphs[iItem].piAdvance[iGlyph], NULL,
1697 &analysis->glyphs[iItem].pGoffset[iGlyph]);
1699 TRACE("ScriptTextOut hr=%08x\n", hr);
1701 if (fSelected)
1703 SetBkColor(analysis->hdc, BkColor);
1704 SetBkMode( analysis->hdc, BkMode);
1705 if (!fDisabled)
1706 SetTextColor(analysis->hdc, TextColor);
1708 if (analysis->glyphs[iItem].fallbackFont)
1709 SelectObject(analysis->hdc, oldFont);
1711 return hr;
1714 /***********************************************************************
1715 * ScriptStringOut (USP10.@)
1717 * This function takes the output of ScriptStringAnalyse and joins the segments
1718 * of glyphs and passes the resulting string to ScriptTextOut. ScriptStringOut
1719 * only processes glyphs.
1721 * Parameters:
1722 * ssa [I] buffer to hold the analysed string components
1723 * iX [I] X axis displacement for output
1724 * iY [I] Y axis displacement for output
1725 * uOptions [I] flags controling output processing
1726 * prc [I] rectangle coordinates
1727 * iMinSel [I] starting pos for substringing output string
1728 * iMaxSel [I] ending pos for substringing output string
1729 * fDisabled [I] controls text highlighting
1731 * RETURNS
1732 * Success: S_OK
1733 * Failure: is the value returned by ScriptTextOut
1735 HRESULT WINAPI ScriptStringOut(SCRIPT_STRING_ANALYSIS ssa,
1736 int iX,
1737 int iY,
1738 UINT uOptions,
1739 const RECT *prc,
1740 int iMinSel,
1741 int iMaxSel,
1742 BOOL fDisabled)
1744 StringAnalysis *analysis;
1745 int item;
1746 HRESULT hr;
1748 TRACE("(%p,%d,%d,0x%1x,%p,%d,%d,%d)\n",
1749 ssa, iX, iY, uOptions, prc, iMinSel, iMaxSel, fDisabled);
1751 if (!(analysis = ssa)) return E_INVALIDARG;
1752 if (!(analysis->dwFlags & SSA_GLYPHS)) return E_INVALIDARG;
1754 for (item = 0; item < analysis->numItems; item++)
1756 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], -1, -1, uOptions, prc, FALSE, fDisabled);
1757 if (FAILED(hr))
1758 return hr;
1761 if (iMinSel < iMaxSel && (iMinSel > 0 || iMaxSel > 0))
1763 if (iMaxSel > 0 && iMinSel < 0)
1764 iMinSel = 0;
1765 for (item = 0; item < analysis->numItems; item++)
1767 hr = SS_ItemOut( ssa, iX, iY, analysis->logical2visual[item], iMinSel, iMaxSel, uOptions, prc, TRUE, fDisabled);
1768 if (FAILED(hr))
1769 return hr;
1773 return S_OK;
1776 /***********************************************************************
1777 * ScriptStringCPtoX (USP10.@)
1780 HRESULT WINAPI ScriptStringCPtoX(SCRIPT_STRING_ANALYSIS ssa, int icp, BOOL fTrailing, int* pX)
1782 int item;
1783 int runningX = 0;
1784 StringAnalysis* analysis = ssa;
1786 TRACE("(%p), %d, %d, (%p)\n", ssa, icp, fTrailing, pX);
1788 if (!ssa || !pX) return S_FALSE;
1789 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1791 /* icp out of range */
1792 if(icp < 0)
1794 analysis->invalid = TRUE;
1795 return E_INVALIDARG;
1798 for(item=0; item<analysis->numItems; item++)
1800 int CP, i;
1801 int offset;
1803 i = analysis->logical2visual[item];
1804 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1805 /* initialize max extents for uninitialized runs */
1806 if (analysis->glyphs[i].iMaxPosX == -1)
1808 if (analysis->pItem[i].a.fRTL)
1809 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1810 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1811 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1812 else
1813 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1814 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1815 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1818 if (icp >= analysis->pItem[i+1].iCharPos || icp < analysis->pItem[i].iCharPos)
1820 runningX += analysis->glyphs[i].iMaxPosX;
1821 continue;
1824 icp -= analysis->pItem[i].iCharPos;
1825 ScriptCPtoX(icp, fTrailing, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1826 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1827 &analysis->pItem[i].a, &offset);
1828 runningX += offset;
1830 *pX = runningX;
1831 return S_OK;
1834 /* icp out of range */
1835 analysis->invalid = TRUE;
1836 return E_INVALIDARG;
1839 /***********************************************************************
1840 * ScriptStringXtoCP (USP10.@)
1843 HRESULT WINAPI ScriptStringXtoCP(SCRIPT_STRING_ANALYSIS ssa, int iX, int* piCh, int* piTrailing)
1845 StringAnalysis* analysis = ssa;
1846 int item;
1848 TRACE("(%p), %d, (%p), (%p)\n", ssa, iX, piCh, piTrailing);
1850 if (!ssa || !piCh || !piTrailing) return S_FALSE;
1851 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
1853 /* out of range */
1854 if(iX < 0)
1856 if (analysis->pItem[0].a.fRTL)
1858 *piCh = 1;
1859 *piTrailing = FALSE;
1861 else
1863 *piCh = -1;
1864 *piTrailing = TRUE;
1866 return S_OK;
1869 for(item=0; item<analysis->numItems; item++)
1871 int i;
1872 int CP;
1874 for (i = 0; i < analysis->numItems && analysis->logical2visual[i] != item; i++)
1875 /* nothing */;
1877 CP = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
1878 /* initialize max extents for uninitialized runs */
1879 if (analysis->glyphs[i].iMaxPosX == -1)
1881 if (analysis->pItem[i].a.fRTL)
1882 ScriptCPtoX(0, FALSE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1883 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1884 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1885 else
1886 ScriptCPtoX(CP, TRUE, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1887 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1888 &analysis->pItem[i].a, &analysis->glyphs[i].iMaxPosX);
1891 if (iX > analysis->glyphs[i].iMaxPosX)
1893 iX -= analysis->glyphs[i].iMaxPosX;
1894 continue;
1897 ScriptXtoCP(iX, CP, analysis->glyphs[i].numGlyphs, analysis->glyphs[i].pwLogClust,
1898 analysis->glyphs[i].psva, analysis->glyphs[i].piAdvance,
1899 &analysis->pItem[i].a, piCh, piTrailing);
1900 *piCh += analysis->pItem[i].iCharPos;
1902 return S_OK;
1905 /* out of range */
1906 *piCh = analysis->pItem[analysis->numItems].iCharPos;
1907 *piTrailing = FALSE;
1909 return S_OK;
1913 /***********************************************************************
1914 * ScriptStringFree (USP10.@)
1916 * Free a string analysis.
1918 * PARAMS
1919 * pssa [I] string analysis.
1921 * RETURNS
1922 * Success: S_OK
1923 * Failure: Non-zero HRESULT value.
1925 HRESULT WINAPI ScriptStringFree(SCRIPT_STRING_ANALYSIS *pssa)
1927 StringAnalysis* analysis;
1928 BOOL invalid;
1929 int i;
1931 TRACE("(%p)\n", pssa);
1933 if (!pssa || !(analysis = *pssa)) return E_INVALIDARG;
1935 invalid = analysis->invalid;
1937 if (analysis->glyphs)
1939 for (i = 0; i < analysis->numItems; i++)
1941 heap_free(analysis->glyphs[i].glyphs);
1942 heap_free(analysis->glyphs[i].pwLogClust);
1943 heap_free(analysis->glyphs[i].piAdvance);
1944 heap_free(analysis->glyphs[i].psva);
1945 heap_free(analysis->glyphs[i].pGoffset);
1946 heap_free(analysis->glyphs[i].abc);
1947 if (analysis->glyphs[i].fallbackFont)
1948 DeleteObject(analysis->glyphs[i].fallbackFont);
1949 ScriptFreeCache((SCRIPT_CACHE *)&analysis->glyphs[i].sc);
1950 heap_free(analysis->glyphs[i].sc);
1952 heap_free(analysis->glyphs);
1955 heap_free(analysis->pItem);
1956 heap_free(analysis->logattrs);
1957 heap_free(analysis->sz);
1958 heap_free(analysis->logical2visual);
1959 heap_free(analysis);
1961 if (invalid) return E_INVALIDARG;
1962 return S_OK;
1965 static inline int get_cluster_size(const WORD *pwLogClust, int cChars, int item,
1966 int direction, int* iCluster, int *check_out)
1968 int clust_size = 1;
1969 int check;
1970 WORD clust = pwLogClust[item];
1972 for (check = item+direction; check < cChars && check >= 0; check+=direction)
1974 if (pwLogClust[check] == clust)
1976 clust_size ++;
1977 if (iCluster && *iCluster == -1)
1978 *iCluster = item;
1980 else break;
1983 if (check_out)
1984 *check_out = check;
1986 return clust_size;
1989 static inline int get_glyph_cluster_advance(const int* piAdvance, const SCRIPT_VISATTR *pva, const WORD *pwLogClust, int cGlyphs, int cChars, int glyph, int direction)
1991 int advance;
1992 int log_clust_max = 0;
1993 int i;
1995 advance = piAdvance[glyph];
1997 for (i = 0; i < cChars; i++)
1999 if (pwLogClust[i] > log_clust_max)
2000 log_clust_max = pwLogClust[i];
2003 if (glyph > log_clust_max)
2004 return advance;
2006 for (glyph+=direction; glyph < cGlyphs && glyph >= 0; glyph +=direction)
2009 if (does_glyph_start_cluster(pva, pwLogClust, cChars, glyph, direction))
2010 break;
2011 if (glyph > log_clust_max)
2012 break;
2013 advance += piAdvance[glyph];
2016 return advance;
2019 /***********************************************************************
2020 * ScriptCPtoX (USP10.@)
2023 HRESULT WINAPI ScriptCPtoX(int iCP,
2024 BOOL fTrailing,
2025 int cChars,
2026 int cGlyphs,
2027 const WORD *pwLogClust,
2028 const SCRIPT_VISATTR *psva,
2029 const int *piAdvance,
2030 const SCRIPT_ANALYSIS *psa,
2031 int *piX)
2033 int item;
2034 float iPosX;
2035 int iSpecial = -1;
2036 int iCluster = -1;
2037 int clust_size = 1;
2038 float special_size = 0.0;
2039 int iMaxPos = 0;
2040 int advance = 0;
2041 BOOL rtl = FALSE;
2043 TRACE("(%d,%d,%d,%d,%p,%p,%p,%p,%p)\n",
2044 iCP, fTrailing, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2045 psa, piX);
2047 if (psa->fRTL && ! psa->fLogicalOrder)
2048 rtl = TRUE;
2050 if (fTrailing)
2051 iCP++;
2053 if (rtl)
2055 int max_clust = pwLogClust[0];
2057 for (item=0; item < cGlyphs; item++)
2058 if (pwLogClust[item] > max_clust)
2060 ERR("We do not handle non reversed clusters properly\n");
2061 break;
2064 iMaxPos = 0;
2065 for (item = max_clust; item >=0; item --)
2066 iMaxPos += piAdvance[item];
2069 iPosX = 0.0;
2070 for (item=0; item < iCP && item < cChars; item++)
2072 if (iSpecial == -1 && (iCluster == -1 || (iCluster != -1 && iCluster+clust_size <= item)))
2074 int check;
2075 int clust = pwLogClust[item];
2077 iCluster = -1;
2078 clust_size = get_cluster_size(pwLogClust, cChars, item, 1, &iCluster,
2079 &check);
2081 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, 1);
2083 if (check >= cChars && !iMaxPos)
2085 for (check = clust; check < cChars; check++)
2086 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, 1);
2087 iSpecial = item;
2088 special_size /= (cChars - item);
2089 iPosX += special_size;
2091 else
2093 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2095 clust_size --;
2096 if (clust_size == 0)
2097 iPosX += advance;
2099 else
2100 iPosX += advance / (float)clust_size;
2103 else if (iSpecial != -1)
2104 iPosX += special_size;
2105 else /* (iCluster != -1) */
2107 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], 1);
2108 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2110 clust_size --;
2111 if (clust_size == 0)
2112 iPosX += adv;
2114 else
2115 iPosX += adv / (float)clust_size;
2119 if (iMaxPos > 0)
2121 iPosX = iMaxPos - iPosX;
2122 if (iPosX < 0)
2123 iPosX = 0;
2126 *piX = iPosX;
2127 TRACE("*piX=%d\n", *piX);
2128 return S_OK;
2131 /***********************************************************************
2132 * ScriptXtoCP (USP10.@)
2135 HRESULT WINAPI ScriptXtoCP(int iX,
2136 int cChars,
2137 int cGlyphs,
2138 const WORD *pwLogClust,
2139 const SCRIPT_VISATTR *psva,
2140 const int *piAdvance,
2141 const SCRIPT_ANALYSIS *psa,
2142 int *piCP,
2143 int *piTrailing)
2145 int item;
2146 float iPosX;
2147 float iLastPosX;
2148 int iSpecial = -1;
2149 int iCluster = -1;
2150 int clust_size = 1;
2151 int cjump = 0;
2152 int advance;
2153 float special_size = 0.0;
2154 int direction = 1;
2156 TRACE("(%d,%d,%d,%p,%p,%p,%p,%p,%p)\n",
2157 iX, cChars, cGlyphs, pwLogClust, psva, piAdvance,
2158 psa, piCP, piTrailing);
2160 if (psa->fRTL && ! psa->fLogicalOrder)
2161 direction = -1;
2163 if (direction<0)
2165 int max_clust = pwLogClust[0];
2167 if (iX < 0)
2169 *piCP = cChars;
2170 *piTrailing = 0;
2171 return S_OK;
2174 for (item=0; item < cChars; item++)
2175 if (pwLogClust[item] > max_clust)
2177 ERR("We do not handle non reversed clusters properly\n");
2178 break;
2182 if (iX < 0)
2184 *piCP = -1;
2185 *piTrailing = 1;
2186 return S_OK;
2189 iPosX = iLastPosX = 0;
2190 if (direction > 0)
2191 item = 0;
2192 else
2193 item = cChars - 1;
2194 for (; iPosX <= iX && item < cChars && item >= 0; item+=direction)
2196 iLastPosX = iPosX;
2197 if (iSpecial == -1 &&
2198 (iCluster == -1 ||
2199 (iCluster != -1 &&
2200 ((direction > 0 && iCluster+clust_size <= item) ||
2201 (direction < 0 && iCluster-clust_size >= item))
2206 int check;
2207 int clust = pwLogClust[item];
2209 iCluster = -1;
2210 cjump = 0;
2211 clust_size = get_cluster_size(pwLogClust, cChars, item, direction,
2212 &iCluster, &check);
2213 advance = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, clust, direction);
2215 if (check >= cChars && direction > 0)
2217 for (check = clust; check < cChars; check++)
2218 special_size += get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, check, direction);
2219 iSpecial = item;
2220 special_size /= (cChars - item);
2221 iPosX += special_size;
2223 else
2225 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2227 if (!cjump)
2228 iPosX += advance;
2229 cjump++;
2231 else
2232 iPosX += advance / (float)clust_size;
2235 else if (iSpecial != -1)
2236 iPosX += special_size;
2237 else /* (iCluster != -1) */
2239 int adv = get_glyph_cluster_advance(piAdvance, psva, pwLogClust, cGlyphs, cChars, pwLogClust[iCluster], direction);
2240 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo)
2242 if (!cjump)
2243 iPosX += adv;
2244 cjump++;
2246 else
2247 iPosX += adv / (float)clust_size;
2251 if (direction > 0)
2253 if (iPosX > iX)
2254 item--;
2255 if (item < cChars && ((iPosX - iLastPosX) / 2.0) + iX >= iPosX)
2257 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
2258 item+=(clust_size-1);
2259 *piTrailing = 1;
2261 else
2262 *piTrailing = 0;
2264 else
2266 if (iX == iLastPosX)
2267 item++;
2268 if (iX >= iLastPosX && iX <= iPosX)
2269 item++;
2271 if (iLastPosX == iX)
2272 *piTrailing = 0;
2273 else if (item < 0 || ((iLastPosX - iPosX) / 2.0) + iX <= iLastPosX)
2275 if (scriptInformation[psa->eScript].props.fNeedsCaretInfo && clust_size > 1)
2276 item-=(clust_size-1);
2277 *piTrailing = 1;
2279 else
2280 *piTrailing = 0;
2283 *piCP = item;
2285 TRACE("*piCP=%d\n", *piCP);
2286 TRACE("*piTrailing=%d\n", *piTrailing);
2287 return S_OK;
2290 /***********************************************************************
2291 * ScriptBreak (USP10.@)
2293 * Retrieve line break information.
2295 * PARAMS
2296 * chars [I] Array of characters.
2297 * sa [I] String analysis.
2298 * la [I] Array of logical attribute structures.
2300 * RETURNS
2301 * Success: S_OK
2302 * Failure: S_FALSE
2304 HRESULT WINAPI ScriptBreak(const WCHAR *chars, int count, const SCRIPT_ANALYSIS *sa, SCRIPT_LOGATTR *la)
2306 TRACE("(%s, %d, %p, %p)\n", debugstr_wn(chars, count), count, sa, la);
2308 if (!la) return S_FALSE;
2310 BREAK_line(chars, count, sa, la);
2312 return S_OK;
2315 /***********************************************************************
2316 * ScriptIsComplex (USP10.@)
2318 * Determine if a string is complex.
2320 * PARAMS
2321 * chars [I] Array of characters to test.
2322 * len [I] Length in characters.
2323 * flag [I] Flag.
2325 * RETURNS
2326 * Success: S_OK
2327 * Failure: S_FALSE
2330 HRESULT WINAPI ScriptIsComplex(const WCHAR *chars, int len, DWORD flag)
2332 int i;
2334 TRACE("(%s,%d,0x%x)\n", debugstr_wn(chars, len), len, flag);
2336 for (i = 0; i < len; i++)
2338 int script;
2340 if ((flag & SIC_ASCIIDIGIT) && chars[i] >= 0x30 && chars[i] <= 0x39)
2341 return S_OK;
2343 script = get_char_script(chars[i]);
2344 if ((scriptInformation[script].props.fComplex && (flag & SIC_COMPLEX))||
2345 (!scriptInformation[script].props.fComplex && (flag & SIC_NEUTRAL)))
2346 return S_OK;
2348 return S_FALSE;
2351 /***********************************************************************
2352 * ScriptShapeOpenType (USP10.@)
2354 * Produce glyphs and visual attributes for a run.
2356 * PARAMS
2357 * hdc [I] Device context.
2358 * psc [I/O] Opaque pointer to a script cache.
2359 * psa [I/O] Script analysis.
2360 * tagScript [I] The OpenType tag for the Script
2361 * tagLangSys [I] The OpenType tag for the Language
2362 * rcRangeChars[I] Array of Character counts in each range
2363 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2364 * cRanges [I] Count of ranges
2365 * pwcChars [I] Array of characters specifying the run.
2366 * cChars [I] Number of characters in pwcChars.
2367 * cMaxGlyphs [I] Length of pwOutGlyphs.
2368 * pwLogClust [O] Array of logical cluster info.
2369 * pCharProps [O] Array of character property values
2370 * pwOutGlyphs [O] Array of glyphs.
2371 * pOutGlyphProps [O] Array of attributes for the retrieved glyphs
2372 * pcGlyphs [O] Number of glyphs returned.
2374 * RETURNS
2375 * Success: S_OK
2376 * Failure: Non-zero HRESULT value.
2378 HRESULT WINAPI ScriptShapeOpenType( HDC hdc, SCRIPT_CACHE *psc,
2379 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2380 OPENTYPE_TAG tagLangSys, int *rcRangeChars,
2381 TEXTRANGE_PROPERTIES **rpRangeProperties,
2382 int cRanges, const WCHAR *pwcChars, int cChars,
2383 int cMaxGlyphs, WORD *pwLogClust,
2384 SCRIPT_CHARPROP *pCharProps, WORD *pwOutGlyphs,
2385 SCRIPT_GLYPHPROP *pOutGlyphProps, int *pcGlyphs)
2387 HRESULT hr;
2388 unsigned int i;
2389 BOOL rtl;
2391 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %d, %d, %p, %p, %p, %p, %p )\n",
2392 hdc, psc, psa,
2393 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2394 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2395 cChars, cMaxGlyphs, pwLogClust, pCharProps, pwOutGlyphs, pOutGlyphProps, pcGlyphs);
2397 if (psa) TRACE("psa values: %d, %d, %d, %d, %d, %d, %d\n", psa->eScript, psa->fRTL, psa->fLayoutRTL,
2398 psa->fLinkBefore, psa->fLinkAfter, psa->fLogicalOrder, psa->fNoGlyphIndex);
2400 if (!pOutGlyphProps || !pcGlyphs || !pCharProps) return E_INVALIDARG;
2401 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2403 if (cRanges)
2404 FIXME("Ranges not supported yet\n");
2406 rtl = (psa && !psa->fLogicalOrder && psa->fRTL);
2408 *pcGlyphs = cChars;
2409 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2410 if (!pwLogClust) return E_FAIL;
2412 ((ScriptCache *)*psc)->userScript = tagScript;
2413 ((ScriptCache *)*psc)->userLang = tagLangSys;
2415 /* set fNoGlyphIndex non truetype/opentype fonts */
2416 if (!psa->fNoGlyphIndex && !((ScriptCache *)*psc)->sfnt)
2417 psa->fNoGlyphIndex = TRUE;
2419 /* Initialize a SCRIPT_VISATTR and LogClust for each char in this run */
2420 for (i = 0; i < cChars; i++)
2422 int idx = i;
2423 if (rtl) idx = cChars - 1 - i;
2424 /* FIXME: set to better values */
2425 pOutGlyphProps[i].sva.uJustification = (pwcChars[idx] == ' ') ? SCRIPT_JUSTIFY_BLANK : SCRIPT_JUSTIFY_CHARACTER;
2426 pOutGlyphProps[i].sva.fClusterStart = 1;
2427 pOutGlyphProps[i].sva.fDiacritic = 0;
2428 pOutGlyphProps[i].sva.fZeroWidth = 0;
2429 pOutGlyphProps[i].sva.fReserved = 0;
2430 pOutGlyphProps[i].sva.fShapeReserved = 0;
2432 /* FIXME: have the shaping engine set this */
2433 pCharProps[i].fCanGlyphAlone = 0;
2435 pwLogClust[i] = idx;
2438 if (psa && !psa->fNoGlyphIndex)
2440 WCHAR *rChars;
2441 if ((hr = SHAPE_CheckFontForRequiredFeatures(hdc, (ScriptCache *)*psc, psa)) != S_OK) return hr;
2443 rChars = heap_alloc(sizeof(WCHAR) * cChars);
2444 if (!rChars) return E_OUTOFMEMORY;
2445 for (i = 0; i < cChars; i++)
2447 int idx = i;
2448 WCHAR chInput;
2449 if (rtl) idx = cChars - 1 - i;
2450 if (psa->fRTL)
2451 chInput = mirror_char(pwcChars[idx]);
2452 else
2453 chInput = pwcChars[idx];
2454 /* special case for tabs */
2455 if (chInput == 0x0009)
2456 chInput = 0x0020;
2457 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, chInput)))
2459 WORD glyph;
2460 if (!hdc)
2462 heap_free(rChars);
2463 return E_PENDING;
2465 if (GetGlyphIndicesW(hdc, &chInput, 1, &glyph, 0) == GDI_ERROR)
2467 heap_free(rChars);
2468 return S_FALSE;
2470 pwOutGlyphs[i] = set_cache_glyph(psc, chInput, glyph);
2472 rChars[i] = chInput;
2475 SHAPE_ContextualShaping(hdc, (ScriptCache *)*psc, psa, rChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2476 SHAPE_ApplyDefaultOpentypeFeatures(hdc, (ScriptCache *)*psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, pwLogClust);
2477 SHAPE_CharGlyphProp(hdc, (ScriptCache *)*psc, psa, pwcChars, cChars, pwOutGlyphs, *pcGlyphs, pwLogClust, pCharProps, pOutGlyphProps);
2478 heap_free(rChars);
2480 else
2482 TRACE("no glyph translation\n");
2483 for (i = 0; i < cChars; i++)
2485 int idx = i;
2486 /* No mirroring done here */
2487 if (rtl) idx = cChars - 1 - i;
2488 pwOutGlyphs[i] = pwcChars[idx];
2492 return S_OK;
2496 /***********************************************************************
2497 * ScriptShape (USP10.@)
2499 * Produce glyphs and visual attributes for a run.
2501 * PARAMS
2502 * hdc [I] Device context.
2503 * psc [I/O] Opaque pointer to a script cache.
2504 * pwcChars [I] Array of characters specifying the run.
2505 * cChars [I] Number of characters in pwcChars.
2506 * cMaxGlyphs [I] Length of pwOutGlyphs.
2507 * psa [I/O] Script analysis.
2508 * pwOutGlyphs [O] Array of glyphs.
2509 * pwLogClust [O] Array of logical cluster info.
2510 * psva [O] Array of visual attributes.
2511 * pcGlyphs [O] Number of glyphs returned.
2513 * RETURNS
2514 * Success: S_OK
2515 * Failure: Non-zero HRESULT value.
2517 HRESULT WINAPI ScriptShape(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcChars,
2518 int cChars, int cMaxGlyphs,
2519 SCRIPT_ANALYSIS *psa, WORD *pwOutGlyphs, WORD *pwLogClust,
2520 SCRIPT_VISATTR *psva, int *pcGlyphs)
2522 HRESULT hr;
2523 int i;
2524 SCRIPT_CHARPROP *charProps;
2525 SCRIPT_GLYPHPROP *glyphProps;
2527 if (!psva || !pcGlyphs) return E_INVALIDARG;
2528 if (cChars > cMaxGlyphs) return E_OUTOFMEMORY;
2530 charProps = heap_alloc_zero(sizeof(SCRIPT_CHARPROP)*cChars);
2531 if (!charProps) return E_OUTOFMEMORY;
2532 glyphProps = heap_alloc_zero(sizeof(SCRIPT_GLYPHPROP)*cMaxGlyphs);
2533 if (!glyphProps)
2535 heap_free(charProps);
2536 return E_OUTOFMEMORY;
2539 hr = ScriptShapeOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, pwcChars, cChars, cMaxGlyphs, pwLogClust, charProps, pwOutGlyphs, glyphProps, pcGlyphs);
2541 if (SUCCEEDED(hr))
2543 for (i = 0; i < *pcGlyphs; i++)
2544 psva[i] = glyphProps[i].sva;
2547 heap_free(charProps);
2548 heap_free(glyphProps);
2550 return hr;
2553 /***********************************************************************
2554 * ScriptPlaceOpenType (USP10.@)
2556 * Produce advance widths for a run.
2558 * PARAMS
2559 * hdc [I] Device context.
2560 * psc [I/O] Opaque pointer to a script cache.
2561 * psa [I/O] String analysis.
2562 * tagScript [I] The OpenType tag for the Script
2563 * tagLangSys [I] The OpenType tag for the Language
2564 * rcRangeChars[I] Array of Character counts in each range
2565 * rpRangeProperties [I] Array of TEXTRANGE_PROPERTIES structures
2566 * cRanges [I] Count of ranges
2567 * pwcChars [I] Array of characters specifying the run.
2568 * pwLogClust [I] Array of logical cluster info
2569 * pCharProps [I] Array of character property values
2570 * cChars [I] Number of characters in pwcChars.
2571 * pwGlyphs [I] Array of glyphs.
2572 * pGlyphProps [I] Array of attributes for the retrieved glyphs
2573 * cGlyphs [I] Count of Glyphs
2574 * piAdvance [O] Array of advance widths.
2575 * pGoffset [O] Glyph offsets.
2576 * pABC [O] Combined ABC width.
2578 * RETURNS
2579 * Success: S_OK
2580 * Failure: Non-zero HRESULT value.
2583 HRESULT WINAPI ScriptPlaceOpenType( HDC hdc, SCRIPT_CACHE *psc, SCRIPT_ANALYSIS *psa,
2584 OPENTYPE_TAG tagScript, OPENTYPE_TAG tagLangSys,
2585 int *rcRangeChars, TEXTRANGE_PROPERTIES **rpRangeProperties,
2586 int cRanges, const WCHAR *pwcChars, WORD *pwLogClust,
2587 SCRIPT_CHARPROP *pCharProps, int cChars,
2588 const WORD *pwGlyphs, const SCRIPT_GLYPHPROP *pGlyphProps,
2589 int cGlyphs, int *piAdvance,
2590 GOFFSET *pGoffset, ABC *pABC
2593 HRESULT hr;
2594 int i;
2596 TRACE("(%p, %p, %p, %s, %s, %p, %p, %d, %s, %p, %p, %d, %p, %p, %d, %p %p %p)\n",
2597 hdc, psc, psa,
2598 debugstr_an((char*)&tagScript,4), debugstr_an((char*)&tagLangSys,4),
2599 rcRangeChars, rpRangeProperties, cRanges, debugstr_wn(pwcChars, cChars),
2600 pwLogClust, pCharProps, cChars, pwGlyphs, pGlyphProps, cGlyphs, piAdvance,
2601 pGoffset, pABC);
2603 if (!pGlyphProps) return E_INVALIDARG;
2604 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2605 if (!pGoffset) return E_FAIL;
2607 if (cRanges)
2608 FIXME("Ranges not supported yet\n");
2610 ((ScriptCache *)*psc)->userScript = tagScript;
2611 ((ScriptCache *)*psc)->userLang = tagLangSys;
2613 if (pABC) memset(pABC, 0, sizeof(ABC));
2614 for (i = 0; i < cGlyphs; i++)
2616 ABC abc;
2617 if (!get_cache_glyph_widths(psc, pwGlyphs[i], &abc))
2619 if (!hdc) return E_PENDING;
2620 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE) && !psa->fNoGlyphIndex)
2622 if (!GetCharABCWidthsI(hdc, 0, 1, (WORD *)&pwGlyphs[i], &abc)) return S_FALSE;
2624 else
2626 INT width;
2627 if (!GetCharWidth32W(hdc, pwGlyphs[i], pwGlyphs[i], &width)) return S_FALSE;
2628 abc.abcB = width;
2629 abc.abcA = abc.abcC = 0;
2631 set_cache_glyph_widths(psc, pwGlyphs[i], &abc);
2633 if (pABC)
2635 pABC->abcA += abc.abcA;
2636 pABC->abcB += abc.abcB;
2637 pABC->abcC += abc.abcC;
2639 /* FIXME: set to more reasonable values */
2640 pGoffset[i].du = pGoffset[i].dv = 0;
2641 if (piAdvance) piAdvance[i] = abc.abcA + abc.abcB + abc.abcC;
2644 if (pABC) TRACE("Total for run: abcA=%d, abcB=%d, abcC=%d\n", pABC->abcA, pABC->abcB, pABC->abcC);
2645 return S_OK;
2648 /***********************************************************************
2649 * ScriptPlace (USP10.@)
2651 * Produce advance widths for a run.
2653 * PARAMS
2654 * hdc [I] Device context.
2655 * psc [I/O] Opaque pointer to a script cache.
2656 * pwGlyphs [I] Array of glyphs.
2657 * cGlyphs [I] Number of glyphs in pwGlyphs.
2658 * psva [I] Array of visual attributes.
2659 * psa [I/O] String analysis.
2660 * piAdvance [O] Array of advance widths.
2661 * pGoffset [O] Glyph offsets.
2662 * pABC [O] Combined ABC width.
2664 * RETURNS
2665 * Success: S_OK
2666 * Failure: Non-zero HRESULT value.
2668 HRESULT WINAPI ScriptPlace(HDC hdc, SCRIPT_CACHE *psc, const WORD *pwGlyphs,
2669 int cGlyphs, const SCRIPT_VISATTR *psva,
2670 SCRIPT_ANALYSIS *psa, int *piAdvance, GOFFSET *pGoffset, ABC *pABC )
2672 HRESULT hr;
2673 SCRIPT_GLYPHPROP *glyphProps;
2674 int i;
2676 TRACE("(%p, %p, %p, %d, %p, %p, %p, %p, %p)\n", hdc, psc, pwGlyphs, cGlyphs, psva, psa,
2677 piAdvance, pGoffset, pABC);
2679 if (!psva) return E_INVALIDARG;
2680 if (!pGoffset) return E_FAIL;
2682 glyphProps = heap_alloc(sizeof(SCRIPT_GLYPHPROP)*cGlyphs);
2683 if (!glyphProps) return E_OUTOFMEMORY;
2685 for (i = 0; i < cGlyphs; i++)
2686 glyphProps[i].sva = psva[i];
2688 hr = ScriptPlaceOpenType(hdc, psc, psa, scriptInformation[psa->eScript].scriptTag, 0, NULL, NULL, 0, NULL, NULL, NULL, 0, pwGlyphs, glyphProps, cGlyphs, piAdvance, pGoffset, pABC);
2690 heap_free(glyphProps);
2692 return hr;
2695 /***********************************************************************
2696 * ScriptGetCMap (USP10.@)
2698 * Retrieve glyph indices.
2700 * PARAMS
2701 * hdc [I] Device context.
2702 * psc [I/O] Opaque pointer to a script cache.
2703 * pwcInChars [I] Array of Unicode characters.
2704 * cChars [I] Number of characters in pwcInChars.
2705 * dwFlags [I] Flags.
2706 * pwOutGlyphs [O] Buffer to receive the array of glyph indices.
2708 * RETURNS
2709 * Success: S_OK
2710 * Failure: Non-zero HRESULT value.
2712 HRESULT WINAPI ScriptGetCMap(HDC hdc, SCRIPT_CACHE *psc, const WCHAR *pwcInChars,
2713 int cChars, DWORD dwFlags, WORD *pwOutGlyphs)
2715 HRESULT hr;
2716 int i;
2718 TRACE("(%p,%p,%s,%d,0x%x,%p)\n", hdc, psc, debugstr_wn(pwcInChars, cChars),
2719 cChars, dwFlags, pwOutGlyphs);
2721 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2723 hr = S_OK;
2725 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2727 for (i = 0; i < cChars; i++)
2729 WCHAR inChar;
2730 if (dwFlags == SGCM_RTL)
2731 inChar = mirror_char(pwcInChars[i]);
2732 else
2733 inChar = pwcInChars[i];
2734 if (!(pwOutGlyphs[i] = get_cache_glyph(psc, inChar)))
2736 WORD glyph;
2737 if (!hdc) return E_PENDING;
2738 if (GetGlyphIndicesW(hdc, &inChar, 1, &glyph, GGI_MARK_NONEXISTING_GLYPHS) == GDI_ERROR) return S_FALSE;
2739 if (glyph == 0xffff)
2741 hr = S_FALSE;
2742 glyph = 0x0;
2744 pwOutGlyphs[i] = set_cache_glyph(psc, inChar, glyph);
2748 else
2750 TRACE("no glyph translation\n");
2751 for (i = 0; i < cChars; i++)
2753 WCHAR inChar;
2754 if (dwFlags == SGCM_RTL)
2755 inChar = mirror_char(pwcInChars[i]);
2756 else
2757 inChar = pwcInChars[i];
2758 pwOutGlyphs[i] = inChar;
2761 return hr;
2764 /***********************************************************************
2765 * ScriptTextOut (USP10.@)
2768 HRESULT WINAPI ScriptTextOut(const HDC hdc, SCRIPT_CACHE *psc, int x, int y, UINT fuOptions,
2769 const RECT *lprc, const SCRIPT_ANALYSIS *psa, const WCHAR *pwcReserved,
2770 int iReserved, const WORD *pwGlyphs, int cGlyphs, const int *piAdvance,
2771 const int *piJustify, const GOFFSET *pGoffset)
2773 HRESULT hr = S_OK;
2775 TRACE("(%p, %p, %d, %d, %04x, %p, %p, %p, %d, %p, %d, %p, %p, %p)\n",
2776 hdc, psc, x, y, fuOptions, lprc, psa, pwcReserved, iReserved, pwGlyphs, cGlyphs,
2777 piAdvance, piJustify, pGoffset);
2779 if (!hdc || !psc) return E_INVALIDARG;
2780 if (!piAdvance || !psa || !pwGlyphs) return E_INVALIDARG;
2782 fuOptions &= ETO_CLIPPED + ETO_OPAQUE;
2783 fuOptions |= ETO_IGNORELANGUAGE;
2784 if (!psa->fNoGlyphIndex) /* Have Glyphs? */
2785 fuOptions |= ETO_GLYPH_INDEX; /* Say don't do translation to glyph */
2787 if (psa->fRTL && psa->fLogicalOrder)
2789 int i;
2790 WORD *rtlGlyphs;
2792 rtlGlyphs = heap_alloc(cGlyphs * sizeof(WORD));
2793 if (!rtlGlyphs)
2794 return E_OUTOFMEMORY;
2796 for (i = 0; i < cGlyphs; i++)
2797 rtlGlyphs[i] = pwGlyphs[cGlyphs-1-i];
2799 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, rtlGlyphs, cGlyphs, NULL))
2800 hr = S_FALSE;
2801 heap_free(rtlGlyphs);
2803 else
2804 if (!ExtTextOutW(hdc, x, y, fuOptions, lprc, pwGlyphs, cGlyphs, NULL))
2805 hr = S_FALSE;
2807 return hr;
2810 /***********************************************************************
2811 * ScriptCacheGetHeight (USP10.@)
2813 * Retrieve the height of the font in the cache.
2815 * PARAMS
2816 * hdc [I] Device context.
2817 * psc [I/O] Opaque pointer to a script cache.
2818 * height [O] Receives font height.
2820 * RETURNS
2821 * Success: S_OK
2822 * Failure: Non-zero HRESULT value.
2824 HRESULT WINAPI ScriptCacheGetHeight(HDC hdc, SCRIPT_CACHE *psc, LONG *height)
2826 HRESULT hr;
2828 TRACE("(%p, %p, %p)\n", hdc, psc, height);
2830 if (!height) return E_INVALIDARG;
2831 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2833 *height = get_cache_height(psc);
2834 return S_OK;
2837 /***********************************************************************
2838 * ScriptGetGlyphABCWidth (USP10.@)
2840 * Retrieve the width of a glyph.
2842 * PARAMS
2843 * hdc [I] Device context.
2844 * psc [I/O] Opaque pointer to a script cache.
2845 * glyph [I] Glyph to retrieve the width for.
2846 * abc [O] ABC widths of the glyph.
2848 * RETURNS
2849 * Success: S_OK
2850 * Failure: Non-zero HRESULT value.
2852 HRESULT WINAPI ScriptGetGlyphABCWidth(HDC hdc, SCRIPT_CACHE *psc, WORD glyph, ABC *abc)
2854 HRESULT hr;
2856 TRACE("(%p, %p, 0x%04x, %p)\n", hdc, psc, glyph, abc);
2858 if (!abc) return E_INVALIDARG;
2859 if ((hr = init_script_cache(hdc, psc)) != S_OK) return hr;
2861 if (!get_cache_glyph_widths(psc, glyph, abc))
2863 if (!hdc) return E_PENDING;
2864 if ((get_cache_pitch_family(psc) & TMPF_TRUETYPE))
2866 if (!GetCharABCWidthsI(hdc, 0, 1, &glyph, abc)) return S_FALSE;
2868 else
2870 INT width;
2871 if (!GetCharWidth32W(hdc, glyph, glyph, &width)) return S_FALSE;
2872 abc->abcB = width;
2873 abc->abcA = abc->abcC = 0;
2875 set_cache_glyph_widths(psc, glyph, abc);
2877 return S_OK;
2880 /***********************************************************************
2881 * ScriptLayout (USP10.@)
2883 * Map embedding levels to visual and/or logical order.
2885 * PARAMS
2886 * runs [I] Size of level array.
2887 * level [I] Array of embedding levels.
2888 * vistolog [O] Map of embedding levels from visual to logical order.
2889 * logtovis [O] Map of embedding levels from logical to visual order.
2891 * RETURNS
2892 * Success: S_OK
2893 * Failure: Non-zero HRESULT value.
2895 * BUGS
2896 * This stub works correctly for any sequence of a single
2897 * embedding level but not for sequences of different
2898 * embedding levels, i.e. mixtures of RTL and LTR scripts.
2900 HRESULT WINAPI ScriptLayout(int runs, const BYTE *level, int *vistolog, int *logtovis)
2902 int* indexs;
2903 int ich;
2905 TRACE("(%d, %p, %p, %p)\n", runs, level, vistolog, logtovis);
2907 if (!level || (!vistolog && !logtovis))
2908 return E_INVALIDARG;
2910 indexs = heap_alloc(sizeof(int) * runs);
2911 if (!indexs)
2912 return E_OUTOFMEMORY;
2915 if (vistolog)
2917 for( ich = 0; ich < runs; ich++)
2918 indexs[ich] = ich;
2920 ich = 0;
2921 while (ich < runs)
2922 ich += BIDI_ReorderV2lLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2923 for (ich = 0; ich < runs; ich++)
2924 vistolog[ich] = indexs[ich];
2928 if (logtovis)
2930 for( ich = 0; ich < runs; ich++)
2931 indexs[ich] = ich;
2933 ich = 0;
2934 while (ich < runs)
2935 ich += BIDI_ReorderL2vLevel(0, indexs+ich, level+ich, runs - ich, FALSE);
2936 for (ich = 0; ich < runs; ich++)
2937 logtovis[ich] = indexs[ich];
2939 heap_free(indexs);
2941 return S_OK;
2944 /***********************************************************************
2945 * ScriptStringGetLogicalWidths (USP10.@)
2947 * Returns logical widths from a string analysis.
2949 * PARAMS
2950 * ssa [I] string analysis.
2951 * piDx [O] logical widths returned.
2953 * RETURNS
2954 * Success: S_OK
2955 * Failure: a non-zero HRESULT.
2957 HRESULT WINAPI ScriptStringGetLogicalWidths(SCRIPT_STRING_ANALYSIS ssa, int *piDx)
2959 int i, j, next = 0;
2960 StringAnalysis *analysis = ssa;
2962 TRACE("%p, %p\n", ssa, piDx);
2964 if (!analysis) return S_FALSE;
2965 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
2967 for (i = 0; i < analysis->numItems; i++)
2969 int cChar = analysis->pItem[i+1].iCharPos - analysis->pItem[i].iCharPos;
2970 int direction = 1;
2972 if (analysis->pItem[i].a.fRTL && ! analysis->pItem[i].a.fLogicalOrder)
2973 direction = -1;
2975 for (j = 0; j < cChar; j++)
2977 int k;
2978 int glyph = analysis->glyphs[i].pwLogClust[j];
2979 int clust_size = get_cluster_size(analysis->glyphs[i].pwLogClust,
2980 cChar, j, direction, NULL, NULL);
2981 int advance = get_glyph_cluster_advance(analysis->glyphs[i].piAdvance, analysis->glyphs[i].psva, analysis->glyphs[i].pwLogClust, analysis->glyphs[i].numGlyphs, cChar, glyph, direction);
2983 for (k = 0; k < clust_size; k++)
2985 piDx[next] = advance / clust_size;
2986 next++;
2987 if (k) j++;
2991 return S_OK;
2994 /***********************************************************************
2995 * ScriptStringValidate (USP10.@)
2997 * Validate a string analysis.
2999 * PARAMS
3000 * ssa [I] string analysis.
3002 * RETURNS
3003 * Success: S_OK
3004 * Failure: S_FALSE if invalid sequences are found
3005 * or a non-zero HRESULT if it fails.
3007 HRESULT WINAPI ScriptStringValidate(SCRIPT_STRING_ANALYSIS ssa)
3009 StringAnalysis *analysis = ssa;
3011 TRACE("(%p)\n", ssa);
3013 if (!analysis) return E_INVALIDARG;
3014 return (analysis->invalid) ? S_FALSE : S_OK;
3017 /***********************************************************************
3018 * ScriptString_pSize (USP10.@)
3020 * Retrieve width and height of an analysed string.
3022 * PARAMS
3023 * ssa [I] string analysis.
3025 * RETURNS
3026 * Success: Pointer to a SIZE structure.
3027 * Failure: NULL
3029 const SIZE * WINAPI ScriptString_pSize(SCRIPT_STRING_ANALYSIS ssa)
3031 int i, j;
3032 StringAnalysis *analysis = ssa;
3034 TRACE("(%p)\n", ssa);
3036 if (!analysis) return NULL;
3037 if (!(analysis->dwFlags & SSA_GLYPHS)) return NULL;
3039 if (!analysis->sz)
3041 if (!(analysis->sz = heap_alloc(sizeof(SIZE)))) return NULL;
3042 analysis->sz->cy = analysis->glyphs[0].sc->tm.tmHeight;
3044 analysis->sz->cx = 0;
3045 for (i = 0; i < analysis->numItems; i++)
3047 if (analysis->glyphs[i].sc->tm.tmHeight > analysis->sz->cy)
3048 analysis->sz->cy = analysis->glyphs[i].sc->tm.tmHeight;
3049 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++)
3050 analysis->sz->cx += analysis->glyphs[i].piAdvance[j];
3053 return analysis->sz;
3056 /***********************************************************************
3057 * ScriptString_pLogAttr (USP10.@)
3059 * Retrieve logical attributes of an analysed string.
3061 * PARAMS
3062 * ssa [I] string analysis.
3064 * RETURNS
3065 * Success: Pointer to an array of SCRIPT_LOGATTR structures.
3066 * Failure: NULL
3068 const SCRIPT_LOGATTR * WINAPI ScriptString_pLogAttr(SCRIPT_STRING_ANALYSIS ssa)
3070 StringAnalysis *analysis = ssa;
3072 TRACE("(%p)\n", ssa);
3074 if (!analysis) return NULL;
3075 if (!(analysis->dwFlags & SSA_BREAK)) return NULL;
3076 return analysis->logattrs;
3079 /***********************************************************************
3080 * ScriptString_pcOutChars (USP10.@)
3082 * Retrieve the length of a string after clipping.
3084 * PARAMS
3085 * ssa [I] String analysis.
3087 * RETURNS
3088 * Success: Pointer to the length.
3089 * Failure: NULL
3091 const int * WINAPI ScriptString_pcOutChars(SCRIPT_STRING_ANALYSIS ssa)
3093 StringAnalysis *analysis = ssa;
3095 TRACE("(%p)\n", ssa);
3097 if (!analysis) return NULL;
3098 return &analysis->clip_len;
3101 /***********************************************************************
3102 * ScriptStringGetOrder (USP10.@)
3104 * Retrieve a glyph order map.
3106 * PARAMS
3107 * ssa [I] String analysis.
3108 * order [I/O] Array of glyph positions.
3110 * RETURNS
3111 * Success: S_OK
3112 * Failure: a non-zero HRESULT.
3114 HRESULT WINAPI ScriptStringGetOrder(SCRIPT_STRING_ANALYSIS ssa, UINT *order)
3116 int i, j;
3117 unsigned int k;
3118 StringAnalysis *analysis = ssa;
3120 TRACE("(%p)\n", ssa);
3122 if (!analysis) return S_FALSE;
3123 if (!(analysis->dwFlags & SSA_GLYPHS)) return S_FALSE;
3125 /* FIXME: handle RTL scripts */
3126 for (i = 0, k = 0; i < analysis->numItems; i++)
3127 for (j = 0; j < analysis->glyphs[i].numGlyphs; j++, k++)
3128 order[k] = k;
3130 return S_OK;
3133 /***********************************************************************
3134 * ScriptGetLogicalWidths (USP10.@)
3136 * Convert advance widths to logical widths.
3138 * PARAMS
3139 * sa [I] Script analysis.
3140 * nbchars [I] Number of characters.
3141 * nbglyphs [I] Number of glyphs.
3142 * glyph_width [I] Array of glyph widths.
3143 * log_clust [I] Array of logical clusters.
3144 * sva [I] Visual attributes.
3145 * widths [O] Array of logical widths.
3147 * RETURNS
3148 * Success: S_OK
3149 * Failure: a non-zero HRESULT.
3151 HRESULT WINAPI ScriptGetLogicalWidths(const SCRIPT_ANALYSIS *sa, int nbchars, int nbglyphs,
3152 const int *glyph_width, const WORD *log_clust,
3153 const SCRIPT_VISATTR *sva, int *widths)
3155 int i;
3157 TRACE("(%p, %d, %d, %p, %p, %p, %p)\n",
3158 sa, nbchars, nbglyphs, glyph_width, log_clust, sva, widths);
3160 /* FIXME */
3161 for (i = 0; i < nbchars; i++) widths[i] = glyph_width[i];
3162 return S_OK;
3165 /***********************************************************************
3166 * ScriptApplyLogicalWidth (USP10.@)
3168 * Generate glyph advance widths.
3170 * PARAMS
3171 * dx [I] Array of logical advance widths.
3172 * num_chars [I] Number of characters.
3173 * num_glyphs [I] Number of glyphs.
3174 * log_clust [I] Array of logical clusters.
3175 * sva [I] Visual attributes.
3176 * advance [I] Array of glyph advance widths.
3177 * sa [I] Script analysis.
3178 * abc [I/O] Summed ABC widths.
3179 * justify [O] Array of glyph advance widths.
3181 * RETURNS
3182 * Success: S_OK
3183 * Failure: a non-zero HRESULT.
3185 HRESULT WINAPI ScriptApplyLogicalWidth(const int *dx, int num_chars, int num_glyphs,
3186 const WORD *log_clust, const SCRIPT_VISATTR *sva,
3187 const int *advance, const SCRIPT_ANALYSIS *sa,
3188 ABC *abc, int *justify)
3190 int i;
3192 FIXME("(%p, %d, %d, %p, %p, %p, %p, %p, %p)\n",
3193 dx, num_chars, num_glyphs, log_clust, sva, advance, sa, abc, justify);
3195 for (i = 0; i < num_chars; i++) justify[i] = advance[i];
3196 return S_OK;
3199 HRESULT WINAPI ScriptJustify(const SCRIPT_VISATTR *sva, const int *advance,
3200 int num_glyphs, int dx, int min_kashida, int *justify)
3202 int i;
3204 FIXME("(%p, %p, %d, %d, %d, %p)\n", sva, advance, num_glyphs, dx, min_kashida, justify);
3206 for (i = 0; i < num_glyphs; i++) justify[i] = advance[i];
3207 return S_OK;