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;
1363 if (changeCount > 0)
1366 target_glyph = nextIndex - changeCount;
1368 target_glyph = nextIndex + (changeCount + 1);
1371 seeking_glyph = target_glyph;
1375 for (i = 0; i < chars; i++)
1377 if (pwLogClust[i] == seeking_glyph)
1384 for (i = chars - 1; i >= 0; i--)
1386 if (pwLogClust[i] == seeking_glyph)
1392 if (target_index == -1)
1395 while (target_index == -1 && seeking_glyph < chars);
1397 if (target_index == -1)
1399 ERR("Unable to find target glyph\n");
1403 if (changeCount < 0)
1406 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1408 if (pwLogClust[i] == target_glyph)
1410 if(pwLogClust[i] == replacing_glyph)
1411 pwLogClust[i] = target_glyph;
1415 if (changed >= changeCount)
1417 replacing_glyph = pwLogClust[i];
1418 pwLogClust[i] = target_glyph;
1425 /* renumber trailing indexes*/
1426 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1428 if (pwLogClust[i] != target_glyph)
1429 pwLogClust[i] += changeCount;
1434 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1435 pwLogClust[i] += changeCount;
1440 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 )
1442 if (psc->GSUB_Table)
1444 const GSUB_Feature *feature;
1445 const GSUB_LookupList *lookup;
1446 const GSUB_Header *header = psc->GSUB_Table;
1447 int lookup_index, lookup_count;
1449 feature = load_GSUB_feature(hdc, psa, psc, feat);
1451 return GSUB_E_NOFEATURE;
1453 TRACE("applying feature %s\n",debugstr_an(feat,4));
1454 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1455 lookup_count = GET_BE_WORD(feature->LookupCount);
1456 TRACE("%i lookups\n", lookup_count);
1457 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1465 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1466 while(i < *pcGlyphs && i >= 0)
1469 INT prevCount = *pcGlyphs;
1471 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1472 if (*pcGlyphs != prevCount)
1474 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1483 return GSUB_E_NOFEATURE;
1486 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1488 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1491 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1495 if ( i+ delta >= cchLen)
1503 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1507 if (psa->fLinkBefore)
1512 if ( i+ delta >= cchLen)
1514 if (psa->fLinkAfter)
1522 if (context_type[i] == jtT)
1523 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1525 return context_type[i];
1528 static inline BOOL right_join_causing(CHAR joining_type)
1530 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1533 static inline BOOL left_join_causing(CHAR joining_type)
1535 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1538 static inline BOOL word_break_causing(WCHAR chr)
1540 /* we are working within a string of characters already guareented to
1541 be within one script, Syriac, so we do not worry about any character
1542 other than the space character outside of that range */
1543 return (chr == 0 || chr == 0x20 );
1547 * ContextualShape_Arabic
1549 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1556 if (*pcGlyphs != cChars)
1558 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1562 if (!psa->fLogicalOrder && psa->fRTL)
1573 if (!psc->GSUB_Table)
1574 psc->GSUB_Table = load_gsub_table(hdc);
1576 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1577 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1579 for (i = 0; i < cChars; i++)
1580 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1582 for (i = 0; i < cChars; i++)
1584 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1585 context_shape[i] = Xr;
1586 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1587 context_shape[i] = Xl;
1588 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)))
1589 context_shape[i] = Xm;
1590 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1591 context_shape[i] = Xr;
1592 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1593 context_shape[i] = Xl;
1595 context_shape[i] = Xn;
1598 /* Contextual Shaping */
1600 while(i < *pcGlyphs)
1602 BOOL shaped = FALSE;
1604 if (psc->GSUB_Table)
1607 INT prevCount = *pcGlyphs;
1608 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1609 if (nextIndex > GSUB_E_NOGLYPH)
1612 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1614 shaped = (nextIndex > GSUB_E_NOGLYPH);
1619 if (context_shape[i] == Xn)
1621 WORD newGlyph = pwOutGlyphs[i];
1622 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1624 /* fall back to presentation form B */
1625 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1626 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1627 pwOutGlyphs[i] = newGlyph;
1634 HeapFree(GetProcessHeap(),0,context_shape);
1635 HeapFree(GetProcessHeap(),0,context_type);
1639 * ContextualShape_Syriac
1643 #define DALATH 0x715
1646 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1653 if (*pcGlyphs != cChars)
1655 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1659 if (!psa->fLogicalOrder && psa->fRTL)
1670 if (!psc->GSUB_Table)
1671 psc->GSUB_Table = load_gsub_table(hdc);
1673 if (!psc->GSUB_Table)
1676 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1677 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1679 for (i = 0; i < cChars; i++)
1680 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1682 for (i = 0; i < cChars; i++)
1684 if (pwcChars[i] == ALAPH)
1686 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1688 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1689 context_shape[i] = Afj;
1690 else if ( rchar != DALATH && rchar != RISH &&
1691 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1692 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1693 context_shape[i] = Afn;
1694 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1695 context_shape[i] = Afx;
1697 context_shape[i] = Xn;
1699 else if (context_type[i] == jtR &&
1700 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1701 context_shape[i] = Xr;
1702 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1703 context_shape[i] = Xl;
1704 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)))
1705 context_shape[i] = Xm;
1706 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1707 context_shape[i] = Xr;
1708 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1709 context_shape[i] = Xl;
1711 context_shape[i] = Xn;
1714 /* Contextual Shaping */
1716 while(i < *pcGlyphs)
1719 INT prevCount = *pcGlyphs;
1720 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1721 if (nextIndex > GSUB_E_NOGLYPH)
1723 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1730 HeapFree(GetProcessHeap(),0,context_shape);
1731 HeapFree(GetProcessHeap(),0,context_type);
1735 * ContextualShape_Phags_pa
1738 #define phags_pa_CANDRABINDU 0xA873
1739 #define phags_pa_START 0xA840
1740 #define phags_pa_END 0xA87F
1742 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1748 if (*pcGlyphs != cChars)
1750 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1754 if (!psa->fLogicalOrder && psa->fRTL)
1765 if (!psc->GSUB_Table)
1766 psc->GSUB_Table = load_gsub_table(hdc);
1768 if (!psc->GSUB_Table)
1771 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1773 for (i = 0; i < cChars; i++)
1775 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1777 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1778 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1779 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1780 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1782 if (jrchar && jlchar)
1783 context_shape[i] = Xm;
1785 context_shape[i] = Xr;
1787 context_shape[i] = Xl;
1789 context_shape[i] = Xn;
1792 context_shape[i] = -1;
1795 /* Contextual Shaping */
1797 while(i < *pcGlyphs)
1799 if (context_shape[i] >= 0)
1802 INT prevCount = *pcGlyphs;
1803 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1804 if (nextIndex > GSUB_E_NOGLYPH)
1806 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1816 HeapFree(GetProcessHeap(),0,context_shape);
1819 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1824 pwOutChars[cWalk] = replacements[0];
1828 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1831 for (j = *pcChars; j > cWalk; j--)
1832 pwOutChars[j] = pwOutChars[j-1];
1833 *pcChars= *pcChars+1;
1834 pwOutChars[cWalk] = replacements[i];
1839 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust)
1845 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1847 for (i = 0; vowels[i].base != 0x0; i++)
1849 if (pwOutChars[cWalk] == vowels[i].base)
1853 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1854 if (vowels[i].parts[1]) { cWalk++; o++; }
1855 if (vowels[i].parts[2]) { cWalk++; o++; }
1857 for (j = (cWalk - offset) + 1; j < *pcChars - offset; j ++)
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);
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);
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 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2629 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2630 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2631 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2632 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2633 {{0x0000,0x0000,0x0000}, 0x0000}};
2635 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2637 int cCount = cChars;
2639 IndicSyllable *syllables = NULL;
2640 int syllable_count = 0;
2641 BOOL modern = get_GSUB_Indic2(psa, psc);
2643 if (*pcGlyphs != cChars)
2645 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2649 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2650 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2652 /* Step 1: Compose Consonents */
2653 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2654 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2656 /* Step 2: Reorder within Syllables */
2657 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2658 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2659 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2662 /* Step 3: Base Form application to syllables */
2663 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2665 HeapFree(GetProcessHeap(),0,input);
2666 HeapFree(GetProcessHeap(),0,syllables);
2669 static int gujarati_lex(WCHAR c)
2673 case 0x0AB0: return lex_Ra;
2675 return unicode_lex(c);
2679 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2681 int cCount = cChars;
2683 IndicSyllable *syllables = NULL;
2684 int syllable_count = 0;
2685 BOOL modern = get_GSUB_Indic2(psa, psc);
2687 if (*pcGlyphs != cChars)
2689 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2693 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2694 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2696 /* Step 1: Reorder within Syllables */
2697 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2698 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2699 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2702 /* Step 2: Base Form application to syllables */
2703 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2705 HeapFree(GetProcessHeap(),0,input);
2706 HeapFree(GetProcessHeap(),0,syllables);
2709 static int oriya_lex(WCHAR c)
2713 case 0x0B30: return lex_Ra;
2715 return unicode_lex(c);
2719 static const VowelComponents Oriya_vowels[] = {
2720 {0x0B48, {0x0B47,0x0B56,0x0000}},
2721 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2722 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2723 {0x0000, {0x0000,0x0000,0x0000}}};
2725 static const ConsonantComponents Oriya_consonants[] = {
2726 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2727 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2728 {{0x0000,0x0000,0x0000}, 0x0000}};
2730 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2732 int cCount = cChars;
2734 IndicSyllable *syllables = NULL;
2735 int syllable_count = 0;
2736 BOOL modern = get_GSUB_Indic2(psa, psc);
2738 if (*pcGlyphs != cChars)
2740 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2744 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2745 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2747 /* Step 1: Decompose Vowels and Compose Consonents */
2748 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust);
2749 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2750 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2752 /* Step 2: Reorder within Syllables */
2753 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2754 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2755 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2758 /* Step 3: Base Form application to syllables */
2759 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2761 HeapFree(GetProcessHeap(),0,input);
2762 HeapFree(GetProcessHeap(),0,syllables);
2765 static int tamil_lex(WCHAR c)
2767 return unicode_lex(c);
2770 static const VowelComponents Tamil_vowels[] = {
2771 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2772 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2773 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2774 {0x0000, {0x0000,0x0000,0x0000}}};
2776 static const ConsonantComponents Tamil_consonants[] = {
2777 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2778 {{0x0000,0x0000,0x0000}, 0x0000}};
2780 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2782 int cCount = cChars;
2784 IndicSyllable *syllables = NULL;
2785 int syllable_count = 0;
2786 BOOL modern = get_GSUB_Indic2(psa, psc);
2788 if (*pcGlyphs != cChars)
2790 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2794 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2795 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2797 /* Step 1: Decompose Vowels and Compose Consonents */
2798 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust);
2799 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2800 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2802 /* Step 2: Reorder within Syllables */
2803 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2804 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2805 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2808 /* Step 3: Base Form application to syllables */
2809 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2811 HeapFree(GetProcessHeap(),0,input);
2812 HeapFree(GetProcessHeap(),0,syllables);
2815 static int telugu_lex(WCHAR c)
2820 case 0x0C44: return lex_Modifier;
2822 return unicode_lex(c);
2826 static const VowelComponents Telugu_vowels[] = {
2827 {0x0C48, {0x0C46,0x0C56,0x0000}},
2828 {0x0000, {0x0000,0x0000,0x0000}}};
2830 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2832 int cCount = cChars;
2834 IndicSyllable *syllables = NULL;
2835 int syllable_count = 0;
2836 BOOL modern = get_GSUB_Indic2(psa, psc);
2838 if (*pcGlyphs != cChars)
2840 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2844 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2845 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2847 /* Step 1: Decompose Vowels */
2848 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust);
2849 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2851 /* Step 2: Reorder within Syllables */
2852 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2853 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2854 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2857 /* Step 3: Base Form application to syllables */
2858 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2860 HeapFree(GetProcessHeap(),0,input);
2861 HeapFree(GetProcessHeap(),0,syllables);
2864 static int kannada_lex(WCHAR c)
2868 case 0x0CB0: return lex_Ra;
2870 return unicode_lex(c);
2874 static const VowelComponents Kannada_vowels[] = {
2875 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2876 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2877 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2878 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2879 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2880 {0x0000, {0x0000,0x0000,0x0000}}};
2882 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2884 int cCount = cChars;
2886 IndicSyllable *syllables = NULL;
2887 int syllable_count = 0;
2888 BOOL modern = get_GSUB_Indic2(psa, psc);
2890 if (*pcGlyphs != cChars)
2892 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2896 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2897 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2899 /* Step 1: Decompose Vowels */
2900 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust);
2901 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2903 /* Step 2: Reorder within Syllables */
2904 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2905 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2906 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2909 /* Step 3: Base Form application to syllables */
2910 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2912 HeapFree(GetProcessHeap(),0,input);
2913 HeapFree(GetProcessHeap(),0,syllables);
2916 static int malayalam_lex(WCHAR c)
2918 return unicode_lex(c);
2921 static const VowelComponents Malayalam_vowels[] = {
2922 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2923 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2924 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2925 {0x0000, {0x0000,0x0000,0x0000}}};
2927 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2929 int cCount = cChars;
2931 IndicSyllable *syllables = NULL;
2932 int syllable_count = 0;
2933 BOOL modern = get_GSUB_Indic2(psa, psc);
2935 if (*pcGlyphs != cChars)
2937 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2941 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2942 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2944 /* Step 1: Decompose Vowels */
2945 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust);
2946 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2948 /* Step 2: Reorder within Syllables */
2949 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2950 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2951 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2954 /* Step 3: Base Form application to syllables */
2955 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2957 HeapFree(GetProcessHeap(),0,input);
2958 HeapFree(GetProcessHeap(),0,syllables);
2961 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)
2965 for (i = 0; i < cGlyphs; i++)
2970 for (k = 0; k < cChars; k++)
2972 if (pwLogClust[k] == i)
2974 char_index[char_count] = k;
2979 if (char_count == 0)
2982 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2984 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2985 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2988 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2991 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
2992 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2995 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 )
2998 int initGlyph, finaGlyph;
3002 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3003 memset(spaces,0,cGlyphs);
3005 if (!psa->fLogicalOrder && psa->fRTL)
3007 initGlyph = cGlyphs-1;
3015 finaGlyph = cGlyphs-1;
3020 for (i = 0; i < cGlyphs; i++)
3022 for (k = 0; k < cChars; k++)
3023 if (pwLogClust[k] == i)
3025 if (pwcChars[k] == 0x0020)
3030 for (i = 0; i < cGlyphs; i++)
3034 BOOL isInit, isFinal;
3036 for (k = 0; k < cChars; k++)
3038 if (pwLogClust[k] == i)
3040 char_index[char_count] = k;
3045 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3046 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3048 if (char_count == 0)
3051 if (char_count == 1)
3053 if (pwcChars[char_index[0]] == 0x0020) /* space */
3055 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3056 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3058 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3059 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3060 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3062 if (!isInit && !isFinal)
3063 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3065 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3067 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3071 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3072 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3073 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3074 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3075 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3076 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3077 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3078 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3080 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3082 else if (!isInit && !isFinal)
3083 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3085 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3087 else if (char_count == 2)
3089 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3090 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3092 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3094 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3096 else if (!isInit && !isFinal)
3097 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3099 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3102 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3103 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3104 HeapFree(GetProcessHeap(),0,spaces);
3107 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 )
3114 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3115 memset(spaces,0,cGlyphs);
3117 if (!psa->fLogicalOrder && psa->fRTL)
3124 finaGlyph = cGlyphs-1;
3128 for (i = 0; i < cGlyphs; i++)
3130 for (k = 0; k < cChars; k++)
3131 if (pwLogClust[k] == i)
3133 if (pwcChars[k] == 0x0020)
3138 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3140 for (i = 0; i < cGlyphs; i++)
3145 for (k = 0; k < cChars; k++)
3147 if (pwLogClust[k] == i)
3149 char_index[char_count] = k;
3154 if (char_count == 0)
3157 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3159 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3160 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3162 else if (i == finaGlyph)
3163 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3165 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3167 /* handle Thai SARA AM (U+0E33) differently than GDEF */
3168 if (char_count == 1 && pwcChars[char_index[0]] == 0x0e33)
3169 pGlyphProp[i].sva.fClusterStart = 0;
3172 HeapFree(GetProcessHeap(),0,spaces);
3173 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3175 /* Do not allow justification between marks and their base */
3176 for (i = 0; i < cGlyphs; i++)
3178 if (!pGlyphProp[i].sva.fClusterStart)
3179 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3183 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)
3187 for (i = 0; i < cGlyphs; i++)
3192 for (k = 0; k < cChars; k++)
3194 if (pwLogClust[k] == i)
3196 char_index[char_count] = k;
3201 if (char_count == 0)
3204 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3206 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3207 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3210 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3212 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3213 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3216 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)
3220 for (i = 0; i < cGlyphs; i++)
3225 for (k = 0; k < cChars; k++)
3227 if (pwLogClust[k] == i)
3229 char_index[char_count] = k;
3234 if (char_count == 0)
3237 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3239 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3240 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3243 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3245 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, cChars, pGlyphProp);
3246 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3248 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3249 for (i = 0; i < cGlyphs; i++)
3251 if (!pGlyphProp[i].sva.fClusterStart)
3253 pGlyphProp[i].sva.fDiacritic = 0;
3254 pGlyphProp[i].sva.fZeroWidth = 0;
3259 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)
3262 IndicSyllable *syllables = NULL;
3263 int syllable_count = 0;
3264 BOOL modern = get_GSUB_Indic2(psa, psc);
3266 for (i = 0; i < cGlyphs; i++)
3271 for (k = 0; k < cChars; k++)
3273 if (pwLogClust[k] == i)
3275 char_index[char_count] = k;
3280 if (char_count == 0)
3282 FIXME("No chars in this glyph? Must be an error\n");
3286 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3288 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3289 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3292 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3294 pGlyphProp[i].sva.fClusterStart = 0;
3295 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3296 switch (lexical(pwcChars[char_index[k]]))
3299 case lex_Matra_post:
3300 case lex_Matra_above:
3301 case lex_Matra_below:
3305 pGlyphProp[i].sva.fClusterStart = 1;
3310 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3312 for (i = 0; i < syllable_count; i++)
3315 WORD g = pwLogClust[syllables[i].start];
3316 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3318 if (pwLogClust[j] != g)
3320 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3326 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3327 HeapFree(GetProcessHeap(), 0, syllables);
3330 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 )
3332 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex);
3335 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 )
3337 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3340 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 )
3342 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3345 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 )
3347 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3350 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 )
3352 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3355 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 )
3357 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3360 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 )
3362 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3365 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 )
3367 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3370 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 )
3372 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3375 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 )
3377 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3380 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)
3382 if (ShapingData[psa->eScript].charGlyphPropProc)
3383 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3385 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3388 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3390 if (ShapingData[psa->eScript].contextProc)
3391 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3394 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)
3399 if (!rpRangeProperties)
3402 if (!psc->GSUB_Table)
3403 psc->GSUB_Table = load_gsub_table(hdc);
3405 if (!psc->GSUB_Table)
3408 if (!psa->fLogicalOrder && psa->fRTL)
3413 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3415 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3416 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3420 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3422 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3423 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3425 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3428 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3430 const GSUB_Feature *feature;
3433 if (!ShapingData[psa->eScript].requiredFeatures)
3436 if (!psc->GSUB_Table)
3437 psc->GSUB_Table = load_gsub_table(hdc);
3439 /* we need to have at least one of the required features */
3441 while (ShapingData[psa->eScript].requiredFeatures[i])
3443 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3449 return USP_E_SCRIPT_NOT_IN_FONT;