2 * Implementation of Shaping for the Uniscribe Script Processor (usp10.dll)
4 * Copyright 2010 CodeWeavers, Aric Stewart
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.
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.
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
32 #include "usp10_internal.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
38 #define FIRST_ARABIC_CHAR 0x0600
39 #define LAST_ARABIC_CHAR 0x06ff
41 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
42 WCHAR*, INT, WORD*, INT*, INT, WORD*);
44 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
59 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
61 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
62 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
64 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
66 static void ShapeCharGlyphProp_Default( 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_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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
78 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 );
79 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 );
80 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 );
81 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 );
82 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 );
84 extern const unsigned short indic_syllabic_table[];
85 extern const unsigned short wine_shaping_table[];
86 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
108 typedef struct tagVowelComponents
114 typedef struct tagConsonantComponents
118 } ConsonantComponents;
120 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
122 typedef int (*combining_lexical_function)(WCHAR c);
124 /* the orders of joined_forms and contextual_features need to line up */
125 static const char* contextual_features[] =
137 static OPENTYPE_FEATURE_RECORD standard_features[] =
139 { MS_MAKE_TAG('c','c','m','p'), 1},
140 { MS_MAKE_TAG('l','o','c','l'), 1},
143 static OPENTYPE_FEATURE_RECORD latin_features[] =
145 { MS_MAKE_TAG('l','i','g','a'), 1},
146 { MS_MAKE_TAG('c','l','i','g'), 1},
149 static OPENTYPE_FEATURE_RECORD arabic_features[] =
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},
159 static const char* required_arabic_features[] =
168 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
170 { MS_MAKE_TAG('d','l','i','g'), 0},
173 static OPENTYPE_FEATURE_RECORD syriac_features[] =
175 { MS_MAKE_TAG('r','l','i','g'), 1},
176 { MS_MAKE_TAG('c','a','l','t'), 1},
177 { MS_MAKE_TAG('l','i','g','a'), 1},
178 { MS_MAKE_TAG('d','l','i','g'), 1},
181 static const char* required_syriac_features[] =
193 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
195 /* Presentation forms */
196 { MS_MAKE_TAG('b','l','w','s'), 1},
197 { MS_MAKE_TAG('a','b','v','s'), 1},
198 { MS_MAKE_TAG('p','s','t','s'), 1},
201 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
203 { MS_MAKE_TAG('a','b','v','s'), 1},
204 { MS_MAKE_TAG('b','l','w','s'), 1},
207 static OPENTYPE_FEATURE_RECORD phags_features[] =
209 { MS_MAKE_TAG('a','b','v','s'), 1},
210 { MS_MAKE_TAG('b','l','w','s'), 1},
211 { MS_MAKE_TAG('c','a','l','t'), 1},
214 static OPENTYPE_FEATURE_RECORD thai_features[] =
216 { MS_MAKE_TAG('c','c','m','p'), 1},
219 static const char* required_lao_features[] =
225 static const char* required_devanagari_features[] =
241 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
243 { MS_MAKE_TAG('p','r','e','s'), 1},
244 { MS_MAKE_TAG('a','b','v','s'), 1},
245 { MS_MAKE_TAG('b','l','w','s'), 1},
246 { MS_MAKE_TAG('p','s','t','s'), 1},
247 { MS_MAKE_TAG('h','a','l','n'), 1},
248 { MS_MAKE_TAG('c','a','l','t'), 1},
251 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
253 { MS_MAKE_TAG('l','i','g','a'), 1},
254 { MS_MAKE_TAG('c','l','i','g'), 1},
257 static const char* required_bengali_features[] =
274 static const char* required_gurmukhi_features[] =
293 static const char* required_oriya_features[] =
310 static const char* required_tamil_features[] =
326 static const char* required_telugu_features[] =
344 static OPENTYPE_FEATURE_RECORD khmer_features[] =
346 { MS_MAKE_TAG('p','r','e','s'), 1},
347 { MS_MAKE_TAG('b','l','w','s'), 1},
348 { MS_MAKE_TAG('a','b','v','s'), 1},
349 { MS_MAKE_TAG('p','s','t','s'), 1},
350 { MS_MAKE_TAG('c','l','i','g'), 1},
353 static const char* required_khmer_features[] =
367 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
369 { MS_MAKE_TAG('c','c','m','p'), 1},
370 { MS_MAKE_TAG('l','o','c','l'), 1},
371 { MS_MAKE_TAG('c','a','l','t'), 1},
372 { MS_MAKE_TAG('l','i','g','a'), 1},
375 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
377 { MS_MAKE_TAG('c','c','m','p'), 1},
378 { MS_MAKE_TAG('l','o','c','l'), 1},
379 { MS_MAKE_TAG('c','a','l','t'), 1},
380 { MS_MAKE_TAG('r','l','i','g'), 1},
383 typedef struct ScriptShapeDataTag {
384 TEXTRANGE_PROPERTIES defaultTextRange;
385 const char** requiredFeatures;
386 OPENTYPE_TAG newOtTag;
387 ContextualShapingProc contextProc;
388 ShapeCharGlyphPropProc charGlyphPropProc;
391 /* in order of scripts */
392 static const ScriptShapeData ShapingData[] =
394 {{ standard_features, 2}, NULL, 0, NULL, NULL},
395 {{ latin_features, 2}, NULL, 0, NULL, NULL},
396 {{ latin_features, 2}, NULL, 0, NULL, NULL},
397 {{ latin_features, 2}, NULL, 0, NULL, NULL},
398 {{ standard_features, 2}, NULL, 0, NULL, NULL},
399 {{ latin_features, 2}, NULL, 0, NULL, NULL},
400 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
401 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
402 {{ hebrew_features, 1}, NULL, 0, ContextualShape_Hebrew, ShapeCharGlyphProp_Hebrew},
403 {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
404 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
405 {{ NULL, 0}, NULL, 0, ContextualShape_Thaana, ShapeCharGlyphProp_None},
406 {{ standard_features, 2}, NULL, 0, NULL, NULL},
407 {{ standard_features, 2}, NULL, 0, NULL, NULL},
408 {{ standard_features, 2}, NULL, 0, NULL, NULL},
409 {{ standard_features, 2}, NULL, 0, NULL, NULL},
410 {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
411 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
412 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
413 {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
414 {{ thai_features, 1}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
415 {{ thai_features, 1}, NULL, 0, ContextualShape_Thai, NULL},
416 {{ thai_features, 1}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
417 {{ thai_features, 1}, required_lao_features, 0, ContextualShape_Lao, ShapeCharGlyphProp_Thai},
418 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
419 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, NULL},
420 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
421 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, NULL},
422 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
423 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
424 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, NULL},
425 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
426 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, NULL},
427 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
428 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
429 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, NULL},
430 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
431 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, NULL},
432 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
433 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, NULL},
434 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
435 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, NULL},
436 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
437 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, NULL},
438 {{ standard_features, 2}, NULL, 0, NULL, NULL},
439 {{ latin_features, 2}, NULL, 0, NULL, NULL},
440 {{ standard_features, 2}, NULL, 0, NULL, NULL},
441 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
442 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
443 {{ standard_features, 2}, NULL, 0, NULL, NULL},
444 {{ standard_features, 2}, NULL, 0, NULL, NULL},
445 {{ standard_features, 2}, NULL, 0, NULL, NULL},
446 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
447 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
448 {{ NULL, 0}, NULL, 0, NULL, NULL},
449 {{ NULL, 0}, NULL, 0, NULL, NULL},
450 {{ NULL, 0}, NULL, 0, NULL, NULL},
451 {{ NULL, 0}, NULL, 0, NULL, NULL},
452 {{ NULL, 0}, NULL, 0, NULL, NULL},
453 {{ NULL, 0}, NULL, 0, NULL, NULL},
454 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
455 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
456 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
457 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
458 {{ NULL, 0}, NULL, 0, NULL, NULL},
459 {{ NULL, 0}, NULL, 0, NULL, NULL},
460 {{ NULL, 0}, NULL, 0, NULL, NULL},
461 {{ NULL, 0}, NULL, 0, NULL, NULL},
462 {{ NULL, 0}, NULL, 0, NULL, NULL},
463 {{ NULL, 0}, NULL, 0, NULL, NULL},
464 {{ NULL, 0}, NULL, 0, NULL, NULL},
465 {{ NULL, 0}, NULL, 0, NULL, NULL},
466 {{ NULL, 0}, NULL, 0, NULL, NULL},
467 {{ NULL, 0}, NULL, 0, NULL, NULL},
468 {{ NULL, 0}, NULL, 0, NULL, NULL},
469 {{ NULL, 0}, NULL, 0, NULL, NULL},
470 {{ NULL, 0}, NULL, 0, NULL, NULL},
471 {{ NULL, 0}, NULL, 0, NULL, NULL},
472 {{ NULL, 0}, NULL, 0, NULL, NULL},
473 {{ hebrew_features, 1}, NULL, 0, ContextualShape_Hebrew, NULL},
474 {{ latin_features, 2}, NULL, 0, NULL, NULL},
475 {{ thai_features, 1}, NULL, 0, ContextualShape_Thai, ShapeCharGlyphProp_Thai},
478 extern scriptData scriptInformation[];
480 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
483 int out_index = GSUB_E_NOGLYPH;
485 TRACE("%i lookups\n", feature->lookup_count);
486 for (i = 0; i < feature->lookup_count; i++)
488 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
489 if (out_index != GSUB_E_NOGLYPH)
492 if (out_index == GSUB_E_NOGLYPH)
493 TRACE("lookups found no glyphs\n");
497 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
498 if (out2!=GSUB_E_NOGLYPH)
504 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
508 if (psc->userScript != 0)
510 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
511 return ShapingData[psa->eScript].newOtTag;
513 return psc->userScript;
516 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
517 return ShapingData[psa->eScript].newOtTag;
519 if (scriptInformation[psa->eScript].scriptTag)
520 return scriptInformation[psa->eScript].scriptTag;
523 * fall back to the font charset
525 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
529 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
530 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
531 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
532 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
533 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
534 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
535 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
536 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
537 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
538 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
539 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
540 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
541 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
542 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
543 default: return MS_MAKE_TAG('l','a','t','n');
547 static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
549 LoadedFeature *feature = NULL;
555 OPENTYPE_TAG language;
561 script = get_opentype_script(hdc,psa,psc,(attempt==2));
562 if (psc->userLang != 0)
563 language = psc->userLang;
565 language = MS_MAKE_TAG('d','f','l','t');
568 OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
570 } while(attempt && !feature);
572 /* try in the default (latin) table */
574 OpenType_GSUB_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]), 1, &tags, &cTags, &feature);
577 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
581 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)
583 LoadedFeature *feature;
585 feature = load_GSUB_feature(hdc, psa, psc, feat);
587 return GSUB_E_NOFEATURE;
589 TRACE("applying feature %s\n",feat);
590 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
593 static VOID *load_gsub_table(HDC hdc)
595 VOID* GSUB_Table = NULL;
596 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
597 if (length != GDI_ERROR)
599 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
600 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
601 TRACE("Loaded GSUB table of %i bytes\n",length);
606 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)
609 INT glyph_count = count;
612 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
613 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
614 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
615 if (rc > GSUB_E_NOGLYPH)
616 rc = count - glyph_count;
620 HeapFree(GetProcessHeap(),0,glyphs);
624 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
628 for (i = 0; i < cGlyphs; i++)
630 if (!pGlyphProp[i].sva.fClusterStart)
633 for (j = 0; j < cChars; j++)
635 if (pwLogClust[j] == i)
638 while (k >= 0 && k <cChars && !pGlyphProp[pwLogClust[k]].sva.fClusterStart)
640 if (k >= 0 && k <cChars && pGlyphProp[pwLogClust[k]].sva.fClusterStart)
641 pwLogClust[j] = pwLogClust[k];
648 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
650 if (changeCount == 0)
655 int target_glyph = nextIndex - write_dir;
657 int target_index = -1;
658 int replacing_glyph = -1;
660 int top_logclust = 0;
665 target_glyph = nextIndex - changeCount;
667 target_glyph = nextIndex + (changeCount + 1);
670 seeking_glyph = target_glyph;
671 for (i = 0; i < chars; i++)
672 if (pwLogClust[i] > top_logclust)
673 top_logclust = pwLogClust[i];
677 for (i = 0; i < chars; i++)
679 if (pwLogClust[i] == seeking_glyph)
686 for (i = chars - 1; i >= 0; i--)
688 if (pwLogClust[i] == seeking_glyph)
694 if (target_index == -1)
697 while (target_index == -1 && seeking_glyph <= top_logclust);
699 if (target_index == -1)
701 ERR("Unable to find target glyph\n");
708 for(i = target_index; i < chars && i >= 0; i+=write_dir)
710 if (pwLogClust[i] == target_glyph)
712 if(pwLogClust[i] == replacing_glyph)
713 pwLogClust[i] = target_glyph;
717 if (changed >= changeCount)
719 replacing_glyph = pwLogClust[i];
720 pwLogClust[i] = target_glyph;
727 /* renumber trailing indexes*/
728 for(i = target_index; i < chars && i >= 0; i+=write_dir)
730 if (pwLogClust[i] != target_glyph)
731 pwLogClust[i] += changeCount;
736 for(i = target_index; i < chars && i >= 0; i+=write_dir)
737 pwLogClust[i] += changeCount;
742 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 )
746 LoadedFeature *feature;
749 feature = load_GSUB_feature(hdc, psa, psc, feat);
751 return GSUB_E_NOFEATURE;
753 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
754 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
762 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
763 while(i < *pcGlyphs && i >= 0)
766 INT prevCount = *pcGlyphs;
768 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
769 if (*pcGlyphs != prevCount)
771 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
780 return GSUB_E_NOFEATURE;
783 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
789 hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL);
791 return(SUCCEEDED(hr));
794 static void insert_glyph(WORD *pwGlyphs, INT *pcGlyphs, INT cChars, INT write_dir, WORD glyph, INT index, WORD *pwLogClust)
797 for (i = *pcGlyphs; i>=index; i--)
798 pwGlyphs[i+1] = pwGlyphs[i];
799 pwGlyphs[index] = glyph;
800 *pcGlyphs = *pcGlyphs+1;
802 UpdateClusters(index-3, 1, write_dir, cChars, pwLogClust);
804 UpdateClusters(index, 1, write_dir, cChars, pwLogClust);
807 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)
811 WCHAR invalid = 0x25cc;
814 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
816 /* Mark invalid combinations */
817 for (i = 0; i < cChars; i++)
818 context_type[i] = lex(pwcChars[i]);
820 GetGlyphIndicesW(hdc, &invalid, 1, &invalid_glyph, 0);
821 for (i = 1, g=1; i < cChars; i++, g++)
823 if (context_type[i] != 0 && context_type[i+write_dir]==context_type[i])
825 insert_glyph(pwGlyphs, pcGlyphs, cChars, write_dir, invalid_glyph, g, pwLogClust);
830 HeapFree(GetProcessHeap(),0,context_type);
833 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
837 if ( i+ delta >= cchLen)
845 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
849 if (psa->fLinkBefore)
854 if ( i+ delta >= cchLen)
864 if (context_type[i] == jtT)
865 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
867 return context_type[i];
870 static inline BOOL right_join_causing(CHAR joining_type)
872 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
875 static inline BOOL left_join_causing(CHAR joining_type)
877 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
880 static inline BOOL word_break_causing(WCHAR chr)
882 /* we are working within a string of characters already guareented to
883 be within one script, Syriac, so we do not worry about any character
884 other than the space character outside of that range */
885 return (chr == 0 || chr == 0x20 );
888 static int combining_lexical_Arabic(WCHAR c)
890 enum {Arab_Norm = 0, Arab_DIAC1, Arab_DIAC2, Arab_DIAC3, Arab_DIAC4, Arab_DIAC5, Arab_DIAC6, Arab_DIAC7, Arab_DIAC8};
901 case 0x06E1: return Arab_DIAC1; break;
904 case 0x0656: return Arab_DIAC2; break;
905 case 0x0651: return Arab_DIAC3; break;
921 case 0x06EC: return Arab_DIAC4; break;
924 case 0x06ED: return Arab_DIAC5; break;
925 case 0x0670: return Arab_DIAC6; break;
926 case 0x0653: return Arab_DIAC7; break;
928 case 0x0654: return Arab_DIAC8; break;
929 default: return Arab_Norm;
934 * ContextualShape_Arabic
936 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
943 if (*pcGlyphs != cChars)
945 ERR("Number of Glyphs and Chars need to match at the beginning\n");
949 if (!psa->fLogicalOrder && psa->fRTL)
960 if (!psc->GSUB_Table)
961 psc->GSUB_Table = load_gsub_table(hdc);
963 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
964 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
966 for (i = 0; i < cChars; i++)
967 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
969 for (i = 0; i < cChars; i++)
971 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
972 context_shape[i] = Xr;
973 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
974 context_shape[i] = Xl;
975 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)))
976 context_shape[i] = Xm;
977 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
978 context_shape[i] = Xr;
979 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
980 context_shape[i] = Xl;
982 context_shape[i] = Xn;
985 /* Contextual Shaping */
994 INT prevCount = *pcGlyphs;
995 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
996 if (nextIndex > GSUB_E_NOGLYPH)
999 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1001 shaped = (nextIndex > GSUB_E_NOGLYPH);
1006 if (context_shape[i] == Xn)
1008 WORD newGlyph = pwOutGlyphs[i];
1009 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1011 /* fall back to presentation form B */
1012 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1013 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1014 pwOutGlyphs[i] = newGlyph;
1021 HeapFree(GetProcessHeap(),0,context_shape);
1022 HeapFree(GetProcessHeap(),0,context_type);
1024 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Arabic);
1027 static int combining_lexical_Hebrew(WCHAR c)
1029 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};
1040 case 0x05BB: return Hebr_DIAC; break;
1044 case 0x05AE: return Hebr_CANT1; break;
1047 case 0x05AC: return Hebr_CANT2; break;
1053 case 0x05AB: return Hebr_CANT3; break;
1057 case 0x059F: return Hebr_CANT4; break;
1059 case 0x05A0: return Hebr_CANT5; break;
1061 case 0x05A5: return Hebr_CANT6; break;
1064 case 0x05A6: return Hebr_CANT7; break;
1067 case 0x05AA: return Hebr_CANT8; break;
1069 case 0x05AD: return Hebr_CANT9; break;
1070 case 0x05AF: return Hebr_CANT10; break;
1071 case 0x05BC: return Hebr_DAGESH; break;
1072 case 0x05C4: return Hebr_DOTABV; break;
1073 case 0x05B9: return Hebr_HOLAM; break;
1074 case 0x05BD: return Hebr_METEG; break;
1075 case 0x05B7: return Hebr_PATAH; break;
1076 case 0x05B8: return Hebr_QAMATS; break;
1077 case 0x05BF: return Hebr_RAFE; break;
1079 case 0x05C2: return Hebr_SHINSIN; break;
1080 default: return Hebr_Norm;
1084 static void ContextualShape_Hebrew(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1088 if (*pcGlyphs != cChars)
1090 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1094 if (!psa->fLogicalOrder && psa->fRTL)
1099 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Hebrew);
1103 * ContextualShape_Syriac
1106 static int combining_lexical_Syriac(WCHAR c)
1108 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};
1116 case 0x73D: return Syriac_DIAC1; break;
1121 case 0x73E: return Syriac_DIAC2; break;
1124 case 0x74A: return Syriac_DIAC3; break;
1127 case 0x73F: return Syriac_DIAC4; break;
1130 case 0x73C: return Syriac_DIAC5; break;
1132 case 0x30A: return Syriac_DIAC6; break;
1134 case 0x325: return Syriac_DIAC7; break;
1136 case 0x303: return Syriac_DIAC8; break;
1141 case 0x331: return Syriac_DIAC9; break;
1142 case 0x308: return Syriac_DIAC10; break;
1143 case 0x304: return Syriac_DIAC11; break;
1144 case 0x307: return Syriac_DIAC12; break;
1145 case 0x323: return Syriac_DIAC13; break;
1146 case 0x743: return Syriac_DIAC14; break;
1147 case 0x744: return Syriac_DIAC15; break;
1148 case 0x745: return Syriac_DIAC16; break;
1149 case 0x746: return Syriac_DIAC17; break;
1150 default: return Syriac_Norm;
1155 #define DALATH 0x715
1158 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1165 if (*pcGlyphs != cChars)
1167 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1171 if (!psa->fLogicalOrder && psa->fRTL)
1182 if (!psc->GSUB_Table)
1183 psc->GSUB_Table = load_gsub_table(hdc);
1185 if (!psc->GSUB_Table)
1188 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1189 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1191 for (i = 0; i < cChars; i++)
1192 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1194 for (i = 0; i < cChars; i++)
1196 if (pwcChars[i] == ALAPH)
1198 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1200 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1201 context_shape[i] = Afj;
1202 else if ( rchar != DALATH && rchar != RISH &&
1203 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1204 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1205 context_shape[i] = Afn;
1206 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1207 context_shape[i] = Afx;
1209 context_shape[i] = Xn;
1211 else if (context_type[i] == jtR &&
1212 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1213 context_shape[i] = Xr;
1214 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1215 context_shape[i] = Xl;
1216 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)))
1217 context_shape[i] = Xm;
1218 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1219 context_shape[i] = Xr;
1220 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1221 context_shape[i] = Xl;
1223 context_shape[i] = Xn;
1226 /* Contextual Shaping */
1228 while(i < *pcGlyphs)
1231 INT prevCount = *pcGlyphs;
1232 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1233 if (nextIndex > GSUB_E_NOGLYPH)
1235 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1242 HeapFree(GetProcessHeap(),0,context_shape);
1243 HeapFree(GetProcessHeap(),0,context_type);
1245 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Syriac);
1248 static int combining_lexical_Thaana(WCHAR c)
1250 enum {Thaana_Norm=0, Thaana_FILI};
1263 case 0x7AF: return Thaana_FILI; break;
1264 default: return Thaana_Norm;
1268 static void ContextualShape_Thaana(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1272 if (*pcGlyphs != cChars)
1274 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1278 if (!psa->fLogicalOrder && psa->fRTL)
1283 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thaana);
1287 * ContextualShape_Phags_pa
1290 #define phags_pa_CANDRABINDU 0xA873
1291 #define phags_pa_START 0xA840
1292 #define phags_pa_END 0xA87F
1294 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1300 if (*pcGlyphs != cChars)
1302 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1306 if (!psa->fLogicalOrder && psa->fRTL)
1317 if (!psc->GSUB_Table)
1318 psc->GSUB_Table = load_gsub_table(hdc);
1320 if (!psc->GSUB_Table)
1323 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1325 for (i = 0; i < cChars; i++)
1327 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1329 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1330 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1331 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1332 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1334 if (jrchar && jlchar)
1335 context_shape[i] = Xm;
1337 context_shape[i] = Xr;
1339 context_shape[i] = Xl;
1341 context_shape[i] = Xn;
1344 context_shape[i] = -1;
1347 /* Contextual Shaping */
1349 while(i < *pcGlyphs)
1351 if (context_shape[i] >= 0)
1354 INT prevCount = *pcGlyphs;
1355 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1356 if (nextIndex > GSUB_E_NOGLYPH)
1358 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1368 HeapFree(GetProcessHeap(),0,context_shape);
1371 static int combining_lexical_Thai(WCHAR c)
1373 enum {Thai_Norm=0, Thai_ABOVE1, Thai_ABOVE2, Thai_ABOVE3, Thai_ABOVE4, Thai_BELOW1, Thai_BELOW2, Thai_AM};
1381 case 0xE37: return Thai_ABOVE1; break;
1383 case 0xE4D: return Thai_ABOVE2; break;
1387 case 0xE4B: return Thai_ABOVE3; break;
1389 case 0xE4E: return Thai_ABOVE4; break;
1391 case 0xE39: return Thai_BELOW1; break;
1392 case 0xE3A: return Thai_BELOW2; break;
1393 case 0xE33: return Thai_AM; break;
1394 default: return Thai_Norm;
1398 static void ContextualShape_Thai(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1402 if (*pcGlyphs != cChars)
1404 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1408 if (!psa->fLogicalOrder && psa->fRTL)
1413 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Thai);
1416 static int combining_lexical_Lao(WCHAR c)
1418 enum {Lao_Norm=0, Lao_ABOVE1, Lao_ABOVE2, Lao_BELOW1, Lao_BELOW2, Lao_AM};
1428 case 0xECD: return Lao_ABOVE1; break;
1433 case 0xECC: return Lao_ABOVE2; break;
1434 case 0xEBC: return Lao_BELOW1; break;
1436 case 0xEB9: return Lao_BELOW2; break;
1437 case 0xEB3: return Lao_AM; break;
1438 default: return Lao_Norm;
1442 static void ContextualShape_Lao(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1446 if (*pcGlyphs != cChars)
1448 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1452 if (!psa->fLogicalOrder && psa->fRTL)
1457 mark_invalid_combinations(hdc, pwcChars, cChars, pwOutGlyphs, pcGlyphs, dirL, pwLogClust, combining_lexical_Lao);
1460 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1465 pwOutChars[cWalk] = replacements[0];
1469 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1472 for (j = *pcChars; j > cWalk; j--)
1473 pwOutChars[j] = pwOutChars[j-1];
1474 *pcChars= *pcChars+1;
1475 pwOutChars[cWalk] = replacements[i];
1480 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1485 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1487 for (i = 0; vowels[i].base != 0x0; i++)
1489 if (pwOutChars[cWalk] == vowels[i].base)
1492 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1493 if (vowels[i].parts[1]) { cWalk++; o++; }
1494 if (vowels[i].parts[2]) { cWalk++; o++; }
1495 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1502 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1508 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1510 for (i = 0; consonants[i].output!= 0x0; i++)
1513 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1514 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1517 if (consonants[i].parts[j]==0x0) /* matched all */
1521 pwOutChars[cWalk] = consonants[i].output;
1522 for(k = cWalk+1; k < *pcChars - j; k++)
1523 pwOutChars[k] = pwOutChars[k+j];
1524 *pcChars = *pcChars - j;
1525 for (k = j ; k > 0; k--)
1526 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1528 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1537 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1542 WORD Ra = pwChar[s->start];
1543 WORD H = pwChar[s->start+1];
1545 TRACE("Doing reorder of Ra to %i\n",s->base);
1546 for (j = s->start; j < s->base-1; j++)
1547 pwChar[j] = pwChar[j+2];
1548 pwChar[s->base-1] = Ra;
1549 pwChar[s->base] = H;
1551 s->ralf = s->base-1;
1556 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1561 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1562 WORD Ra = pwChar[s->start];
1563 WORD H = pwChar[s->start+1];
1564 for (loc = s->end; loc > stop; loc--)
1565 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1568 TRACE("Doing reorder of Ra to %i\n",loc);
1569 for (j = s->start; j < loc-1; j++)
1570 pwChar[j] = pwChar[j+2];
1576 if (s->blwf >= 0) s->blwf -= 2;
1577 if (s->pref >= 0) s->pref -= 2;
1581 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1586 WORD Ra = pwChar[s->start];
1587 WORD H = pwChar[s->start+1];
1589 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1590 for (j = s->start; j < s->end-1; j++)
1591 pwChar[j] = pwChar[j+2];
1592 pwChar[s->end-1] = Ra;
1597 if (s->blwf >= 0) s->blwf -= 2;
1598 if (s->pref >= 0) s->pref -= 2;
1602 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1606 /* reorder Matras */
1607 if (s->end > s->base)
1609 for (i = 1; i <= s->end-s->base; i++)
1611 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1614 WCHAR c = pwChar[s->base+i];
1615 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1616 for (j = s->base+i; j > s->base; j--)
1617 pwChar[j] = pwChar[j-1];
1618 pwChar[s->base] = c;
1620 if (s->ralf >= s->base) s->ralf++;
1621 if (s->blwf >= s->base) s->blwf++;
1622 if (s->pref >= s->base) s->pref++;
1629 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1633 /* reorder Matras */
1634 if (s->end > s->base)
1636 for (i = 1; i <= s->end-s->base; i++)
1638 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1641 WCHAR c = pwChar[s->base+i];
1642 TRACE("Doing reorder of %x to %i\n",c,s->start);
1643 for (j = s->base+i; j > s->start; j--)
1644 pwChar[j] = pwChar[j-1];
1645 pwChar[s->start] = c;
1647 if (s->ralf >= 0) s->ralf++;
1648 if (s->blwf >= 0) s->blwf++;
1649 if (s->pref >= 0) s->pref++;
1656 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1658 if (s->blwf >= 0 && g->blwf > g->base)
1662 for (loc = s->end; loc > s->blwf; loc--)
1663 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1666 g_offset = (loc - s->blwf) - 1;
1670 WORD blwf = glyphs[g->blwf];
1671 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1672 /* do not care about the pwChar array anymore, just the glyphs */
1673 for (j = 0; j < g_offset; j++)
1674 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1675 glyphs[g->blwf + g_offset] = blwf;
1680 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1684 /* reorder previously moved Matras to correct position*/
1685 for (i = s->start; i < s->base; i++)
1687 if (lexical(pwChar[i]) == lex_Matra_pre)
1690 int g_start = g->start + i - s->start;
1691 if (g_start < g->base -1 )
1693 WCHAR og = glyphs[g_start];
1694 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1695 for (j = g_start; j < g->base-1; j++)
1696 glyphs[j] = glyphs[j+1];
1697 glyphs[g->base-1] = og;
1703 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1705 if (s->pref >= 0 && g->pref > g->base)
1708 WCHAR og = glyphs[g->pref];
1709 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1710 for (j = g->pref; j > g->base; j--)
1711 glyphs[j] = glyphs[j-1];
1712 glyphs[g->base] = og;
1716 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1718 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1719 if (s->start == s->base && s->base == s->end) return;
1720 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1722 Reorder_Ra_follows_base(pwChar, s, lexical);
1723 Reorder_Matra_precede_base(pwChar, s, lexical);
1726 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1728 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1729 if (s->start == s->base && s->base == s->end) return;
1730 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1732 Reorder_Ra_follows_matra(pwChar, s, lexical);
1733 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1736 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1738 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1739 if (s->start == s->base && s->base == s->end) return;
1740 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1742 Reorder_Ra_follows_base(pwChar, s, lexical);
1743 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1746 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1748 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1749 if (s->start == s->base && s->base == s->end) return;
1750 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1752 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1753 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1756 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1758 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1759 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1760 if (s->start == s->base && s->base == s->end) return;
1761 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1763 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1766 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1768 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1769 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1770 if (s->start == s->base && s->base == s->end) return;
1771 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1773 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1774 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1778 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1783 if (glyph_index->start > index)
1784 glyph_index->start += shift;
1785 if (glyph_index->base > index)
1786 glyph_index->base+= shift;
1787 if (glyph_index->end > index)
1788 glyph_index->end+= shift;
1789 if (glyph_index->ralf > index)
1790 glyph_index->ralf+= shift;
1791 if (glyph_index->blwf > index)
1792 glyph_index->blwf+= shift;
1793 if (glyph_index->pref > index)
1794 glyph_index->pref+= shift;
1797 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 )
1799 int index = glyph_index->start;
1804 while(index <= glyph_index->end)
1807 INT prevCount = *pcGlyphs;
1808 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1809 if (nextIndex > GSUB_E_NOGLYPH)
1811 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1812 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1820 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1823 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)))))
1825 if (index + i <= end-1)
1831 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)
1833 INT index, nextIndex;
1836 count = syllable->base - syllable->start;
1839 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1840 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1842 INT prevCount = *pcGlyphs;
1843 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1844 if (nextIndex > GSUB_E_NOGLYPH)
1846 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1847 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1848 g_offset += (*pcGlyphs - prevCount);
1852 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1856 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)
1859 INT prevCount = *pcGlyphs;
1861 if (syllable->ralf >= 0)
1863 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1864 if (nextIndex > GSUB_E_NOGLYPH)
1866 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1867 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1872 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1875 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1876 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1877 is_consonant(lexical(pwChars[index+i+1])))))
1879 if (index + i <= end-1)
1885 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)
1887 INT index, nextIndex;
1888 INT count, g_offset=0;
1889 INT ralf = syllable->ralf;
1891 count = syllable->end - syllable->base;
1893 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
1897 INT prevCount = *pcGlyphs;
1898 if (ralf >=0 && ralf < index)
1906 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1907 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1908 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1911 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
1912 if (nextIndex > GSUB_E_NOGLYPH)
1914 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1915 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
1916 g_offset += (*pcGlyphs - prevCount);
1920 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1921 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1922 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1926 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
1930 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)
1933 int overall_shift = 0;
1934 LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
1935 LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
1936 LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
1937 LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
1938 LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
1939 LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
1940 LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
1941 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
1942 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
1943 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
1944 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
1945 IndicSyllable glyph_indexs;
1947 for (c = 0; c < syllable_count; c++)
1950 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
1951 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
1952 old_end = glyph_indexs.end;
1956 TRACE("applying feature locl\n");
1957 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
1961 TRACE("applying feature nukt\n");
1962 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
1966 TRACE("applying feature akhn\n");
1967 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
1971 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
1974 TRACE("applying feature rkrf\n");
1975 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
1978 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
1982 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
1984 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
1988 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
1991 TRACE("applying feature pstf\n");
1992 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
1996 TRACE("applying feature vatu\n");
1997 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2001 TRACE("applying feature cjct\n");
2002 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2006 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2008 overall_shift += glyph_indexs.end - old_end;
2012 static inline int unicode_lex(WCHAR c)
2016 if (!c) return lex_Generic;
2017 if (c == 0x200D) return lex_ZWJ;
2018 if (c == 0x200C) return lex_ZWNJ;
2019 if (c == 0x00A0) return lex_NBSP;
2021 type = get_table_entry( indic_syllabic_table, c );
2023 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2027 case 0x0d07: /* Unknown */
2028 case 0x0e07: /* Unknwon */
2029 default: return lex_Generic;
2035 case 0x0014: return lex_Modifier;
2043 case 0x0010: return lex_Consonant;
2044 case 0x0004: return lex_Nukta;
2045 case 0x0005: return lex_Halant;
2047 case 0x0008: return lex_Vowel;
2049 case 0x0107: return lex_Matra_post;
2051 case 0x0307: return lex_Matra_pre;
2057 case 0x0407: return lex_Composed_Vowel;
2058 case 0x0507: return lex_Matra_above;
2059 case 0x0607: return lex_Matra_below;
2060 case 0x000c: return lex_Ra;
2064 static int sinhala_lex(WCHAR c)
2071 case 0x0DDE: return lex_Matra_post;
2073 return unicode_lex(c);
2077 static const VowelComponents Sinhala_vowels[] = {
2078 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2079 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2080 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2081 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2082 {0x0000, {0x0000,0x0000,0x0}}};
2084 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2086 int cCount = cChars;
2089 IndicSyllable *syllables = NULL;
2090 int syllable_count = 0;
2092 if (*pcGlyphs != cChars)
2094 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2098 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2100 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2102 /* Step 1: Decompose multi part vowels */
2103 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2105 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2107 /* Step 2: Reorder within Syllables */
2108 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2109 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2111 /* Step 3: Strip dangling joiners */
2112 for (i = 0; i < cCount; i++)
2114 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2115 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2119 /* Step 4: Base Form application to syllables */
2120 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2122 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2124 HeapFree(GetProcessHeap(),0,input);
2125 HeapFree(GetProcessHeap(),0,syllables);
2128 static int devanagari_lex(WCHAR c)
2132 case 0x0930: return lex_Ra;
2134 return unicode_lex(c);
2138 static const ConsonantComponents Devanagari_consonants[] ={
2139 {{0x0928, 0x093C, 0x00000}, 0x0929},
2140 {{0x0930, 0x093C, 0x00000}, 0x0931},
2141 {{0x0933, 0x093C, 0x00000}, 0x0934},
2142 {{0x0915, 0x093C, 0x00000}, 0x0958},
2143 {{0x0916, 0x093C, 0x00000}, 0x0959},
2144 {{0x0917, 0x093C, 0x00000}, 0x095A},
2145 {{0x091C, 0x093C, 0x00000}, 0x095B},
2146 {{0x0921, 0x093C, 0x00000}, 0x095C},
2147 {{0x0922, 0x093C, 0x00000}, 0x095D},
2148 {{0x092B, 0x093C, 0x00000}, 0x095E},
2149 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2151 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2153 int cCount = cChars;
2155 IndicSyllable *syllables = NULL;
2156 int syllable_count = 0;
2157 BOOL modern = get_GSUB_Indic2(psa, psc);
2159 if (*pcGlyphs != cChars)
2161 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2165 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2166 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2168 /* Step 1: Compose Consonant and Nukta */
2169 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2170 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2172 /* Step 2: Reorder within Syllables */
2173 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2174 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2175 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2178 /* Step 3: Base Form application to syllables */
2179 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2181 HeapFree(GetProcessHeap(),0,input);
2182 HeapFree(GetProcessHeap(),0,syllables);
2185 static int bengali_lex(WCHAR c)
2189 case 0x09B0: return lex_Ra;
2191 return unicode_lex(c);
2195 static const VowelComponents Bengali_vowels[] = {
2196 {0x09CB, {0x09C7,0x09BE,0x0000}},
2197 {0x09CC, {0x09C7,0x09D7,0x0000}},
2198 {0x0000, {0x0000,0x0000,0x0000}}};
2200 static const ConsonantComponents Bengali_consonants[] = {
2201 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2202 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2203 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2204 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2205 {{0x0000,0x0000,0x0000}, 0x0000}};
2207 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2209 int cCount = cChars;
2211 IndicSyllable *syllables = NULL;
2212 int syllable_count = 0;
2213 BOOL modern = get_GSUB_Indic2(psa, psc);
2215 if (*pcGlyphs != cChars)
2217 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2221 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2222 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2224 /* Step 1: Decompose Vowels and Compose Consonants */
2225 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2226 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2227 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2229 /* Step 2: Reorder within Syllables */
2230 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2231 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2232 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2235 /* Step 3: Initial form is only applied to the beginning of words */
2236 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2238 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2242 if (index > 0) index++;
2244 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2248 /* Step 4: Base Form application to syllables */
2249 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2251 HeapFree(GetProcessHeap(),0,input);
2252 HeapFree(GetProcessHeap(),0,syllables);
2255 static int gurmukhi_lex(WCHAR c)
2258 return lex_Modifier;
2260 return unicode_lex(c);
2263 static const ConsonantComponents Gurmukhi_consonants[] = {
2264 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2265 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2266 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2267 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2268 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2269 {{0x0000,0x0000,0x0000}, 0x0000}};
2271 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2273 int cCount = cChars;
2275 IndicSyllable *syllables = NULL;
2276 int syllable_count = 0;
2277 BOOL modern = get_GSUB_Indic2(psa, psc);
2279 if (*pcGlyphs != cChars)
2281 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2285 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2286 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2288 /* Step 1: Compose Consonants */
2289 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2290 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2292 /* Step 2: Reorder within Syllables */
2293 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2294 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2295 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2298 /* Step 3: Base Form application to syllables */
2299 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2301 HeapFree(GetProcessHeap(),0,input);
2302 HeapFree(GetProcessHeap(),0,syllables);
2305 static int gujarati_lex(WCHAR c)
2309 case 0x0AB0: return lex_Ra;
2311 return unicode_lex(c);
2315 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2317 int cCount = cChars;
2319 IndicSyllable *syllables = NULL;
2320 int syllable_count = 0;
2321 BOOL modern = get_GSUB_Indic2(psa, psc);
2323 if (*pcGlyphs != cChars)
2325 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2329 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2330 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2332 /* Step 1: Reorder within Syllables */
2333 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2334 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2335 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2338 /* Step 2: Base Form application to syllables */
2339 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2341 HeapFree(GetProcessHeap(),0,input);
2342 HeapFree(GetProcessHeap(),0,syllables);
2345 static int oriya_lex(WCHAR c)
2349 case 0x0B30: return lex_Ra;
2351 return unicode_lex(c);
2355 static const VowelComponents Oriya_vowels[] = {
2356 {0x0B48, {0x0B47,0x0B56,0x0000}},
2357 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2358 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2359 {0x0000, {0x0000,0x0000,0x0000}}};
2361 static const ConsonantComponents Oriya_consonants[] = {
2362 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2363 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2364 {{0x0000,0x0000,0x0000}, 0x0000}};
2366 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2368 int cCount = cChars;
2370 IndicSyllable *syllables = NULL;
2371 int syllable_count = 0;
2372 BOOL modern = get_GSUB_Indic2(psa, psc);
2374 if (*pcGlyphs != cChars)
2376 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2380 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2381 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2383 /* Step 1: Decompose Vowels and Compose Consonants */
2384 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2385 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2386 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2388 /* Step 2: Reorder within Syllables */
2389 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2390 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2391 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2394 /* Step 3: Base Form application to syllables */
2395 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2397 HeapFree(GetProcessHeap(),0,input);
2398 HeapFree(GetProcessHeap(),0,syllables);
2401 static int tamil_lex(WCHAR c)
2403 return unicode_lex(c);
2406 static const VowelComponents Tamil_vowels[] = {
2407 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2408 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2409 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2410 {0x0000, {0x0000,0x0000,0x0000}}};
2412 static const ConsonantComponents Tamil_consonants[] = {
2413 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2414 {{0x0000,0x0000,0x0000}, 0x0000}};
2416 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2418 int cCount = cChars;
2420 IndicSyllable *syllables = NULL;
2421 int syllable_count = 0;
2422 BOOL modern = get_GSUB_Indic2(psa, psc);
2424 if (*pcGlyphs != cChars)
2426 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2430 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2431 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2433 /* Step 1: Decompose Vowels and Compose Consonants */
2434 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2435 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2436 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2438 /* Step 2: Reorder within Syllables */
2439 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2440 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2441 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2444 /* Step 3: Base Form application to syllables */
2445 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2447 HeapFree(GetProcessHeap(),0,input);
2448 HeapFree(GetProcessHeap(),0,syllables);
2451 static int telugu_lex(WCHAR c)
2456 case 0x0C44: return lex_Modifier;
2458 return unicode_lex(c);
2462 static const VowelComponents Telugu_vowels[] = {
2463 {0x0C48, {0x0C46,0x0C56,0x0000}},
2464 {0x0000, {0x0000,0x0000,0x0000}}};
2466 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2468 int cCount = cChars;
2470 IndicSyllable *syllables = NULL;
2471 int syllable_count = 0;
2472 BOOL modern = get_GSUB_Indic2(psa, psc);
2474 if (*pcGlyphs != cChars)
2476 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2480 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2481 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2483 /* Step 1: Decompose Vowels */
2484 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2485 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2487 /* Step 2: Reorder within Syllables */
2488 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2489 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2490 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2493 /* Step 3: Base Form application to syllables */
2494 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2496 HeapFree(GetProcessHeap(),0,input);
2497 HeapFree(GetProcessHeap(),0,syllables);
2500 static int kannada_lex(WCHAR c)
2504 case 0x0CB0: return lex_Ra;
2506 return unicode_lex(c);
2510 static const VowelComponents Kannada_vowels[] = {
2511 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2512 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2513 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2514 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2515 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2516 {0x0000, {0x0000,0x0000,0x0000}}};
2518 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2520 int cCount = cChars;
2522 IndicSyllable *syllables = NULL;
2523 int syllable_count = 0;
2524 BOOL modern = get_GSUB_Indic2(psa, psc);
2526 if (*pcGlyphs != cChars)
2528 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2532 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2533 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2535 /* Step 1: Decompose Vowels */
2536 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2537 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2539 /* Step 2: Reorder within Syllables */
2540 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2541 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2542 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2545 /* Step 3: Base Form application to syllables */
2546 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2548 HeapFree(GetProcessHeap(),0,input);
2549 HeapFree(GetProcessHeap(),0,syllables);
2552 static int malayalam_lex(WCHAR c)
2554 return unicode_lex(c);
2557 static const VowelComponents Malayalam_vowels[] = {
2558 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2559 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2560 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2561 {0x0000, {0x0000,0x0000,0x0000}}};
2563 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2565 int cCount = cChars;
2567 IndicSyllable *syllables = NULL;
2568 int syllable_count = 0;
2569 BOOL modern = get_GSUB_Indic2(psa, psc);
2571 if (*pcGlyphs != cChars)
2573 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2577 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2578 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2580 /* Step 1: Decompose Vowels */
2581 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2582 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2584 /* Step 2: Reorder within Syllables */
2585 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2586 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2587 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2590 /* Step 3: Base Form application to syllables */
2591 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2593 HeapFree(GetProcessHeap(),0,input);
2594 HeapFree(GetProcessHeap(),0,syllables);
2597 static int khmer_lex(WCHAR c)
2599 return unicode_lex(c);
2602 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2604 int cCount = cChars;
2606 IndicSyllable *syllables = NULL;
2607 int syllable_count = 0;
2609 if (*pcGlyphs != cChars)
2611 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2615 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2616 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2618 /* Step 1: Reorder within Syllables */
2619 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2620 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2621 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2624 /* Step 2: Base Form application to syllables */
2625 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2627 HeapFree(GetProcessHeap(),0,input);
2628 HeapFree(GetProcessHeap(),0,syllables);
2631 static inline BOOL mongolian_wordbreak(WCHAR chr)
2633 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2636 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2642 if (*pcGlyphs != cChars)
2644 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2648 if (!psa->fLogicalOrder && psa->fRTL)
2653 if (!psc->GSUB_Table)
2654 psc->GSUB_Table = load_gsub_table(hdc);
2656 if (!psc->GSUB_Table)
2659 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2661 for (i = 0; i < cChars; i++)
2663 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2665 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2666 context_shape[i] = Xn;
2668 context_shape[i] = Xl;
2672 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2673 context_shape[i] = Xr;
2675 context_shape[i] = Xm;
2679 /* Contextual Shaping */
2681 while(i < *pcGlyphs)
2684 INT prevCount = *pcGlyphs;
2685 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2686 if (nextIndex > GSUB_E_NOGLYPH)
2688 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2695 HeapFree(GetProcessHeap(),0,context_shape);
2698 static void ShapeCharGlyphProp_Default( 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)
2702 for (i = 0; i < cGlyphs; i++)
2707 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2710 for (; k < cChars && pwLogClust[k] == i; k++)
2711 char_index[char_count++] = k;
2714 if (char_count == 0)
2717 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2719 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2720 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2723 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2726 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2727 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2730 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 )
2733 int initGlyph, finaGlyph;
2737 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2738 memset(spaces,0,cGlyphs);
2740 if (!psa->fLogicalOrder && psa->fRTL)
2742 initGlyph = cGlyphs-1;
2750 finaGlyph = cGlyphs-1;
2755 for (i = 0; i < cGlyphs; i++)
2757 for (k = 0; k < cChars; k++)
2758 if (pwLogClust[k] == i)
2760 if (pwcChars[k] == 0x0020)
2765 for (i = 0; i < cGlyphs; i++)
2769 BOOL isInit, isFinal;
2771 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2774 for (; k < cChars && pwLogClust[k] == i; k++)
2775 char_index[char_count++] = k;
2778 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2779 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2781 if (char_count == 0)
2784 if (char_count == 1)
2786 if (pwcChars[char_index[0]] == 0x0020) /* space */
2788 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2789 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2791 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2792 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2793 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2795 if (!isInit && !isFinal)
2796 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2798 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2800 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2804 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2805 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2806 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2807 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2808 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2809 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2810 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2811 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2813 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2815 else if (!isInit && !isFinal)
2816 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2818 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2820 else if (char_count == 2)
2822 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2823 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2825 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2827 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2829 else if (!isInit && !isFinal)
2830 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2832 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2835 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2836 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2837 HeapFree(GetProcessHeap(),0,spaces);
2840 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 )
2844 for (i = 0; i < cGlyphs; i++)
2849 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2852 for (; k < cChars && pwLogClust[k] == i; k++)
2853 char_index[char_count++] = k;
2856 if (char_count == 0)
2857 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2860 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2861 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2862 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2866 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2867 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2870 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 )
2876 if (!psa->fLogicalOrder && psa->fRTL)
2883 finaGlyph = cGlyphs-1;
2887 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2889 for (i = 0; i < cGlyphs; i++)
2895 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2898 for (; k < cChars && pwLogClust[k] == i; k++)
2899 char_index[char_count++] = k;
2903 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2905 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2907 if (char_count == 0)
2910 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2911 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2913 /* handle Thai SARA AM (U+0E33) differently than GDEF */
2914 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
2915 pGlyphProp[i].sva.fClusterStart = 0;
2918 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2920 /* Do not allow justification between marks and their base */
2921 for (i = 0; i < cGlyphs; i++)
2923 if (!pGlyphProp[i].sva.fClusterStart)
2924 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2928 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)
2932 for (i = 0; i < cGlyphs; i++)
2937 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2940 for (; k < cChars && pwLogClust[k] == i; k++)
2941 char_index[char_count++] = k;
2944 if (char_count == 0)
2947 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2949 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2950 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2953 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2955 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2956 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2959 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)
2963 for (i = 0; i < cGlyphs; i++)
2968 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
2971 for (; k < cChars && pwLogClust[k] == i; k++)
2972 char_index[char_count++] = k;
2975 if (char_count == 0)
2978 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2980 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2981 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2984 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2986 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2987 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2989 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2990 for (i = 0; i < cGlyphs; i++)
2992 if (!pGlyphProp[i].sva.fClusterStart)
2994 pGlyphProp[i].sva.fDiacritic = 0;
2995 pGlyphProp[i].sva.fZeroWidth = 0;
3000 static void ShapeCharGlyphProp_BaseIndic( 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, lexical_function lexical, BOOL use_syllables, BOOL override_gsub)
3004 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3005 for (i = 0; i < cGlyphs; i++)
3010 k = USP10_FindGlyphInLogClust(pwLogClust, cChars, i);
3013 for (; k < cChars && pwLogClust[k] == i; k++)
3014 char_index[char_count++] = k;
3019 /* Most indic scripts do not set fDiacritic or fZeroWidth */
3020 pGlyphProp[i].sva.fDiacritic = FALSE;
3021 pGlyphProp[i].sva.fZeroWidth = FALSE;
3024 if (char_count == 0)
3026 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3030 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3032 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3033 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3036 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3038 pGlyphProp[i].sva.fClusterStart = 0;
3039 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3040 switch (lexical(pwcChars[char_index[k]]))
3043 case lex_Matra_post:
3044 case lex_Matra_above:
3045 case lex_Matra_below:
3051 /* check for dangling joiners */
3052 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
3053 pGlyphProp[i].sva.fClusterStart = 1;
3058 pGlyphProp[i].sva.fClusterStart = 1;
3065 IndicSyllable *syllables = NULL;
3066 int syllable_count = 0;
3067 BOOL modern = get_GSUB_Indic2(psa, psc);
3069 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3071 for (i = 0; i < syllable_count; i++)
3074 WORD g = pwLogClust[syllables[i].start];
3075 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3077 if (pwLogClust[j] != g)
3079 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3085 HeapFree(GetProcessHeap(), 0, syllables);
3088 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3091 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 )
3093 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
3096 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 )
3098 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
3101 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 )
3103 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
3106 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 )
3108 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
3111 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 )
3113 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
3116 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 )
3118 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
3121 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 )
3123 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
3126 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 )
3128 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
3131 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 )
3133 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
3136 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 )
3138 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
3141 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 )
3143 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
3146 void SHAPE_CharGlyphProp(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)
3148 if (ShapingData[psa->eScript].charGlyphPropProc)
3149 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3151 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3154 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3156 if (!psc->GSUB_Table)
3157 psc->GSUB_Table = load_gsub_table(hdc);
3159 if (ShapingData[psa->eScript].contextProc)
3160 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3163 static void SHAPE_ApplyOpenTypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, const TEXTRANGE_PROPERTIES *rpRangeProperties, WORD *pwLogClust)
3168 if (!rpRangeProperties)
3171 if (!psc->GSUB_Table)
3172 psc->GSUB_Table = load_gsub_table(hdc);
3174 if (!psc->GSUB_Table)
3177 if (!psa->fLogicalOrder && psa->fRTL)
3182 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3184 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3185 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3189 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3191 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3192 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3194 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3197 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3199 LoadedFeature *feature;
3202 if (!ShapingData[psa->eScript].requiredFeatures)
3205 if (!psc->GSUB_Table)
3206 psc->GSUB_Table = load_gsub_table(hdc);
3208 /* we need to have at least one of the required features */
3210 while (ShapingData[psa->eScript].requiredFeatures[i])
3212 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3218 return USP_E_SCRIPT_NOT_IN_FONT;
3221 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
3222 SCRIPT_ANALYSIS *psa, int cMaxTags,
3223 OPENTYPE_TAG *pScriptTags, int *pcTags)
3226 OPENTYPE_TAG searching = 0x00000000;
3228 if (!psc->GSUB_Table)
3229 psc->GSUB_Table = load_gsub_table(hdc);
3231 if (psa && scriptInformation[psa->eScript].scriptTag)
3232 searching = scriptInformation[psa->eScript].scriptTag;
3234 hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL);
3240 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
3241 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3242 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
3246 OPENTYPE_TAG searching = 0x00000000;
3247 BOOL fellback = FALSE;
3249 if (!psc->GSUB_Table)
3250 psc->GSUB_Table = load_gsub_table(hdc);
3252 if (psa && psc->userLang != 0)
3253 searching = psc->userLang;
3255 hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL);
3259 hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL);
3262 if (FAILED(hr) || fellback)
3264 if (SUCCEEDED(hr) && fellback && psa)
3269 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
3270 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
3271 OPENTYPE_TAG tagLangSys, int cMaxTags,
3272 OPENTYPE_TAG *pFeatureTags, int *pcTags)
3275 BOOL filter = FALSE;
3277 if (!psc->GSUB_Table)
3278 psc->GSUB_Table = load_gsub_table(hdc);
3280 if (psa && scriptInformation[psa->eScript].scriptTag)
3282 FIXME("Filtering not implemented\n");
3286 hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);