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
31 #include "usp10_internal.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(uniscribe);
37 #define FIRST_ARABIC_CHAR 0x0600
38 #define LAST_ARABIC_CHAR 0x06ff
40 typedef VOID (*ContextualShapingProc)(HDC, ScriptCache*, SCRIPT_ANALYSIS*,
41 WCHAR*, INT, WORD*, INT*, INT, WORD*);
43 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
44 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
45 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
46 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
47 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
48 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
49 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
50 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
51 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
52 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
53 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
54 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
55 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust);
57 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
59 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);
60 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 );
61 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 );
62 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 );
63 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 );
64 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 );
65 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 );
66 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 );
67 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 );
68 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 );
69 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 );
70 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 );
71 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 );
72 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 );
73 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 );
75 extern const unsigned short indic_syllabic_table[];
76 extern const unsigned short wine_shaping_table[];
77 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
99 #ifdef WORDS_BIGENDIAN
100 #define GET_BE_WORD(x) (x)
102 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
105 /* These are all structures needed for the GSUB table */
106 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
107 #define GSUB_E_NOFEATURE -2
108 #define GSUB_E_NOGLYPH -1
124 GSUB_ScriptRecord ScriptRecord[1];
130 } GSUB_LangSysRecord;
135 GSUB_LangSysRecord LangSysRecord[1];
139 WORD LookupOrder; /* Reserved */
140 WORD ReqFeatureIndex;
142 WORD FeatureIndex[1];
148 } GSUB_FeatureRecord;
152 GSUB_FeatureRecord FeatureRecord[1];
156 WORD FeatureParams; /* Reserved */
158 WORD LookupListIndex[1];
177 } GSUB_CoverageFormat1;
182 WORD StartCoverageIndex;
188 GSUB_RangeRecord RangeRecord[1];
189 } GSUB_CoverageFormat2;
192 WORD SubstFormat; /* = 1 */
195 } GSUB_SingleSubstFormat1;
198 WORD SubstFormat; /* = 2 */
202 }GSUB_SingleSubstFormat2;
205 WORD SubstFormat; /* = 1 */
209 }GSUB_MultipleSubstFormat1;
217 WORD SubstFormat; /* = 1 */
221 }GSUB_LigatureSubstFormat1;
236 WORD LookupListIndex;
238 }GSUB_SubstLookupRecord;
241 WORD SubstFormat; /* = 1 */
243 WORD ChainSubRuleSetCount;
244 WORD ChainSubRuleSet[1];
245 }GSUB_ChainContextSubstFormat1;
248 WORD SubstFormat; /* = 3 */
249 WORD BacktrackGlyphCount;
251 }GSUB_ChainContextSubstFormat3_1;
254 WORD InputGlyphCount;
256 }GSUB_ChainContextSubstFormat3_2;
259 WORD LookaheadGlyphCount;
261 }GSUB_ChainContextSubstFormat3_3;
265 GSUB_SubstLookupRecord SubstLookupRecord[1];
266 }GSUB_ChainContextSubstFormat3_4;
269 WORD SubstFormat; /* = 1 */
271 WORD AlternateSetCount;
272 WORD AlternateSet[1];
273 } GSUB_AlternateSubstFormat1;
280 /* These are all structures needed for the GDEF table */
281 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
283 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
290 WORD MarkAttachClassDef;
297 WORD ClassValueArray[1];
298 } GDEF_ClassDefFormat1;
304 } GDEF_ClassRangeRecord;
308 WORD ClassRangeCount;
309 GDEF_ClassRangeRecord ClassRangeRecord[1];
310 } GDEF_ClassDefFormat2;
312 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
314 typedef struct tagVowelComponents
320 typedef struct tagConsonantComponents
324 } ConsonantComponents;
326 typedef void (*second_reorder_function)(LPWSTR pwChar, IndicSyllable *syllable,WORD* pwGlyphs, IndicSyllable* glyph_index, lexical_function lex);
328 /* the orders of joined_forms and contextual_features need to line up */
329 static const char* contextual_features[] =
341 static OPENTYPE_FEATURE_RECORD standard_features[] =
343 { MS_MAKE_TAG('c','c','m','p'), 1},
344 { MS_MAKE_TAG('l','o','c','l'), 1},
347 static OPENTYPE_FEATURE_RECORD latin_features[] =
349 { MS_MAKE_TAG('l','i','g','a'), 1},
350 { MS_MAKE_TAG('c','l','i','g'), 1},
353 static OPENTYPE_FEATURE_RECORD arabic_features[] =
355 { MS_MAKE_TAG('r','l','i','g'), 1},
356 { MS_MAKE_TAG('c','a','l','t'), 1},
357 { MS_MAKE_TAG('l','i','g','a'), 1},
358 { MS_MAKE_TAG('d','l','i','g'), 1},
359 { MS_MAKE_TAG('c','s','w','h'), 1},
360 { MS_MAKE_TAG('m','s','e','t'), 1},
363 static const char* required_arabic_features[] =
372 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
374 { MS_MAKE_TAG('d','l','i','g'), 0},
377 static OPENTYPE_FEATURE_RECORD syriac_features[] =
379 { MS_MAKE_TAG('r','l','i','g'), 1},
380 { MS_MAKE_TAG('c','a','l','t'), 1},
381 { MS_MAKE_TAG('l','i','g','a'), 1},
382 { MS_MAKE_TAG('d','l','i','g'), 1},
385 static const char* required_syriac_features[] =
397 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
399 /* Presentation forms */
400 { MS_MAKE_TAG('b','l','w','s'), 1},
401 { MS_MAKE_TAG('a','b','v','s'), 1},
402 { MS_MAKE_TAG('p','s','t','s'), 1},
405 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
407 { MS_MAKE_TAG('a','b','v','s'), 1},
408 { MS_MAKE_TAG('b','l','w','s'), 1},
411 static OPENTYPE_FEATURE_RECORD phags_features[] =
413 { MS_MAKE_TAG('a','b','v','s'), 1},
414 { MS_MAKE_TAG('b','l','w','s'), 1},
415 { MS_MAKE_TAG('c','a','l','t'), 1},
418 static OPENTYPE_FEATURE_RECORD thai_features[] =
420 { MS_MAKE_TAG('c','c','m','p'), 1},
423 static const char* required_lao_features[] =
429 static const char* required_devanagari_features[] =
445 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
447 { MS_MAKE_TAG('p','r','e','s'), 1},
448 { MS_MAKE_TAG('a','b','v','s'), 1},
449 { MS_MAKE_TAG('b','l','w','s'), 1},
450 { MS_MAKE_TAG('p','s','t','s'), 1},
451 { MS_MAKE_TAG('h','a','l','n'), 1},
452 { MS_MAKE_TAG('c','a','l','t'), 1},
455 static const char* required_bengali_features[] =
472 static const char* required_gurmukhi_features[] =
491 static const char* required_oriya_features[] =
508 static const char* required_tamil_features[] =
524 static const char* required_telugu_features[] =
542 typedef struct ScriptShapeDataTag {
543 TEXTRANGE_PROPERTIES defaultTextRange;
544 const char** requiredFeatures;
547 ContextualShapingProc contextProc;
548 ShapeCharGlyphPropProc charGlyphPropProc;
551 /* in order of scripts */
552 static const ScriptShapeData ShapingData[] =
554 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
555 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
556 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
557 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
558 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
559 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
560 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
561 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
562 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
563 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
564 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
565 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
566 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
567 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
568 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
569 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
570 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
571 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
572 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
573 {{ phags_features, 3}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
574 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
575 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
576 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
577 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
578 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
579 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
580 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
581 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
582 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
583 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
584 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
585 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
586 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
587 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
588 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
589 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
590 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
591 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
592 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
593 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
594 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
595 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
596 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
597 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
598 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
599 {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
600 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
603 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
605 const GSUB_CoverageFormat1* cf1;
609 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
611 int count = GET_BE_WORD(cf1->GlyphCount);
613 TRACE("Coverage Format 1, %i glyphs\n",count);
614 for (i = 0; i < count; i++)
615 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
619 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
621 const GSUB_CoverageFormat2* cf2;
624 cf2 = (const GSUB_CoverageFormat2*)cf1;
626 count = GET_BE_WORD(cf2->RangeCount);
627 TRACE("Coverage Format 2, %i ranges\n",count);
628 for (i = 0; i < count; i++)
630 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
632 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
633 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
635 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
636 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
642 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
647 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
649 const GSUB_ScriptList *script;
650 const GSUB_Script *deflt = NULL;
652 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
654 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
655 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
657 const GSUB_Script *scr;
660 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
661 scr = (const GSUB_Script*)((const BYTE*)script + offset);
663 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
665 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
671 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
675 const GSUB_LangSys *Lang;
677 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
679 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
681 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
682 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
684 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
687 offset = GET_BE_WORD(script->DefaultLangSys);
690 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
696 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
699 const GSUB_FeatureList *feature;
700 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
702 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
703 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
705 int index = GET_BE_WORD(lang->FeatureIndex[i]);
706 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
708 const GSUB_Feature *feat;
709 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
716 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
719 TRACE("Single Substitution Subtable\n");
721 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
724 const GSUB_SingleSubstFormat1 *ssf1;
725 offset = GET_BE_WORD(look->SubTable[j]);
726 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
727 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
729 int offset = GET_BE_WORD(ssf1->Coverage);
730 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
731 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
733 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
734 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
735 TRACE(" 0x%x\n",glyphs[glyph_index]);
736 return glyph_index + write_dir;
741 const GSUB_SingleSubstFormat2 *ssf2;
745 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
746 offset = GET_BE_WORD(ssf1->Coverage);
747 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
748 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
749 TRACE(" Coverage index %i\n",index);
752 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
753 return GSUB_E_NOGLYPH;
755 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
756 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
757 TRACE("0x%x\n",glyphs[glyph_index]);
758 return glyph_index + write_dir;
762 return GSUB_E_NOGLYPH;
765 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
768 TRACE("Multiple Substitution Subtable\n");
770 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
773 const GSUB_MultipleSubstFormat1 *msf1;
774 offset = GET_BE_WORD(look->SubTable[j]);
775 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
777 offset = GET_BE_WORD(msf1->Coverage);
778 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
781 const GSUB_Sequence *seq;
784 offset = GET_BE_WORD(msf1->Sequence[index]);
785 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
786 sub_count = GET_BE_WORD(seq->GlyphCount);
787 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
789 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
790 glyphs[j] =glyphs[j-(sub_count-1)];
792 for (j = 0; j < sub_count; j++)
794 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
796 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
798 *glyph_count = *glyph_count + (sub_count - 1);
800 if (TRACE_ON(uniscribe))
802 for (j = 0; j < sub_count; j++)
803 TRACE(" 0x%x",glyphs[glyph_index+j]);
807 return glyph_index + (sub_count * write_dir);
810 return GSUB_E_NOGLYPH;
813 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
816 TRACE("Alternate Substitution Subtable\n");
818 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
821 const GSUB_AlternateSubstFormat1 *asf1;
824 offset = GET_BE_WORD(look->SubTable[j]);
825 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
826 offset = GET_BE_WORD(asf1->Coverage);
828 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
831 const GSUB_AlternateSet *as;
832 offset = GET_BE_WORD(asf1->AlternateSet[index]);
833 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
834 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
835 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
836 return GSUB_E_NOGLYPH;
838 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
839 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
840 TRACE(" 0x%x\n",glyphs[glyph_index]);
841 return glyph_index + write_dir;
844 return GSUB_E_NOGLYPH;
847 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
851 TRACE("Ligature Substitution Subtable\n");
852 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
854 const GSUB_LigatureSubstFormat1 *lsf1;
857 offset = GET_BE_WORD(look->SubTable[j]);
858 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
859 offset = GET_BE_WORD(lsf1->Coverage);
860 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
861 TRACE(" Coverage index %i\n",index);
864 const GSUB_LigatureSet *ls;
867 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
868 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
869 count = GET_BE_WORD(ls->LigatureCount);
870 TRACE(" LigatureSet has %i members\n",count);
871 for (k = 0; k < count; k++)
873 const GSUB_Ligature *lig;
874 int CompCount,l,CompIndex;
876 offset = GET_BE_WORD(ls->Ligature[k]);
877 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
878 CompCount = GET_BE_WORD(lig->CompCount) - 1;
879 CompIndex = glyph_index+write_dir;
880 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
883 CompGlyph = GET_BE_WORD(lig->Component[l]);
884 if (CompGlyph != glyphs[CompIndex])
886 CompIndex += write_dir;
890 int replaceIdx = glyph_index;
892 replaceIdx = glyph_index - CompCount;
894 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
895 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
896 TRACE("0x%x\n",glyphs[replaceIdx]);
900 for (j = replaceIdx + 1; j < *glyph_count; j++)
901 glyphs[j] =glyphs[j+CompCount];
902 *glyph_count = *glyph_count - CompCount;
904 return replaceIdx + write_dir;
909 return GSUB_E_NOGLYPH;
912 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
917 TRACE("Chaining Contextual Substitution Subtable\n");
918 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
920 const GSUB_ChainContextSubstFormat1 *ccsf1;
922 int dirLookahead = write_dir;
923 int dirBacktrack = -1 * write_dir;
925 offset = GET_BE_WORD(look->SubTable[j]);
926 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
927 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
929 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
932 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
934 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
937 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
941 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
942 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
943 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
944 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
945 int newIndex = glyph_index;
947 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
949 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
951 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
953 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
954 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
957 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
959 TRACE("Matched Backtrack\n");
961 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
963 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
964 for (k = 0; k < indexGlyphs; k++)
966 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
967 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
970 if (k != indexGlyphs)
972 TRACE("Matched IndexGlyphs\n");
974 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
976 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
978 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
979 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
982 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
984 TRACE("Matched LookAhead\n");
986 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
988 if (GET_BE_WORD(ccsf3_4->SubstCount))
990 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
992 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
993 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
995 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
996 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
999 ERR("Chain failed to generate a glyph\n");
1005 else return GSUB_E_NOGLYPH;
1011 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1014 const GSUB_LookupTable *look;
1016 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1017 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1018 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1019 switch(GET_BE_WORD(look->LookupType))
1022 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1024 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1026 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1028 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1030 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1032 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1034 return GSUB_E_NOGLYPH;
1037 static INT GSUB_apply_feature_all_lookups(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1040 int out_index = GSUB_E_NOGLYPH;
1041 const GSUB_LookupList *lookup;
1043 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1045 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1046 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1048 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1049 if (out_index != GSUB_E_NOGLYPH)
1052 if (out_index == GSUB_E_NOGLYPH)
1053 TRACE("lookups found no glyphs\n");
1057 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1058 if (out2!=GSUB_E_NOGLYPH)
1064 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1068 if (psc->userScript != 0)
1070 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1071 return ShapingData[psa->eScript].newOtTag;
1073 return (char*)&psc->userScript;
1076 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1077 return ShapingData[psa->eScript].newOtTag;
1079 if (ShapingData[psa->eScript].otTag[0] != 0)
1080 return ShapingData[psa->eScript].otTag;
1083 * fall back to the font charset
1085 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1088 case ANSI_CHARSET: return "latn";
1089 case BALTIC_CHARSET: return "latn"; /* ?? */
1090 case CHINESEBIG5_CHARSET: return "hani";
1091 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1092 case GB2312_CHARSET: return "hani";
1093 case GREEK_CHARSET: return "grek";
1094 case HANGUL_CHARSET: return "hang";
1095 case RUSSIAN_CHARSET: return "cyrl";
1096 case SHIFTJIS_CHARSET: return "kana";
1097 case TURKISH_CHARSET: return "latn"; /* ?? */
1098 case VIETNAMESE_CHARSET: return "latn";
1099 case JOHAB_CHARSET: return "latn"; /* ?? */
1100 case ARABIC_CHARSET: return "arab";
1101 case HEBREW_CHARSET: return "hebr";
1102 case THAI_CHARSET: return "thai";
1103 default: return "latn";
1107 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1109 const GSUB_Feature *feature;
1113 script = get_opentype_script(hdc,psa,psc,FALSE);
1115 for (i = 0; i < psc->feature_count; i++)
1117 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1118 return psc->features[i].feature;
1123 if (psc->GSUB_Table)
1125 const GSUB_Script *script;
1126 const GSUB_LangSys *language;
1131 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1135 if (psc->userLang != 0)
1136 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1138 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1140 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1142 } while(attempt && !feature);
1144 /* try in the default (latin) table */
1147 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1150 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1152 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1157 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1159 psc->feature_count++;
1162 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1164 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1166 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1167 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1168 psc->features[psc->feature_count - 1].feature = feature;
1172 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)
1174 const GSUB_Feature *feature;
1176 feature = load_GSUB_feature(hdc, psa, psc, feat);
1178 return GSUB_E_NOFEATURE;
1180 TRACE("applying feature %s\n",feat);
1181 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1184 static VOID *load_gsub_table(HDC hdc)
1186 VOID* GSUB_Table = NULL;
1187 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1188 if (length != GDI_ERROR)
1190 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1191 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1192 TRACE("Loaded GSUB table of %i bytes\n",length);
1197 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)
1200 INT glyph_count = count;
1203 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1204 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1205 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1206 if (rc > GSUB_E_NOGLYPH)
1207 rc = count - glyph_count;
1211 HeapFree(GetProcessHeap(),0,glyphs);
1215 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1219 const GDEF_ClassDefFormat1 *cf1;
1224 offset = GET_BE_WORD(header->GlyphClassDef);
1228 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1229 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1231 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1233 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1234 if (index < GET_BE_WORD(cf1->GlyphCount))
1235 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1238 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1240 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1242 top = GET_BE_WORD(cf2->ClassRangeCount);
1243 for (i = 0; i < top; i++)
1245 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1246 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1248 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1254 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1259 static VOID *load_gdef_table(HDC hdc)
1261 VOID* GDEF_Table = NULL;
1262 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1263 if (length != GDI_ERROR)
1265 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1266 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1267 TRACE("Loaded GDEF table of %i bytes\n",length);
1272 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, const WORD cChars, SCRIPT_GLYPHPROP *pGlyphProp)
1276 if (!psc->GDEF_Table)
1277 psc->GDEF_Table = load_gdef_table(hdc);
1279 for (i = 0; i < cGlyphs; i++)
1285 for (k = 0; k < cChars; k++)
1286 if (pwLogClust[k] == i)
1289 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1295 pGlyphProp[i].sva.fClusterStart = 1;
1296 pGlyphProp[i].sva.fDiacritic = 0;
1297 pGlyphProp[i].sva.fZeroWidth = 0;
1300 pGlyphProp[i].sva.fClusterStart = 1;
1301 pGlyphProp[i].sva.fDiacritic = 0;
1302 pGlyphProp[i].sva.fZeroWidth = 0;
1305 pGlyphProp[i].sva.fClusterStart = 0;
1306 pGlyphProp[i].sva.fDiacritic = 1;
1307 pGlyphProp[i].sva.fZeroWidth = 1;
1309 case ComponentGlyph:
1310 pGlyphProp[i].sva.fClusterStart = 0;
1311 pGlyphProp[i].sva.fDiacritic = 0;
1312 pGlyphProp[i].sva.fZeroWidth = 0;
1315 ERR("Unknown glyph class %i\n",class);
1316 pGlyphProp[i].sva.fClusterStart = 1;
1317 pGlyphProp[i].sva.fDiacritic = 0;
1318 pGlyphProp[i].sva.fZeroWidth = 0;
1321 if (char_count == 0)
1322 pGlyphProp[i].sva.fClusterStart = 0;
1326 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1330 for (i = 0; i < cGlyphs; i++)
1332 if (!pGlyphProp[i].sva.fClusterStart)
1335 for (j = 0; j < cChars; j++)
1337 if (pwLogClust[j] == i)
1340 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1342 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1343 pwLogClust[j] = pwLogClust[k];
1350 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1352 if (changeCount == 0)
1357 int target_glyph = nextIndex - write_dir;
1359 int target_index = -1;
1360 int replacing_glyph = -1;
1362 int top_logclust = 0;
1364 if (changeCount > 0)
1367 target_glyph = nextIndex - changeCount;
1369 target_glyph = nextIndex + (changeCount + 1);
1372 seeking_glyph = target_glyph;
1373 for (i = 0; i < chars; i++)
1374 if (pwLogClust[i] > top_logclust)
1375 top_logclust = pwLogClust[i];
1379 for (i = 0; i < chars; i++)
1381 if (pwLogClust[i] == seeking_glyph)
1388 for (i = chars - 1; i >= 0; i--)
1390 if (pwLogClust[i] == seeking_glyph)
1396 if (target_index == -1)
1399 while (target_index == -1 && seeking_glyph <= top_logclust);
1401 if (target_index == -1)
1403 ERR("Unable to find target glyph\n");
1407 if (changeCount < 0)
1410 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1412 if (pwLogClust[i] == target_glyph)
1414 if(pwLogClust[i] == replacing_glyph)
1415 pwLogClust[i] = target_glyph;
1419 if (changed >= changeCount)
1421 replacing_glyph = pwLogClust[i];
1422 pwLogClust[i] = target_glyph;
1429 /* renumber trailing indexes*/
1430 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1432 if (pwLogClust[i] != target_glyph)
1433 pwLogClust[i] += changeCount;
1438 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1439 pwLogClust[i] += changeCount;
1444 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 )
1446 if (psc->GSUB_Table)
1448 const GSUB_Feature *feature;
1449 const GSUB_LookupList *lookup;
1450 const GSUB_Header *header = psc->GSUB_Table;
1451 int lookup_index, lookup_count;
1453 feature = load_GSUB_feature(hdc, psa, psc, feat);
1455 return GSUB_E_NOFEATURE;
1457 TRACE("applying feature %s\n",debugstr_an(feat,4));
1458 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1459 lookup_count = GET_BE_WORD(feature->LookupCount);
1460 TRACE("%i lookups\n", lookup_count);
1461 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1469 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1470 while(i < *pcGlyphs && i >= 0)
1473 INT prevCount = *pcGlyphs;
1475 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1476 if (*pcGlyphs != prevCount)
1478 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1487 return GSUB_E_NOFEATURE;
1490 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1492 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1495 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1499 if ( i+ delta >= cchLen)
1507 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1511 if (psa->fLinkBefore)
1516 if ( i+ delta >= cchLen)
1518 if (psa->fLinkAfter)
1526 if (context_type[i] == jtT)
1527 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1529 return context_type[i];
1532 static inline BOOL right_join_causing(CHAR joining_type)
1534 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1537 static inline BOOL left_join_causing(CHAR joining_type)
1539 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1542 static inline BOOL word_break_causing(WCHAR chr)
1544 /* we are working within a string of characters already guareented to
1545 be within one script, Syriac, so we do not worry about any character
1546 other than the space character outside of that range */
1547 return (chr == 0 || chr == 0x20 );
1551 * ContextualShape_Arabic
1553 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1560 if (*pcGlyphs != cChars)
1562 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1566 if (!psa->fLogicalOrder && psa->fRTL)
1577 if (!psc->GSUB_Table)
1578 psc->GSUB_Table = load_gsub_table(hdc);
1580 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1581 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1583 for (i = 0; i < cChars; i++)
1584 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1586 for (i = 0; i < cChars; i++)
1588 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1589 context_shape[i] = Xr;
1590 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1591 context_shape[i] = Xl;
1592 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)))
1593 context_shape[i] = Xm;
1594 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1595 context_shape[i] = Xr;
1596 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1597 context_shape[i] = Xl;
1599 context_shape[i] = Xn;
1602 /* Contextual Shaping */
1604 while(i < *pcGlyphs)
1606 BOOL shaped = FALSE;
1608 if (psc->GSUB_Table)
1611 INT prevCount = *pcGlyphs;
1612 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1613 if (nextIndex > GSUB_E_NOGLYPH)
1616 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1618 shaped = (nextIndex > GSUB_E_NOGLYPH);
1623 if (context_shape[i] == Xn)
1625 WORD newGlyph = pwOutGlyphs[i];
1626 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1628 /* fall back to presentation form B */
1629 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1630 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1631 pwOutGlyphs[i] = newGlyph;
1638 HeapFree(GetProcessHeap(),0,context_shape);
1639 HeapFree(GetProcessHeap(),0,context_type);
1643 * ContextualShape_Syriac
1647 #define DALATH 0x715
1650 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1657 if (*pcGlyphs != cChars)
1659 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1663 if (!psa->fLogicalOrder && psa->fRTL)
1674 if (!psc->GSUB_Table)
1675 psc->GSUB_Table = load_gsub_table(hdc);
1677 if (!psc->GSUB_Table)
1680 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1681 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1683 for (i = 0; i < cChars; i++)
1684 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1686 for (i = 0; i < cChars; i++)
1688 if (pwcChars[i] == ALAPH)
1690 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1692 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1693 context_shape[i] = Afj;
1694 else if ( rchar != DALATH && rchar != RISH &&
1695 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1696 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1697 context_shape[i] = Afn;
1698 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1699 context_shape[i] = Afx;
1701 context_shape[i] = Xn;
1703 else if (context_type[i] == jtR &&
1704 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1705 context_shape[i] = Xr;
1706 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1707 context_shape[i] = Xl;
1708 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)))
1709 context_shape[i] = Xm;
1710 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1711 context_shape[i] = Xr;
1712 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1713 context_shape[i] = Xl;
1715 context_shape[i] = Xn;
1718 /* Contextual Shaping */
1720 while(i < *pcGlyphs)
1723 INT prevCount = *pcGlyphs;
1724 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1725 if (nextIndex > GSUB_E_NOGLYPH)
1727 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1734 HeapFree(GetProcessHeap(),0,context_shape);
1735 HeapFree(GetProcessHeap(),0,context_type);
1739 * ContextualShape_Phags_pa
1742 #define phags_pa_CANDRABINDU 0xA873
1743 #define phags_pa_START 0xA840
1744 #define phags_pa_END 0xA87F
1746 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1752 if (*pcGlyphs != cChars)
1754 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1758 if (!psa->fLogicalOrder && psa->fRTL)
1769 if (!psc->GSUB_Table)
1770 psc->GSUB_Table = load_gsub_table(hdc);
1772 if (!psc->GSUB_Table)
1775 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1777 for (i = 0; i < cChars; i++)
1779 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1781 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1782 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1783 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1784 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1786 if (jrchar && jlchar)
1787 context_shape[i] = Xm;
1789 context_shape[i] = Xr;
1791 context_shape[i] = Xl;
1793 context_shape[i] = Xn;
1796 context_shape[i] = -1;
1799 /* Contextual Shaping */
1801 while(i < *pcGlyphs)
1803 if (context_shape[i] >= 0)
1806 INT prevCount = *pcGlyphs;
1807 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1808 if (nextIndex > GSUB_E_NOGLYPH)
1810 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1820 HeapFree(GetProcessHeap(),0,context_shape);
1823 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1828 pwOutChars[cWalk] = replacements[0];
1832 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1835 for (j = *pcChars; j > cWalk; j--)
1836 pwOutChars[j] = pwOutChars[j-1];
1837 *pcChars= *pcChars+1;
1838 pwOutChars[cWalk] = replacements[i];
1843 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust, INT cChars)
1848 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1850 for (i = 0; vowels[i].base != 0x0; i++)
1852 if (pwOutChars[cWalk] == vowels[i].base)
1855 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1856 if (vowels[i].parts[1]) { cWalk++; o++; }
1857 if (vowels[i].parts[2]) { cWalk++; o++; }
1858 UpdateClusters(cWalk, o, 1, cChars, pwLogClust);
1865 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1871 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1873 for (i = 0; consonants[i].output!= 0x0; i++)
1876 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1877 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1880 if (consonants[i].parts[j]==0x0) /* matched all */
1884 pwOutChars[cWalk] = consonants[i].output;
1885 for(k = cWalk+1; k < *pcChars - j; k++)
1886 pwOutChars[k] = pwOutChars[k+j];
1887 *pcChars = *pcChars - j;
1888 for (k = j ; k > 0; k--)
1889 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1891 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1900 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1905 WORD Ra = pwChar[s->start];
1906 WORD H = pwChar[s->start+1];
1908 TRACE("Doing reorder of Ra to %i\n",s->base);
1909 for (j = s->start; j < s->base-1; j++)
1910 pwChar[j] = pwChar[j+2];
1911 pwChar[s->base-1] = Ra;
1912 pwChar[s->base] = H;
1914 s->ralf = s->base-1;
1919 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1924 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1925 WORD Ra = pwChar[s->start];
1926 WORD H = pwChar[s->start+1];
1927 for (loc = s->end; loc > stop; loc--)
1928 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1931 TRACE("Doing reorder of Ra to %i\n",loc);
1932 for (j = s->start; j < loc-1; j++)
1933 pwChar[j] = pwChar[j+2];
1939 if (s->blwf >= 0) s->blwf -= 2;
1940 if (s->pref >= 0) s->pref -= 2;
1944 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1949 WORD Ra = pwChar[s->start];
1950 WORD H = pwChar[s->start+1];
1952 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1953 for (j = s->start; j < s->end-1; j++)
1954 pwChar[j] = pwChar[j+2];
1955 pwChar[s->end-1] = Ra;
1960 if (s->blwf >= 0) s->blwf -= 2;
1961 if (s->pref >= 0) s->pref -= 2;
1965 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1969 /* reorder Matras */
1970 if (s->end > s->base)
1972 for (i = 1; i <= s->end-s->base; i++)
1974 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1977 WCHAR c = pwChar[s->base+i];
1978 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1979 for (j = s->base+i; j > s->base; j--)
1980 pwChar[j] = pwChar[j-1];
1981 pwChar[s->base] = c;
1983 if (s->ralf >= s->base) s->ralf++;
1984 if (s->blwf >= s->base) s->blwf++;
1985 if (s->pref >= s->base) s->pref++;
1992 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1996 /* reorder Matras */
1997 if (s->end > s->base)
1999 for (i = 1; i <= s->end-s->base; i++)
2001 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
2004 WCHAR c = pwChar[s->base+i];
2005 TRACE("Doing reorder of %x to %i\n",c,s->start);
2006 for (j = s->base+i; j > s->start; j--)
2007 pwChar[j] = pwChar[j-1];
2008 pwChar[s->start] = c;
2010 if (s->ralf >= 0) s->ralf++;
2011 if (s->blwf >= 0) s->blwf++;
2012 if (s->pref >= 0) s->pref++;
2019 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2021 if (s->blwf >= 0 && g->blwf > g->base)
2025 for (loc = s->end; loc > s->blwf; loc--)
2026 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2029 g_offset = (loc - s->blwf) - 1;
2033 WORD blwf = glyphs[g->blwf];
2034 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2035 /* do not care about the pwChar array anymore, just the glyphs */
2036 for (j = 0; j < g_offset; j++)
2037 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2038 glyphs[g->blwf + g_offset] = blwf;
2043 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2047 /* reorder previously moved Matras to correct position*/
2048 for (i = s->start; i < s->base; i++)
2050 if (lexical(pwChar[i]) == lex_Matra_pre)
2053 int g_start = g->start + i - s->start;
2054 if (g_start < g->base -1 )
2056 WCHAR og = glyphs[g_start];
2057 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2058 for (j = g_start; j < g->base-1; j++)
2059 glyphs[j] = glyphs[j+1];
2060 glyphs[g->base-1] = og;
2066 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2068 if (s->pref >= 0 && g->pref > g->base)
2071 WCHAR og = glyphs[g->pref];
2072 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2073 for (j = g->pref; j > g->base; j--)
2074 glyphs[j] = glyphs[j-1];
2075 glyphs[g->base] = og;
2079 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2081 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2082 if (s->start == s->base && s->base == s->end) return;
2083 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2085 Reorder_Ra_follows_base(pwChar, s, lexical);
2086 Reorder_Matra_precede_base(pwChar, s, lexical);
2089 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2091 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2092 if (s->start == s->base && s->base == s->end) return;
2093 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2095 Reorder_Ra_follows_matra(pwChar, s, lexical);
2096 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2099 static void Reorder_Like_Bengali(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2101 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2102 if (s->start == s->base && s->base == s->end) return;
2103 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2105 Reorder_Ra_follows_base(pwChar, s, lexical);
2106 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2109 static void Reorder_Like_Kannada(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2111 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2112 if (s->start == s->base && s->base == s->end) return;
2113 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2115 Reorder_Ra_follows_syllable(pwChar, s, lexical);
2116 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2119 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2121 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2122 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2123 if (s->start == s->base && s->base == s->end) return;
2124 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2126 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2129 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2131 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2132 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2133 if (s->start == s->base && s->base == s->end) return;
2134 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2136 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2137 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2141 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2146 if (glyph_index->start > index)
2147 glyph_index->start += shift;
2148 if (glyph_index->base > index)
2149 glyph_index->base+= shift;
2150 if (glyph_index->end > index)
2151 glyph_index->end+= shift;
2152 if (glyph_index->ralf > index)
2153 glyph_index->ralf+= shift;
2154 if (glyph_index->blwf > index)
2155 glyph_index->blwf+= shift;
2156 if (glyph_index->pref > index)
2157 glyph_index->pref+= shift;
2160 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, const GSUB_Feature *feature )
2162 int index = glyph_index->start;
2167 while(index <= glyph_index->end)
2170 INT prevCount = *pcGlyphs;
2171 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2172 if (nextIndex > GSUB_E_NOGLYPH)
2174 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2175 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2183 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2186 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)))))
2188 if (index + i <= end-1)
2194 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)
2196 INT index, nextIndex;
2199 count = syllable->base - syllable->start;
2202 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2203 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2205 INT prevCount = *pcGlyphs;
2206 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2207 if (nextIndex > GSUB_E_NOGLYPH)
2209 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2210 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2211 g_offset += (*pcGlyphs - prevCount);
2215 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2219 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)
2222 INT prevCount = *pcGlyphs;
2224 if (syllable->ralf >= 0)
2226 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2227 if (nextIndex > GSUB_E_NOGLYPH)
2229 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2230 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2235 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2238 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2239 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2240 is_consonant(lexical(pwChars[index+i+1])))))
2242 if (index + i <= end-1)
2248 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)
2250 INT index, nextIndex;
2251 INT count, g_offset=0;
2252 INT ralf = syllable->ralf;
2254 count = syllable->end - syllable->base;
2256 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2260 INT prevCount = *pcGlyphs;
2261 if (ralf >=0 && ralf < index)
2269 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2270 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2271 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2274 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2275 if (nextIndex > GSUB_E_NOGLYPH)
2277 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2278 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2279 g_offset += (*pcGlyphs - prevCount);
2283 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2284 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2285 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2289 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2293 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)
2296 int overall_shift = 0;
2297 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2298 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2299 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2300 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2301 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2302 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2303 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2304 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2305 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2306 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2307 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2308 IndicSyllable glyph_indexs;
2310 for (c = 0; c < syllable_count; c++)
2313 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2314 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2315 old_end = glyph_indexs.end;
2319 TRACE("applying feature locl\n");
2320 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2324 TRACE("applying feature nukt\n");
2325 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2329 TRACE("applying feature akhn\n");
2330 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2334 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2337 TRACE("applying feature rkrf\n");
2338 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2341 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2345 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2347 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2351 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2354 TRACE("applying feature pstf\n");
2355 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2359 TRACE("applying feature vatu\n");
2360 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2364 TRACE("applying feature cjct\n");
2365 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2369 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2371 overall_shift += glyph_indexs.end - old_end;
2375 static inline int unicode_lex(WCHAR c)
2379 if (!c) return lex_Generic;
2380 if (c == 0x200D) return lex_ZWJ;
2381 if (c == 0x200C) return lex_ZWNJ;
2382 if (c == 0x00A0) return lex_NBSP;
2384 type = get_table_entry( indic_syllabic_table, c );
2386 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2390 case 0x0d07: /* Unknown */
2391 case 0x0e07: /* Unknwon */
2392 default: return lex_Generic;
2398 case 0x0014: return lex_Modifier;
2406 case 0x0010: return lex_Consonant;
2407 case 0x0004: return lex_Nukta;
2408 case 0x0005: return lex_Halant;
2410 case 0x0008: return lex_Vowel;
2412 case 0x0107: return lex_Matra_post;
2414 case 0x0307: return lex_Matra_pre;
2420 case 0x0407: return lex_Composed_Vowel;
2421 case 0x0507: return lex_Matra_above;
2422 case 0x0607: return lex_Matra_below;
2423 case 0x000c: return lex_Ra;
2427 static int sinhala_lex(WCHAR c)
2434 case 0x0DDE: return lex_Matra_post;
2436 return unicode_lex(c);
2440 static const VowelComponents Sinhala_vowels[] = {
2441 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2442 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2443 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2444 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2445 {0x0000, {0x0000,0x0000,0x0}}};
2447 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2449 int cCount = cChars;
2452 IndicSyllable *syllables = NULL;
2453 int syllable_count = 0;
2455 if (*pcGlyphs != cChars)
2457 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2461 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2463 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2465 /* Step 1: Decompose multi part vowels */
2466 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust, cChars);
2468 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2470 /* Step 2: Reorder within Syllables */
2471 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2472 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2474 /* Step 3: Strip dangling joiners */
2475 for (i = 0; i < cCount; i++)
2477 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2478 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2482 /* Step 4: Base Form application to syllables */
2483 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2485 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2487 HeapFree(GetProcessHeap(),0,input);
2488 HeapFree(GetProcessHeap(),0,syllables);
2491 static int devanagari_lex(WCHAR c)
2495 case 0x0930: return lex_Ra;
2497 return unicode_lex(c);
2501 static const ConsonantComponents Devanagari_consonants[] ={
2502 {{0x0928, 0x093C, 0x00000}, 0x0929},
2503 {{0x0930, 0x093C, 0x00000}, 0x0931},
2504 {{0x0933, 0x093C, 0x00000}, 0x0934},
2505 {{0x0915, 0x093C, 0x00000}, 0x0958},
2506 {{0x0916, 0x093C, 0x00000}, 0x0959},
2507 {{0x0917, 0x093C, 0x00000}, 0x095A},
2508 {{0x091C, 0x093C, 0x00000}, 0x095B},
2509 {{0x0921, 0x093C, 0x00000}, 0x095C},
2510 {{0x0922, 0x093C, 0x00000}, 0x095D},
2511 {{0x092B, 0x093C, 0x00000}, 0x095E},
2512 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2514 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2516 int cCount = cChars;
2518 IndicSyllable *syllables = NULL;
2519 int syllable_count = 0;
2520 BOOL modern = get_GSUB_Indic2(psa, psc);
2522 if (*pcGlyphs != cChars)
2524 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2528 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2529 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2531 /* Step 1: Compose Consonant and Nukta */
2532 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2533 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2535 /* Step 2: Reorder within Syllables */
2536 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2537 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2538 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2541 /* Step 3: Base Form application to syllables */
2542 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2544 HeapFree(GetProcessHeap(),0,input);
2545 HeapFree(GetProcessHeap(),0,syllables);
2548 static int bengali_lex(WCHAR c)
2552 case 0x09B0: return lex_Ra;
2554 return unicode_lex(c);
2558 static const VowelComponents Bengali_vowels[] = {
2559 {0x09CB, {0x09C7,0x09BE,0x0000}},
2560 {0x09CC, {0x09C7,0x09D7,0x0000}},
2561 {0x0000, {0x0000,0x0000,0x0000}}};
2563 static const ConsonantComponents Bengali_consonants[] = {
2564 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2565 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2566 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2567 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2568 {{0x0000,0x0000,0x0000}, 0x0000}};
2570 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2572 int cCount = cChars;
2574 IndicSyllable *syllables = NULL;
2575 int syllable_count = 0;
2576 BOOL modern = get_GSUB_Indic2(psa, psc);
2578 if (*pcGlyphs != cChars)
2580 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2584 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2585 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2587 /* Step 1: Decompose Vowels and Compose Consonents */
2588 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust, cChars);
2589 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2590 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2592 /* Step 2: Reorder within Syllables */
2593 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2594 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2595 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2598 /* Step 3: Initial form is only applied to the beginning of words */
2599 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2601 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2605 if (index > 0) index++;
2607 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2611 /* Step 4: Base Form application to syllables */
2612 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2614 HeapFree(GetProcessHeap(),0,input);
2615 HeapFree(GetProcessHeap(),0,syllables);
2618 static int gurmukhi_lex(WCHAR c)
2621 return lex_Modifier;
2623 return unicode_lex(c);
2626 static const ConsonantComponents Gurmukhi_consonants[] = {
2627 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2628 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2629 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2630 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2631 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2632 {{0x0000,0x0000,0x0000}, 0x0000}};
2634 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2636 int cCount = cChars;
2638 IndicSyllable *syllables = NULL;
2639 int syllable_count = 0;
2640 BOOL modern = get_GSUB_Indic2(psa, psc);
2642 if (*pcGlyphs != cChars)
2644 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2648 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2649 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2651 /* Step 1: Compose Consonents */
2652 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2653 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2655 /* Step 2: Reorder within Syllables */
2656 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2657 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2658 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2661 /* Step 3: Base Form application to syllables */
2662 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2664 HeapFree(GetProcessHeap(),0,input);
2665 HeapFree(GetProcessHeap(),0,syllables);
2668 static int gujarati_lex(WCHAR c)
2672 case 0x0AB0: return lex_Ra;
2674 return unicode_lex(c);
2678 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2680 int cCount = cChars;
2682 IndicSyllable *syllables = NULL;
2683 int syllable_count = 0;
2684 BOOL modern = get_GSUB_Indic2(psa, psc);
2686 if (*pcGlyphs != cChars)
2688 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2692 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2693 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2695 /* Step 1: Reorder within Syllables */
2696 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2697 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2698 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2701 /* Step 2: Base Form application to syllables */
2702 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2704 HeapFree(GetProcessHeap(),0,input);
2705 HeapFree(GetProcessHeap(),0,syllables);
2708 static int oriya_lex(WCHAR c)
2712 case 0x0B30: return lex_Ra;
2714 return unicode_lex(c);
2718 static const VowelComponents Oriya_vowels[] = {
2719 {0x0B48, {0x0B47,0x0B56,0x0000}},
2720 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2721 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2722 {0x0000, {0x0000,0x0000,0x0000}}};
2724 static const ConsonantComponents Oriya_consonants[] = {
2725 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2726 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2727 {{0x0000,0x0000,0x0000}, 0x0000}};
2729 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2731 int cCount = cChars;
2733 IndicSyllable *syllables = NULL;
2734 int syllable_count = 0;
2735 BOOL modern = get_GSUB_Indic2(psa, psc);
2737 if (*pcGlyphs != cChars)
2739 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2743 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2744 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2746 /* Step 1: Decompose Vowels and Compose Consonents */
2747 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust, cChars);
2748 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2749 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2751 /* Step 2: Reorder within Syllables */
2752 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2753 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2754 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2757 /* Step 3: Base Form application to syllables */
2758 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2760 HeapFree(GetProcessHeap(),0,input);
2761 HeapFree(GetProcessHeap(),0,syllables);
2764 static int tamil_lex(WCHAR c)
2766 return unicode_lex(c);
2769 static const VowelComponents Tamil_vowels[] = {
2770 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2771 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2772 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2773 {0x0000, {0x0000,0x0000,0x0000}}};
2775 static const ConsonantComponents Tamil_consonants[] = {
2776 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2777 {{0x0000,0x0000,0x0000}, 0x0000}};
2779 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2781 int cCount = cChars;
2783 IndicSyllable *syllables = NULL;
2784 int syllable_count = 0;
2785 BOOL modern = get_GSUB_Indic2(psa, psc);
2787 if (*pcGlyphs != cChars)
2789 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2793 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2794 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2796 /* Step 1: Decompose Vowels and Compose Consonents */
2797 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust, cChars);
2798 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2799 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2801 /* Step 2: Reorder within Syllables */
2802 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2803 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2804 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2807 /* Step 3: Base Form application to syllables */
2808 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2810 HeapFree(GetProcessHeap(),0,input);
2811 HeapFree(GetProcessHeap(),0,syllables);
2814 static int telugu_lex(WCHAR c)
2819 case 0x0C44: return lex_Modifier;
2821 return unicode_lex(c);
2825 static const VowelComponents Telugu_vowels[] = {
2826 {0x0C48, {0x0C46,0x0C56,0x0000}},
2827 {0x0000, {0x0000,0x0000,0x0000}}};
2829 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2831 int cCount = cChars;
2833 IndicSyllable *syllables = NULL;
2834 int syllable_count = 0;
2835 BOOL modern = get_GSUB_Indic2(psa, psc);
2837 if (*pcGlyphs != cChars)
2839 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2843 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2844 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2846 /* Step 1: Decompose Vowels */
2847 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust, cChars);
2848 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2850 /* Step 2: Reorder within Syllables */
2851 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2852 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2853 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2856 /* Step 3: Base Form application to syllables */
2857 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2859 HeapFree(GetProcessHeap(),0,input);
2860 HeapFree(GetProcessHeap(),0,syllables);
2863 static int kannada_lex(WCHAR c)
2867 case 0x0CB0: return lex_Ra;
2869 return unicode_lex(c);
2873 static const VowelComponents Kannada_vowels[] = {
2874 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2875 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2876 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2877 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2878 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2879 {0x0000, {0x0000,0x0000,0x0000}}};
2881 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2883 int cCount = cChars;
2885 IndicSyllable *syllables = NULL;
2886 int syllable_count = 0;
2887 BOOL modern = get_GSUB_Indic2(psa, psc);
2889 if (*pcGlyphs != cChars)
2891 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2895 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2896 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2898 /* Step 1: Decompose Vowels */
2899 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust, cChars);
2900 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2902 /* Step 2: Reorder within Syllables */
2903 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2904 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2905 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2908 /* Step 3: Base Form application to syllables */
2909 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2911 HeapFree(GetProcessHeap(),0,input);
2912 HeapFree(GetProcessHeap(),0,syllables);
2915 static int malayalam_lex(WCHAR c)
2917 return unicode_lex(c);
2920 static const VowelComponents Malayalam_vowels[] = {
2921 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2922 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2923 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2924 {0x0000, {0x0000,0x0000,0x0000}}};
2926 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2928 int cCount = cChars;
2930 IndicSyllable *syllables = NULL;
2931 int syllable_count = 0;
2932 BOOL modern = get_GSUB_Indic2(psa, psc);
2934 if (*pcGlyphs != cChars)
2936 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2940 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2941 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2943 /* Step 1: Decompose Vowels */
2944 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust, cChars);
2945 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2947 /* Step 2: Reorder within Syllables */
2948 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2949 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2950 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2953 /* Step 3: Base Form application to syllables */
2954 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2956 HeapFree(GetProcessHeap(),0,input);
2957 HeapFree(GetProcessHeap(),0,syllables);
2960 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)
2964 for (i = 0; i < cGlyphs; i++)
2969 for (k = 0; k < cChars; k++)
2971 if (pwLogClust[k] == i)
2973 char_index[char_count] = k;
2978 if (char_count == 0)
2981 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2983 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2984 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2987 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2990 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2991 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2994 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 )
2997 int initGlyph, finaGlyph;
3001 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3002 memset(spaces,0,cGlyphs);
3004 if (!psa->fLogicalOrder && psa->fRTL)
3006 initGlyph = cGlyphs-1;
3014 finaGlyph = cGlyphs-1;
3019 for (i = 0; i < cGlyphs; i++)
3021 for (k = 0; k < cChars; k++)
3022 if (pwLogClust[k] == i)
3024 if (pwcChars[k] == 0x0020)
3029 for (i = 0; i < cGlyphs; i++)
3033 BOOL isInit, isFinal;
3035 for (k = 0; k < cChars; k++)
3037 if (pwLogClust[k] == i)
3039 char_index[char_count] = k;
3044 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3045 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3047 if (char_count == 0)
3050 if (char_count == 1)
3052 if (pwcChars[char_index[0]] == 0x0020) /* space */
3054 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3055 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3057 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3058 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3059 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3061 if (!isInit && !isFinal)
3062 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3064 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3066 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3070 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3071 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3072 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3073 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3074 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3075 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3076 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3077 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3079 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3081 else if (!isInit && !isFinal)
3082 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3084 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3086 else if (char_count == 2)
3088 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3089 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3091 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3093 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3095 else if (!isInit && !isFinal)
3096 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3098 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3101 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3102 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3103 HeapFree(GetProcessHeap(),0,spaces);
3106 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 )
3113 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3114 memset(spaces,0,cGlyphs);
3116 if (!psa->fLogicalOrder && psa->fRTL)
3123 finaGlyph = cGlyphs-1;
3127 for (i = 0; i < cGlyphs; i++)
3129 for (k = 0; k < cChars; k++)
3130 if (pwLogClust[k] == i)
3132 if (pwcChars[k] == 0x0020)
3137 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3139 for (i = 0; i < cGlyphs; i++)
3144 for (k = 0; k < cChars; k++)
3146 if (pwLogClust[k] == i)
3148 char_index[char_count] = k;
3153 if (char_count == 0)
3156 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3158 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3159 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3161 else if (i == finaGlyph)
3162 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3164 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3166 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3167 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3168 pGlyphProp[i].sva.fClusterStart = 0;
3171 HeapFree(GetProcessHeap(),0,spaces);
3172 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3174 /* Do not allow justification between marks and their base */
3175 for (i = 0; i < cGlyphs; i++)
3177 if (!pGlyphProp[i].sva.fClusterStart)
3178 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3182 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)
3186 for (i = 0; i < cGlyphs; i++)
3191 for (k = 0; k < cChars; k++)
3193 if (pwLogClust[k] == i)
3195 char_index[char_count] = k;
3200 if (char_count == 0)
3203 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3205 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3206 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3209 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3211 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3212 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3215 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)
3219 for (i = 0; i < cGlyphs; i++)
3224 for (k = 0; k < cChars; k++)
3226 if (pwLogClust[k] == i)
3228 char_index[char_count] = k;
3233 if (char_count == 0)
3236 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3238 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3239 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3242 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3244 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3245 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3247 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3248 for (i = 0; i < cGlyphs; i++)
3250 if (!pGlyphProp[i].sva.fClusterStart)
3252 pGlyphProp[i].sva.fDiacritic = 0;
3253 pGlyphProp[i].sva.fZeroWidth = 0;
3258 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)
3262 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3263 for (i = 0; i < cGlyphs; i++)
3268 for (k = 0; k < cChars; k++)
3270 if (pwLogClust[k] == i)
3272 char_index[char_count] = k;
3277 /* Indic scripts do not set fDiacritic or fZeroWidth */
3278 pGlyphProp[i].sva.fDiacritic = FALSE;
3279 pGlyphProp[i].sva.fZeroWidth = FALSE;
3281 if (char_count == 0)
3284 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3286 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3287 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3290 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3292 pGlyphProp[i].sva.fClusterStart = 0;
3293 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3294 switch (lexical(pwcChars[char_index[k]]))
3297 case lex_Matra_post:
3298 case lex_Matra_above:
3299 case lex_Matra_below:
3308 pGlyphProp[i].sva.fClusterStart = 1;
3315 IndicSyllable *syllables = NULL;
3316 int syllable_count = 0;
3317 BOOL modern = get_GSUB_Indic2(psa, psc);
3319 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3321 for (i = 0; i < syllable_count; i++)
3324 WORD g = pwLogClust[syllables[i].start];
3325 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3327 if (pwLogClust[j] != g)
3329 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3335 HeapFree(GetProcessHeap(), 0, syllables);
3338 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3341 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 )
3343 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex, FALSE);
3346 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 )
3348 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex, TRUE);
3351 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 )
3353 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex, TRUE);
3356 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 )
3358 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex, TRUE);
3361 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 )
3363 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex, TRUE);
3366 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 )
3368 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex, TRUE);
3371 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 )
3373 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex, TRUE);
3376 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 )
3378 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex, TRUE);
3381 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 )
3383 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex, TRUE);
3386 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 )
3388 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex, TRUE);
3391 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)
3393 if (ShapingData[psa->eScript].charGlyphPropProc)
3394 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3396 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3399 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3401 if (!psc->GSUB_Table)
3402 psc->GSUB_Table = load_gsub_table(hdc);
3404 if (ShapingData[psa->eScript].contextProc)
3405 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3408 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)
3413 if (!rpRangeProperties)
3416 if (!psc->GSUB_Table)
3417 psc->GSUB_Table = load_gsub_table(hdc);
3419 if (!psc->GSUB_Table)
3422 if (!psa->fLogicalOrder && psa->fRTL)
3427 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3429 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3430 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3434 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3436 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3437 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3439 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3442 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3444 const GSUB_Feature *feature;
3447 if (!ShapingData[psa->eScript].requiredFeatures)
3450 if (!psc->GSUB_Table)
3451 psc->GSUB_Table = load_gsub_table(hdc);
3453 /* we need to have at least one of the required features */
3455 while (ShapingData[psa->eScript].requiredFeatures[i])
3457 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3463 return USP_E_SCRIPT_NOT_IN_FONT;