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_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
56 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
58 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
60 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
62 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);
63 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 );
64 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 );
65 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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
74 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 );
75 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 );
76 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 );
77 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 );
79 extern const unsigned short indic_syllabic_table[];
80 extern const unsigned short wine_shaping_table[];
81 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
103 typedef struct tagVowelComponents
109 typedef struct tagConsonantComponents
113 } ConsonantComponents;
115 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
117 /* the orders of joined_forms and contextual_features need to line up */
118 static const char* contextual_features[] =
130 static OPENTYPE_FEATURE_RECORD standard_features[] =
132 { MS_MAKE_TAG('c','c','m','p'), 1},
133 { MS_MAKE_TAG('l','o','c','l'), 1},
136 static OPENTYPE_FEATURE_RECORD latin_features[] =
138 { MS_MAKE_TAG('l','i','g','a'), 1},
139 { MS_MAKE_TAG('c','l','i','g'), 1},
142 static OPENTYPE_FEATURE_RECORD arabic_features[] =
144 { MS_MAKE_TAG('r','l','i','g'), 1},
145 { MS_MAKE_TAG('c','a','l','t'), 1},
146 { MS_MAKE_TAG('l','i','g','a'), 1},
147 { MS_MAKE_TAG('d','l','i','g'), 1},
148 { MS_MAKE_TAG('c','s','w','h'), 1},
149 { MS_MAKE_TAG('m','s','e','t'), 1},
152 static const char* required_arabic_features[] =
161 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
163 { MS_MAKE_TAG('d','l','i','g'), 0},
166 static OPENTYPE_FEATURE_RECORD syriac_features[] =
168 { MS_MAKE_TAG('r','l','i','g'), 1},
169 { MS_MAKE_TAG('c','a','l','t'), 1},
170 { MS_MAKE_TAG('l','i','g','a'), 1},
171 { MS_MAKE_TAG('d','l','i','g'), 1},
174 static const char* required_syriac_features[] =
186 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
188 /* Presentation forms */
189 { MS_MAKE_TAG('b','l','w','s'), 1},
190 { MS_MAKE_TAG('a','b','v','s'), 1},
191 { MS_MAKE_TAG('p','s','t','s'), 1},
194 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
196 { MS_MAKE_TAG('a','b','v','s'), 1},
197 { MS_MAKE_TAG('b','l','w','s'), 1},
200 static OPENTYPE_FEATURE_RECORD phags_features[] =
202 { MS_MAKE_TAG('a','b','v','s'), 1},
203 { MS_MAKE_TAG('b','l','w','s'), 1},
204 { MS_MAKE_TAG('c','a','l','t'), 1},
207 static OPENTYPE_FEATURE_RECORD thai_features[] =
209 { MS_MAKE_TAG('c','c','m','p'), 1},
212 static const char* required_lao_features[] =
218 static const char* required_devanagari_features[] =
234 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
236 { MS_MAKE_TAG('p','r','e','s'), 1},
237 { MS_MAKE_TAG('a','b','v','s'), 1},
238 { MS_MAKE_TAG('b','l','w','s'), 1},
239 { MS_MAKE_TAG('p','s','t','s'), 1},
240 { MS_MAKE_TAG('h','a','l','n'), 1},
241 { MS_MAKE_TAG('c','a','l','t'), 1},
244 static OPENTYPE_FEATURE_RECORD myanmar_features[] =
246 { MS_MAKE_TAG('l','i','g','a'), 1},
247 { MS_MAKE_TAG('c','l','i','g'), 1},
250 static const char* required_bengali_features[] =
267 static const char* required_gurmukhi_features[] =
286 static const char* required_oriya_features[] =
303 static const char* required_tamil_features[] =
319 static const char* required_telugu_features[] =
337 static OPENTYPE_FEATURE_RECORD khmer_features[] =
339 { MS_MAKE_TAG('p','r','e','s'), 1},
340 { MS_MAKE_TAG('b','l','w','s'), 1},
341 { MS_MAKE_TAG('a','b','v','s'), 1},
342 { MS_MAKE_TAG('p','s','t','s'), 1},
343 { MS_MAKE_TAG('c','l','i','g'), 1},
346 static const char* required_khmer_features[] =
360 static OPENTYPE_FEATURE_RECORD no_features[] =
363 static OPENTYPE_FEATURE_RECORD ethiopic_features[] =
365 { MS_MAKE_TAG('c','c','m','p'), 1},
366 { MS_MAKE_TAG('l','o','c','l'), 1},
367 { MS_MAKE_TAG('c','a','l','t'), 1},
368 { MS_MAKE_TAG('l','i','g','a'), 1},
371 static OPENTYPE_FEATURE_RECORD mongolian_features[] =
373 { MS_MAKE_TAG('c','c','m','p'), 1},
374 { MS_MAKE_TAG('l','o','c','l'), 1},
375 { MS_MAKE_TAG('c','a','l','t'), 1},
376 { MS_MAKE_TAG('r','l','i','g'), 1},
379 typedef struct ScriptShapeDataTag {
380 TEXTRANGE_PROPERTIES defaultTextRange;
381 const char** requiredFeatures;
382 OPENTYPE_TAG newOtTag;
383 ContextualShapingProc contextProc;
384 ShapeCharGlyphPropProc charGlyphPropProc;
387 /* in order of scripts */
388 static const ScriptShapeData ShapingData[] =
390 {{ standard_features, 2}, NULL, 0, NULL, NULL},
391 {{ latin_features, 2}, NULL, 0, NULL, NULL},
392 {{ latin_features, 2}, NULL, 0, NULL, NULL},
393 {{ latin_features, 2}, NULL, 0, NULL, NULL},
394 {{ standard_features, 2}, NULL, 0, NULL, NULL},
395 {{ latin_features, 2}, NULL, 0, NULL, NULL},
396 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
397 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
398 {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
399 {{ syriac_features, 4}, required_syriac_features, 0, ContextualShape_Syriac, ShapeCharGlyphProp_None},
400 {{ arabic_features, 6}, required_arabic_features, 0, ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
401 {{ NULL, 0}, NULL, 0, NULL, ShapeCharGlyphProp_None},
402 {{ standard_features, 2}, NULL, 0, NULL, NULL},
403 {{ standard_features, 2}, NULL, 0, NULL, NULL},
404 {{ standard_features, 2}, NULL, 0, NULL, NULL},
405 {{ standard_features, 2}, NULL, 0, NULL, NULL},
406 {{ sinhala_features, 3}, NULL, 0, ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
407 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
408 {{ tibetan_features, 2}, NULL, 0, NULL, ShapeCharGlyphProp_Tibet},
409 {{ phags_features, 3}, NULL, 0, ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
410 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
411 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
412 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
413 {{ thai_features, 1}, required_lao_features, 0, NULL, ShapeCharGlyphProp_Thai},
414 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
415 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('d','e','v','2'), ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
416 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
417 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
418 {{ devanagari_features, 6}, required_bengali_features, MS_MAKE_TAG('b','n','g','2'), ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
419 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
420 {{ devanagari_features, 6}, required_gurmukhi_features, MS_MAKE_TAG('g','u','r','2'), ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
421 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
422 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
423 {{ devanagari_features, 6}, required_devanagari_features, MS_MAKE_TAG('g','j','r','2'), ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
424 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
425 {{ devanagari_features, 6}, required_oriya_features, MS_MAKE_TAG('o','r','y','2'), ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
426 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
427 {{ devanagari_features, 6}, required_tamil_features, MS_MAKE_TAG('t','a','m','2'), ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
428 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
429 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('t','e','l','2'), ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
430 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
431 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('k','n','d','2'), ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
432 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
433 {{ devanagari_features, 6}, required_telugu_features, MS_MAKE_TAG('m','l','m','2'), ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
434 {{ standard_features, 2}, NULL, 0, NULL, NULL},
435 {{ latin_features, 2}, NULL, 0, NULL, NULL},
436 {{ standard_features, 2}, NULL, 0, NULL, NULL},
437 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
438 {{ myanmar_features, 2}, NULL, 0, NULL, NULL},
439 {{ standard_features, 2}, NULL, 0, NULL, NULL},
440 {{ standard_features, 2}, NULL, 0, NULL, NULL},
441 {{ standard_features, 2}, NULL, 0, NULL, NULL},
442 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
443 {{ khmer_features, 5}, required_khmer_features, 0, ContextualShape_Khmer, ShapeCharGlyphProp_Khmer},
444 {{ no_features, 0}, NULL, 0, NULL, NULL},
445 {{ no_features, 0}, NULL, 0, NULL, NULL},
446 {{ no_features, 0}, NULL, 0, NULL, NULL},
447 {{ no_features, 0}, NULL, 0, NULL, NULL},
448 {{ no_features, 0}, NULL, 0, NULL, NULL},
449 {{ no_features, 0}, NULL, 0, NULL, NULL},
450 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
451 {{ ethiopic_features, 4}, NULL, 0, NULL, NULL},
452 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
453 {{ mongolian_features, 4}, NULL, 0, ContextualShape_Mongolian, NULL},
454 {{ no_features, 0}, NULL, 0, NULL, NULL},
455 {{ no_features, 0}, NULL, 0, NULL, NULL},
456 {{ no_features, 0}, NULL, 0, NULL, NULL},
457 {{ no_features, 0}, NULL, 0, NULL, NULL},
458 {{ no_features, 0}, NULL, 0, NULL, NULL},
459 {{ no_features, 0}, NULL, 0, NULL, NULL},
460 {{ no_features, 0}, NULL, 0, NULL, NULL},
461 {{ no_features, 0}, NULL, 0, NULL, NULL},
462 {{ no_features, 0}, NULL, 0, NULL, NULL},
463 {{ no_features, 0}, NULL, 0, NULL, NULL},
464 {{ no_features, 0}, NULL, 0, NULL, NULL},
465 {{ no_features, 0}, NULL, 0, NULL, NULL},
466 {{ no_features, 0}, NULL, 0, NULL, NULL},
467 {{ no_features, 0}, NULL, 0, NULL, NULL},
468 {{ no_features, 0}, NULL, 0, NULL, NULL},
469 {{ hebrew_features, 1}, NULL, 0, NULL, NULL},
470 {{ latin_features, 2}, NULL, 0, NULL, NULL},
471 {{ thai_features, 1}, NULL, 0, NULL, ShapeCharGlyphProp_Thai},
474 extern scriptData scriptInformation[];
476 static INT GSUB_apply_feature_all_lookups(LPCVOID header, LoadedFeature *feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
479 int out_index = GSUB_E_NOGLYPH;
481 TRACE("%i lookups\n", feature->lookup_count);
482 for (i = 0; i < feature->lookup_count; i++)
484 out_index = OpenType_apply_GSUB_lookup(header, feature->lookups[i], glyphs, glyph_index, write_dir, glyph_count);
485 if (out_index != GSUB_E_NOGLYPH)
488 if (out_index == GSUB_E_NOGLYPH)
489 TRACE("lookups found no glyphs\n");
493 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
494 if (out2!=GSUB_E_NOGLYPH)
500 static OPENTYPE_TAG get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
504 if (psc->userScript != 0)
506 if (tryNew && ShapingData[psa->eScript].newOtTag != 0 && psc->userScript == scriptInformation[psa->eScript].scriptTag)
507 return ShapingData[psa->eScript].newOtTag;
509 return psc->userScript;
512 if (tryNew && ShapingData[psa->eScript].newOtTag != 0)
513 return ShapingData[psa->eScript].newOtTag;
515 if (scriptInformation[psa->eScript].scriptTag)
516 return scriptInformation[psa->eScript].scriptTag;
519 * fall back to the font charset
521 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
525 case BALTIC_CHARSET: return MS_MAKE_TAG('l','a','t','n');
526 case CHINESEBIG5_CHARSET: return MS_MAKE_TAG('h','a','n','i');
527 case EASTEUROPE_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
528 case GB2312_CHARSET: return MS_MAKE_TAG('h','a','n','i');
529 case GREEK_CHARSET: return MS_MAKE_TAG('g','r','e','k');
530 case HANGUL_CHARSET: return MS_MAKE_TAG('h','a','n','g');
531 case RUSSIAN_CHARSET: return MS_MAKE_TAG('c','y','r','l');
532 case SHIFTJIS_CHARSET: return MS_MAKE_TAG('k','a','n','a');
533 case TURKISH_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
534 case VIETNAMESE_CHARSET: return MS_MAKE_TAG('l','a','t','n');
535 case JOHAB_CHARSET: return MS_MAKE_TAG('l','a','t','n'); /* ?? */
536 case ARABIC_CHARSET: return MS_MAKE_TAG('a','r','a','b');
537 case HEBREW_CHARSET: return MS_MAKE_TAG('h','e','b','r');
538 case THAI_CHARSET: return MS_MAKE_TAG('t','h','a','i');
539 default: return MS_MAKE_TAG('l','a','t','n');
543 static LoadedFeature* load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
545 LoadedFeature *feature = NULL;
551 OPENTYPE_TAG language;
557 script = get_opentype_script(hdc,psa,psc,(attempt==2));
558 if (psc->userLang != 0)
559 language = psc->userLang;
561 language = MS_MAKE_TAG('d','f','l','t');
564 OpenType_GSUB_GetFontFeatureTags(psc, script, language, FALSE, MS_MAKE_TAG(feat[0],feat[1],feat[2],feat[3]), 1, &tags, &cTags, &feature);
566 } while(attempt && !feature);
568 /* try in the default (latin) table */
570 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);
573 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
577 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)
579 LoadedFeature *feature;
581 feature = load_GSUB_feature(hdc, psa, psc, feat);
583 return GSUB_E_NOFEATURE;
585 TRACE("applying feature %s\n",feat);
586 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
589 static VOID *load_gsub_table(HDC hdc)
591 VOID* GSUB_Table = NULL;
592 int length = GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, NULL, 0);
593 if (length != GDI_ERROR)
595 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
596 GetFontData(hdc, MS_MAKE_TAG('G', 'S', 'U', 'B'), 0, GSUB_Table, length);
597 TRACE("Loaded GSUB table of %i bytes\n",length);
602 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)
605 INT glyph_count = count;
608 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
609 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
610 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
611 if (rc > GSUB_E_NOGLYPH)
612 rc = count - glyph_count;
616 HeapFree(GetProcessHeap(),0,glyphs);
620 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
624 for (i = 0; i < cGlyphs; i++)
626 if (!pGlyphProp[i].sva.fClusterStart)
629 for (j = 0; j < cChars; j++)
631 if (pwLogClust[j] == i)
634 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
636 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
637 pwLogClust[j] = pwLogClust[k];
644 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
646 if (changeCount == 0)
651 int target_glyph = nextIndex - write_dir;
653 int target_index = -1;
654 int replacing_glyph = -1;
656 int top_logclust = 0;
661 target_glyph = nextIndex - changeCount;
663 target_glyph = nextIndex + (changeCount + 1);
666 seeking_glyph = target_glyph;
667 for (i = 0; i < chars; i++)
668 if (pwLogClust[i] > top_logclust)
669 top_logclust = pwLogClust[i];
673 for (i = 0; i < chars; i++)
675 if (pwLogClust[i] == seeking_glyph)
682 for (i = chars - 1; i >= 0; i--)
684 if (pwLogClust[i] == seeking_glyph)
690 if (target_index == -1)
693 while (target_index == -1 && seeking_glyph <= top_logclust);
695 if (target_index == -1)
697 ERR("Unable to find target glyph\n");
704 for(i = target_index; i < chars && i >= 0; i+=write_dir)
706 if (pwLogClust[i] == target_glyph)
708 if(pwLogClust[i] == replacing_glyph)
709 pwLogClust[i] = target_glyph;
713 if (changed >= changeCount)
715 replacing_glyph = pwLogClust[i];
716 pwLogClust[i] = target_glyph;
723 /* renumber trailing indexes*/
724 for(i = target_index; i < chars && i >= 0; i+=write_dir)
726 if (pwLogClust[i] != target_glyph)
727 pwLogClust[i] += changeCount;
732 for(i = target_index; i < chars && i >= 0; i+=write_dir)
733 pwLogClust[i] += changeCount;
738 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 )
742 LoadedFeature *feature;
745 feature = load_GSUB_feature(hdc, psa, psc, feat);
747 return GSUB_E_NOFEATURE;
749 TRACE("applying feature %s: %i lookups\n",debugstr_an(feat,4),feature->lookup_count);
750 for (lookup_index = 0; lookup_index < feature->lookup_count; lookup_index++)
758 TRACE("applying lookup (%i/%i)\n",lookup_index,feature->lookup_count);
759 while(i < *pcGlyphs && i >= 0)
762 INT prevCount = *pcGlyphs;
764 nextIndex = OpenType_apply_GSUB_lookup(psc->GSUB_Table, feature->lookups[lookup_index], pwOutGlyphs, i, write_dir, pcGlyphs);
765 if (*pcGlyphs != prevCount)
767 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
776 return GSUB_E_NOFEATURE;
779 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
785 hr = OpenType_GSUB_GetFontScriptTags(psc, ShapingData[psa->eScript].newOtTag, 1, &tag, &count, NULL);
787 return(SUCCEEDED(hr));
790 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
794 if ( i+ delta >= cchLen)
802 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
806 if (psa->fLinkBefore)
811 if ( i+ delta >= cchLen)
821 if (context_type[i] == jtT)
822 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
824 return context_type[i];
827 static inline BOOL right_join_causing(CHAR joining_type)
829 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
832 static inline BOOL left_join_causing(CHAR joining_type)
834 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
837 static inline BOOL word_break_causing(WCHAR chr)
839 /* we are working within a string of characters already guareented to
840 be within one script, Syriac, so we do not worry about any character
841 other than the space character outside of that range */
842 return (chr == 0 || chr == 0x20 );
846 * ContextualShape_Arabic
848 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
855 if (*pcGlyphs != cChars)
857 ERR("Number of Glyphs and Chars need to match at the beginning\n");
861 if (!psa->fLogicalOrder && psa->fRTL)
872 if (!psc->GSUB_Table)
873 psc->GSUB_Table = load_gsub_table(hdc);
875 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
876 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
878 for (i = 0; i < cChars; i++)
879 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
881 for (i = 0; i < cChars; i++)
883 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
884 context_shape[i] = Xr;
885 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
886 context_shape[i] = Xl;
887 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)))
888 context_shape[i] = Xm;
889 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
890 context_shape[i] = Xr;
891 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
892 context_shape[i] = Xl;
894 context_shape[i] = Xn;
897 /* Contextual Shaping */
906 INT prevCount = *pcGlyphs;
907 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
908 if (nextIndex > GSUB_E_NOGLYPH)
911 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
913 shaped = (nextIndex > GSUB_E_NOGLYPH);
918 if (context_shape[i] == Xn)
920 WORD newGlyph = pwOutGlyphs[i];
921 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
923 /* fall back to presentation form B */
924 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
925 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
926 pwOutGlyphs[i] = newGlyph;
933 HeapFree(GetProcessHeap(),0,context_shape);
934 HeapFree(GetProcessHeap(),0,context_type);
938 * ContextualShape_Syriac
945 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
952 if (*pcGlyphs != cChars)
954 ERR("Number of Glyphs and Chars need to match at the beginning\n");
958 if (!psa->fLogicalOrder && psa->fRTL)
969 if (!psc->GSUB_Table)
970 psc->GSUB_Table = load_gsub_table(hdc);
972 if (!psc->GSUB_Table)
975 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
976 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
978 for (i = 0; i < cChars; i++)
979 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
981 for (i = 0; i < cChars; i++)
983 if (pwcChars[i] == ALAPH)
985 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
987 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
988 context_shape[i] = Afj;
989 else if ( rchar != DALATH && rchar != RISH &&
990 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
991 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
992 context_shape[i] = Afn;
993 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
994 context_shape[i] = Afx;
996 context_shape[i] = Xn;
998 else if (context_type[i] == jtR &&
999 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1000 context_shape[i] = Xr;
1001 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1002 context_shape[i] = Xl;
1003 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)))
1004 context_shape[i] = Xm;
1005 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1006 context_shape[i] = Xr;
1007 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1008 context_shape[i] = Xl;
1010 context_shape[i] = Xn;
1013 /* Contextual Shaping */
1015 while(i < *pcGlyphs)
1018 INT prevCount = *pcGlyphs;
1019 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1020 if (nextIndex > GSUB_E_NOGLYPH)
1022 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1029 HeapFree(GetProcessHeap(),0,context_shape);
1030 HeapFree(GetProcessHeap(),0,context_type);
1034 * ContextualShape_Phags_pa
1037 #define phags_pa_CANDRABINDU 0xA873
1038 #define phags_pa_START 0xA840
1039 #define phags_pa_END 0xA87F
1041 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1047 if (*pcGlyphs != cChars)
1049 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1053 if (!psa->fLogicalOrder && psa->fRTL)
1064 if (!psc->GSUB_Table)
1065 psc->GSUB_Table = load_gsub_table(hdc);
1067 if (!psc->GSUB_Table)
1070 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1072 for (i = 0; i < cChars; i++)
1074 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1076 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1077 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1078 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1079 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1081 if (jrchar && jlchar)
1082 context_shape[i] = Xm;
1084 context_shape[i] = Xr;
1086 context_shape[i] = Xl;
1088 context_shape[i] = Xn;
1091 context_shape[i] = -1;
1094 /* Contextual Shaping */
1096 while(i < *pcGlyphs)
1098 if (context_shape[i] >= 0)
1101 INT prevCount = *pcGlyphs;
1102 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1103 if (nextIndex > GSUB_E_NOGLYPH)
1105 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1115 HeapFree(GetProcessHeap(),0,context_shape);
1118 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1123 pwOutChars[cWalk] = replacements[0];
1127 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1130 for (j = *pcChars; j > cWalk; j--)
1131 pwOutChars[j] = pwOutChars[j-1];
1132 *pcChars= *pcChars+1;
1133 pwOutChars[cWalk] = replacements[i];
1138 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1143 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1145 for (i = 0; vowels[i].base != 0x0; i++)
1147 if (pwOutChars[cWalk] == vowels[i].base)
1150 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1151 if (vowels[i].parts[1]) { cWalk++; o++; }
1152 if (vowels[i].parts[2]) { cWalk++; o++; }
1153 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1160 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1166 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1168 for (i = 0; consonants[i].output!= 0x0; i++)
1171 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1172 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1175 if (consonants[i].parts[j]==0x0) /* matched all */
1179 pwOutChars[cWalk] = consonants[i].output;
1180 for(k = cWalk+1; k < *pcChars - j; k++)
1181 pwOutChars[k] = pwOutChars[k+j];
1182 *pcChars = *pcChars - j;
1183 for (k = j ; k > 0; k--)
1184 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1186 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1195 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1200 WORD Ra = pwChar[s->start];
1201 WORD H = pwChar[s->start+1];
1203 TRACE("Doing reorder of Ra to %i\n",s->base);
1204 for (j = s->start; j < s->base-1; j++)
1205 pwChar[j] = pwChar[j+2];
1206 pwChar[s->base-1] = Ra;
1207 pwChar[s->base] = H;
1209 s->ralf = s->base-1;
1214 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1219 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1220 WORD Ra = pwChar[s->start];
1221 WORD H = pwChar[s->start+1];
1222 for (loc = s->end; loc > stop; loc--)
1223 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1226 TRACE("Doing reorder of Ra to %i\n",loc);
1227 for (j = s->start; j < loc-1; j++)
1228 pwChar[j] = pwChar[j+2];
1234 if (s->blwf >= 0) s->blwf -= 2;
1235 if (s->pref >= 0) s->pref -= 2;
1239 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1244 WORD Ra = pwChar[s->start];
1245 WORD H = pwChar[s->start+1];
1247 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1248 for (j = s->start; j < s->end-1; j++)
1249 pwChar[j] = pwChar[j+2];
1250 pwChar[s->end-1] = Ra;
1255 if (s->blwf >= 0) s->blwf -= 2;
1256 if (s->pref >= 0) s->pref -= 2;
1260 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1264 /* reorder Matras */
1265 if (s->end > s->base)
1267 for (i = 1; i <= s->end-s->base; i++)
1269 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1272 WCHAR c = pwChar[s->base+i];
1273 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1274 for (j = s->base+i; j > s->base; j--)
1275 pwChar[j] = pwChar[j-1];
1276 pwChar[s->base] = c;
1278 if (s->ralf >= s->base) s->ralf++;
1279 if (s->blwf >= s->base) s->blwf++;
1280 if (s->pref >= s->base) s->pref++;
1287 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1291 /* reorder Matras */
1292 if (s->end > s->base)
1294 for (i = 1; i <= s->end-s->base; i++)
1296 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1299 WCHAR c = pwChar[s->base+i];
1300 TRACE("Doing reorder of %x to %i\n",c,s->start);
1301 for (j = s->base+i; j > s->start; j--)
1302 pwChar[j] = pwChar[j-1];
1303 pwChar[s->start] = c;
1305 if (s->ralf >= 0) s->ralf++;
1306 if (s->blwf >= 0) s->blwf++;
1307 if (s->pref >= 0) s->pref++;
1314 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1316 if (s->blwf >= 0 && g->blwf > g->base)
1320 for (loc = s->end; loc > s->blwf; loc--)
1321 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
1324 g_offset = (loc - s->blwf) - 1;
1328 WORD blwf = glyphs[g->blwf];
1329 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
1330 /* do not care about the pwChar array anymore, just the glyphs */
1331 for (j = 0; j < g_offset; j++)
1332 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
1333 glyphs[g->blwf + g_offset] = blwf;
1338 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1342 /* reorder previously moved Matras to correct position*/
1343 for (i = s->start; i < s->base; i++)
1345 if (lexical(pwChar[i]) == lex_Matra_pre)
1348 int g_start = g->start + i - s->start;
1349 if (g_start < g->base -1 )
1351 WCHAR og = glyphs[g_start];
1352 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
1353 for (j = g_start; j < g->base-1; j++)
1354 glyphs[j] = glyphs[j+1];
1355 glyphs[g->base-1] = og;
1361 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
1363 if (s->pref >= 0 && g->pref > g->base)
1366 WCHAR og = glyphs[g->pref];
1367 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
1368 for (j = g->pref; j > g->base; j--)
1369 glyphs[j] = glyphs[j-1];
1370 glyphs[g->base] = og;
1374 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1376 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1377 if (s->start == s->base && s->base == s->end) return;
1378 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1380 Reorder_Ra_follows_base(pwChar, s, lexical);
1381 Reorder_Matra_precede_base(pwChar, s, lexical);
1384 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1386 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1387 if (s->start == s->base && s->base == s->end) return;
1388 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1390 Reorder_Ra_follows_matra(pwChar, s, lexical);
1391 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1394 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1396 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1397 if (s->start == s->base && s->base == s->end) return;
1398 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1400 Reorder_Ra_follows_base(pwChar, s, lexical);
1401 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1404 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1406 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1407 if (s->start == s->base && s->base == s->end) return;
1408 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1410 Reorder_Ra_follows_syllable(pwChar, s, lexical);
1411 Reorder_Matra_precede_syllable(pwChar, s, lexical);
1414 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1416 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1417 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1418 if (s->start == s->base && s->base == s->end) return;
1419 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1421 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
1424 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
1426 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
1427 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
1428 if (s->start == s->base && s->base == s->end) return;
1429 if (lexical(pwChar[s->base]) == lex_Vowel) return;
1431 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
1432 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
1436 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
1441 if (glyph_index->start > index)
1442 glyph_index->start += shift;
1443 if (glyph_index->base > index)
1444 glyph_index->base+= shift;
1445 if (glyph_index->end > index)
1446 glyph_index->end+= shift;
1447 if (glyph_index->ralf > index)
1448 glyph_index->ralf+= shift;
1449 if (glyph_index->blwf > index)
1450 glyph_index->blwf+= shift;
1451 if (glyph_index->pref > index)
1452 glyph_index->pref+= shift;
1455 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 )
1457 int index = glyph_index->start;
1462 while(index <= glyph_index->end)
1465 INT prevCount = *pcGlyphs;
1466 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
1467 if (nextIndex > GSUB_E_NOGLYPH)
1469 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1470 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
1478 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1481 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)))))
1483 if (index + i <= end-1)
1489 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)
1491 INT index, nextIndex;
1494 count = syllable->base - syllable->start;
1497 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
1498 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
1500 INT prevCount = *pcGlyphs;
1501 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
1502 if (nextIndex > GSUB_E_NOGLYPH)
1504 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1505 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
1506 g_offset += (*pcGlyphs - prevCount);
1510 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
1514 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)
1517 INT prevCount = *pcGlyphs;
1519 if (syllable->ralf >= 0)
1521 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
1522 if (nextIndex > GSUB_E_NOGLYPH)
1524 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1525 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
1530 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
1533 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
1534 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
1535 is_consonant(lexical(pwChars[index+i+1])))))
1537 if (index + i <= end-1)
1543 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)
1545 INT index, nextIndex;
1546 INT count, g_offset=0;
1547 INT ralf = syllable->ralf;
1549 count = syllable->end - syllable->base;
1551 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
1555 INT prevCount = *pcGlyphs;
1556 if (ralf >=0 && ralf < index)
1564 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1565 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1566 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1569 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
1570 if (nextIndex > GSUB_E_NOGLYPH)
1572 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
1573 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
1574 g_offset += (*pcGlyphs - prevCount);
1578 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
1579 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
1580 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
1584 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
1588 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)
1591 int overall_shift = 0;
1592 LoadedFeature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
1593 LoadedFeature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
1594 LoadedFeature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
1595 LoadedFeature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
1596 LoadedFeature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
1597 LoadedFeature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
1598 LoadedFeature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
1599 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
1600 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
1601 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
1602 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
1603 IndicSyllable glyph_indexs;
1605 for (c = 0; c < syllable_count; c++)
1608 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
1609 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
1610 old_end = glyph_indexs.end;
1614 TRACE("applying feature locl\n");
1615 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
1619 TRACE("applying feature nukt\n");
1620 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
1624 TRACE("applying feature akhn\n");
1625 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
1629 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
1632 TRACE("applying feature rkrf\n");
1633 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
1636 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
1640 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
1642 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
1646 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
1649 TRACE("applying feature pstf\n");
1650 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
1654 TRACE("applying feature vatu\n");
1655 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
1659 TRACE("applying feature cjct\n");
1660 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
1664 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
1666 overall_shift += glyph_indexs.end - old_end;
1670 static inline int unicode_lex(WCHAR c)
1674 if (!c) return lex_Generic;
1675 if (c == 0x200D) return lex_ZWJ;
1676 if (c == 0x200C) return lex_ZWNJ;
1677 if (c == 0x00A0) return lex_NBSP;
1679 type = get_table_entry( indic_syllabic_table, c );
1681 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
1685 case 0x0d07: /* Unknown */
1686 case 0x0e07: /* Unknwon */
1687 default: return lex_Generic;
1693 case 0x0014: return lex_Modifier;
1701 case 0x0010: return lex_Consonant;
1702 case 0x0004: return lex_Nukta;
1703 case 0x0005: return lex_Halant;
1705 case 0x0008: return lex_Vowel;
1707 case 0x0107: return lex_Matra_post;
1709 case 0x0307: return lex_Matra_pre;
1715 case 0x0407: return lex_Composed_Vowel;
1716 case 0x0507: return lex_Matra_above;
1717 case 0x0607: return lex_Matra_below;
1718 case 0x000c: return lex_Ra;
1722 static int sinhala_lex(WCHAR c)
1729 case 0x0DDE: return lex_Matra_post;
1731 return unicode_lex(c);
1735 static const VowelComponents Sinhala_vowels[] = {
1736 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
1737 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
1738 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
1739 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
1740 {0x0000, {0x0000,0x0000,0x0}}};
1742 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1744 int cCount = cChars;
1747 IndicSyllable *syllables = NULL;
1748 int syllable_count = 0;
1750 if (*pcGlyphs != cChars)
1752 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1756 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
1758 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1760 /* Step 1: Decompose multi part vowels */
1761 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
1763 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1765 /* Step 2: Reorder within Syllables */
1766 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
1767 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1769 /* Step 3: Strip dangling joiners */
1770 for (i = 0; i < cCount; i++)
1772 if ((input[i] == 0x200D || input[i] == 0x200C) &&
1773 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
1777 /* Step 4: Base Form application to syllables */
1778 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1780 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
1782 HeapFree(GetProcessHeap(),0,input);
1783 HeapFree(GetProcessHeap(),0,syllables);
1786 static int devanagari_lex(WCHAR c)
1790 case 0x0930: return lex_Ra;
1792 return unicode_lex(c);
1796 static const ConsonantComponents Devanagari_consonants[] ={
1797 {{0x0928, 0x093C, 0x00000}, 0x0929},
1798 {{0x0930, 0x093C, 0x00000}, 0x0931},
1799 {{0x0933, 0x093C, 0x00000}, 0x0934},
1800 {{0x0915, 0x093C, 0x00000}, 0x0958},
1801 {{0x0916, 0x093C, 0x00000}, 0x0959},
1802 {{0x0917, 0x093C, 0x00000}, 0x095A},
1803 {{0x091C, 0x093C, 0x00000}, 0x095B},
1804 {{0x0921, 0x093C, 0x00000}, 0x095C},
1805 {{0x0922, 0x093C, 0x00000}, 0x095D},
1806 {{0x092B, 0x093C, 0x00000}, 0x095E},
1807 {{0x092F, 0x093C, 0x00000}, 0x095F}};
1809 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1811 int cCount = cChars;
1813 IndicSyllable *syllables = NULL;
1814 int syllable_count = 0;
1815 BOOL modern = get_GSUB_Indic2(psa, psc);
1817 if (*pcGlyphs != cChars)
1819 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1823 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1824 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1826 /* Step 1: Compose Consonant and Nukta */
1827 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
1828 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1830 /* Step 2: Reorder within Syllables */
1831 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
1832 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1833 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1836 /* Step 3: Base Form application to syllables */
1837 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
1839 HeapFree(GetProcessHeap(),0,input);
1840 HeapFree(GetProcessHeap(),0,syllables);
1843 static int bengali_lex(WCHAR c)
1847 case 0x09B0: return lex_Ra;
1849 return unicode_lex(c);
1853 static const VowelComponents Bengali_vowels[] = {
1854 {0x09CB, {0x09C7,0x09BE,0x0000}},
1855 {0x09CC, {0x09C7,0x09D7,0x0000}},
1856 {0x0000, {0x0000,0x0000,0x0000}}};
1858 static const ConsonantComponents Bengali_consonants[] = {
1859 {{0x09A4,0x09CD,0x200D}, 0x09CE},
1860 {{0x09A1,0x09BC,0x0000}, 0x09DC},
1861 {{0x09A2,0x09BC,0x0000}, 0x09DD},
1862 {{0x09AF,0x09BC,0x0000}, 0x09DF},
1863 {{0x0000,0x0000,0x0000}, 0x0000}};
1865 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1867 int cCount = cChars;
1869 IndicSyllable *syllables = NULL;
1870 int syllable_count = 0;
1871 BOOL modern = get_GSUB_Indic2(psa, psc);
1873 if (*pcGlyphs != cChars)
1875 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1879 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
1880 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1882 /* Step 1: Decompose Vowels and Compose Consonents */
1883 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
1884 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
1885 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1887 /* Step 2: Reorder within Syllables */
1888 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
1889 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1890 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1893 /* Step 3: Initial form is only applied to the beginning of words */
1894 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
1896 if (cCount == 0 || input[cCount] == 0x0020) /* space */
1900 if (index > 0) index++;
1902 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
1906 /* Step 4: Base Form application to syllables */
1907 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
1909 HeapFree(GetProcessHeap(),0,input);
1910 HeapFree(GetProcessHeap(),0,syllables);
1913 static int gurmukhi_lex(WCHAR c)
1916 return lex_Modifier;
1918 return unicode_lex(c);
1921 static const ConsonantComponents Gurmukhi_consonants[] = {
1922 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
1923 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
1924 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
1925 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
1926 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
1927 {{0x0000,0x0000,0x0000}, 0x0000}};
1929 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1931 int cCount = cChars;
1933 IndicSyllable *syllables = NULL;
1934 int syllable_count = 0;
1935 BOOL modern = get_GSUB_Indic2(psa, psc);
1937 if (*pcGlyphs != cChars)
1939 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1943 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1944 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1946 /* Step 1: Compose Consonents */
1947 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
1948 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1950 /* Step 2: Reorder within Syllables */
1951 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
1952 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1953 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1956 /* Step 3: Base Form application to syllables */
1957 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
1959 HeapFree(GetProcessHeap(),0,input);
1960 HeapFree(GetProcessHeap(),0,syllables);
1963 static int gujarati_lex(WCHAR c)
1967 case 0x0AB0: return lex_Ra;
1969 return unicode_lex(c);
1973 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1975 int cCount = cChars;
1977 IndicSyllable *syllables = NULL;
1978 int syllable_count = 0;
1979 BOOL modern = get_GSUB_Indic2(psa, psc);
1981 if (*pcGlyphs != cChars)
1983 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1987 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1988 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1990 /* Step 1: Reorder within Syllables */
1991 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
1992 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1993 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1996 /* Step 2: Base Form application to syllables */
1997 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
1999 HeapFree(GetProcessHeap(),0,input);
2000 HeapFree(GetProcessHeap(),0,syllables);
2003 static int oriya_lex(WCHAR c)
2007 case 0x0B30: return lex_Ra;
2009 return unicode_lex(c);
2013 static const VowelComponents Oriya_vowels[] = {
2014 {0x0B48, {0x0B47,0x0B56,0x0000}},
2015 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2016 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2017 {0x0000, {0x0000,0x0000,0x0000}}};
2019 static const ConsonantComponents Oriya_consonants[] = {
2020 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2021 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2022 {{0x0000,0x0000,0x0000}, 0x0000}};
2024 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2026 int cCount = cChars;
2028 IndicSyllable *syllables = NULL;
2029 int syllable_count = 0;
2030 BOOL modern = get_GSUB_Indic2(psa, psc);
2032 if (*pcGlyphs != cChars)
2034 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2038 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2039 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2041 /* Step 1: Decompose Vowels and Compose Consonents */
2042 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2043 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2044 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2046 /* Step 2: Reorder within Syllables */
2047 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2048 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2049 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2052 /* Step 3: Base Form application to syllables */
2053 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2055 HeapFree(GetProcessHeap(),0,input);
2056 HeapFree(GetProcessHeap(),0,syllables);
2059 static int tamil_lex(WCHAR c)
2061 return unicode_lex(c);
2064 static const VowelComponents Tamil_vowels[] = {
2065 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2066 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2067 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2068 {0x0000, {0x0000,0x0000,0x0000}}};
2070 static const ConsonantComponents Tamil_consonants[] = {
2071 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2072 {{0x0000,0x0000,0x0000}, 0x0000}};
2074 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2076 int cCount = cChars;
2078 IndicSyllable *syllables = NULL;
2079 int syllable_count = 0;
2080 BOOL modern = get_GSUB_Indic2(psa, psc);
2082 if (*pcGlyphs != cChars)
2084 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2088 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2089 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2091 /* Step 1: Decompose Vowels and Compose Consonents */
2092 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2093 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2094 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2096 /* Step 2: Reorder within Syllables */
2097 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2098 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2099 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2102 /* Step 3: Base Form application to syllables */
2103 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2105 HeapFree(GetProcessHeap(),0,input);
2106 HeapFree(GetProcessHeap(),0,syllables);
2109 static int telugu_lex(WCHAR c)
2114 case 0x0C44: return lex_Modifier;
2116 return unicode_lex(c);
2120 static const VowelComponents Telugu_vowels[] = {
2121 {0x0C48, {0x0C46,0x0C56,0x0000}},
2122 {0x0000, {0x0000,0x0000,0x0000}}};
2124 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2126 int cCount = cChars;
2128 IndicSyllable *syllables = NULL;
2129 int syllable_count = 0;
2130 BOOL modern = get_GSUB_Indic2(psa, psc);
2132 if (*pcGlyphs != cChars)
2134 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2138 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2139 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2141 /* Step 1: Decompose Vowels */
2142 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2143 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2145 /* Step 2: Reorder within Syllables */
2146 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2147 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2148 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2151 /* Step 3: Base Form application to syllables */
2152 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2154 HeapFree(GetProcessHeap(),0,input);
2155 HeapFree(GetProcessHeap(),0,syllables);
2158 static int kannada_lex(WCHAR c)
2162 case 0x0CB0: return lex_Ra;
2164 return unicode_lex(c);
2168 static const VowelComponents Kannada_vowels[] = {
2169 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2170 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2171 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2172 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2173 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2174 {0x0000, {0x0000,0x0000,0x0000}}};
2176 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2178 int cCount = cChars;
2180 IndicSyllable *syllables = NULL;
2181 int syllable_count = 0;
2182 BOOL modern = get_GSUB_Indic2(psa, psc);
2184 if (*pcGlyphs != cChars)
2186 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2190 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2191 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2193 /* Step 1: Decompose Vowels */
2194 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2195 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2197 /* Step 2: Reorder within Syllables */
2198 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2199 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2200 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2203 /* Step 3: Base Form application to syllables */
2204 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2206 HeapFree(GetProcessHeap(),0,input);
2207 HeapFree(GetProcessHeap(),0,syllables);
2210 static int malayalam_lex(WCHAR c)
2212 return unicode_lex(c);
2215 static const VowelComponents Malayalam_vowels[] = {
2216 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2217 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2218 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2219 {0x0000, {0x0000,0x0000,0x0000}}};
2221 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2223 int cCount = cChars;
2225 IndicSyllable *syllables = NULL;
2226 int syllable_count = 0;
2227 BOOL modern = get_GSUB_Indic2(psa, psc);
2229 if (*pcGlyphs != cChars)
2231 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2235 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2236 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2238 /* Step 1: Decompose Vowels */
2239 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2240 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2242 /* Step 2: Reorder within Syllables */
2243 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2244 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2245 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2248 /* Step 3: Base Form application to syllables */
2249 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2251 HeapFree(GetProcessHeap(),0,input);
2252 HeapFree(GetProcessHeap(),0,syllables);
2255 static int khmer_lex(WCHAR c)
2257 return unicode_lex(c);
2260 static void ContextualShape_Khmer(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2262 int cCount = cChars;
2264 IndicSyllable *syllables = NULL;
2265 int syllable_count = 0;
2267 if (*pcGlyphs != cChars)
2269 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2273 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2274 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2276 /* Step 1: Reorder within Syllables */
2277 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, khmer_lex, Reorder_Like_Devanagari, FALSE);
2278 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2279 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2282 /* Step 2: Base Form application to syllables */
2283 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, khmer_lex, NULL, FALSE);
2285 HeapFree(GetProcessHeap(),0,input);
2286 HeapFree(GetProcessHeap(),0,syllables);
2289 static inline BOOL mongolian_wordbreak(WCHAR chr)
2291 return ((chr == 0x0020) || (chr == 0x200C) || (chr == 0x202F) || (chr == 0x180E) || (chr == 0x1800) || (chr == 0x1802) || (chr == 0x1803) || (chr == 0x1805) || (chr == 0x1808) || (chr == 0x1809) || (chr == 0x1807));
2294 static void ContextualShape_Mongolian(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2300 if (*pcGlyphs != cChars)
2302 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2306 if (!psa->fLogicalOrder && psa->fRTL)
2311 if (!psc->GSUB_Table)
2312 psc->GSUB_Table = load_gsub_table(hdc);
2314 if (!psc->GSUB_Table)
2317 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
2319 for (i = 0; i < cChars; i++)
2321 if (i == 0 || mongolian_wordbreak(pwcChars[i-1]))
2323 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2324 context_shape[i] = Xn;
2326 context_shape[i] = Xl;
2330 if ((i == cChars-1) || mongolian_wordbreak(pwcChars[i+1]))
2331 context_shape[i] = Xr;
2333 context_shape[i] = Xm;
2337 /* Contextual Shaping */
2339 while(i < *pcGlyphs)
2342 INT prevCount = *pcGlyphs;
2343 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
2344 if (nextIndex > GSUB_E_NOGLYPH)
2346 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
2353 HeapFree(GetProcessHeap(),0,context_shape);
2356 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)
2360 for (i = 0; i < cGlyphs; i++)
2365 for (k = 0; k < cChars; k++)
2367 if (pwLogClust[k] == i)
2369 char_index[char_count] = k;
2374 if (char_count == 0)
2377 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2379 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2380 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2383 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2386 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2387 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2390 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 )
2393 int initGlyph, finaGlyph;
2397 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2398 memset(spaces,0,cGlyphs);
2400 if (!psa->fLogicalOrder && psa->fRTL)
2402 initGlyph = cGlyphs-1;
2410 finaGlyph = cGlyphs-1;
2415 for (i = 0; i < cGlyphs; i++)
2417 for (k = 0; k < cChars; k++)
2418 if (pwLogClust[k] == i)
2420 if (pwcChars[k] == 0x0020)
2425 for (i = 0; i < cGlyphs; i++)
2429 BOOL isInit, isFinal;
2431 for (k = 0; k < cChars; k++)
2433 if (pwLogClust[k] == i)
2435 char_index[char_count] = k;
2440 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
2441 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
2443 if (char_count == 0)
2446 if (char_count == 1)
2448 if (pwcChars[char_index[0]] == 0x0020) /* space */
2450 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
2451 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2453 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
2454 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
2455 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
2457 if (!isInit && !isFinal)
2458 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
2460 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
2462 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2466 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
2467 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
2468 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
2469 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
2470 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
2471 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
2472 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
2473 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
2475 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2477 else if (!isInit && !isFinal)
2478 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2480 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2482 else if (char_count == 2)
2484 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
2485 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
2487 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2489 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2491 else if (!isInit && !isFinal)
2492 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2494 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2497 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2498 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2499 HeapFree(GetProcessHeap(),0,spaces);
2502 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 )
2509 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2510 memset(spaces,0,cGlyphs);
2512 if (!psa->fLogicalOrder && psa->fRTL)
2519 finaGlyph = cGlyphs-1;
2523 for (i = 0; i < cGlyphs; i++)
2525 for (k = 0; k < cChars; k++)
2526 if (pwLogClust[k] == i)
2528 if (pwcChars[k] == 0x0020)
2533 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2535 for (i = 0; i < cGlyphs; i++)
2540 for (k = 0; k < cChars; k++)
2542 if (pwLogClust[k] == i)
2544 char_index[char_count] = k;
2549 if (char_count == 0)
2552 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2554 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2555 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2557 else if (i == finaGlyph)
2558 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2560 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2562 /* handle Thai SARA AM (U+0E33) differently than GDEF */
2563 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
2564 pGlyphProp[i].sva.fClusterStart = 0;
2567 HeapFree(GetProcessHeap(),0,spaces);
2568 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2570 /* Do not allow justification between marks and their base */
2571 for (i = 0; i < cGlyphs; i++)
2573 if (!pGlyphProp[i].sva.fClusterStart)
2574 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2578 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)
2582 for (i = 0; i < cGlyphs; i++)
2587 for (k = 0; k < cChars; k++)
2589 if (pwLogClust[k] == i)
2591 char_index[char_count] = k;
2596 if (char_count == 0)
2599 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2601 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2602 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2605 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2607 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2608 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2611 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)
2615 for (i = 0; i < cGlyphs; i++)
2620 for (k = 0; k < cChars; k++)
2622 if (pwLogClust[k] == i)
2624 char_index[char_count] = k;
2629 if (char_count == 0)
2632 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2634 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2635 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2638 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2640 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2641 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2643 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2644 for (i = 0; i < cGlyphs; i++)
2646 if (!pGlyphProp[i].sva.fClusterStart)
2648 pGlyphProp[i].sva.fDiacritic = 0;
2649 pGlyphProp[i].sva.fZeroWidth = 0;
2654 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)
2658 OpenType_GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2659 for (i = 0; i < cGlyphs; i++)
2664 for (k = 0; k < cChars; k++)
2666 if (pwLogClust[k] == i)
2668 char_index[char_count] = k;
2675 /* Most indic scripts do not set fDiacritic or fZeroWidth */
2676 pGlyphProp[i].sva.fDiacritic = FALSE;
2677 pGlyphProp[i].sva.fZeroWidth = FALSE;
2680 if (char_count == 0)
2683 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2685 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2686 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2689 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2691 pGlyphProp[i].sva.fClusterStart = 0;
2692 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2693 switch (lexical(pwcChars[char_index[k]]))
2696 case lex_Matra_post:
2697 case lex_Matra_above:
2698 case lex_Matra_below:
2704 /* check for dangling joiners */
2705 if (pwcChars[char_index[k]-1] == 0x0020 || pwcChars[char_index[k]+1] == 0x0020)
2706 pGlyphProp[i].sva.fClusterStart = 1;
2711 pGlyphProp[i].sva.fClusterStart = 1;
2718 IndicSyllable *syllables = NULL;
2719 int syllable_count = 0;
2720 BOOL modern = get_GSUB_Indic2(psa, psc);
2722 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
2724 for (i = 0; i < syllable_count; i++)
2727 WORD g = pwLogClust[syllables[i].start];
2728 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
2730 if (pwLogClust[j] != g)
2732 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
2738 HeapFree(GetProcessHeap(), 0, syllables);
2741 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2744 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 )
2746 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE, FALSE);
2749 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 )
2751 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE, TRUE);
2754 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 )
2756 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE, TRUE);
2759 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 )
2761 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE, TRUE);
2764 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 )
2766 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE, TRUE);
2769 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 )
2771 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE, TRUE);
2774 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 )
2776 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE, TRUE);
2779 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 )
2781 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE, TRUE);
2784 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 )
2786 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE, TRUE);
2789 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 )
2791 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE, TRUE);
2794 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 )
2796 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, khmer_lex, TRUE, TRUE);
2799 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)
2801 if (ShapingData[psa->eScript].charGlyphPropProc)
2802 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2804 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2807 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2809 if (!psc->GSUB_Table)
2810 psc->GSUB_Table = load_gsub_table(hdc);
2812 if (ShapingData[psa->eScript].contextProc)
2813 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2816 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)
2821 if (!rpRangeProperties)
2824 if (!psc->GSUB_Table)
2825 psc->GSUB_Table = load_gsub_table(hdc);
2827 if (!psc->GSUB_Table)
2830 if (!psa->fLogicalOrder && psa->fRTL)
2835 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
2837 if (rpRangeProperties->potfRecords[i].lParameter > 0)
2838 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
2842 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
2844 const TEXTRANGE_PROPERTIES *rpRangeProperties;
2845 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
2847 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
2850 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
2852 LoadedFeature *feature;
2855 if (!ShapingData[psa->eScript].requiredFeatures)
2858 if (!psc->GSUB_Table)
2859 psc->GSUB_Table = load_gsub_table(hdc);
2861 /* we need to have at least one of the required features */
2863 while (ShapingData[psa->eScript].requiredFeatures[i])
2865 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
2871 return USP_E_SCRIPT_NOT_IN_FONT;
2874 HRESULT SHAPE_GetFontScriptTags( HDC hdc, ScriptCache *psc,
2875 SCRIPT_ANALYSIS *psa, int cMaxTags,
2876 OPENTYPE_TAG *pScriptTags, int *pcTags)
2879 OPENTYPE_TAG searching = 0x00000000;
2881 if (!psc->GSUB_Table)
2882 psc->GSUB_Table = load_gsub_table(hdc);
2884 if (psa && scriptInformation[psa->eScript].scriptTag)
2885 searching = scriptInformation[psa->eScript].scriptTag;
2887 hr = OpenType_GSUB_GetFontScriptTags(psc, searching, cMaxTags, pScriptTags, pcTags, NULL);
2893 HRESULT SHAPE_GetFontLanguageTags( HDC hdc, ScriptCache *psc,
2894 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2895 int cMaxTags, OPENTYPE_TAG *pLangSysTags,
2899 OPENTYPE_TAG searching = 0x00000000;
2900 BOOL fellback = FALSE;
2902 if (!psc->GSUB_Table)
2903 psc->GSUB_Table = load_gsub_table(hdc);
2905 if (psa && psc->userLang != 0)
2906 searching = psc->userLang;
2908 hr = OpenType_GSUB_GetFontLanguageTags(psc, tagScript, searching, cMaxTags, pLangSysTags, pcTags, NULL);
2912 hr = OpenType_GSUB_GetFontLanguageTags(psc, MS_MAKE_TAG('l','a','t','n'), searching, cMaxTags, pLangSysTags, pcTags, NULL);
2915 if (FAILED(hr) || fellback)
2917 if (SUCCEEDED(hr) && fellback && psa)
2922 HRESULT SHAPE_GetFontFeatureTags( HDC hdc, ScriptCache *psc,
2923 SCRIPT_ANALYSIS *psa, OPENTYPE_TAG tagScript,
2924 OPENTYPE_TAG tagLangSys, int cMaxTags,
2925 OPENTYPE_TAG *pFeatureTags, int *pcTags)
2928 BOOL filter = FALSE;
2930 if (!psc->GSUB_Table)
2931 psc->GSUB_Table = load_gsub_table(hdc);
2933 if (psa && scriptInformation[psa->eScript].scriptTag)
2935 FIXME("Filtering not implemented\n");
2939 hr = OpenType_GSUB_GetFontFeatureTags(psc, tagScript, tagLangSys, filter, 0x00000000, cMaxTags, pFeatureTags, pcTags, NULL);