[USP10] Sync with Wine Staging 3.3. CORE-14434
[reactos.git] / dll / win32 / usp10 / shape.c
1 /*
2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
3 *
4 * Copyright 2010 CodeWeavers, Aric Stewart
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 */
21 #include <stdarg.h>
22 #include <stdlib.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "winnls.h"
29 #include "usp10.h"
30 #include "winternl.h"
31
32 #include "usp10_internal.h"
33
34 #include "wine/debug.h"
35 #include "wine/heap.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38
39 #define FIRST_ARABIC_CHAR 0x0600
40 #define LAST_ARABIC_CHAR 0x06ff
41
42 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
43 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44
45 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
63 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
64 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
65
66 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
67
68 static void ShapeCharGlyphProp_Default( ScriptCache* psc, SCRIPT_ANALYSIS* psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD* pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP* pGlyphProp);
69 static void ShapeCharGlyphProp_Control( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
70 static void ShapeCharGlyphProp_Latin( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
71 static void ShapeCharGlyphProp_Arabic( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
72 static void ShapeCharGlyphProp_Hebrew( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP* pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
73 static void ShapeCharGlyphProp_Thai( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
74 static void ShapeCharGlyphProp_None( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
75 static void ShapeCharGlyphProp_Tibet( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
76 static void ShapeCharGlyphProp_Sinhala( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
77 static void ShapeCharGlyphProp_Devanagari( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
78 static void ShapeCharGlyphProp_Bengali( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
79 static void ShapeCharGlyphProp_Gurmukhi( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
80 static void ShapeCharGlyphProp_Gujarati( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
81 static void ShapeCharGlyphProp_Oriya( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
82 static void ShapeCharGlyphProp_Tamil( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
83 static void ShapeCharGlyphProp_Telugu( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
84 static void ShapeCharGlyphProp_Kannada( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
85 static void ShapeCharGlyphProp_Malayalam( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
86 static void ShapeCharGlyphProp_Khmer( HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, const WCHAR* pwcChars, const INT cChars, const WORD* pwGlyphs, const INT cGlyphs, WORD *pwLogClust, SCRIPT_CHARPROP *pCharProp, SCRIPT_GLYPHPROP *pGlyphProp );
87
88 extern const unsigned short indic_syllabic_table[] DECLSPEC_HIDDEN;
89 extern const unsigned short wine_shaping_table[] DECLSPEC_HIDDEN;
90 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4] DECLSPEC_HIDDEN;
91
92 enum joining_types {
93 jtU,
94 jtT,
95 jtR,
96 jtL,
97 jtD,
98 jtC
99 };
100
101 enum joined_forms {
102 Xn=0,
103 Xr,
104 Xl,
105 Xm,
106 /* Syriac Alaph */
107 Afj,
108 Afn,
109 Afx
110 };
111
112 typedef struct tagVowelComponents
113 {
114 WCHAR base;
115 WCHAR parts[3];
116 } VowelComponents;
117
118 typedef struct tagConsonantComponents
119 {
120 WCHAR parts[3];
121 WCHAR output;
122 } ConsonantComponents;
123
124 typedef void (*second_reorder_function)(const WCHAR *chars, const IndicSyllable *syllable,
125 WORD *glyphs, const IndicSyllable *glyph_index, lexical_function lex);
126
127 typedef int (*combining_lexical_function)(WCHAR c);
128
129 /* the orders of joined_forms and contextual_features need to line up */
130 static const char *const contextual_features[] =
131 {
132 "isol",
133 "fina",
134 "init",
135 "medi",
136 /* Syriac Alaph */
137 "med2",
138 "fin2",
139 "fin3"
140 };
141
142 static OPENTYPE_FEATURE_RECORD standard_features[] =
143 {
144 { MS_MAKE_TAG('c','c','m','p'), 1},
145 { MS_MAKE_TAG('l','o','c','l'), 1},
146 };
147
148 static OPENTYPE_FEATURE_RECORD latin_features[] =
149 {
150 { MS_MAKE_TAG('l','o','c','l'), 1},
151 { MS_MAKE_TAG('c','c','m','p'), 1},
152 { MS_MAKE_TAG('l','i','g','a'), 1},
153 { MS_MAKE_TAG('c','l','i','g'), 1},
154 };
155
156 static OPENTYPE_FEATURE_RECORD latin_gpos_features[] =
157 {
158 { MS_MAKE_TAG('k','e','r','n'), 1},
159 { MS_MAKE_TAG('m','a','r','k'), 1},
160 { MS_MAKE_TAG('m','k','m','k'), 1},
161 };
162
163 static OPENTYPE_FEATURE_RECORD arabic_features[] =
164 {
165 { MS_MAKE_TAG('r','l','i','g'), 1},
166 { MS_MAKE_TAG('c','a','l','t'), 1},
167 { MS_MAKE_TAG('l','i','g','a'), 1},
168 { MS_MAKE_TAG('d','l','i','g'), 1},
169 { MS_MAKE_TAG('c','s','w','h'), 1},
170 { MS_MAKE_TAG('m','s','e','t'), 1},
171 };
172
173 static const char *const required_arabic_features[] =
174 {
175 "fina",
176 "init",
177 "medi",
178 "rlig",
179 NULL
180 };
181
182 static OPENTYPE_FEATURE_RECORD arabic_gpos_features[] =
183 {
184 { MS_MAKE_TAG('c','u','r','s'), 1},
185 { MS_MAKE_TAG('k','e','r','n'), 1},
186 { MS_MAKE_TAG('m','a','r','k'), 1},
187 { MS_MAKE_TAG('m','k','m','k'), 1},
188 };
189
190 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
191 {
192 { MS_MAKE_TAG('c','c','m','p'), 1},
193 { MS_MAKE_TAG('d','l','i','g'), 0},
194 };
195
196 static OPENTYPE_FEATURE_RECORD hebrew_gpos_features[] =
197 {
198 { MS_MAKE_TAG('k','e','r','n'), 1},
199 { MS_MAKE_TAG('m','a','r','k'), 1},
200 };
201
202 static OPENTYPE_FEATURE_RECORD syriac_features[] =
203 {
204 { MS_MAKE_TAG('r','l','i','g'), 1},
205 { MS_MAKE_TAG('c','a','l','t'), 1},
206 { MS_MAKE_TAG('l','i','g','a'), 1},
207 { MS_MAKE_TAG('d','l','i','g'), 1},
208 };
209
210 static const char *const required_syriac_features[] =
211 {
212 "fina",
213 "fin2",
214 "fin3",
215 "init",
216 "medi",
217 "med2",
218 "rlig",
219 NULL
220 };
221
222 static OPENTYPE_FEATURE_RECORD syriac_gpos_features[] =
223 {
224 { MS_MAKE_TAG('k','e','r','n'), 1},
225 { MS_MAKE_TAG('m','a','r','k'), 1},
226 { MS_MAKE_TAG('m','k','m','k'), 1},
227 };
228
229 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
230 {
231 /* Presentation forms */
232 { MS_MAKE_TAG('b','l','w','s'), 1},
233 { MS_MAKE_TAG('a','b','v','s'), 1},
234 { MS_MAKE_TAG('p','s','t','s'), 1},
235 };
236
237 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
238 {
239 { MS_MAKE_TAG('a','b','v','s'), 1},
240 { MS_MAKE_TAG('b','l','w','s'), 1},
241 };
242
243 static OPENTYPE_FEATURE_RECORD tibetan_gpos_features[] =
244 {
245 { MS_MAKE_TAG('a','b','v','m'), 1},
246 { MS_MAKE_TAG('b','l','w','m'), 1},
247 };
248
249 static OPENTYPE_FEATURE_RECORD phags_features[] =
250 {
251 { MS_MAKE_TAG('a','b','v','s'), 1},
252 { MS_MAKE_TAG('b','l','w','s'), 1},
253 { MS_MAKE_TAG('c','a','l','t'), 1},
254 };
255
256 static OPENTYPE_FEATURE_RECORD thai_features[] =
257 {
258 { MS_MAKE_TAG('c','c','m','p'), 1},
259 };
260
261 static OPENTYPE_FEATURE_RECORD thai_gpos_features[] =
262 {
263 { MS_MAKE_TAG('k','e','r','n'), 1},
264 { MS_MAKE_TAG('m','a','r','k'), 1},
265 { MS_MAKE_TAG('m','k','m','k'), 1},
266 };
267
268 static const char *const required_lao_features[] =
269 {
270 "ccmp",
271 NULL
272 };
273
274 static const char *const required_devanagari_features[] =
275 {
276 "nukt",
277 "akhn",
278 "rphf",
279 "blwf",
280 "half",
281 "vatu",
282 "pres",
283 "abvs",
284 "blws",
285 "psts",
286 "haln",
287 NULL
288 };
289
290 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
291 {
292 { MS_MAKE_TAG('p','r','e','s'), 1},
293 { MS_MAKE_TAG('a','b','v','s'), 1},
294 { MS_MAKE_TAG('b','l','w','s'), 1},
295 { MS_MAKE_TAG('p','s','t','s'), 1},
296 { MS_MAKE_TAG('h','a','l','n'), 1},
297 { MS_MAKE_TAG('c','a','l','t'), 1},
298 };
299
300 static OPENTYPE_FEATURE_RECORD devanagari_gpos_features[] =
301 {
302 { MS_MAKE_TAG('k','e','r','n'), 1},
303 { MS_MAKE_TAG('d','i','s','t'), 1},
304 { MS_MAKE_TAG('a','b','v','m'), 1},
305 { MS_MAKE_TAG('b','l','w','m'), 1},
306 };
307
308 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
309 {
310 { MS_MAKE_TAG('l','i','g','a'), 1},
311 { MS_MAKE_TAG('c','l','i','g'), 1},
312 };
313
314 static const char *const required_bengali_features[] =
315 {
316 "nukt",
317 "akhn",
318 "rphf",
319 "blwf",
320 "half",
321 "vatu",
322 "pstf",
323 "init",
324 "abvs",
325 "blws",
326 "psts",
327 "haln",
328 NULL
329 };
330
331 static const char *const required_gurmukhi_features[] =
332 {
333 "nukt",
334 "akhn",
335 "rphf",
336 "blwf",
337 "half",
338 "pstf",
339 "vatu",
340 "cjct",
341 "pres",
342 "abvs",
343 "blws",
344 "psts",
345 "haln",
346 "calt",
347 NULL
348 };
349
350 static const char *const required_oriya_features[] =
351 {
352 "nukt",
353 "akhn",
354 "rphf",
355 "blwf",
356 "pstf",
357 "cjct",
358 "pres",
359 "abvs",
360 "blws",
361 "psts",
362 "haln",
363 "calt",
364 NULL
365 };
366
367 static const char *const required_tamil_features[] =
368 {
369 "nukt",
370 "akhn",
371 "rphf",
372 "pref",
373 "half",
374 "pres",
375 "abvs",
376 "blws",
377 "psts",
378 "haln",
379 "calt",
380 NULL
381 };
382
383 static const char *const required_telugu_features[] =
384 {
385 "nukt",
386 "akhn",
387 "rphf",
388 "pref",
389 "half",
390 "pstf",
391 "cjct",
392 "pres",
393 "abvs",
394 "blws",
395 "psts",
396 "haln",
397 "calt",
398 NULL
399 };
400
401 static OPENTYPE_FEATURE_RECORD khmer_features[] =
402 {
403 { MS_MAKE_TAG('p','r','e','s'), 1},
404 { MS_MAKE_TAG('b','l','w','s'), 1},
405 { MS_MAKE_TAG('a','b','v','s'), 1},
406 { MS_MAKE_TAG('p','s','t','s'), 1},
407 { MS_MAKE_TAG('c','l','i','g'), 1},
408 };
409
410 static const char *const required_khmer_features[] =
411 {
412 "pref",
413 "blwf",
414 "abvf",
415 "pstf",
416 "pres",
417 "blws",
418 "abvs",
419 "psts",
420 "clig",
421 NULL
422 };
423
424 static OPENTYPE_FEATURE_RECORD khmer_gpos_features[] =
425 {
426 { MS_MAKE_TAG('d','i','s','t'), 1},
427 { MS_MAKE_TAG('b','l','w','m'), 1},
428 { MS_MAKE_TAG('a','b','v','m'), 1},
429 { MS_MAKE_TAG('m','k','m','k'), 1},
430 };
431
432 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
433 {
434 { MS_MAKE_TAG('c','c','m','p'), 1},
435 { MS_MAKE_TAG('l','o','c','l'), 1},
436 { MS_MAKE_TAG('c','a','l','t'), 1},
437 { MS_MAKE_TAG('l','i','g','a'), 1},
438 };
439
440 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
441 {
442 { MS_MAKE_TAG('c','c','m','p'), 1},
443 { MS_MAKE_TAG('l','o','c','l'), 1},
444 { MS_MAKE_TAG('c','a','l','t'), 1},
445 { MS_MAKE_TAG('r','l','i','g'), 1},
446 };
447
448 typedef struct ScriptShapeDataTag {
449 TEXTRANGE_PROPERTIES defaultTextRange;
450 TEXTRANGE_PROPERTIES defaultGPOSTextRange;
451 const char *const *requiredFeatures;
452 OPENTYPE_TAG newOtTag;
453 ContextualShapingProc contextProc;
454 ShapeCharGlyphPropProc charGlyphPropProc;
455 } ScriptShapeData;
456
457 /* in order of scripts */
458 static const ScriptShapeData ShapingData[] =
459 {
460 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
461 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
462 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
463 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
464 {{ standard_features, 2}, {NULL, 0}, NULL, 0, ContextualShape_Control, ShapeCharGlyphProp_Control},
465 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
466 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
467 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
468 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
469 {{ syriac_features, 4}, {syriac_gpos_features, 3}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
470 {{ arabic_features, 6}, {arabic_gpos_features, 4}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
471 {{ NULL, 0}, {NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
472 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
473 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
474 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
475 {{ standard_features, 2}, {latin_gpos_features, 3}, NULL, 0, NULL, NULL},
476 {{ sinhala_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
477 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
478 {{ tibetan_features, 2}, {tibetan_gpos_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
479 {{ phags_features, 3}, {NULL, 0}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
480 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
481 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, NULL},
482 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
483 {{ thai_features, 1}, {thai_gpos_features, 3}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
484 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
485 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
486 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
487 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
488 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
489 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
490 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
491 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
492 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
493 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
494 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
495 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
496 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
497 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
498 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
499 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
500 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
501 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
502 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
503 {{ devanagari_features, 6}, {devanagari_gpos_features, 4}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
504 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
505 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
506 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
507 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
508 {{ myanmar_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
509 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
510 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
511 {{ standard_features, 2}, {NULL, 0}, NULL, 0, NULL, NULL},
512 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
513 {{ khmer_features, 5}, {khmer_gpos_features, 4}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
514 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
515 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
516 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
517 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
518 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
519 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
520 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
521 {{ ethiopic_features, 4}, {NULL, 0}, NULL, 0, NULL, NULL},
522 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
523 {{ mongolian_features, 4}, {NULL, 0}, NULL, 0, ContextualShape_Mongolian, NULL},
524 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
525 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
526 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
527 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
528 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
529 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
530 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
531 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
532 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
533 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
534 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
535 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
536 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
537 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
538 {{ NULL, 0}, {NULL, 0}, NULL, 0, NULL, NULL},
539 {{ hebrew_features, 2}, {hebrew_gpos_features, 2}, NULL, 0, ContextualShape_Hebrew, NULL},
540 {{ latin_features, 4}, {latin_gpos_features, 3}, NULL, 0, NULL, ShapeCharGlyphProp_Latin},
541 {{ thai_features, 1}, {thai_gpos_features, 3}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
542 };
543
544 extern scriptData scriptInformation[];
545
546 static int GSUB_apply_feature_all_lookups(const void *header, LoadedFeature *feature,
547 WORD *glyphs, unsigned int glyph_index, int write_dir, int *glyph_count)
548 {
549 int i;
550 int out_index = GSUB_E_NOGLYPH;
551
552 TRACE("%i lookups\n", feature->lookup_count);
553 for (i = 0; i < feature->lookup_count; i++)
554 {
555 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
556 if (out_index != GSUB_E_NOGLYPH)
557 break;
558 }
559 if (out_index == GSUB_E_NOGLYPH)
560 TRACE("lookups found no glyphs\n");
561 else
562 {
563 int out2;
564 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
565 if (out2!=GSUB_E_NOGLYPH)
566 out_index = out2;
567 }
568 return out_index;
569 }
570
571 static OPENTYPE_TAG get_opentype_script(HDC hdc, const SCRIPT_ANALYSIS *psa,
572 const ScriptCache *script_cache, BOOL try_new)
573 {
574 UINT charset;
575
576 if (script_cache->userScript)
577 {
578 if (try_new && ShapingData[psa->eScript].newOtTag
579 && script_cache->userScript == scriptInformation[psa->eScript].scriptTag)
580 return ShapingData[psa->eScript].newOtTag;
581
582 return script_cache->userScript;
583 }
584
585 if (try_new && ShapingData[psa->eScript].newOtTag)
586 return ShapingData[psa->eScript].newOtTag;
587
588 if (scriptInformation[psa->eScript].scriptTag)
589 return scriptInformation[psa->eScript].scriptTag;
590
591 /*
592 * fall back to the font charset
593 */
594 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
595 switch (charset)
596 {
597 case ANSI_CHARSET:
598 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
599 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
600 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
601 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
602 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
603 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
604 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
605 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
606 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
607 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
608 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
609 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
610 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
611 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
612 default: return MS_MAKE_TAG('l','a','t','n');
613 }
614 }
615
616 static LoadedFeature* load_OT_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, char tableType, const char* feat)
617 {
618 LoadedFeature *feature = NULL;
619
620 if (psc->GSUB_Table || psc->GPOS_Table)
621 {
622 int attempt = 2;
623 OPENTYPE_TAG tags;
624 OPENTYPE_TAG language;
625 OPENTYPE_TAG script = 0x00000000;
626 int cTags;
627
628 do
629 {
630 script = get_opentype_script(hdc,psa,psc,(attempt==2));
631 if (psc->userLang != 0)
632 language = psc->userLang;
633 else
634 language = MS_MAKE_TAG('d','f','l','t');
635 attempt--;
636
637 OpenType_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
638
639 } while(attempt && !feature);
640
641 /* try in the default (latin) table */
642 if (!feature)
643 {
644 if (!script)
645 script = MS_MAKE_TAG('l','a','t','n');
646 OpenType_GetFontFeatureTags(psc, script, MS_MAKE_TAG('d','f','l','t'), FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), tableType, 1, &tags, &cTags, &feature);
647 }
648 }
649
650 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
651 return feature;
652 }
653
654 static INT apply_GSUB_feature_to_glyph(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *glyphs, INT index, INT write_dir, INT* glyph_count, const char* feat)
655 {
656 LoadedFeature *feature;
657
658 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
659 if (!feature)
660 return GSUB_E_NOFEATURE;
661
662 TRACE("applying feature %s\n",feat);
663 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
664 }
665
666 static VOID *load_gsub_table(HDC hdc)
667 {
668 VOID* GSUB_Table = NULL;
669 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
670 if (length != GDI_ERROR)
671 {
672 GSUB_Table = heap_alloc(length);
673 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
674 TRACE("Loaded GSUB table of %i bytes\n",length);
675 }
676 return GSUB_Table;
677 }
678
679 static VOID *load_gpos_table(HDC hdc)
680 {
681 VOID* GPOS_Table = NULL;
682 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, NULL, 0);
683 if (length != GDI_ERROR)
684 {
685 GPOS_Table = heap_alloc(length);
686 GetFontData(hdc, MS_MAKE_TAG('G', 'P', 'O', 'S'), 0, GPOS_Table, length);
687 TRACE("Loaded GPOS table of %i bytes\n",length);
688 }
689 return GPOS_Table;
690 }
691
692 static VOID *load_gdef_table(HDC hdc)
693 {
694 VOID* GDEF_Table = NULL;
695 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, NULL, 0);
696 if (length != GDI_ERROR)
697 {
698 GDEF_Table = heap_alloc(length);
699 GetFontData(hdc, MS_MAKE_TAG('G', 'D', 'E', 'F'), 0, GDEF_Table, length);
700 TRACE("Loaded GDEF table of %i bytes\n",length);
701 }
702 return GDEF_Table;
703 }
704
705 static VOID load_ot_tables(HDC hdc, ScriptCache *psc)
706 {
707 if (!psc->GSUB_Table)
708 psc->GSUB_Table = load_gsub_table(hdc);
709 if (!psc->GPOS_Table)
710 psc->GPOS_Table = load_gpos_table(hdc);
711 if (!psc->GDEF_Table)
712 psc->GDEF_Table = load_gdef_table(hdc);
713 }
714
715 INT SHAPE_does_GSUB_feature_apply_to_chars(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, const WCHAR *chars, INT write_dir, INT count, const char* feature)
716 {
717 WORD *glyphs;
718 INT glyph_count = count;
719 INT rc;
720
721 glyphs = heap_alloc(2 * count * sizeof(*glyphs));
722 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
723 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
724 if (rc > GSUB_E_NOGLYPH)
725 rc = count - glyph_count;
726 else
727 rc = 0;
728
729 heap_free(glyphs);
730 return rc;
731 }
732
733 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
734 {
735 int i;
736
737 for (i = 0; i < cGlyphs; i++)
738 {
739 if (!pGlyphProp[i].sva.fClusterStart)
740 {
741 int j;
742 for (j = 0; j < cChars; j++)
743 {
744 if (pwLogClust[j] == i)
745 {
746 int k = j;
747 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
748 k-=1;
749 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
750 pwLogClust[j] = pwLogClust[k];
751 }
752 }
753 }
754 }
755 }
756
757 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
758 {
759 if (changeCount == 0)
760 return;
761 else
762 {
763 int cluster_dir = pwLogClust[0] < pwLogClust[chars-1] ? 1 : -1;
764 int i;
765 int target_glyph = nextIndex - write_dir;
766 int target_index = -1;
767 int replacing_glyph = -1;
768 int changed = 0;
769
770 if (changeCount > 0)
771 {
772 if (write_dir > 0)
773 target_glyph = nextIndex - changeCount;
774 else
775 target_glyph = nextIndex + (changeCount + 1);
776 }
777
778 target_index = USP10_FindGlyphInLogClust(pwLogClust, chars, target_glyph);
779 if (target_index == -1)
780 {
781 ERR("Unable to find target glyph\n");
782 return;
783 }
784
785 if (changeCount < 0)
786 {
787 /* merge glyphs */
788 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
789 {
790 if (pwLogClust[i] == target_glyph)
791 continue;
792 if(pwLogClust[i] == replacing_glyph)
793 pwLogClust[i] = target_glyph;
794 else
795 {
796 changed--;
797 if (changed >= changeCount)
798 {
799 replacing_glyph = pwLogClust[i];
800 pwLogClust[i] = target_glyph;
801 }
802 else
803 break;
804 }
805 }
806
807 /* renumber trailing indexes */
808 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
809 {
810 if (pwLogClust[i] != target_glyph)
811 pwLogClust[i] += changeCount;
812 }
813 }
814 else
815 {
816 for (i = target_index; i < chars && i >= 0; i += cluster_dir)
817 pwLogClust[i] += changeCount;
818 }
819 }
820 }
821
822 static int apply_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache* psc, WORD *pwOutGlyphs, int write_dir, INT* pcGlyphs, INT cChars, const char* feat, WORD *pwLogClust )
823 {
824 if (psc->GSUB_Table)
825 {
826 LoadedFeature *feature;
827 int lookup_index;
828
829 feature = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, feat);
830 if (!feature)
831 return GSUB_E_NOFEATURE;
832
833 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
834 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
835 {
836 int i;
837
838 if (write_dir > 0)
839 i = 0;
840 else
841 i = *pcGlyphs-1;
842 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
843 while(i < *pcGlyphs && i >= 0)
844 {
845 INT nextIndex;
846 INT prevCount = *pcGlyphs;
847
848 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
849 if (*pcGlyphs != prevCount)
850 {
851 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
852 i = nextIndex;
853 }
854 else
855 i+=write_dir;
856 }
857 }
858 return *pcGlyphs;
859 }
860 return GSUB_E_NOFEATURE;
861 }
862
863 static void GPOS_apply_feature(const ScriptCache *psc, const OUTLINETEXTMETRICW *otm,
864 const LOGFONTW *logfont, const SCRIPT_ANALYSIS *analysis, int *advance,
865 const LoadedFeature *feature, const WORD *glyphs, int glyph_count, GOFFSET *goffset)
866 {
867 int dir = analysis->fLogicalOrder && analysis->fRTL ? -1 : 1;
868 unsigned int start_idx, i, j;
869
870 TRACE("%i lookups\n", feature->lookup_count);
871
872 start_idx = dir < 0 ? glyph_count - 1 : 0;
873 for (i = 0; i < feature->lookup_count; i++)
874 {
875 for (j = 0; j < glyph_count; )
876 j += OpenType_apply_GPOS_lookup(psc, otm, logfont, analysis, advance,
877 feature->lookups[i], glyphs, start_idx + dir * j, glyph_count, goffset);
878 }
879 }
880
881 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
882 {
883 OPENTYPE_TAG tag;
884 HRESULT hr;
885 int count = 0;
886
887 hr = OpenType_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count);
888
889 return(SUCCEEDED(hr));
890 }
891
892 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
893 {
894 int i;
895 for (i = *pcGlyphs; i>=index; i--)
896 pwGlyphs[i+1] = pwGlyphs[i];
897 pwGlyphs[index] = glyph;
898 *pcGlyphs = *pcGlyphs+1;
899 if (write_dir < 0)
900 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
901 else
902 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
903 }
904
905 static void mark_invalid_combinations(HDC hdc, const WCHAR* pwcChars, INT cChars, WORD *pwGlyphs, INT *pcGlyphs, INT write_dir, WORD *pwLogClust, combining_lexical_function lex)
906 {
907 CHAR *context_type;
908 int i,g;
909 WCHAR invalid = 0x25cc;
910 WORD invalid_glyph;
911
912 context_type = heap_alloc(cChars);
913
914 /* Mark invalid combinations */
915 for (i = 0; i < cChars; i++)
916 context_type[i] = lex(pwcChars[i]);
917
918 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
919 for (i = 1, g=1; i < cChars - 1; i++, g++)
920 {
921 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
922 {
923 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
924 g++;
925 }
926 }
927
928 heap_free(context_type);
929 }
930
931 static void ContextualShape_Control(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
932 {
933 int i;
934 for (i=0; i < cChars; i++)
935 {
936 switch (pwcChars[i])
937 {
938 case 0x000A:
939 case 0x000D:
940 pwOutGlyphs[i] = psc->sfp.wgBlank;
941 break;
942 default:
943 if (pwcChars[i] < 0x1C)
944 pwOutGlyphs[i] = psc->sfp.wgDefault;
945 else
946 pwOutGlyphs[i] = psc->sfp.wgBlank;
947 }
948 }
949 }
950
951 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
952 {
953 if (i + delta < 0)
954 return 0;
955 if ( i+ delta >= cchLen)
956 return 0;
957
958 i += delta;
959
960 return chars[i];
961 }
962
963 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
964 {
965 if (i + delta < 0)
966 {
967 if (psa->fLinkBefore)
968 return jtR;
969 else
970 return jtU;
971 }
972 if ( i+ delta >= cchLen)
973 {
974 if (psa->fLinkAfter)
975 return jtL;
976 else
977 return jtU;
978 }
979
980 i += delta;
981
982 if (context_type[i] == jtT)
983 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
984 else
985 return context_type[i];
986 }
987
988 static inline BOOL right_join_causing(CHAR joining_type)
989 {
990 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
991 }
992
993 static inline BOOL left_join_causing(CHAR joining_type)
994 {
995 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
996 }
997
998 static inline BOOL word_break_causing(WCHAR chr)
999 {
1000 /* we are working within a string of characters already guareented to
1001 be within one script, Syriac, so we do not worry about any character
1002 other than the space character outside of that range */
1003 return (chr == 0 || chr == 0x20 );
1004 }
1005
1006 static int combining_lexical_Arabic(WCHAR c)
1007 {
1008 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
1009
1010 switch(c)
1011 {
1012 case 0x064B:
1013 case 0x064C:
1014 case 0x064E:
1015 case 0x064F:
1016 case 0x0652:
1017 case 0x0657:
1018 case 0x0658:
1019 case 0x06E1: return Arab_DIAC1;
1020 case 0x064D:
1021 case 0x0650:
1022 case 0x0656: return Arab_DIAC2;
1023 case 0x0651: return Arab_DIAC3;
1024 case 0x0610:
1025 case 0x0611:
1026 case 0x0612:
1027 case 0x0613:
1028 case 0x0614:
1029 case 0x0659:
1030 case 0x06D6:
1031 case 0x06DC:
1032 case 0x06DF:
1033 case 0x06E0:
1034 case 0x06E2:
1035 case 0x06E4:
1036 case 0x06E7:
1037 case 0x06E8:
1038 case 0x06EB:
1039 case 0x06EC: return Arab_DIAC4;
1040 case 0x06E3:
1041 case 0x06EA:
1042 case 0x06ED: return Arab_DIAC5;
1043 case 0x0670: return Arab_DIAC6;
1044 case 0x0653: return Arab_DIAC7;
1045 case 0x0655:
1046 case 0x0654: return Arab_DIAC8;
1047 default: return Arab_Norm;
1048 }
1049 }
1050
1051 /*
1052 * ContextualShape_Arabic
1053 */
1054 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1055 {
1056 CHAR *context_type;
1057 INT *context_shape;
1058 INT dirR, dirL;
1059 int i;
1060 int char_index;
1061 int glyph_index;
1062
1063 if (*pcGlyphs != cChars)
1064 {
1065 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1066 return;
1067 }
1068
1069 if (psa->fLogicalOrder && psa->fRTL)
1070 {
1071 dirR = -1;
1072 dirL = 1;
1073 }
1074 else
1075 {
1076 dirR = 1;
1077 dirL = -1;
1078 }
1079
1080 load_ot_tables(hdc, psc);
1081
1082 context_type = heap_alloc(cChars);
1083 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1084
1085 for (i = 0; i < cChars; i++)
1086 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1087
1088 for (i = 0; i < cChars; i++)
1089 {
1090 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1091 context_shape[i] = Xr;
1092 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1093 context_shape[i] = Xl;
1094 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1095 context_shape[i] = Xm;
1096 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1097 context_shape[i] = Xr;
1098 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1099 context_shape[i] = Xl;
1100 else
1101 context_shape[i] = Xn;
1102 }
1103
1104 /* Contextual Shaping */
1105 if (dirL > 0)
1106 char_index = glyph_index = 0;
1107 else
1108 char_index = glyph_index = cChars-1;
1109
1110 while(char_index < cChars && char_index >= 0)
1111 {
1112 BOOL shaped = FALSE;
1113
1114 if (psc->GSUB_Table)
1115 {
1116 INT nextIndex, offset = 0;
1117 INT prevCount = *pcGlyphs;
1118
1119 /* Apply CCMP first */
1120 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1121
1122 if (prevCount != *pcGlyphs)
1123 {
1124 offset = *pcGlyphs - prevCount;
1125 if (dirL < 0)
1126 glyph_index -= offset * dirL;
1127 }
1128
1129 /* Apply the contextual feature */
1130 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1131
1132 if (nextIndex > GSUB_E_NOGLYPH)
1133 {
1134 UpdateClusters(glyph_index, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1135 char_index += dirL;
1136 if (!offset)
1137 glyph_index = nextIndex;
1138 else
1139 {
1140 offset = *pcGlyphs - prevCount;
1141 glyph_index += dirL * (offset + 1);
1142 }
1143 shaped = TRUE;
1144 }
1145 else if (nextIndex == GSUB_E_NOGLYPH)
1146 {
1147 char_index += dirL;
1148 glyph_index += dirL;
1149 shaped = TRUE;
1150 }
1151 }
1152
1153 if (!shaped)
1154 {
1155 if (context_shape[char_index] == Xn)
1156 {
1157 WORD newGlyph = pwOutGlyphs[glyph_index];
1158 if (pwcChars[char_index] >= FIRST_ARABIC_CHAR && pwcChars[char_index] <= LAST_ARABIC_CHAR)
1159 {
1160 /* fall back to presentation form B */
1161 WCHAR context_char = wine_shaping_forms[pwcChars[char_index] - FIRST_ARABIC_CHAR][context_shape[char_index]];
1162 if (context_char != pwcChars[char_index] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1163 pwOutGlyphs[glyph_index] = newGlyph;
1164 }
1165 }
1166 char_index += dirL;
1167 glyph_index += dirL;
1168 }
1169 }
1170
1171 heap_free(context_shape);
1172 heap_free(context_type);
1173
1174 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1175 }
1176
1177 static int combining_lexical_Hebrew(WCHAR c)
1178 {
1179 enum {Hebr_Norm=0, Hebr_DIAC, Hebr_CANT1, Hebr_CANT2, Hebr_CANT3, Hebr_CANT4, Hebr_CANT5, Hebr_CANT6, Hebr_CANT7, Hebr_CANT8, Hebr_CANT9, Hebr_CANT10, Hebr_DAGESH, Hebr_DOTABV, Hebr_HOLAM, Hebr_METEG, Hebr_PATAH, Hebr_QAMATS, Hebr_RAFE, Hebr_SHINSIN};
1180
1181 switch(c)
1182 {
1183 case 0x05B0:
1184 case 0x05B1:
1185 case 0x05B2:
1186 case 0x05B3:
1187 case 0x05B4:
1188 case 0x05B5:
1189 case 0x05B6:
1190 case 0x05BB: return Hebr_DIAC;
1191 case 0x0599:
1192 case 0x05A1:
1193 case 0x05A9:
1194 case 0x05AE: return Hebr_CANT1;
1195 case 0x0597:
1196 case 0x05A8:
1197 case 0x05AC: return Hebr_CANT2;
1198 case 0x0592:
1199 case 0x0593:
1200 case 0x0594:
1201 case 0x0595:
1202 case 0x05A7:
1203 case 0x05AB: return Hebr_CANT3;
1204 case 0x0598:
1205 case 0x059C:
1206 case 0x059E:
1207 case 0x059F: return Hebr_CANT4;
1208 case 0x059D:
1209 case 0x05A0: return Hebr_CANT5;
1210 case 0x059B:
1211 case 0x05A5: return Hebr_CANT6;
1212 case 0x0591:
1213 case 0x05A3:
1214 case 0x05A6: return Hebr_CANT7;
1215 case 0x0596:
1216 case 0x05A4:
1217 case 0x05AA: return Hebr_CANT8;
1218 case 0x059A:
1219 case 0x05AD: return Hebr_CANT9;
1220 case 0x05AF: return Hebr_CANT10;
1221 case 0x05BC: return Hebr_DAGESH;
1222 case 0x05C4: return Hebr_DOTABV;
1223 case 0x05B9: return Hebr_HOLAM;
1224 case 0x05BD: return Hebr_METEG;
1225 case 0x05B7: return Hebr_PATAH;
1226 case 0x05B8: return Hebr_QAMATS;
1227 case 0x05BF: return Hebr_RAFE;
1228 case 0x05C1:
1229 case 0x05C2: return Hebr_SHINSIN;
1230 default: return Hebr_Norm;
1231 }
1232 }
1233
1234 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1235 {
1236 INT dirL;
1237
1238 if (*pcGlyphs != cChars)
1239 {
1240 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1241 return;
1242 }
1243
1244 if (!psa->fLogicalOrder && psa->fRTL)
1245 dirL = -1;
1246 else
1247 dirL = 1;
1248
1249 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1250 }
1251
1252 /*
1253 * ContextualShape_Syriac
1254 */
1255
1256 static int combining_lexical_Syriac(WCHAR c)
1257 {
1258 enum {Syriac_Norm=0, Syriac_DIAC1, Syriac_DIAC2, Syriac_DIAC3, Syriac_DIAC4, Syriac_DIAC5, Syriac_DIAC6, Syriac_DIAC7, Syriac_DIAC8, Syriac_DIAC9, Syriac_DIAC10, Syriac_DIAC11, Syriac_DIAC12, Syriac_DIAC13, Syriac_DIAC14, Syriac_DIAC15, Syriac_DIAC16, Syriac_DIAC17};
1259
1260 switch(c)
1261 {
1262 case 0x730:
1263 case 0x733:
1264 case 0x736:
1265 case 0x73A:
1266 case 0x73D: return Syriac_DIAC1;
1267 case 0x731:
1268 case 0x734:
1269 case 0x737:
1270 case 0x73B:
1271 case 0x73E: return Syriac_DIAC2;
1272 case 0x740:
1273 case 0x749:
1274 case 0x74A: return Syriac_DIAC3;
1275 case 0x732:
1276 case 0x735:
1277 case 0x73F: return Syriac_DIAC4;
1278 case 0x738:
1279 case 0x739:
1280 case 0x73C: return Syriac_DIAC5;
1281 case 0x741:
1282 case 0x30A: return Syriac_DIAC6;
1283 case 0x742:
1284 case 0x325: return Syriac_DIAC7;
1285 case 0x747:
1286 case 0x303: return Syriac_DIAC8;
1287 case 0x748:
1288 case 0x32D:
1289 case 0x32E:
1290 case 0x330:
1291 case 0x331: return Syriac_DIAC9;
1292 case 0x308: return Syriac_DIAC10;
1293 case 0x304: return Syriac_DIAC11;
1294 case 0x307: return Syriac_DIAC12;
1295 case 0x323: return Syriac_DIAC13;
1296 case 0x743: return Syriac_DIAC14;
1297 case 0x744: return Syriac_DIAC15;
1298 case 0x745: return Syriac_DIAC16;
1299 case 0x746: return Syriac_DIAC17;
1300 default: return Syriac_Norm;
1301 }
1302 }
1303
1304 #define ALAPH 0x710
1305 #define DALATH 0x715
1306 #define RISH 0x72A
1307
1308 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1309 {
1310 CHAR *context_type;
1311 INT *context_shape;
1312 INT dirR, dirL;
1313 int i;
1314 int char_index;
1315 int glyph_index;
1316
1317 if (*pcGlyphs != cChars)
1318 {
1319 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1320 return;
1321 }
1322
1323 if (!psa->fLogicalOrder && psa->fRTL)
1324 {
1325 dirR = 1;
1326 dirL = -1;
1327 }
1328 else
1329 {
1330 dirR = -1;
1331 dirL = 1;
1332 }
1333
1334 load_ot_tables(hdc, psc);
1335
1336 if (!psc->GSUB_Table)
1337 return;
1338
1339 context_type = heap_alloc(cChars);
1340 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1341
1342 for (i = 0; i < cChars; i++)
1343 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1344
1345 for (i = 0; i < cChars; i++)
1346 {
1347 if (pwcChars[i] == ALAPH)
1348 {
1349 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1350
1351 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1352 context_shape[i] = Afj;
1353 else if ( rchar != DALATH && rchar != RISH &&
1354 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1355 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1356 context_shape[i] = Afn;
1357 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1358 context_shape[i] = Afx;
1359 else
1360 context_shape[i] = Xn;
1361 }
1362 else if (context_type[i] == jtR &&
1363 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1364 context_shape[i] = Xr;
1365 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1366 context_shape[i] = Xl;
1367 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)) && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1368 context_shape[i] = Xm;
1369 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1370 context_shape[i] = Xr;
1371 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1372 context_shape[i] = Xl;
1373 else
1374 context_shape[i] = Xn;
1375 }
1376
1377 /* Contextual Shaping */
1378 if (dirL > 0)
1379 char_index = glyph_index = 0;
1380 else
1381 char_index = glyph_index = cChars-1;
1382
1383 while(char_index < cChars && char_index >= 0)
1384 {
1385 INT nextIndex, offset = 0;
1386 INT prevCount = *pcGlyphs;
1387
1388 /* Apply CCMP first */
1389 apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, "ccmp");
1390
1391 if (prevCount != *pcGlyphs)
1392 {
1393 offset = *pcGlyphs - prevCount;
1394 if (dirL < 0)
1395 glyph_index -= offset * dirL;
1396 }
1397
1398 /* Apply the contextual feature */
1399 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1400 if (nextIndex > GSUB_E_NOGLYPH)
1401 {
1402 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1403 char_index += dirL;
1404 if (!offset)
1405 glyph_index = nextIndex;
1406 else
1407 {
1408 offset = *pcGlyphs - prevCount;
1409 glyph_index += dirL * (offset + 1);
1410 }
1411 }
1412 else
1413 {
1414 char_index += dirL;
1415 glyph_index += dirL;
1416 }
1417 }
1418
1419 heap_free(context_shape);
1420 heap_free(context_type);
1421
1422 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1423 }
1424
1425 static int combining_lexical_Thaana(WCHAR c)
1426 {
1427 enum {Thaana_Norm=0, Thaana_FILI};
1428
1429 switch(c)
1430 {
1431 case 0x7A6:
1432 case 0x7A7:
1433 case 0x7A8:
1434 case 0x7A9:
1435 case 0x7AA:
1436 case 0x7AB:
1437 case 0x7AC:
1438 case 0x7AD:
1439 case 0x7AE:
1440 case 0x7AF: return Thaana_FILI;
1441 default: return Thaana_Norm;
1442 }
1443 }
1444
1445 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1446 {
1447 INT dirL;
1448
1449 if (*pcGlyphs != cChars)
1450 {
1451 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1452 return;
1453 }
1454
1455 if (!psa->fLogicalOrder && psa->fRTL)
1456 dirL = -1;
1457 else
1458 dirL = 1;
1459
1460 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1461 }
1462
1463 /*
1464 * ContextualShape_Phags_pa
1465 */
1466
1467 #define phags_pa_CANDRABINDU 0xA873
1468 #define phags_pa_START 0xA840
1469 #define phags_pa_END 0xA87F
1470
1471 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1472 {
1473 INT *context_shape;
1474 INT dirR, dirL;
1475 int i;
1476 int char_index;
1477 int glyph_index;
1478
1479 if (*pcGlyphs != cChars)
1480 {
1481 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1482 return;
1483 }
1484
1485 if (!psa->fLogicalOrder && psa->fRTL)
1486 {
1487 dirR = 1;
1488 dirL = -1;
1489 }
1490 else
1491 {
1492 dirR = -1;
1493 dirL = 1;
1494 }
1495
1496 load_ot_tables(hdc, psc);
1497
1498 if (!psc->GSUB_Table)
1499 return;
1500
1501 context_shape = heap_alloc(cChars * sizeof(*context_shape));
1502
1503 for (i = 0; i < cChars; i++)
1504 {
1505 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1506 {
1507 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1508 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1509 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1510 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1511
1512 if (jrchar && jlchar)
1513 context_shape[i] = Xm;
1514 else if (jrchar)
1515 context_shape[i] = Xr;
1516 else if (jlchar)
1517 context_shape[i] = Xl;
1518 else
1519 context_shape[i] = Xn;
1520 }
1521 else
1522 context_shape[i] = -1;
1523 }
1524
1525 /* Contextual Shaping */
1526 if (dirL > 0)
1527 char_index = glyph_index = 0;
1528 else
1529 char_index = glyph_index = cChars-1;
1530
1531 while(char_index < cChars && char_index >= 0)
1532 {
1533 if (context_shape[char_index] >= 0)
1534 {
1535 INT nextIndex;
1536 INT prevCount = *pcGlyphs;
1537 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index, dirL, pcGlyphs, contextual_features[context_shape[char_index]]);
1538
1539 if (nextIndex > GSUB_E_NOGLYPH)
1540 {
1541 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1542 glyph_index = nextIndex;
1543 char_index += dirL;
1544 }
1545 else
1546 {
1547 char_index += dirL;
1548 glyph_index += dirL;
1549 }
1550 }
1551 else
1552 {
1553 char_index += dirL;
1554 glyph_index += dirL;
1555 }
1556 }
1557
1558 heap_free(context_shape);
1559 }
1560
1561 static int combining_lexical_Thai(WCHAR c)
1562 {
1563 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1564
1565 switch(c)
1566 {
1567 case 0xE31:
1568 case 0xE34:
1569 case 0xE35:
1570 case 0xE36:
1571 case 0xE37: return Thai_ABOVE1;
1572 case 0xE47:
1573 case 0xE4D: return Thai_ABOVE2;
1574 case 0xE48:
1575 case 0xE49:
1576 case 0xE4A:
1577 case 0xE4B: return Thai_ABOVE3;
1578 case 0xE4C:
1579 case 0xE4E: return Thai_ABOVE4;
1580 case 0xE38:
1581 case 0xE39: return Thai_BELOW1;
1582 case 0xE3A: return Thai_BELOW2;
1583 case 0xE33: return Thai_AM;
1584 default: return Thai_Norm;
1585 }
1586 }
1587
1588 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1589 {
1590 INT dirL;
1591
1592 if (*pcGlyphs != cChars)
1593 {
1594 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1595 return;
1596 }
1597
1598 if (!psa->fLogicalOrder && psa->fRTL)
1599 dirL = -1;
1600 else
1601 dirL = 1;
1602
1603 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1604 }
1605
1606 static int combining_lexical_Lao(WCHAR c)
1607 {
1608 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1609
1610 switch(c)
1611 {
1612 case 0xEB1:
1613 case 0xEB4:
1614 case 0xEB5:
1615 case 0xEB6:
1616 case 0xEB7:
1617 case 0xEBB:
1618 case 0xECD: return Lao_ABOVE1;
1619 case 0xEC8:
1620 case 0xEC9:
1621 case 0xECA:
1622 case 0xECB:
1623 case 0xECC: return Lao_ABOVE2;
1624 case 0xEBC: return Lao_BELOW1;
1625 case 0xEB8:
1626 case 0xEB9: return Lao_BELOW2;
1627 case 0xEB3: return Lao_AM;
1628 default: return Lao_Norm;
1629 }
1630 }
1631
1632 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1633 {
1634 INT dirL;
1635
1636 if (*pcGlyphs != cChars)
1637 {
1638 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1639 return;
1640 }
1641
1642 if (!psa->fLogicalOrder && psa->fRTL)
1643 dirL = -1;
1644 else
1645 dirL = 1;
1646
1647 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1648 }
1649
1650 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1651 {
1652 int i;
1653
1654 /* Replace */
1655 pwOutChars[cWalk] = replacements[0];
1656 cWalk=cWalk+1;
1657
1658 /* Insert */
1659 for (i = 1; i < 3 && replacements[i] != 0x0000; i++)
1660 {
1661 int j;
1662 for (j = *pcChars; j > cWalk; j--)
1663 pwOutChars[j] = pwOutChars[j-1];
1664 *pcChars= *pcChars+1;
1665 pwOutChars[cWalk] = replacements[i];
1666 cWalk = cWalk+1;
1667 }
1668 }
1669
1670 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1671 {
1672 int i;
1673 int cWalk;
1674
1675 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1676 {
1677 for (i = 0; vowels[i].base != 0x0; i++)
1678 {
1679 if (pwOutChars[cWalk] == vowels[i].base)
1680 {
1681 int o = 0;
1682 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1683 if (vowels[i].parts[1]) { cWalk++; o++; }
1684 if (vowels[i].parts[2]) { cWalk++; o++; }
1685 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1686 break;
1687 }
1688 }
1689 }
1690 }
1691
1692 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1693 {
1694 int i;
1695 int offset = 0;
1696 int cWalk;
1697
1698 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1699 {
1700 for (i = 0; consonants[i].output!= 0x0; i++)
1701 {
1702 int j;
1703 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1704 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1705 break;
1706
1707 if (consonants[i].parts[j]==0x0) /* matched all */
1708 {
1709 int k;
1710 j--;
1711 pwOutChars[cWalk] = consonants[i].output;
1712 for(k = cWalk+1; k < *pcChars - j; k++)
1713 pwOutChars[k] = pwOutChars[k+j];
1714 *pcChars = *pcChars - j;
1715 for (k = j ; k > 0; k--)
1716 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1717 offset += j;
1718 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1719 pwLogClust[k]--;
1720 break;
1721 }
1722 }
1723 cWalk++;
1724 }
1725 }
1726
1727 static void Reorder_Ra_follows_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1728 {
1729 if (s->ralf >= 0)
1730 {
1731 int j;
1732 WORD Ra = pwChar[s->start];
1733 WORD H = pwChar[s->start+1];
1734
1735 TRACE("Doing reorder of Ra to %i\n",s->base);
1736 for (j = s->start; j < s->base-1; j++)
1737 pwChar[j] = pwChar[j+2];
1738 pwChar[s->base-1] = Ra;
1739 pwChar[s->base] = H;
1740
1741 s->ralf = s->base-1;
1742 s->base -= 2;
1743 }
1744 }
1745
1746 static void Reorder_Ra_follows_matra(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1747 {
1748 if (s->ralf >= 0)
1749 {
1750 int j,loc;
1751 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1752 WORD Ra = pwChar[s->start];
1753 WORD H = pwChar[s->start+1];
1754 for (loc = s->end; loc > stop; loc--)
1755 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1756 break;
1757
1758 TRACE("Doing reorder of Ra to %i\n",loc);
1759 for (j = s->start; j < loc-1; j++)
1760 pwChar[j] = pwChar[j+2];
1761 pwChar[loc-1] = Ra;
1762 pwChar[loc] = H;
1763
1764 s->ralf = loc-1;
1765 s->base -= 2;
1766 if (s->blwf >= 0) s->blwf -= 2;
1767 if (s->pref >= 0) s->pref -= 2;
1768 }
1769 }
1770
1771 static void Reorder_Ra_follows_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1772 {
1773 if (s->ralf >= 0)
1774 {
1775 int j;
1776 WORD Ra = pwChar[s->start];
1777 WORD H = pwChar[s->start+1];
1778
1779 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1780 for (j = s->start; j < s->end-1; j++)
1781 pwChar[j] = pwChar[j+2];
1782 pwChar[s->end-1] = Ra;
1783 pwChar[s->end] = H;
1784
1785 s->ralf = s->end-1;
1786 s->base -= 2;
1787 if (s->blwf >= 0) s->blwf -= 2;
1788 if (s->pref >= 0) s->pref -= 2;
1789 }
1790 }
1791
1792 static void Reorder_Matra_precede_base(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1793 {
1794 int i;
1795
1796 /* reorder Matras */
1797 if (s->end > s->base)
1798 {
1799 for (i = 1; i <= s->end-s->base; i++)
1800 {
1801 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1802 {
1803 int j;
1804 WCHAR c = pwChar[s->base+i];
1805 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1806 for (j = s->base+i; j > s->base; j--)
1807 pwChar[j] = pwChar[j-1];
1808 pwChar[s->base] = c;
1809
1810 if (s->ralf >= s->base) s->ralf++;
1811 if (s->blwf >= s->base) s->blwf++;
1812 if (s->pref >= s->base) s->pref++;
1813 s->base ++;
1814 }
1815 }
1816 }
1817 }
1818
1819 static void Reorder_Matra_precede_syllable(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1820 {
1821 int i;
1822
1823 /* reorder Matras */
1824 if (s->end > s->base)
1825 {
1826 for (i = 1; i <= s->end-s->base; i++)
1827 {
1828 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1829 {
1830 int j;
1831 WCHAR c = pwChar[s->base+i];
1832 TRACE("Doing reorder of %x to %i\n",c,s->start);
1833 for (j = s->base+i; j > s->start; j--)
1834 pwChar[j] = pwChar[j-1];
1835 pwChar[s->start] = c;
1836
1837 if (s->ralf >= 0) s->ralf++;
1838 if (s->blwf >= 0) s->blwf++;
1839 if (s->pref >= 0) s->pref++;
1840 s->base ++;
1841 }
1842 }
1843 }
1844 }
1845
1846 static void SecondReorder_Blwf_follows_matra(const WCHAR *chars, const IndicSyllable *s,
1847 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1848 {
1849 if (s->blwf >= 0 && g->blwf > g->base)
1850 {
1851 int j,loc;
1852 int g_offset;
1853 for (loc = s->end; loc > s->blwf; loc--)
1854 if (lexical(chars[loc]) == lex_Matra_below || lexical(chars[loc]) == lex_Matra_above
1855 || lexical(chars[loc]) == lex_Matra_post)
1856 break;
1857
1858 g_offset = (loc - s->blwf) - 1;
1859
1860 if (loc != s->blwf)
1861 {
1862 WORD blwf = glyphs[g->blwf];
1863 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1864 /* do not care about the pwChar array anymore, just the glyphs */
1865 for (j = 0; j < g_offset; j++)
1866 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1867 glyphs[g->blwf + g_offset] = blwf;
1868 }
1869 }
1870 }
1871
1872 static void SecondReorder_Matra_precede_base(const WCHAR *chars, const IndicSyllable *s,
1873 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1874 {
1875 int i;
1876
1877 /* reorder previously moved Matras to correct position*/
1878 for (i = s->start; i < s->base; i++)
1879 {
1880 if (lexical(chars[i]) == lex_Matra_pre)
1881 {
1882 int j;
1883 int g_start = g->start + i - s->start;
1884 if (g_start < g->base -1 )
1885 {
1886 WCHAR og = glyphs[g_start];
1887 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1888 for (j = g_start; j < g->base-1; j++)
1889 glyphs[j] = glyphs[j+1];
1890 glyphs[g->base-1] = og;
1891 }
1892 }
1893 }
1894 }
1895
1896 static void SecondReorder_Pref_precede_base(const IndicSyllable *s,
1897 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1898 {
1899 if (s->pref >= 0 && g->pref > g->base)
1900 {
1901 int j;
1902 WCHAR og = glyphs[g->pref];
1903 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1904 for (j = g->pref; j > g->base; j--)
1905 glyphs[j] = glyphs[j-1];
1906 glyphs[g->base] = og;
1907 }
1908 }
1909
1910 static void Reorder_Like_Sinhala(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1911 {
1912 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1913 if (s->start == s->base && s->base == s->end) return;
1914 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1915
1916 Reorder_Ra_follows_base(pwChar, s, lexical);
1917 Reorder_Matra_precede_base(pwChar, s, lexical);
1918 }
1919
1920 static void Reorder_Like_Devanagari(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1921 {
1922 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1923 if (s->start == s->base && s->base == s->end) return;
1924 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1925
1926 Reorder_Ra_follows_matra(pwChar, s, lexical);
1927 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1928 }
1929
1930 static void Reorder_Like_Bengali(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1931 {
1932 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1933 if (s->start == s->base && s->base == s->end) return;
1934 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1935
1936 Reorder_Ra_follows_base(pwChar, s, lexical);
1937 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1938 }
1939
1940 static void Reorder_Like_Kannada(WCHAR *pwChar, IndicSyllable *s, lexical_function lexical)
1941 {
1942 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1943 if (s->start == s->base && s->base == s->end) return;
1944 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1945
1946 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1947 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1948 }
1949
1950 static void SecondReorder_Like_Telugu(const WCHAR *chars, const IndicSyllable *s,
1951 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1952 {
1953 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1954 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1955 if (s->start == s->base && s->base == s->end) return;
1956 if (lexical(chars[s->base]) == lex_Vowel) return;
1957
1958 SecondReorder_Blwf_follows_matra(chars, s, glyphs, g, lexical);
1959 }
1960
1961 static void SecondReorder_Like_Tamil(const WCHAR *chars, const IndicSyllable *s,
1962 WORD *glyphs, const IndicSyllable *g, lexical_function lexical)
1963 {
1964 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1965 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1966 if (s->start == s->base && s->base == s->end) return;
1967 if (lexical(chars[s->base]) == lex_Vowel) return;
1968
1969 SecondReorder_Matra_precede_base(chars, s, glyphs, g, lexical);
1970 SecondReorder_Pref_precede_base(s, glyphs, g, lexical);
1971 }
1972
1973
1974 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1975 {
1976 if (shift == 0)
1977 return;
1978
1979 if (glyph_index->start > index)
1980 glyph_index->start += shift;
1981 if (glyph_index->base > index)
1982 glyph_index->base+= shift;
1983 if (glyph_index->end > index)
1984 glyph_index->end+= shift;
1985 if (glyph_index->ralf > index)
1986 glyph_index->ralf+= shift;
1987 if (glyph_index->blwf > index)
1988 glyph_index->blwf+= shift;
1989 if (glyph_index->pref > index)
1990 glyph_index->pref+= shift;
1991 }
1992
1993 static void Apply_Indic_BasicForm(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, LoadedFeature *feature )
1994 {
1995 int index = glyph_index->start;
1996
1997 if (!feature)
1998 return;
1999
2000 while(index <= glyph_index->end)
2001 {
2002 INT nextIndex;
2003 INT prevCount = *pcGlyphs;
2004 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2005 if (nextIndex > GSUB_E_NOGLYPH)
2006 {
2007 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2008 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2009 index = nextIndex;
2010 }
2011 else
2012 index++;
2013 }
2014 }
2015
2016 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2017 {
2018 int i = 0;
2019 while (i + index < end - 1 && !(is_consonant(lexical(pwChars[index+i])) && (lexical(pwChars[index+i+1]) == lex_Halant || (index + i < end - 2 && lexical(pwChars[index+i+1]) == lex_Nukta && lexical(pwChars[index+i+2] == lex_Halant)))))
2020 i++;
2021 if (index + i <= end-1)
2022 return index + i;
2023 else
2024 return -1;
2025 }
2026
2027 static void Apply_Indic_PreBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, const char* feature)
2028 {
2029 INT index, nextIndex;
2030 INT count,g_offset;
2031
2032 count = syllable->base - syllable->start;
2033
2034 g_offset = 0;
2035 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2036 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2037 {
2038 INT prevCount = *pcGlyphs;
2039 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2040 if (nextIndex > GSUB_E_NOGLYPH)
2041 {
2042 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2043 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2044 g_offset += (*pcGlyphs - prevCount);
2045 }
2046
2047 index+=2;
2048 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2049 }
2050 }
2051
2052 static void Apply_Indic_Rphf(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index)
2053 {
2054 INT nextIndex;
2055 INT prevCount = *pcGlyphs;
2056
2057 if (syllable->ralf >= 0)
2058 {
2059 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2060 if (nextIndex > GSUB_E_NOGLYPH)
2061 {
2062 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2063 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2064 }
2065 }
2066 }
2067
2068 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2069 {
2070 int i = 0;
2071 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2072 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2073 is_consonant(lexical(pwChars[index+i+1])))))
2074 i++;
2075 if (index + i <= end-1)
2076 return index+i;
2077 else
2078 return -1;
2079 }
2080
2081 static void Apply_Indic_PostBase(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllable, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, IndicSyllable *glyph_index, BOOL modern, const char* feat)
2082 {
2083 INT index, nextIndex;
2084 INT count, g_offset=0;
2085 INT ralf = syllable->ralf;
2086
2087 count = syllable->end - syllable->base;
2088
2089 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2090
2091 while (index >= 0)
2092 {
2093 INT prevCount = *pcGlyphs;
2094 if (ralf >=0 && ralf < index)
2095 {
2096 g_offset--;
2097 ralf = -1;
2098 }
2099
2100 if (!modern)
2101 {
2102 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2103 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2104 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2105 }
2106
2107 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2108 if (nextIndex > GSUB_E_NOGLYPH)
2109 {
2110 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2111 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2112 g_offset += (*pcGlyphs - prevCount);
2113 }
2114 else if (!modern)
2115 {
2116 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2117 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2118 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2119 }
2120
2121 index+=2;
2122 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2123 }
2124 }
2125
2126 static void ShapeIndicSyllables(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwChars, INT cChars, IndicSyllable *syllables, INT syllable_count, WORD *pwOutGlyphs, INT* pcGlyphs, WORD *pwLogClust, lexical_function lexical, second_reorder_function second_reorder, BOOL modern)
2127 {
2128 int c;
2129 int overall_shift = 0;
2130 LoadedFeature *locl = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "locl"):NULL;
2131 LoadedFeature *nukt = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "nukt");
2132 LoadedFeature *akhn = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "akhn");
2133 LoadedFeature *rkrf = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rkrf"):NULL;
2134 LoadedFeature *pstf = load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pstf");
2135 LoadedFeature *vatu = (!rkrf)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "vatu"):NULL;
2136 LoadedFeature *cjct = (modern)?load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "cjct"):NULL;
2137 BOOL rphf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "rphf") != NULL);
2138 BOOL pref = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "pref") != NULL);
2139 BOOL blwf = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "blwf") != NULL);
2140 BOOL half = (load_OT_feature(hdc, psa, psc, FEATURE_GSUB_TABLE, "half") != NULL);
2141 IndicSyllable glyph_indexs;
2142
2143 for (c = 0; c < syllable_count; c++)
2144 {
2145 int old_end;
2146 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2147 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2148 old_end = glyph_indexs.end;
2149
2150 if (locl)
2151 {
2152 TRACE("applying feature locl\n");
2153 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2154 }
2155 if (nukt)
2156 {
2157 TRACE("applying feature nukt\n");
2158 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2159 }
2160 if (akhn)
2161 {
2162 TRACE("applying feature akhn\n");
2163 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2164 }
2165
2166 if (rphf)
2167 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2168 if (rkrf)
2169 {
2170 TRACE("applying feature rkrf\n");
2171 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2172 }
2173 if (pref)
2174 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2175 if (blwf)
2176 {
2177 if (!modern)
2178 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2179
2180 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2181
2182 }
2183 if (half)
2184 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2185 if (pstf)
2186 {
2187 TRACE("applying feature pstf\n");
2188 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2189 }
2190 if (vatu)
2191 {
2192 TRACE("applying feature vatu\n");
2193 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2194 }
2195 if (cjct)
2196 {
2197 TRACE("applying feature cjct\n");
2198 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2199 }
2200
2201 if (second_reorder)
2202 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2203
2204 overall_shift += glyph_indexs.end - old_end;
2205 }
2206 }
2207
2208 static inline int unicode_lex(WCHAR c)
2209 {
2210 int type;
2211
2212 if (!c) return lex_Generic;
2213 if (c == 0x200D) return lex_ZWJ;
2214 if (c == 0x200C) return lex_ZWNJ;
2215 if (c == 0x00A0) return lex_NBSP;
2216
2217 type = get_table_entry( indic_syllabic_table, c );
2218
2219 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2220
2221 switch( type )
2222 {
2223 case 0x0d07: /* Unknown */
2224 case 0x0e07: /* Unknown */
2225 default: return lex_Generic;
2226 case 0x0001:
2227 case 0x0002:
2228 case 0x0011:
2229 case 0x0012:
2230 case 0x0013:
2231 case 0x0014: return lex_Modifier;
2232 case 0x0003:
2233 case 0x0009:
2234 case 0x000a:
2235 case 0x000b:
2236 case 0x000d:
2237 case 0x000e:
2238 case 0x000f:
2239 case 0x0010: return lex_Consonant;
2240 case 0x0004: return lex_Nukta;
2241 case 0x0005: return lex_Halant;
2242 case 0x0006:
2243 case 0x0008: return lex_Vowel;
2244 case 0x0007:
2245 case 0x0107: return lex_Matra_post;
2246 case 0x0207:
2247 case 0x0307: return lex_Matra_pre;
2248 case 0x0807:
2249 case 0x0907:
2250 case 0x0a07:
2251 case 0x0b07:
2252 case 0x0c07:
2253 case 0x0407: return lex_Composed_Vowel;
2254 case 0x0507: return lex_Matra_above;
2255 case 0x0607: return lex_Matra_below;
2256 case 0x000c:
2257 case 0x0015: return lex_Ra;
2258 };
2259 }
2260
2261 static int sinhala_lex(WCHAR c)
2262 {
2263 switch (c)
2264 {
2265 case 0x0DDA:
2266 case 0x0DDD:
2267 case 0x0DDC:
2268 case 0x0DDE: return lex_Matra_post;
2269 default:
2270 return unicode_lex(c);
2271 }
2272 }
2273
2274 static const VowelComponents Sinhala_vowels[] = {
2275 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2276 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2277 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2278 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2279 {0x0000, {0x0000,0x0000,0x0}}};
2280
2281 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2282 {
2283 int cCount = cChars;
2284 int i;
2285 WCHAR *input;
2286 IndicSyllable *syllables = NULL;
2287 int syllable_count = 0;
2288
2289 if (*pcGlyphs != cChars)
2290 {
2291 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2292 return;
2293 }
2294
2295 input = heap_alloc(3 * cChars * sizeof(*input));
2296
2297 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2298
2299 /* Step 1: Decompose multi part vowels */
2300 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2301
2302 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2303
2304 /* Step 2: Reorder within Syllables */
2305 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2306 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2307
2308 /* Step 3: Strip dangling joiners */
2309 for (i = 0; i < cCount; i++)
2310 {
2311 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2312 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2313 input[i] = 0x0020;
2314 }
2315
2316 /* Step 4: Base Form application to syllables */
2317 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2318 *pcGlyphs = cCount;
2319 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2320
2321 heap_free(input);
2322 heap_free(syllables);
2323 }
2324
2325 static int devanagari_lex(WCHAR c)
2326 {
2327 switch (c)
2328 {
2329 case 0x0930: return lex_Ra;
2330 default:
2331 return unicode_lex(c);
2332 }
2333 }
2334
2335 static const ConsonantComponents Devanagari_consonants[] ={
2336 {{0x0928, 0x093C, 0x00000}, 0x0929},
2337 {{0x0930, 0x093C, 0x00000}, 0x0931},
2338 {{0x0933, 0x093C, 0x00000}, 0x0934},
2339 {{0x0915, 0x093C, 0x00000}, 0x0958},
2340 {{0x0916, 0x093C, 0x00000}, 0x0959},
2341 {{0x0917, 0x093C, 0x00000}, 0x095A},
2342 {{0x091C, 0x093C, 0x00000}, 0x095B},
2343 {{0x0921, 0x093C, 0x00000}, 0x095C},
2344 {{0x0922, 0x093C, 0x00000}, 0x095D},
2345 {{0x092B, 0x093C, 0x00000}, 0x095E},
2346 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2347
2348 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2349 {
2350 int cCount = cChars;
2351 WCHAR *input;
2352 IndicSyllable *syllables = NULL;
2353 int syllable_count = 0;
2354 BOOL modern = get_GSUB_Indic2(psa, psc);
2355
2356 if (*pcGlyphs != cChars)
2357 {
2358 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2359 return;
2360 }
2361
2362 input = heap_alloc(cChars * sizeof(*input));
2363 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2364
2365 /* Step 1: Compose Consonant and Nukta */
2366 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2367 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2368
2369 /* Step 2: Reorder within Syllables */
2370 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2371 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2372 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2373 *pcGlyphs = cCount;
2374
2375 /* Step 3: Base Form application to syllables */
2376 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2377
2378 heap_free(input);
2379 heap_free(syllables);
2380 }
2381
2382 static int bengali_lex(WCHAR c)
2383 {
2384 switch (c)
2385 {
2386 case 0x09B0: return lex_Ra;
2387 default:
2388 return unicode_lex(c);
2389 }
2390 }
2391
2392 static const VowelComponents Bengali_vowels[] = {
2393 {0x09CB, {0x09C7,0x09BE,0x0000}},
2394 {0x09CC, {0x09C7,0x09D7,0x0000}},
2395 {0x0000, {0x0000,0x0000,0x0000}}};
2396
2397 static const ConsonantComponents Bengali_consonants[] = {
2398 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2399 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2400 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2401 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2402 {{0x0000,0x0000,0x0000}, 0x0000}};
2403
2404 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2405 {
2406 int cCount = cChars;
2407 WCHAR *input;
2408 IndicSyllable *syllables = NULL;
2409 int syllable_count = 0;
2410 BOOL modern = get_GSUB_Indic2(psa, psc);
2411
2412 if (*pcGlyphs != cChars)
2413 {
2414 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2415 return;
2416 }
2417
2418 input = heap_alloc(2 * cChars * sizeof(*input));
2419 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2420
2421 /* Step 1: Decompose Vowels and Compose Consonants */
2422 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2423 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2424 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2425
2426 /* Step 2: Reorder within Syllables */
2427 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2428 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2429 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2430 *pcGlyphs = cCount;
2431
2432 /* Step 3: Initial form is only applied to the beginning of words */
2433 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2434 {
2435 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2436 {
2437 int index = cCount;
2438 int gCount = 1;
2439 if (index > 0) index++;
2440
2441 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2442 }
2443 }
2444
2445 /* Step 4: Base Form application to syllables */
2446 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2447
2448 heap_free(input);
2449 heap_free(syllables);
2450 }
2451
2452 static int gurmukhi_lex(WCHAR c)
2453 {
2454 if (c == 0x0A71)
2455 return lex_Modifier;
2456 else
2457 return unicode_lex(c);
2458 }
2459
2460 static const ConsonantComponents Gurmukhi_consonants[] = {
2461 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2462 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2463 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2464 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2465 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2466 {{0x0000,0x0000,0x0000}, 0x0000}};
2467
2468 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2469 {
2470 int cCount = cChars;
2471 WCHAR *input;
2472 IndicSyllable *syllables = NULL;
2473 int syllable_count = 0;
2474 BOOL modern = get_GSUB_Indic2(psa, psc);
2475
2476 if (*pcGlyphs != cChars)
2477 {
2478 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2479 return;
2480 }
2481
2482 input = heap_alloc(cChars * sizeof(*input));
2483 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2484
2485 /* Step 1: Compose Consonants */
2486 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2487 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2488
2489 /* Step 2: Reorder within Syllables */
2490 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2491 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2492 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2493 *pcGlyphs = cCount;
2494
2495 /* Step 3: Base Form application to syllables */
2496 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2497
2498 heap_free(input);
2499 heap_free(syllables);
2500 }
2501
2502 static int gujarati_lex(WCHAR c)
2503 {
2504 switch (c)
2505 {
2506 case 0x0AB0: return lex_Ra;
2507 default:
2508 return unicode_lex(c);
2509 }
2510 }
2511
2512 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2513 {
2514 int cCount = cChars;
2515 WCHAR *input;
2516 IndicSyllable *syllables = NULL;
2517 int syllable_count = 0;
2518 BOOL modern = get_GSUB_Indic2(psa, psc);
2519
2520 if (*pcGlyphs != cChars)
2521 {
2522 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2523 return;
2524 }
2525
2526 input = heap_alloc(cChars * sizeof(*input));
2527 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2528
2529 /* Step 1: Reorder within Syllables */
2530 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2531 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2532 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2533 *pcGlyphs = cCount;
2534
2535 /* Step 2: Base Form application to syllables */
2536 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2537
2538 heap_free(input);
2539 heap_free(syllables);
2540 }
2541
2542 static int oriya_lex(WCHAR c)
2543 {
2544 switch (c)
2545 {
2546 case 0x0B30: return lex_Ra;
2547 default:
2548 return unicode_lex(c);
2549 }
2550 }
2551
2552 static const VowelComponents Oriya_vowels[] = {
2553 {0x0B48, {0x0B47,0x0B56,0x0000}},
2554 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2555 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2556 {0x0000, {0x0000,0x0000,0x0000}}};
2557
2558 static const ConsonantComponents Oriya_consonants[] = {
2559 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2560 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2561 {{0x0000,0x0000,0x0000}, 0x0000}};
2562
2563 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2564 {
2565 int cCount = cChars;
2566 WCHAR *input;
2567 IndicSyllable *syllables = NULL;
2568 int syllable_count = 0;
2569 BOOL modern = get_GSUB_Indic2(psa, psc);
2570
2571 if (*pcGlyphs != cChars)
2572 {
2573 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2574 return;
2575 }
2576
2577 input = heap_alloc(2 * cChars * sizeof(*input));
2578 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2579
2580 /* Step 1: Decompose Vowels and Compose Consonants */
2581 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2582 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2583 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2584
2585 /* Step 2: Reorder within Syllables */
2586 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2587 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2588 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2589 *pcGlyphs = cCount;
2590
2591 /* Step 3: Base Form application to syllables */
2592 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2593
2594 heap_free(input);
2595 heap_free(syllables);
2596 }
2597
2598 static int tamil_lex(WCHAR c)
2599 {
2600 return unicode_lex(c);
2601 }
2602
2603 static const VowelComponents Tamil_vowels[] = {
2604 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2605 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2606 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2607 {0x0000, {0x0000,0x0000,0x0000}}};
2608
2609 static const ConsonantComponents Tamil_consonants[] = {
2610 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2611 {{0x0000,0x0000,0x0000}, 0x0000}};
2612
2613 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2614 {
2615 int cCount = cChars;
2616 WCHAR *input;
2617 IndicSyllable *syllables = NULL;
2618 int syllable_count = 0;
2619 BOOL modern = get_GSUB_Indic2(psa, psc);
2620
2621 if (*pcGlyphs != cChars)
2622 {
2623 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2624 return;
2625 }
2626
2627 input = heap_alloc(2 * cChars * sizeof(*input));
2628 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2629
2630 /* Step 1: Decompose Vowels and Compose Consonants */
2631 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2632 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2633 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2634
2635 /* Step 2: Reorder within Syllables */
2636 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2637 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2638 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2639 *pcGlyphs = cCount;
2640
2641 /* Step 3: Base Form application to syllables */
2642 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2643
2644 heap_free(input);
2645 heap_free(syllables);
2646 }
2647
2648 static int telugu_lex(WCHAR c)
2649 {
2650 switch (c)
2651 {
2652 case 0x0C43:
2653 case 0x0C44: return lex_Modifier;
2654 default:
2655 return unicode_lex(c);
2656 }
2657 }
2658
2659 static const VowelComponents Telugu_vowels[] = {
2660 {0x0C48, {0x0C46,0x0C56,0x0000}},
2661 {0x0000, {0x0000,0x0000,0x0000}}};
2662
2663 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2664 {
2665 int cCount = cChars;
2666 WCHAR *input;
2667 IndicSyllable *syllables = NULL;
2668 int syllable_count = 0;
2669 BOOL modern = get_GSUB_Indic2(psa, psc);
2670
2671 if (*pcGlyphs != cChars)
2672 {
2673 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2674 return;
2675 }
2676
2677 input = heap_alloc(2 * cChars * sizeof(*input));
2678 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2679
2680 /* Step 1: Decompose Vowels */
2681 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2682 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2683
2684 /* Step 2: Reorder within Syllables */
2685 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2686 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2687 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2688 *pcGlyphs = cCount;
2689
2690 /* Step 3: Base Form application to syllables */
2691 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2692
2693 heap_free(input);
2694 heap_free(syllables);
2695 }
2696
2697 static int kannada_lex(WCHAR c)
2698 {
2699 switch (c)
2700 {
2701 case 0x0CB0: return lex_Ra;
2702 default:
2703 return unicode_lex(c);
2704 }
2705 }
2706
2707 static const VowelComponents Kannada_vowels[] = {
2708 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2709 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2710 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2711 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2712 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2713 {0x0000, {0x0000,0x0000,0x0000}}};
2714
2715 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2716 {
2717 int cCount = cChars;
2718 WCHAR *input;
2719 IndicSyllable *syllables = NULL;
2720 int syllable_count = 0;
2721 BOOL modern = get_GSUB_Indic2(psa, psc);
2722
2723 if (*pcGlyphs != cChars)
2724 {
2725 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2726 return;
2727 }
2728
2729 input = heap_alloc(3 * cChars * sizeof(*input));
2730 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2731
2732 /* Step 1: Decompose Vowels */
2733 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2734 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2735
2736 /* Step 2: Reorder within Syllables */
2737 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2738 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2739 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2740 *pcGlyphs = cCount;
2741
2742 /* Step 3: Base Form application to syllables */
2743 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2744
2745 heap_free(input);
2746 heap_free(syllables);
2747 }
2748
2749 static int malayalam_lex(WCHAR c)
2750 {
2751 return unicode_lex(c);
2752 }
2753
2754 static const VowelComponents Malayalam_vowels[] = {
2755 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2756 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2757 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2758 {0x0000, {0x0000,0x0000,0x0000}}};
2759
2760 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2761 {
2762 int cCount = cChars;
2763 WCHAR *input;
2764 IndicSyllable *syllables = NULL;
2765 int syllable_count = 0;
2766 BOOL modern = get_GSUB_Indic2(psa, psc);
2767
2768 if (*pcGlyphs != cChars)
2769 {
2770 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2771 return;
2772 }
2773
2774 input = heap_alloc(2 * cChars * sizeof(*input));
2775 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2776
2777 /* Step 1: Decompose Vowels */
2778 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2779 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2780
2781 /* Step 2: Reorder within Syllables */
2782 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2783 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2784 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2785 *pcGlyphs = cCount;
2786
2787 /* Step 3: Base Form application to syllables */
2788 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2789
2790 heap_free(input);
2791 heap_free(syllables);
2792 }
2793
2794 static int khmer_lex(WCHAR c)
2795 {
2796 return unicode_lex(c);
2797 }
2798
2799 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2800 {
2801 int cCount = cChars;
2802 WCHAR *input;
2803 IndicSyllable *