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