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 thai_features[] =
413 { MS_MAKE_TAG('c','c','m','p'), 1},
416 static const char* required_lao_features[] =
422 static const char* required_devanagari_features[] =
438 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
440 { MS_MAKE_TAG('p','r','e','s'), 1},
441 { MS_MAKE_TAG('a','b','v','s'), 1},
442 { MS_MAKE_TAG('b','l','w','s'), 1},
443 { MS_MAKE_TAG('p','s','t','s'), 1},
444 { MS_MAKE_TAG('h','a','l','n'), 1},
445 { MS_MAKE_TAG('c','a','l','t'), 1},
448 static const char* required_bengali_features[] =
465 static const char* required_gurmukhi_features[] =
484 static const char* required_oriya_features[] =
501 static const char* required_tamil_features[] =
517 static const char* required_telugu_features[] =
535 typedef struct ScriptShapeDataTag {
536 TEXTRANGE_PROPERTIES defaultTextRange;
537 const char** requiredFeatures;
540 ContextualShapingProc contextProc;
541 ShapeCharGlyphPropProc charGlyphPropProc;
544 /* in order of scripts */
545 static const ScriptShapeData ShapingData[] =
547 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
548 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
549 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
550 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
551 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
552 {{ latin_features, 2}, NULL, "latn", "", NULL, NULL},
553 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
554 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
555 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
556 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
557 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
558 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
559 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
560 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
561 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
562 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
563 {{ sinhala_features, 3}, NULL, "sinh", "", ContextualShape_Sinhala, ShapeCharGlyphProp_Sinhala},
564 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
565 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
566 {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
567 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
568 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
569 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
570 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
571 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
572 {{ devanagari_features, 6}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
573 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
574 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
575 {{ devanagari_features, 6}, required_bengali_features, "beng", "bng2", ContextualShape_Bengali, ShapeCharGlyphProp_Bengali},
576 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
577 {{ devanagari_features, 6}, required_gurmukhi_features, "guru", "gur2", ContextualShape_Gurmukhi, ShapeCharGlyphProp_Gurmukhi},
578 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
579 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
580 {{ devanagari_features, 6}, required_devanagari_features, "gujr", "gjr2", ContextualShape_Gujarati, ShapeCharGlyphProp_Gujarati},
581 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
582 {{ devanagari_features, 6}, required_oriya_features, "orya", "ory2", ContextualShape_Oriya, ShapeCharGlyphProp_Oriya},
583 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
584 {{ devanagari_features, 6}, required_tamil_features, "taml", "tam2", ContextualShape_Tamil, ShapeCharGlyphProp_Tamil},
585 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
586 {{ devanagari_features, 6}, required_telugu_features, "telu", "tel2", ContextualShape_Telugu, ShapeCharGlyphProp_Telugu},
587 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
588 {{ devanagari_features, 6}, required_telugu_features, "knda", "knd2", ContextualShape_Kannada, ShapeCharGlyphProp_Kannada},
589 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
590 {{ devanagari_features, 6}, required_telugu_features, "mlym", "mlm2", ContextualShape_Malayalam, ShapeCharGlyphProp_Malayalam},
591 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
592 {{ latin_features, 2}, NULL, "latn" , "", NULL, NULL},
593 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
596 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
598 const GSUB_CoverageFormat1* cf1;
602 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
604 int count = GET_BE_WORD(cf1->GlyphCount);
606 TRACE("Coverage Format 1, %i glyphs\n",count);
607 for (i = 0; i < count; i++)
608 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
612 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
614 const GSUB_CoverageFormat2* cf2;
617 cf2 = (const GSUB_CoverageFormat2*)cf1;
619 count = GET_BE_WORD(cf2->RangeCount);
620 TRACE("Coverage Format 2, %i ranges\n",count);
621 for (i = 0; i < count; i++)
623 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
625 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
626 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
628 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
629 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
635 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
640 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
642 const GSUB_ScriptList *script;
643 const GSUB_Script *deflt = NULL;
645 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
647 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
648 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
650 const GSUB_Script *scr;
653 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
654 scr = (const GSUB_Script*)((const BYTE*)script + offset);
656 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
658 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
664 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
668 const GSUB_LangSys *Lang;
670 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
672 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
674 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
675 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
677 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
680 offset = GET_BE_WORD(script->DefaultLangSys);
683 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
689 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
692 const GSUB_FeatureList *feature;
693 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
695 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
696 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
698 int index = GET_BE_WORD(lang->FeatureIndex[i]);
699 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
701 const GSUB_Feature *feat;
702 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
709 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
712 TRACE("Single Substitution Subtable\n");
714 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
717 const GSUB_SingleSubstFormat1 *ssf1;
718 offset = GET_BE_WORD(look->SubTable[j]);
719 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
720 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
722 int offset = GET_BE_WORD(ssf1->Coverage);
723 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
724 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
726 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
727 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
728 TRACE(" 0x%x\n",glyphs[glyph_index]);
729 return glyph_index + write_dir;
734 const GSUB_SingleSubstFormat2 *ssf2;
738 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
739 offset = GET_BE_WORD(ssf1->Coverage);
740 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
741 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
742 TRACE(" Coverage index %i\n",index);
745 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
746 return GSUB_E_NOGLYPH;
748 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
749 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
750 TRACE("0x%x\n",glyphs[glyph_index]);
751 return glyph_index + write_dir;
755 return GSUB_E_NOGLYPH;
758 static INT GSUB_apply_MultipleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
761 TRACE("Multiple Substitution Subtable\n");
763 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
766 const GSUB_MultipleSubstFormat1 *msf1;
767 offset = GET_BE_WORD(look->SubTable[j]);
768 msf1 = (const GSUB_MultipleSubstFormat1*)((const BYTE*)look+offset);
770 offset = GET_BE_WORD(msf1->Coverage);
771 index = GSUB_is_glyph_covered((const BYTE*)msf1+offset, glyphs[glyph_index]);
774 const GSUB_Sequence *seq;
777 offset = GET_BE_WORD(msf1->Sequence[index]);
778 seq = (const GSUB_Sequence*)((const BYTE*)msf1+offset);
779 sub_count = GET_BE_WORD(seq->GlyphCount);
780 TRACE(" Glyph 0x%x (+%i)->",glyphs[glyph_index],(sub_count-1));
782 for (j = (*glyph_count)+(sub_count-1); j > glyph_index; j--)
783 glyphs[j] =glyphs[j-(sub_count-1)];
785 for (j = 0; j < sub_count; j++)
787 glyphs[glyph_index + (sub_count-1) - j] = GET_BE_WORD(seq->Substitute[j]);
789 glyphs[glyph_index + j] = GET_BE_WORD(seq->Substitute[j]);
791 *glyph_count = *glyph_count + (sub_count - 1);
793 if (TRACE_ON(uniscribe))
795 for (j = 0; j < sub_count; j++)
796 TRACE(" 0x%x",glyphs[glyph_index+j]);
800 return glyph_index + (sub_count * write_dir);
803 return GSUB_E_NOGLYPH;
806 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
809 TRACE("Alternate Substitution Subtable\n");
811 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
814 const GSUB_AlternateSubstFormat1 *asf1;
817 offset = GET_BE_WORD(look->SubTable[j]);
818 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
819 offset = GET_BE_WORD(asf1->Coverage);
821 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
824 const GSUB_AlternateSet *as;
825 offset = GET_BE_WORD(asf1->AlternateSet[index]);
826 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
827 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
828 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
829 return GSUB_E_NOGLYPH;
831 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
832 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
833 TRACE(" 0x%x\n",glyphs[glyph_index]);
834 return glyph_index + write_dir;
837 return GSUB_E_NOGLYPH;
840 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
844 TRACE("Ligature Substitution Subtable\n");
845 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
847 const GSUB_LigatureSubstFormat1 *lsf1;
850 offset = GET_BE_WORD(look->SubTable[j]);
851 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
852 offset = GET_BE_WORD(lsf1->Coverage);
853 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
854 TRACE(" Coverage index %i\n",index);
857 const GSUB_LigatureSet *ls;
860 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
861 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
862 count = GET_BE_WORD(ls->LigatureCount);
863 TRACE(" LigatureSet has %i members\n",count);
864 for (k = 0; k < count; k++)
866 const GSUB_Ligature *lig;
867 int CompCount,l,CompIndex;
869 offset = GET_BE_WORD(ls->Ligature[k]);
870 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
871 CompCount = GET_BE_WORD(lig->CompCount) - 1;
872 CompIndex = glyph_index+write_dir;
873 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
876 CompGlyph = GET_BE_WORD(lig->Component[l]);
877 if (CompGlyph != glyphs[CompIndex])
879 CompIndex += write_dir;
883 int replaceIdx = glyph_index;
885 replaceIdx = glyph_index - CompCount;
887 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
888 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
889 TRACE("0x%x\n",glyphs[replaceIdx]);
893 for (j = replaceIdx + 1; j < *glyph_count; j++)
894 glyphs[j] =glyphs[j+CompCount];
895 *glyph_count = *glyph_count - CompCount;
897 return replaceIdx + write_dir;
902 return GSUB_E_NOGLYPH;
905 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
910 TRACE("Chaining Contextual Substitution Subtable\n");
911 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
913 const GSUB_ChainContextSubstFormat1 *ccsf1;
915 int dirLookahead = write_dir;
916 int dirBacktrack = -1 * write_dir;
918 offset = GET_BE_WORD(look->SubTable[j]);
919 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
920 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
922 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
925 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
927 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
930 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
934 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
935 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
936 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
937 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
938 int newIndex = glyph_index;
940 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
942 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
944 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
946 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
947 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
950 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
952 TRACE("Matched Backtrack\n");
954 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
956 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
957 for (k = 0; k < indexGlyphs; k++)
959 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
960 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
963 if (k != indexGlyphs)
965 TRACE("Matched IndexGlyphs\n");
967 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
969 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
971 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
972 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
975 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
977 TRACE("Matched LookAhead\n");
979 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
981 if (GET_BE_WORD(ccsf3_4->SubstCount))
983 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
985 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
986 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
988 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
989 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
992 ERR("Chain failed to generate a glyph\n");
998 else return GSUB_E_NOGLYPH;
1004 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
1007 const GSUB_LookupTable *look;
1009 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
1010 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
1011 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
1012 switch(GET_BE_WORD(look->LookupType))
1015 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1017 return GSUB_apply_MultipleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1019 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1021 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
1023 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
1025 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
1027 return GSUB_E_NOGLYPH;
1030 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)
1033 int out_index = GSUB_E_NOGLYPH;
1034 const GSUB_LookupList *lookup;
1036 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1038 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
1039 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
1041 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
1042 if (out_index != GSUB_E_NOGLYPH)
1045 if (out_index == GSUB_E_NOGLYPH)
1046 TRACE("lookups found no glyphs\n");
1050 out2 = GSUB_apply_feature_all_lookups(header, feature, glyphs, glyph_index, write_dir, glyph_count);
1051 if (out2!=GSUB_E_NOGLYPH)
1057 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
1061 if (psc->userScript != 0)
1063 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
1064 return ShapingData[psa->eScript].newOtTag;
1066 return (char*)&psc->userScript;
1069 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
1070 return ShapingData[psa->eScript].newOtTag;
1072 if (ShapingData[psa->eScript].otTag[0] != 0)
1073 return ShapingData[psa->eScript].otTag;
1076 * fall back to the font charset
1078 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
1081 case ANSI_CHARSET: return "latn";
1082 case BALTIC_CHARSET: return "latn"; /* ?? */
1083 case CHINESEBIG5_CHARSET: return "hani";
1084 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
1085 case GB2312_CHARSET: return "hani";
1086 case GREEK_CHARSET: return "grek";
1087 case HANGUL_CHARSET: return "hang";
1088 case RUSSIAN_CHARSET: return "cyrl";
1089 case SHIFTJIS_CHARSET: return "kana";
1090 case TURKISH_CHARSET: return "latn"; /* ?? */
1091 case VIETNAMESE_CHARSET: return "latn";
1092 case JOHAB_CHARSET: return "latn"; /* ?? */
1093 case ARABIC_CHARSET: return "arab";
1094 case HEBREW_CHARSET: return "hebr";
1095 case THAI_CHARSET: return "thai";
1096 default: return "latn";
1100 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
1102 const GSUB_Feature *feature;
1106 script = get_opentype_script(hdc,psa,psc,FALSE);
1108 for (i = 0; i < psc->feature_count; i++)
1110 if (strncmp(psc->features[i].tag,feat,4)==0 && strncmp(psc->features[i].script,script,4)==0)
1111 return psc->features[i].feature;
1116 if (psc->GSUB_Table)
1118 const GSUB_Script *script;
1119 const GSUB_LangSys *language;
1124 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
1128 if (psc->userLang != 0)
1129 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
1131 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1133 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1135 } while(attempt && !feature);
1137 /* try in the default (latin) table */
1140 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
1143 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
1145 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
1150 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
1152 psc->feature_count++;
1155 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
1157 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
1159 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
1160 lstrcpynA(psc->features[psc->feature_count - 1].script, script, 5);
1161 psc->features[psc->feature_count - 1].feature = feature;
1165 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)
1167 const GSUB_Feature *feature;
1169 feature = load_GSUB_feature(hdc, psa, psc, feat);
1171 return GSUB_E_NOFEATURE;
1173 TRACE("applying feature %s\n",feat);
1174 return GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
1177 static VOID *load_gsub_table(HDC hdc)
1179 VOID* GSUB_Table = NULL;
1180 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
1181 if (length != GDI_ERROR)
1183 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
1184 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
1185 TRACE("Loaded GSUB table of %i bytes\n",length);
1190 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)
1193 INT glyph_count = count;
1196 glyphs = HeapAlloc(GetProcessHeap(),0,sizeof(WORD)*(count*2));
1197 GetGlyphIndicesW(hdc, chars, count, glyphs, 0);
1198 rc = apply_GSUB_feature_to_glyph(hdc, psa, psc, glyphs, 0, write_dir, &glyph_count, feature);
1199 if (rc > GSUB_E_NOGLYPH)
1200 rc = count - glyph_count;
1204 HeapFree(GetProcessHeap(),0,glyphs);
1208 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1212 const GDEF_ClassDefFormat1 *cf1;
1217 offset = GET_BE_WORD(header->GlyphClassDef);
1221 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1222 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1224 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1226 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1227 if (index < GET_BE_WORD(cf1->GlyphCount))
1228 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1231 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1233 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1235 top = GET_BE_WORD(cf2->ClassRangeCount);
1236 for (i = 0; i < top; i++)
1238 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1239 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1241 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1247 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1252 static VOID *load_gdef_table(HDC hdc)
1254 VOID* GDEF_Table = NULL;
1255 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1256 if (length != GDI_ERROR)
1258 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1259 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1260 TRACE("Loaded GDEF table of %i bytes\n",length);
1265 static void GDEF_UpdateGlyphProps(HDC hdc, ScriptCache *psc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1269 if (!psc->GDEF_Table)
1270 psc->GDEF_Table = load_gdef_table(hdc);
1272 for (i = 0; i < cGlyphs; i++)
1276 class = GDEF_get_glyph_class(psc->GDEF_Table, pwGlyphs[i]);
1282 pGlyphProp[i].sva.fClusterStart = 1;
1283 pGlyphProp[i].sva.fDiacritic = 0;
1284 pGlyphProp[i].sva.fZeroWidth = 0;
1287 pGlyphProp[i].sva.fClusterStart = 1;
1288 pGlyphProp[i].sva.fDiacritic = 0;
1289 pGlyphProp[i].sva.fZeroWidth = 0;
1292 pGlyphProp[i].sva.fClusterStart = 0;
1293 pGlyphProp[i].sva.fDiacritic = 1;
1294 pGlyphProp[i].sva.fZeroWidth = 1;
1296 case ComponentGlyph:
1297 pGlyphProp[i].sva.fClusterStart = 0;
1298 pGlyphProp[i].sva.fDiacritic = 0;
1299 pGlyphProp[i].sva.fZeroWidth = 0;
1302 ERR("Unknown glyph class %i\n",class);
1303 pGlyphProp[i].sva.fClusterStart = 1;
1304 pGlyphProp[i].sva.fDiacritic = 0;
1305 pGlyphProp[i].sva.fZeroWidth = 0;
1310 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1314 for (i = 0; i < cGlyphs; i++)
1316 if (!pGlyphProp[i].sva.fClusterStart)
1319 for (j = 0; j < cChars; j++)
1321 if (pwLogClust[j] == i)
1324 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1326 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1327 pwLogClust[j] = pwLogClust[k];
1334 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1336 if (changeCount == 0)
1341 int target_glyph = nextIndex - write_dir;
1343 int target_index = -1;
1344 int replacing_glyph = -1;
1348 if (changeCount > 0)
1349 target_glyph = nextIndex - ((changeCount+1)*write_dir);
1351 seeking_glyph = target_glyph;
1355 for (i = 0; i < chars; i++)
1357 if (pwLogClust[i] == seeking_glyph)
1364 for (i = chars - 1; i >= 0; i--)
1366 if (pwLogClust[i] == seeking_glyph)
1372 if (target_index == -1)
1375 while (target_index == -1 && seeking_glyph < chars);
1377 if (target_index == -1)
1379 ERR("Unable to find target glyph\n");
1383 if (changeCount < 0)
1386 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1388 if (pwLogClust[i] == target_glyph)
1390 if(pwLogClust[i] == replacing_glyph)
1391 pwLogClust[i] = target_glyph;
1395 if (changed >= changeCount)
1397 replacing_glyph = pwLogClust[i];
1398 pwLogClust[i] = target_glyph;
1405 /* renumber trailing indexes*/
1406 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1408 if (pwLogClust[i] != target_glyph)
1409 pwLogClust[i] += changeCount;
1414 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1415 pwLogClust[i] += changeCount;
1420 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 )
1422 if (psc->GSUB_Table)
1424 const GSUB_Feature *feature;
1425 const GSUB_LookupList *lookup;
1426 const GSUB_Header *header = psc->GSUB_Table;
1427 int lookup_index, lookup_count;
1429 feature = load_GSUB_feature(hdc, psa, psc, feat);
1431 return GSUB_E_NOFEATURE;
1433 TRACE("applying feature %s\n",debugstr_an(feat,4));
1434 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
1435 lookup_count = GET_BE_WORD(feature->LookupCount);
1436 TRACE("%i lookups\n", lookup_count);
1437 for (lookup_index = 0; lookup_index < lookup_count; lookup_index++)
1445 TRACE("applying lookup (%i/%i)\n",lookup_index,lookup_count);
1446 while(i < *pcGlyphs && i >= 0)
1449 INT prevCount = *pcGlyphs;
1451 nextIndex = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[lookup_index]), pwOutGlyphs, i, write_dir, pcGlyphs);
1452 if (*pcGlyphs != prevCount)
1454 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1463 return GSUB_E_NOFEATURE;
1466 static inline BOOL get_GSUB_Indic2(SCRIPT_ANALYSIS *psa, ScriptCache *psc)
1468 return(GSUB_get_script_table(psc->GSUB_Table,ShapingData[psa->eScript].newOtTag)!=NULL);
1471 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1475 if ( i+ delta >= cchLen)
1483 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1487 if (psa->fLinkBefore)
1492 if ( i+ delta >= cchLen)
1494 if (psa->fLinkAfter)
1502 if (context_type[i] == jtT)
1503 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1505 return context_type[i];
1508 static inline BOOL right_join_causing(CHAR joining_type)
1510 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1513 static inline BOOL left_join_causing(CHAR joining_type)
1515 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1518 static inline BOOL word_break_causing(WCHAR chr)
1520 /* we are working within a string of characters already guareented to
1521 be within one script, Syriac, so we do not worry about any character
1522 other than the space character outside of that range */
1523 return (chr == 0 || chr == 0x20 );
1527 * ContextualShape_Arabic
1529 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1536 if (*pcGlyphs != cChars)
1538 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1542 if (!psa->fLogicalOrder && psa->fRTL)
1553 if (!psc->GSUB_Table)
1554 psc->GSUB_Table = load_gsub_table(hdc);
1556 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1557 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1559 for (i = 0; i < cChars; i++)
1560 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1562 for (i = 0; i < cChars; i++)
1564 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1565 context_shape[i] = Xr;
1566 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1567 context_shape[i] = Xl;
1568 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)))
1569 context_shape[i] = Xm;
1570 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1571 context_shape[i] = Xr;
1572 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1573 context_shape[i] = Xl;
1575 context_shape[i] = Xn;
1578 /* Contextual Shaping */
1580 while(i < *pcGlyphs)
1582 BOOL shaped = FALSE;
1584 if (psc->GSUB_Table)
1587 INT prevCount = *pcGlyphs;
1588 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1589 if (nextIndex > GSUB_E_NOGLYPH)
1592 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1594 shaped = (nextIndex > GSUB_E_NOGLYPH);
1599 if (context_shape[i] == Xn)
1601 WORD newGlyph = pwOutGlyphs[i];
1602 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1604 /* fall back to presentation form B */
1605 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1606 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1607 pwOutGlyphs[i] = newGlyph;
1614 HeapFree(GetProcessHeap(),0,context_shape);
1615 HeapFree(GetProcessHeap(),0,context_type);
1619 * ContextualShape_Syriac
1623 #define DALATH 0x715
1626 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1633 if (*pcGlyphs != cChars)
1635 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1639 if (!psa->fLogicalOrder && psa->fRTL)
1650 if (!psc->GSUB_Table)
1651 psc->GSUB_Table = load_gsub_table(hdc);
1653 if (!psc->GSUB_Table)
1656 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1657 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1659 for (i = 0; i < cChars; i++)
1660 context_type[i] = get_table_entry( wine_shaping_table, pwcChars[i] );
1662 for (i = 0; i < cChars; i++)
1664 if (pwcChars[i] == ALAPH)
1666 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1668 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1669 context_shape[i] = Afj;
1670 else if ( rchar != DALATH && rchar != RISH &&
1671 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1672 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1673 context_shape[i] = Afn;
1674 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1675 context_shape[i] = Afx;
1677 context_shape[i] = Xn;
1679 else if (context_type[i] == jtR &&
1680 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1681 context_shape[i] = Xr;
1682 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1683 context_shape[i] = Xl;
1684 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)))
1685 context_shape[i] = Xm;
1686 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1687 context_shape[i] = Xr;
1688 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1689 context_shape[i] = Xl;
1691 context_shape[i] = Xn;
1694 /* Contextual Shaping */
1696 while(i < *pcGlyphs)
1699 INT prevCount = *pcGlyphs;
1700 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1701 if (nextIndex > GSUB_E_NOGLYPH)
1703 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1710 HeapFree(GetProcessHeap(),0,context_shape);
1711 HeapFree(GetProcessHeap(),0,context_type);
1715 * ContextualShape_Phags_pa
1718 #define phags_pa_CANDRABINDU 0xA873
1719 #define phags_pa_START 0xA840
1720 #define phags_pa_END 0xA87F
1722 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1728 if (*pcGlyphs != cChars)
1730 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1734 if (!psa->fLogicalOrder && psa->fRTL)
1745 if (!psc->GSUB_Table)
1746 psc->GSUB_Table = load_gsub_table(hdc);
1748 if (!psc->GSUB_Table)
1751 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1753 for (i = 0; i < cChars; i++)
1755 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1757 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1758 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1759 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1760 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1762 if (jrchar && jlchar)
1763 context_shape[i] = Xm;
1765 context_shape[i] = Xr;
1767 context_shape[i] = Xl;
1769 context_shape[i] = Xn;
1772 context_shape[i] = -1;
1775 /* Contextual Shaping */
1777 while(i < *pcGlyphs)
1779 if (context_shape[i] >= 0)
1782 INT prevCount = *pcGlyphs;
1783 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1784 if (nextIndex > GSUB_E_NOGLYPH)
1786 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1796 HeapFree(GetProcessHeap(),0,context_shape);
1799 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1804 pwOutChars[cWalk] = replacements[0];
1808 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1811 for (j = *pcChars; j > cWalk; j--)
1812 pwOutChars[j] = pwOutChars[j-1];
1813 *pcChars= *pcChars+1;
1814 pwOutChars[cWalk] = replacements[i];
1819 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[], WORD* pwLogClust)
1825 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1827 for (i = 0; vowels[i].base != 0x0; i++)
1829 if (pwOutChars[cWalk] == vowels[i].base)
1833 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1834 if (vowels[i].parts[1]) { cWalk++; o++; }
1835 if (vowels[i].parts[2]) { cWalk++; o++; }
1837 for (j = (cWalk - offset) + 1; j < *pcChars - offset; j ++)
1845 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[], WORD* pwLogClust)
1851 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1853 for (i = 0; consonants[i].output!= 0x0; i++)
1856 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1857 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1860 if (consonants[i].parts[j]==0x0) /* matched all */
1864 pwOutChars[cWalk] = consonants[i].output;
1865 for(k = cWalk+1; k < *pcChars - j; k++)
1866 pwOutChars[k] = pwOutChars[k+j];
1867 *pcChars = *pcChars - j;
1868 for (k = j ; k > 0; k--)
1869 pwLogClust[cWalk + k + offset] = pwLogClust[cWalk + offset];
1871 for (k = cWalk + j + offset; k < *pcChars + offset; k++)
1880 static void Reorder_Ra_follows_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1885 WORD Ra = pwChar[s->start];
1886 WORD H = pwChar[s->start+1];
1888 TRACE("Doing reorder of Ra to %i\n",s->base);
1889 for (j = s->start; j < s->base-1; j++)
1890 pwChar[j] = pwChar[j+2];
1891 pwChar[s->base-1] = Ra;
1892 pwChar[s->base] = H;
1894 s->ralf = s->base-1;
1899 static void Reorder_Ra_follows_matra(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1904 int stop = (s->blwf >=0)? s->blwf+1 : s->base;
1905 WORD Ra = pwChar[s->start];
1906 WORD H = pwChar[s->start+1];
1907 for (loc = s->end; loc > stop; loc--)
1908 if (lexical(pwChar[loc]) == lex_Matra_post || lexical(pwChar[loc]) == lex_Matra_below)
1911 TRACE("Doing reorder of Ra to %i\n",loc);
1912 for (j = s->start; j < loc-1; j++)
1913 pwChar[j] = pwChar[j+2];
1919 if (s->blwf >= 0) s->blwf -= 2;
1920 if (s->pref >= 0) s->pref -= 2;
1924 static void Reorder_Ra_follows_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1929 WORD Ra = pwChar[s->start];
1930 WORD H = pwChar[s->start+1];
1932 TRACE("Doing reorder of Ra to %i\n",s->end-1);
1933 for (j = s->start; j < s->end-1; j++)
1934 pwChar[j] = pwChar[j+2];
1935 pwChar[s->end-1] = Ra;
1940 if (s->blwf >= 0) s->blwf -= 2;
1941 if (s->pref >= 0) s->pref -= 2;
1945 static void Reorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1949 /* reorder Matras */
1950 if (s->end > s->base)
1952 for (i = 1; i <= s->end-s->base; i++)
1954 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1957 WCHAR c = pwChar[s->base+i];
1958 TRACE("Doing reorder of %x %x\n",c,pwChar[s->base]);
1959 for (j = s->base+i; j > s->base; j--)
1960 pwChar[j] = pwChar[j-1];
1961 pwChar[s->base] = c;
1963 if (s->ralf >= s->base) s->ralf++;
1964 if (s->blwf >= s->base) s->blwf++;
1965 if (s->pref >= s->base) s->pref++;
1972 static void Reorder_Matra_precede_syllable(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
1976 /* reorder Matras */
1977 if (s->end > s->base)
1979 for (i = 1; i <= s->end-s->base; i++)
1981 if (lexical(pwChar[s->base+i]) == lex_Matra_pre)
1984 WCHAR c = pwChar[s->base+i];
1985 TRACE("Doing reorder of %x to %i\n",c,s->start);
1986 for (j = s->base+i; j > s->start; j--)
1987 pwChar[j] = pwChar[j-1];
1988 pwChar[s->start] = c;
1990 if (s->ralf >= 0) s->ralf++;
1991 if (s->blwf >= 0) s->blwf++;
1992 if (s->pref >= 0) s->pref++;
1999 static void SecondReorder_Blwf_follows_matra(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2001 if (s->blwf >= 0 && g->blwf > g->base)
2005 for (loc = s->end; loc > s->blwf; loc--)
2006 if (lexical(pwChar[loc]) == lex_Matra_below || lexical(pwChar[loc]) == lex_Matra_above || lexical(pwChar[loc]) == lex_Matra_post)
2009 g_offset = (loc - s->blwf) - 1;
2013 WORD blwf = glyphs[g->blwf];
2014 TRACE("Doing reorder of Below-base to %i (glyph offset %i)\n",loc,g_offset);
2015 /* do not care about the pwChar array anymore, just the glyphs */
2016 for (j = 0; j < g_offset; j++)
2017 glyphs[g->blwf + j] = glyphs[g->blwf + j + 1];
2018 glyphs[g->blwf + g_offset] = blwf;
2023 static void SecondReorder_Matra_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2027 /* reorder previously moved Matras to correct position*/
2028 for (i = s->start; i < s->base; i++)
2030 if (lexical(pwChar[i]) == lex_Matra_pre)
2033 int g_start = g->start + i - s->start;
2034 if (g_start < g->base -1 )
2036 WCHAR og = glyphs[g_start];
2037 TRACE("Doing reorder of matra from %i to %i\n",g_start,g->base);
2038 for (j = g_start; j < g->base-1; j++)
2039 glyphs[j] = glyphs[j+1];
2040 glyphs[g->base-1] = og;
2046 static void SecondReorder_Pref_precede_base(LPWSTR pwChar, IndicSyllable *s, WORD *glyphs, IndicSyllable *g, lexical_function lexical)
2048 if (s->pref >= 0 && g->pref > g->base)
2051 WCHAR og = glyphs[g->pref];
2052 TRACE("Doing reorder of pref from %i to %i\n",g->pref,g->base);
2053 for (j = g->pref; j > g->base; j--)
2054 glyphs[j] = glyphs[j-1];
2055 glyphs[g->base] = og;
2059 static void Reorder_Like_Sinhala(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2061 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2062 if (s->start == s->base && s->base == s->end) return;
2063 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2065 Reorder_Ra_follows_base(pwChar, s, lexical);
2066 Reorder_Matra_precede_base(pwChar, s, lexical);
2069 static void Reorder_Like_Devanagari(LPWSTR pwChar, IndicSyllable *s, lexical_function lexical)
2071 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2072 if (s->start == s->base && s->base == s->end) return;
2073 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2075 Reorder_Ra_follows_matra(pwChar, s, lexical);
2076 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2079 static void Reorder_Like_Bengali(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_syllable(pwChar, s, lexical);
2089 static void Reorder_Like_Kannada(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_syllable(pwChar, s, lexical);
2096 Reorder_Matra_precede_syllable(pwChar, s, lexical);
2099 static void SecondReorder_Like_Telugu(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2101 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2102 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2103 if (s->start == s->base && s->base == s->end) return;
2104 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2106 SecondReorder_Blwf_follows_matra(pwChar, s, pwGlyphs, g, lexical);
2109 static void SecondReorder_Like_Tamil(LPWSTR pwChar, IndicSyllable *s, WORD* pwGlyphs, IndicSyllable *g, lexical_function lexical)
2111 TRACE("Syllable (%i..%i..%i)\n",s->start,s->base,s->end);
2112 TRACE("Glyphs (%i..%i..%i)\n",g->start,g->base,g->end);
2113 if (s->start == s->base && s->base == s->end) return;
2114 if (lexical(pwChar[s->base]) == lex_Vowel) return;
2116 SecondReorder_Matra_precede_base(pwChar, s, pwGlyphs, g, lexical);
2117 SecondReorder_Pref_precede_base(pwChar, s, pwGlyphs, g, lexical);
2121 static inline void shift_syllable_glyph_indexs(IndicSyllable *glyph_index, INT index, INT shift)
2126 if (glyph_index->start > index)
2127 glyph_index->start += shift;
2128 if (glyph_index->base > index)
2129 glyph_index->base+= shift;
2130 if (glyph_index->end > index)
2131 glyph_index->end+= shift;
2132 if (glyph_index->ralf > index)
2133 glyph_index->ralf+= shift;
2134 if (glyph_index->blwf > index)
2135 glyph_index->blwf+= shift;
2136 if (glyph_index->pref > index)
2137 glyph_index->pref+= shift;
2140 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 )
2142 int index = glyph_index->start;
2147 while(index <= glyph_index->end)
2150 INT prevCount = *pcGlyphs;
2151 nextIndex = GSUB_apply_feature_all_lookups(psc->GSUB_Table, feature, pwOutGlyphs, index, 1, pcGlyphs);
2152 if (nextIndex > GSUB_E_NOGLYPH)
2154 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2155 shift_syllable_glyph_indexs(glyph_index,index,*pcGlyphs - prevCount);
2163 static inline INT find_consonant_halant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2166 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)))))
2168 if (index + i <= end-1)
2174 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)
2176 INT index, nextIndex;
2179 count = syllable->base - syllable->start;
2182 index = find_consonant_halant(&pwChars[syllable->start], 0, count, lexical);
2183 while (index >= 0 && index + g_offset < (glyph_index->base - glyph_index->start))
2185 INT prevCount = *pcGlyphs;
2186 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->start+g_offset, 1, pcGlyphs, feature);
2187 if (nextIndex > GSUB_E_NOGLYPH)
2189 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2190 shift_syllable_glyph_indexs(glyph_index, index + glyph_index->start + g_offset, (*pcGlyphs - prevCount));
2191 g_offset += (*pcGlyphs - prevCount);
2195 index = find_consonant_halant(&pwChars[syllable->start], index, count, lexical);
2199 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)
2202 INT prevCount = *pcGlyphs;
2204 if (syllable->ralf >= 0)
2206 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, glyph_index->ralf, 1, pcGlyphs, "rphf");
2207 if (nextIndex > GSUB_E_NOGLYPH)
2209 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2210 shift_syllable_glyph_indexs(glyph_index,glyph_index->ralf,*pcGlyphs - prevCount);
2215 static inline INT find_halant_consonant(WCHAR* pwChars, INT index, INT end, lexical_function lexical)
2218 while (index + i < end-1 && !(lexical(pwChars[index+i]) == lex_Halant &&
2219 ((index + i < end-2 && lexical(pwChars[index+i]) == lex_Nukta && is_consonant(lexical(pwChars[index+i+1]))) ||
2220 is_consonant(lexical(pwChars[index+i+1])))))
2222 if (index + i <= end-1)
2228 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)
2230 INT index, nextIndex;
2231 INT count, g_offset=0;
2232 INT ralf = syllable->ralf;
2234 count = syllable->end - syllable->base;
2236 index = find_halant_consonant(&pwChars[syllable->base], 0, count, lexical);
2240 INT prevCount = *pcGlyphs;
2241 if (ralf >=0 && ralf < index)
2249 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2250 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2251 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2254 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, index+glyph_index->base+g_offset, 1, pcGlyphs, feat);
2255 if (nextIndex > GSUB_E_NOGLYPH)
2257 UpdateClusters(nextIndex, *pcGlyphs - prevCount, 1, cChars, pwLogClust);
2258 shift_syllable_glyph_indexs(glyph_index,index+glyph_index->start+g_offset, (*pcGlyphs - prevCount));
2259 g_offset += (*pcGlyphs - prevCount);
2263 WORD g = pwOutGlyphs[index+glyph_index->base+g_offset];
2264 pwOutGlyphs[index+glyph_index->base+g_offset] = pwOutGlyphs[index+glyph_index->base+g_offset+1];
2265 pwOutGlyphs[index+glyph_index->base+g_offset+1] = g;
2269 index = find_halant_consonant(&pwChars[syllable->base], index, count, lexical);
2273 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)
2276 int overall_shift = 0;
2277 const GSUB_Feature *locl = (modern)?load_GSUB_feature(hdc, psa, psc, "locl"):NULL;
2278 const GSUB_Feature *nukt = load_GSUB_feature(hdc, psa, psc, "nukt");
2279 const GSUB_Feature *akhn = load_GSUB_feature(hdc, psa, psc, "akhn");
2280 const GSUB_Feature *rkrf = (modern)?load_GSUB_feature(hdc, psa, psc, "rkrf"):NULL;
2281 const GSUB_Feature *pstf = load_GSUB_feature(hdc, psa, psc, "pstf");
2282 const GSUB_Feature *vatu = (!rkrf)?load_GSUB_feature(hdc, psa, psc, "vatu"):NULL;
2283 const GSUB_Feature *cjct = (modern)?load_GSUB_feature(hdc, psa, psc, "cjct"):NULL;
2284 BOOL rphf = (load_GSUB_feature(hdc, psa, psc, "rphf") != NULL);
2285 BOOL pref = (load_GSUB_feature(hdc, psa, psc, "pref") != NULL);
2286 BOOL blwf = (load_GSUB_feature(hdc, psa, psc, "blwf") != NULL);
2287 BOOL half = (load_GSUB_feature(hdc, psa, psc, "half") != NULL);
2288 IndicSyllable glyph_indexs;
2290 for (c = 0; c < syllable_count; c++)
2293 memcpy(&glyph_indexs, &syllables[c], sizeof(IndicSyllable));
2294 shift_syllable_glyph_indexs(&glyph_indexs, -1, overall_shift);
2295 old_end = glyph_indexs.end;
2299 TRACE("applying feature locl\n");
2300 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, locl);
2304 TRACE("applying feature nukt\n");
2305 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, nukt);
2309 TRACE("applying feature akhn\n");
2310 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, akhn);
2314 Apply_Indic_Rphf(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs);
2317 TRACE("applying feature rkrf\n");
2318 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, rkrf);
2321 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "pref");
2325 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "blwf");
2327 Apply_Indic_PostBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, modern, "blwf");
2331 Apply_Indic_PreBase(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, "half");
2334 TRACE("applying feature pstf\n");
2335 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, pstf);
2339 TRACE("applying feature vatu\n");
2340 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, vatu);
2344 TRACE("applying feature cjct\n");
2345 Apply_Indic_BasicForm(hdc, psc, psa, pwChars, cChars, &syllables[c], pwOutGlyphs, pcGlyphs, pwLogClust, lexical, &glyph_indexs, cjct);
2349 second_reorder(pwChars, &syllables[c], pwOutGlyphs, &glyph_indexs, lexical);
2351 overall_shift += glyph_indexs.end - old_end;
2355 static inline int unicode_lex(WCHAR c)
2359 if (!c) return lex_Generic;
2360 if (c == 0x200D) return lex_ZWJ;
2361 if (c == 0x200C) return lex_ZWNJ;
2362 if (c == 0x00A0) return lex_NBSP;
2364 type = get_table_entry( indic_syllabic_table, c );
2366 if ((type & 0x00ff) != 0x0007) type = type & 0x00ff;
2370 case 0x0d07: /* Unknown */
2371 case 0x0e07: /* Unknwon */
2372 default: return lex_Generic;
2378 case 0x0014: return lex_Modifier;
2386 case 0x0010: return lex_Consonant;
2387 case 0x0004: return lex_Nukta;
2388 case 0x0005: return lex_Halant;
2390 case 0x0008: return lex_Vowel;
2392 case 0x0107: return lex_Matra_post;
2394 case 0x0307: return lex_Matra_pre;
2400 case 0x0407: return lex_Composed_Vowel;
2401 case 0x0507: return lex_Matra_above;
2402 case 0x0607: return lex_Matra_below;
2403 case 0x000c: return lex_Ra;
2407 static int sinhala_lex(WCHAR c)
2414 case 0x0DDE: return lex_Matra_post;
2416 return unicode_lex(c);
2420 static const VowelComponents Sinhala_vowels[] = {
2421 {0x0DDA, {0x0DD9,0x0DDA,0x0}},
2422 {0x0DDC, {0x0DD9,0x0DDC,0x0}},
2423 {0x0DDD, {0x0DD9,0x0DDD,0x0}},
2424 {0x0DDE, {0x0DD9,0x0DDE,0x0}},
2425 {0x0000, {0x0000,0x0000,0x0}}};
2427 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2429 int cCount = cChars;
2432 IndicSyllable *syllables = NULL;
2433 int syllable_count = 0;
2435 if (*pcGlyphs != cChars)
2437 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2441 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
2443 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2445 /* Step 1: Decompose multi part vowels */
2446 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels, pwLogClust);
2448 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2450 /* Step 2: Reorder within Syllables */
2451 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, sinhala_lex, Reorder_Like_Sinhala, TRUE);
2452 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2454 /* Step 3: Strip dangling joiners */
2455 for (i = 0; i < cCount; i++)
2457 if ((input[i] == 0x200D || input[i] == 0x200C) &&
2458 (i == 0 || input[i-1] == 0x0020 || i == cCount-1 || input[i+1] == 0x0020))
2462 /* Step 4: Base Form application to syllables */
2463 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2465 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, sinhala_lex, NULL, TRUE);
2467 HeapFree(GetProcessHeap(),0,input);
2468 HeapFree(GetProcessHeap(),0,syllables);
2471 static int devanagari_lex(WCHAR c)
2475 case 0x0930: return lex_Ra;
2477 return unicode_lex(c);
2481 static const ConsonantComponents Devanagari_consonants[] ={
2482 {{0x0928, 0x093C, 0x00000}, 0x0929},
2483 {{0x0930, 0x093C, 0x00000}, 0x0931},
2484 {{0x0933, 0x093C, 0x00000}, 0x0934},
2485 {{0x0915, 0x093C, 0x00000}, 0x0958},
2486 {{0x0916, 0x093C, 0x00000}, 0x0959},
2487 {{0x0917, 0x093C, 0x00000}, 0x095A},
2488 {{0x091C, 0x093C, 0x00000}, 0x095B},
2489 {{0x0921, 0x093C, 0x00000}, 0x095C},
2490 {{0x0922, 0x093C, 0x00000}, 0x095D},
2491 {{0x092B, 0x093C, 0x00000}, 0x095E},
2492 {{0x092F, 0x093C, 0x00000}, 0x095F}};
2494 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2496 int cCount = cChars;
2498 IndicSyllable *syllables = NULL;
2499 int syllable_count = 0;
2500 BOOL modern = get_GSUB_Indic2(psa, psc);
2502 if (*pcGlyphs != cChars)
2504 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2508 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2509 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2511 /* Step 1: Compose Consonant and Nukta */
2512 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants, pwLogClust);
2513 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2515 /* Step 2: Reorder within Syllables */
2516 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, devanagari_lex, Reorder_Like_Devanagari, modern);
2517 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2518 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2521 /* Step 3: Base Form application to syllables */
2522 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, devanagari_lex, NULL, modern);
2524 HeapFree(GetProcessHeap(),0,input);
2525 HeapFree(GetProcessHeap(),0,syllables);
2528 static int bengali_lex(WCHAR c)
2532 case 0x09B0: return lex_Ra;
2534 return unicode_lex(c);
2538 static const VowelComponents Bengali_vowels[] = {
2539 {0x09CB, {0x09C7,0x09BE,0x0000}},
2540 {0x09CC, {0x09C7,0x09D7,0x0000}},
2541 {0x0000, {0x0000,0x0000,0x0000}}};
2543 static const ConsonantComponents Bengali_consonants[] = {
2544 {{0x09A4,0x09CD,0x200D}, 0x09CE},
2545 {{0x09A1,0x09BC,0x0000}, 0x09DC},
2546 {{0x09A2,0x09BC,0x0000}, 0x09DD},
2547 {{0x09AF,0x09BC,0x0000}, 0x09DF},
2548 {{0x0000,0x0000,0x0000}, 0x0000}};
2550 static void ContextualShape_Bengali(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2552 int cCount = cChars;
2554 IndicSyllable *syllables = NULL;
2555 int syllable_count = 0;
2556 BOOL modern = get_GSUB_Indic2(psa, psc);
2558 if (*pcGlyphs != cChars)
2560 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2564 input = HeapAlloc(GetProcessHeap(), 0, (cChars * 2) * sizeof(WCHAR));
2565 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2567 /* Step 1: Decompose Vowels and Compose Consonents */
2568 DecomposeVowels(hdc, input, &cCount, Bengali_vowels, pwLogClust);
2569 ComposeConsonants(hdc, input, &cCount, Bengali_consonants, pwLogClust);
2570 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2572 /* Step 2: Reorder within Syllables */
2573 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, bengali_lex, Reorder_Like_Bengali, modern);
2574 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2575 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2578 /* Step 3: Initial form is only applied to the beginning of words */
2579 for (cCount = cCount - 1 ; cCount >= 0; cCount --)
2581 if (cCount == 0 || input[cCount] == 0x0020) /* space */
2585 if (index > 0) index++;
2587 apply_GSUB_feature_to_glyph(hdc, psa, psc, &pwOutGlyphs[index], 0, 1, &gCount, "init");
2591 /* Step 4: Base Form application to syllables */
2592 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, bengali_lex, NULL, modern);
2594 HeapFree(GetProcessHeap(),0,input);
2595 HeapFree(GetProcessHeap(),0,syllables);
2598 static int gurmukhi_lex(WCHAR c)
2601 return lex_Modifier;
2603 return unicode_lex(c);
2606 static const ConsonantComponents Gurmukhi_consonants[] = {
2607 {{0x0A32,0x0A3C,0x0000}, 0x0A33},
2608 {{0x0A38,0x0A3C,0x0000}, 0x0A36},
2609 {{0x0A16,0x0A3C,0x0000}, 0x0A59},
2610 {{0x0A17,0x0A3C,0x0000}, 0x0A5A},
2611 {{0x0A1C,0x0A3C,0x0000}, 0x0A5B},
2612 {{0x0A2B,0x0A3C,0x0000}, 0x0A5E},
2613 {{0x0000,0x0000,0x0000}, 0x0000}};
2615 static void ContextualShape_Gurmukhi(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2617 int cCount = cChars;
2619 IndicSyllable *syllables = NULL;
2620 int syllable_count = 0;
2621 BOOL modern = get_GSUB_Indic2(psa, psc);
2623 if (*pcGlyphs != cChars)
2625 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2629 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2630 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2632 /* Step 1: Compose Consonents */
2633 ComposeConsonants(hdc, input, &cCount, Gurmukhi_consonants, pwLogClust);
2634 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2636 /* Step 2: Reorder within Syllables */
2637 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gurmukhi_lex, Reorder_Like_Bengali, modern);
2638 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2639 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2642 /* Step 3: Base Form application to syllables */
2643 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gurmukhi_lex, NULL, modern);
2645 HeapFree(GetProcessHeap(),0,input);
2646 HeapFree(GetProcessHeap(),0,syllables);
2649 static int gujarati_lex(WCHAR c)
2653 case 0x0AB0: return lex_Ra;
2655 return unicode_lex(c);
2659 static void ContextualShape_Gujarati(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2661 int cCount = cChars;
2663 IndicSyllable *syllables = NULL;
2664 int syllable_count = 0;
2665 BOOL modern = get_GSUB_Indic2(psa, psc);
2667 if (*pcGlyphs != cChars)
2669 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2673 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
2674 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2676 /* Step 1: Reorder within Syllables */
2677 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, gujarati_lex, Reorder_Like_Devanagari, modern);
2678 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2679 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2682 /* Step 2: Base Form application to syllables */
2683 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, gujarati_lex, NULL, modern);
2685 HeapFree(GetProcessHeap(),0,input);
2686 HeapFree(GetProcessHeap(),0,syllables);
2689 static int oriya_lex(WCHAR c)
2693 case 0x0B30: return lex_Ra;
2695 return unicode_lex(c);
2699 static const VowelComponents Oriya_vowels[] = {
2700 {0x0B48, {0x0B47,0x0B56,0x0000}},
2701 {0x0B4B, {0x0B47,0x0B3E,0x0000}},
2702 {0x0B4C, {0x0B47,0x0B57,0x0000}},
2703 {0x0000, {0x0000,0x0000,0x0000}}};
2705 static const ConsonantComponents Oriya_consonants[] = {
2706 {{0x0B21,0x0B3C,0x0000}, 0x0B5C},
2707 {{0x0B22,0x0B3C,0x0000}, 0x0B5D},
2708 {{0x0000,0x0000,0x0000}, 0x0000}};
2710 static void ContextualShape_Oriya(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2712 int cCount = cChars;
2714 IndicSyllable *syllables = NULL;
2715 int syllable_count = 0;
2716 BOOL modern = get_GSUB_Indic2(psa, psc);
2718 if (*pcGlyphs != cChars)
2720 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2724 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2725 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2727 /* Step 1: Decompose Vowels and Compose Consonents */
2728 DecomposeVowels(hdc, input, &cCount, Oriya_vowels, pwLogClust);
2729 ComposeConsonants(hdc, input, &cCount, Oriya_consonants, pwLogClust);
2730 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2732 /* Step 2: Reorder within Syllables */
2733 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, oriya_lex, Reorder_Like_Bengali, modern);
2734 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2735 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2738 /* Step 3: Base Form application to syllables */
2739 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, oriya_lex, NULL, modern);
2741 HeapFree(GetProcessHeap(),0,input);
2742 HeapFree(GetProcessHeap(),0,syllables);
2745 static int tamil_lex(WCHAR c)
2747 return unicode_lex(c);
2750 static const VowelComponents Tamil_vowels[] = {
2751 {0x0BCA, {0x0BC6,0x0BBE,0x0000}},
2752 {0x0BCB, {0x0BC7,0x0BBE,0x0000}},
2753 {0x0BCB, {0x0BC6,0x0BD7,0x0000}},
2754 {0x0000, {0x0000,0x0000,0x0000}}};
2756 static const ConsonantComponents Tamil_consonants[] = {
2757 {{0x0B92,0x0BD7,0x0000}, 0x0B94},
2758 {{0x0000,0x0000,0x0000}, 0x0000}};
2760 static void ContextualShape_Tamil(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2762 int cCount = cChars;
2764 IndicSyllable *syllables = NULL;
2765 int syllable_count = 0;
2766 BOOL modern = get_GSUB_Indic2(psa, psc);
2768 if (*pcGlyphs != cChars)
2770 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2774 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2775 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2777 /* Step 1: Decompose Vowels and Compose Consonents */
2778 DecomposeVowels(hdc, input, &cCount, Tamil_vowels, pwLogClust);
2779 ComposeConsonants(hdc, input, &cCount, Tamil_consonants, pwLogClust);
2780 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2782 /* Step 2: Reorder within Syllables */
2783 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, tamil_lex, Reorder_Like_Bengali, modern);
2784 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2785 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2788 /* Step 3: Base Form application to syllables */
2789 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, tamil_lex, SecondReorder_Like_Tamil, modern);
2791 HeapFree(GetProcessHeap(),0,input);
2792 HeapFree(GetProcessHeap(),0,syllables);
2795 static int telugu_lex(WCHAR c)
2800 case 0x0C44: return lex_Modifier;
2802 return unicode_lex(c);
2806 static const VowelComponents Telugu_vowels[] = {
2807 {0x0C48, {0x0C46,0x0C56,0x0000}},
2808 {0x0000, {0x0000,0x0000,0x0000}}};
2810 static void ContextualShape_Telugu(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2812 int cCount = cChars;
2814 IndicSyllable *syllables = NULL;
2815 int syllable_count = 0;
2816 BOOL modern = get_GSUB_Indic2(psa, psc);
2818 if (*pcGlyphs != cChars)
2820 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2824 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2825 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2827 /* Step 1: Decompose Vowels */
2828 DecomposeVowels(hdc, input, &cCount, Telugu_vowels, pwLogClust);
2829 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2831 /* Step 2: Reorder within Syllables */
2832 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, telugu_lex, Reorder_Like_Bengali, modern);
2833 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2834 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2837 /* Step 3: Base Form application to syllables */
2838 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, telugu_lex, SecondReorder_Like_Telugu, modern);
2840 HeapFree(GetProcessHeap(),0,input);
2841 HeapFree(GetProcessHeap(),0,syllables);
2844 static int kannada_lex(WCHAR c)
2848 case 0x0CB0: return lex_Ra;
2850 return unicode_lex(c);
2854 static const VowelComponents Kannada_vowels[] = {
2855 {0x0CC0, {0x0CBF,0x0CD5,0x0000}},
2856 {0x0CC7, {0x0CC6,0x0CD5,0x0000}},
2857 {0x0CC8, {0x0CC6,0x0CD6,0x0000}},
2858 {0x0CCA, {0x0CC6,0x0CC2,0x0000}},
2859 {0x0CCB, {0x0CC6,0x0CC2,0x0CD5}},
2860 {0x0000, {0x0000,0x0000,0x0000}}};
2862 static void ContextualShape_Kannada(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2864 int cCount = cChars;
2866 IndicSyllable *syllables = NULL;
2867 int syllable_count = 0;
2868 BOOL modern = get_GSUB_Indic2(psa, psc);
2870 if (*pcGlyphs != cChars)
2872 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2876 input = HeapAlloc(GetProcessHeap(), 0, (cChars*3) * sizeof(WCHAR));
2877 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2879 /* Step 1: Decompose Vowels */
2880 DecomposeVowels(hdc, input, &cCount, Kannada_vowels, pwLogClust);
2881 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2883 /* Step 2: Reorder within Syllables */
2884 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, kannada_lex, Reorder_Like_Kannada, modern);
2885 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2886 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2889 /* Step 3: Base Form application to syllables */
2890 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, kannada_lex, SecondReorder_Like_Telugu, modern);
2892 HeapFree(GetProcessHeap(),0,input);
2893 HeapFree(GetProcessHeap(),0,syllables);
2896 static int malayalam_lex(WCHAR c)
2898 return unicode_lex(c);
2901 static const VowelComponents Malayalam_vowels[] = {
2902 {0x0D4A, {0x0D46,0x0D3E,0x0000}},
2903 {0x0D4B, {0x0D47,0x0D3E,0x0000}},
2904 {0x0D4C, {0x0D46,0x0D57,0x0000}},
2905 {0x0000, {0x0000,0x0000,0x0000}}};
2907 static void ContextualShape_Malayalam(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2909 int cCount = cChars;
2911 IndicSyllable *syllables = NULL;
2912 int syllable_count = 0;
2913 BOOL modern = get_GSUB_Indic2(psa, psc);
2915 if (*pcGlyphs != cChars)
2917 ERR("Number of Glyphs and Chars need to match at the beginning\n");
2921 input = HeapAlloc(GetProcessHeap(), 0, (cChars*2) * sizeof(WCHAR));
2922 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
2924 /* Step 1: Decompose Vowels */
2925 DecomposeVowels(hdc, input, &cCount, Malayalam_vowels, pwLogClust);
2926 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
2928 /* Step 2: Reorder within Syllables */
2929 Indic_ReorderCharacters( hdc, psa, psc, input, cCount, &syllables, &syllable_count, malayalam_lex, Reorder_Like_Devanagari, modern);
2930 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
2931 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
2934 /* Step 3: Base Form application to syllables */
2935 ShapeIndicSyllables(hdc, psc, psa, input, cChars, syllables, syllable_count, pwOutGlyphs, pcGlyphs, pwLogClust, malayalam_lex, SecondReorder_Like_Tamil, modern);
2937 HeapFree(GetProcessHeap(),0,input);
2938 HeapFree(GetProcessHeap(),0,syllables);
2941 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)
2945 for (i = 0; i < cGlyphs; i++)
2950 for (k = 0; k < cChars; k++)
2952 if (pwLogClust[k] == i)
2954 char_index[char_count] = k;
2959 if (char_count == 0)
2961 FIXME("No chars in this glyph? Must be an error\n");
2965 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2967 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2968 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2971 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2974 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2975 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2978 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 )
2981 int initGlyph, finaGlyph;
2985 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2986 memset(spaces,0,cGlyphs);
2988 if (!psa->fLogicalOrder && psa->fRTL)
2990 initGlyph = cGlyphs-1;
2998 finaGlyph = cGlyphs-1;
3003 for (i = 0; i < cGlyphs; i++)
3005 for (k = 0; k < cChars; k++)
3006 if (pwLogClust[k] == i)
3008 if (pwcChars[k] == 0x0020)
3013 for (i = 0; i < cGlyphs; i++)
3017 BOOL isInit, isFinal;
3019 for (k = 0; k < cChars; k++)
3021 if (pwLogClust[k] == i)
3023 char_index[char_count] = k;
3028 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
3029 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
3031 if (char_count == 0)
3033 FIXME("No chars in this glyph? Must be an error\n");
3037 if (char_count == 1)
3039 if (pwcChars[char_index[0]] == 0x0020) /* space */
3041 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
3042 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3044 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
3045 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
3046 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
3048 if (!isInit && !isFinal)
3049 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
3051 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
3053 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3057 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
3058 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
3059 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
3060 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
3061 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
3062 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
3063 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
3064 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
3066 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3068 else if (!isInit && !isFinal)
3069 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
3071 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3073 else if (char_count == 2)
3075 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
3076 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
3078 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
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;
3088 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3089 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3090 HeapFree(GetProcessHeap(),0,spaces);
3093 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 )
3100 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
3101 memset(spaces,0,cGlyphs);
3103 if (!psa->fLogicalOrder && psa->fRTL)
3110 finaGlyph = cGlyphs-1;
3114 for (i = 0; i < cGlyphs; i++)
3116 for (k = 0; k < cChars; k++)
3117 if (pwLogClust[k] == i)
3119 if (pwcChars[k] == 0x0020)
3124 for (i = 0; i < cGlyphs; i++)
3129 for (k = 0; k < cChars; k++)
3131 if (pwLogClust[k] == i)
3133 char_index[char_count] = k;
3138 if (char_count == 0)
3140 FIXME("No chars in this glyph? Must be an error\n");
3144 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3146 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3147 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3149 else if (i == finaGlyph)
3150 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3152 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3155 HeapFree(GetProcessHeap(),0,spaces);
3156 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3157 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3159 /* Do not allow justification between marks and their base */
3160 for (i = 0; i < cGlyphs; i++)
3162 if (!pGlyphProp[i].sva.fClusterStart)
3163 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3167 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)
3171 for (i = 0; i < cGlyphs; i++)
3176 for (k = 0; k < cChars; k++)
3178 if (pwLogClust[k] == i)
3180 char_index[char_count] = k;
3185 if (char_count == 0)
3187 FIXME("No chars in this glyph? Must be an error\n");
3191 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3193 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
3194 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3197 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3199 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3200 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3203 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)
3207 for (i = 0; i < cGlyphs; i++)
3212 for (k = 0; k < cChars; k++)
3214 if (pwLogClust[k] == i)
3216 char_index[char_count] = k;
3221 if (char_count == 0)
3223 FIXME("No chars in this glyph? Must be an error\n");
3227 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3229 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3230 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3233 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3235 GDEF_UpdateGlyphProps(hdc, psc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
3236 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3238 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
3239 for (i = 0; i < cGlyphs; i++)
3241 if (!pGlyphProp[i].sva.fClusterStart)
3243 pGlyphProp[i].sva.fDiacritic = 0;
3244 pGlyphProp[i].sva.fZeroWidth = 0;
3249 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)
3252 IndicSyllable *syllables = NULL;
3253 int syllable_count = 0;
3254 BOOL modern = get_GSUB_Indic2(psa, psc);
3256 for (i = 0; i < cGlyphs; i++)
3261 for (k = 0; k < cChars; k++)
3263 if (pwLogClust[k] == i)
3265 char_index[char_count] = k;
3270 if (char_count == 0)
3272 FIXME("No chars in this glyph? Must be an error\n");
3276 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
3278 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
3279 pCharProp[char_index[0]].fCanGlyphAlone = 1;
3282 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
3284 pGlyphProp[i].sva.fClusterStart = 0;
3285 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
3286 switch (lexical(pwcChars[char_index[k]]))
3289 case lex_Matra_post:
3290 case lex_Matra_above:
3291 case lex_Matra_below:
3295 pGlyphProp[i].sva.fClusterStart = 1;
3300 Indic_ParseSyllables( hdc, psa, psc, pwcChars, cChars, &syllables, &syllable_count, lexical, modern);
3302 for (i = 0; i < syllable_count; i++)
3305 WORD g = pwLogClust[syllables[i].start];
3306 for (j = syllables[i].start+1; j <= syllables[i].end; j++)
3308 if (pwLogClust[j] != g)
3310 pGlyphProp[pwLogClust[j]].sva.fClusterStart = 0;
3316 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
3317 HeapFree(GetProcessHeap(), 0, syllables);
3320 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 )
3322 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, sinhala_lex);
3325 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 )
3327 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
3330 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 )
3332 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, bengali_lex);
3335 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 )
3337 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gurmukhi_lex);
3340 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 )
3342 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, gujarati_lex);
3345 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 )
3347 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, oriya_lex);
3350 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 )
3352 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, tamil_lex);
3355 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 )
3357 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, telugu_lex);
3360 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 )
3362 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, kannada_lex);
3365 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 )
3367 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, malayalam_lex);
3370 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)
3372 if (ShapingData[psa->eScript].charGlyphPropProc)
3373 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3375 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
3378 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
3380 if (ShapingData[psa->eScript].contextProc)
3381 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
3384 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)
3389 if (!rpRangeProperties)
3392 if (!psc->GSUB_Table)
3393 psc->GSUB_Table = load_gsub_table(hdc);
3395 if (!psc->GSUB_Table)
3398 if (!psa->fLogicalOrder && psa->fRTL)
3403 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
3405 if (rpRangeProperties->potfRecords[i].lParameter > 0)
3406 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
3410 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
3412 const TEXTRANGE_PROPERTIES *rpRangeProperties;
3413 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
3415 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
3418 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
3420 const GSUB_Feature *feature;
3423 if (!ShapingData[psa->eScript].requiredFeatures)
3426 if (!psc->GSUB_Table)
3427 psc->GSUB_Table = load_gsub_table(hdc);
3429 /* we need to have at least one of the required features */
3431 while (ShapingData[psa->eScript].requiredFeatures[i])
3433 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
3439 return USP_E_SCRIPT_NOT_IN_FONT;