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);
50 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
52 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);
53 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 );
54 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 );
55 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 );
56 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 );
57 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 );
59 extern const unsigned short wine_shaping_table[];
60 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
82 #ifdef WORDS_BIGENDIAN
83 #define GET_BE_WORD(x) (x)
85 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
88 /* These are all structures needed for the GSUB table */
89 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
90 #define GSUB_E_NOFEATURE -2
91 #define GSUB_E_NOGLYPH -1
107 GSUB_ScriptRecord ScriptRecord[1];
113 } GSUB_LangSysRecord;
118 GSUB_LangSysRecord LangSysRecord[1];
122 WORD LookupOrder; /* Reserved */
123 WORD ReqFeatureIndex;
125 WORD FeatureIndex[1];
131 } GSUB_FeatureRecord;
135 GSUB_FeatureRecord FeatureRecord[1];
139 WORD FeatureParams; /* Reserved */
141 WORD LookupListIndex[1];
160 } GSUB_CoverageFormat1;
165 WORD StartCoverageIndex;
171 GSUB_RangeRecord RangeRecord[1];
172 } GSUB_CoverageFormat2;
175 WORD SubstFormat; /* = 1 */
178 } GSUB_SingleSubstFormat1;
181 WORD SubstFormat; /* = 2 */
185 }GSUB_SingleSubstFormat2;
188 WORD SubstFormat; /* = 1 */
192 }GSUB_LigatureSubstFormat1;
207 WORD LookupListIndex;
209 }GSUB_SubstLookupRecord;
212 WORD SubstFormat; /* = 1 */
214 WORD ChainSubRuleSetCount;
215 WORD ChainSubRuleSet[1];
216 }GSUB_ChainContextSubstFormat1;
219 WORD SubstFormat; /* = 3 */
220 WORD BacktrackGlyphCount;
222 }GSUB_ChainContextSubstFormat3_1;
225 WORD InputGlyphCount;
227 }GSUB_ChainContextSubstFormat3_2;
230 WORD LookaheadGlyphCount;
232 }GSUB_ChainContextSubstFormat3_3;
236 GSUB_SubstLookupRecord SubstLookupRecord[1];
237 }GSUB_ChainContextSubstFormat3_4;
240 WORD SubstFormat; /* = 1 */
242 WORD AlternateSetCount;
243 WORD AlternateSet[1];
244 } GSUB_AlternateSubstFormat1;
251 /* These are all structures needed for the GDEF table */
252 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
254 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
261 WORD MarkAttachClassDef;
268 WORD ClassValueArray[1];
269 } GDEF_ClassDefFormat1;
275 } GDEF_ClassRangeRecord;
279 WORD ClassRangeCount;
280 GDEF_ClassRangeRecord ClassRangeRecord[1];
281 } GDEF_ClassDefFormat2;
283 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
285 typedef struct tagVowelComponents
291 typedef struct tagConsonantComponents
295 } ConsonantComponents;
297 /* the orders of joined_forms and contextual_features need to line up */
298 static const char* contextual_features[] =
310 static OPENTYPE_FEATURE_RECORD standard_features[] =
312 { MS_MAKE_TAG('l','i','g','a'), 1},
313 { MS_MAKE_TAG('c','l','i','g'), 1},
316 static OPENTYPE_FEATURE_RECORD arabic_features[] =
318 { MS_MAKE_TAG('r','l','i','g'), 1},
319 { MS_MAKE_TAG('c','a','l','t'), 1},
320 { MS_MAKE_TAG('l','i','g','a'), 1},
321 { MS_MAKE_TAG('d','l','i','g'), 1},
322 { MS_MAKE_TAG('c','s','w','h'), 1},
323 { MS_MAKE_TAG('m','s','e','t'), 1},
326 static const char* required_arabic_features[] =
335 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
337 { MS_MAKE_TAG('d','l','i','g'), 1},
340 static OPENTYPE_FEATURE_RECORD syriac_features[] =
342 { MS_MAKE_TAG('r','l','i','g'), 1},
343 { MS_MAKE_TAG('c','a','l','t'), 1},
344 { MS_MAKE_TAG('l','i','g','a'), 1},
345 { MS_MAKE_TAG('d','l','i','g'), 1},
348 static const char* required_syriac_features[] =
360 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
363 { MS_MAKE_TAG('a','k','h','n'), 1},
364 { MS_MAKE_TAG('r','p','h','f'), 1},
365 { MS_MAKE_TAG('v','a','t','u'), 1},
366 { MS_MAKE_TAG('p','s','t','f'), 1},
367 /* Presentation forms */
368 { MS_MAKE_TAG('b','l','w','s'), 1},
369 { MS_MAKE_TAG('a','b','v','s'), 1},
370 { MS_MAKE_TAG('p','s','t','s'), 1},
373 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
375 { MS_MAKE_TAG('a','b','v','s'), 1},
376 { MS_MAKE_TAG('b','l','w','s'), 1},
379 static OPENTYPE_FEATURE_RECORD thai_features[] =
381 { MS_MAKE_TAG('c','c','m','p'), 1},
384 static const char* required_lao_features[] =
390 static const char* required_devanagari_features[] =
406 static OPENTYPE_FEATURE_RECORD devanagari_features[] =
408 /* Localized forms */
409 { MS_MAKE_TAG('l','o','c','l'), 1},
411 { MS_MAKE_TAG('n','u','k','t'), 1},
412 { MS_MAKE_TAG('a','k','h','n'), 1},
413 { MS_MAKE_TAG('r','p','h','f'), 1},
414 { MS_MAKE_TAG('r','k','r','f'), 1},
415 { MS_MAKE_TAG('b','l','w','f'), 1},
416 { MS_MAKE_TAG('h','a','l','f'), 1},
417 { MS_MAKE_TAG('v','a','t','u'), 1},
418 { MS_MAKE_TAG('c','j','c','t'), 1},
419 /* Presentation forms */
420 { MS_MAKE_TAG('p','r','e','s'), 1},
421 { MS_MAKE_TAG('a','b','v','s'), 1},
422 { MS_MAKE_TAG('b','l','w','s'), 1},
423 { MS_MAKE_TAG('p','s','t','s'), 1},
424 { MS_MAKE_TAG('h','a','l','n'), 1},
425 { MS_MAKE_TAG('c','a','l','t'), 1},
428 typedef struct ScriptShapeDataTag {
429 TEXTRANGE_PROPERTIES defaultTextRange;
430 const char** requiredFeatures;
433 ContextualShapingProc contextProc;
434 ShapeCharGlyphPropProc charGlyphPropProc;
437 /* in order of scripts */
438 static const ScriptShapeData ShapingData[] =
440 {{ standard_features, 2}, NULL, "", "", NULL, NULL},
441 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
442 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
443 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
444 {{ standard_features, 2}, NULL, "" , "", NULL, NULL},
445 {{ standard_features, 2}, NULL, "latn", "", NULL, NULL},
446 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
447 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
448 {{ hebrew_features, 1}, NULL, "hebr", "", NULL, NULL},
449 {{ syriac_features, 4}, required_syriac_features, "syrc", "", ContextualShape_Syriac, ShapeCharGlyphProp_None},
450 {{ arabic_features, 6}, required_arabic_features, "arab", "", ContextualShape_Arabic, ShapeCharGlyphProp_Arabic},
451 {{ NULL, 0}, NULL, "thaa", "", NULL, ShapeCharGlyphProp_None},
452 {{ standard_features, 2}, NULL, "grek", "", NULL, NULL},
453 {{ standard_features, 2}, NULL, "cyrl", "", NULL, NULL},
454 {{ standard_features, 2}, NULL, "armn", "", NULL, NULL},
455 {{ standard_features, 2}, NULL, "geor", "", NULL, NULL},
456 {{ sinhala_features, 7}, NULL, "sinh", "", ContextualShape_Sinhala, NULL},
457 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
458 {{ tibetan_features, 2}, NULL, "tibt", "", NULL, ShapeCharGlyphProp_Tibet},
459 {{ tibetan_features, 2}, NULL, "phag", "", ContextualShape_Phags_pa, ShapeCharGlyphProp_Thai},
460 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
461 {{ thai_features, 1}, NULL, "thai", "", NULL, ShapeCharGlyphProp_Thai},
462 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
463 {{ thai_features, 1}, required_lao_features, "lao", "", NULL, ShapeCharGlyphProp_Thai},
464 {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
465 {{ devanagari_features, 15}, required_devanagari_features, "deva", "dev2", ContextualShape_Devanagari, ShapeCharGlyphProp_Devanagari},
468 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
470 const GSUB_CoverageFormat1* cf1;
474 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
476 int count = GET_BE_WORD(cf1->GlyphCount);
478 TRACE("Coverage Format 1, %i glyphs\n",count);
479 for (i = 0; i < count; i++)
480 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
484 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
486 const GSUB_CoverageFormat2* cf2;
489 cf2 = (const GSUB_CoverageFormat2*)cf1;
491 count = GET_BE_WORD(cf2->RangeCount);
492 TRACE("Coverage Format 2, %i ranges\n",count);
493 for (i = 0; i < count; i++)
495 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
497 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
498 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
500 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
501 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
507 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
512 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
514 const GSUB_ScriptList *script;
515 const GSUB_Script *deflt = NULL;
517 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
519 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
520 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
522 const GSUB_Script *scr;
525 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
526 scr = (const GSUB_Script*)((const BYTE*)script + offset);
528 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
530 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
536 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
540 const GSUB_LangSys *Lang;
542 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
544 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
546 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
547 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
549 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
552 offset = GET_BE_WORD(script->DefaultLangSys);
555 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
561 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
564 const GSUB_FeatureList *feature;
565 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
567 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
568 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
570 int index = GET_BE_WORD(lang->FeatureIndex[i]);
571 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
573 const GSUB_Feature *feat;
574 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
581 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
584 TRACE("Single Substitution Subtable\n");
586 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
589 const GSUB_SingleSubstFormat1 *ssf1;
590 offset = GET_BE_WORD(look->SubTable[j]);
591 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
592 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
594 int offset = GET_BE_WORD(ssf1->Coverage);
595 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
596 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
598 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
599 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
600 TRACE(" 0x%x\n",glyphs[glyph_index]);
601 return glyph_index + 1;
606 const GSUB_SingleSubstFormat2 *ssf2;
610 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
611 offset = GET_BE_WORD(ssf1->Coverage);
612 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
613 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
614 TRACE(" Coverage index %i\n",index);
617 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
618 return GSUB_E_NOGLYPH;
620 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
621 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
622 TRACE("0x%x\n",glyphs[glyph_index]);
623 return glyph_index + 1;
627 return GSUB_E_NOGLYPH;
630 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
633 TRACE("Alternate Substitution Subtable\n");
635 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
638 const GSUB_AlternateSubstFormat1 *asf1;
641 offset = GET_BE_WORD(look->SubTable[j]);
642 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
643 offset = GET_BE_WORD(asf1->Coverage);
645 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
648 const GSUB_AlternateSet *as;
649 offset = GET_BE_WORD(asf1->AlternateSet[index]);
650 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
651 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
652 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
653 return GSUB_E_NOGLYPH;
655 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
656 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
657 TRACE(" 0x%x\n",glyphs[glyph_index]);
658 return glyph_index + 1;
661 return GSUB_E_NOGLYPH;
664 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
668 TRACE("Ligature Substitution Subtable\n");
669 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
671 const GSUB_LigatureSubstFormat1 *lsf1;
674 offset = GET_BE_WORD(look->SubTable[j]);
675 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
676 offset = GET_BE_WORD(lsf1->Coverage);
677 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
678 TRACE(" Coverage index %i\n",index);
681 const GSUB_LigatureSet *ls;
684 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
685 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
686 count = GET_BE_WORD(ls->LigatureCount);
687 TRACE(" LigatureSet has %i members\n",count);
688 for (k = 0; k < count; k++)
690 const GSUB_Ligature *lig;
691 int CompCount,l,CompIndex;
693 offset = GET_BE_WORD(ls->Ligature[k]);
694 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
695 CompCount = GET_BE_WORD(lig->CompCount) - 1;
696 CompIndex = glyph_index+write_dir;
697 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
700 CompGlyph = GET_BE_WORD(lig->Component[l]);
701 if (CompGlyph != glyphs[CompIndex])
703 CompIndex += write_dir;
707 int replaceIdx = glyph_index;
709 replaceIdx = glyph_index - CompCount;
711 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
712 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
713 TRACE("0x%x\n",glyphs[replaceIdx]);
717 for (j = replaceIdx + 1; j < *glyph_count; j++)
718 glyphs[j] =glyphs[j+CompCount];
719 *glyph_count = *glyph_count - CompCount;
721 return replaceIdx + 1;
726 return GSUB_E_NOGLYPH;
729 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
734 TRACE("Chaining Contextual Substitution Subtable\n");
735 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
737 const GSUB_ChainContextSubstFormat1 *ccsf1;
739 int dirLookahead = write_dir;
740 int dirBacktrack = -1 * write_dir;
742 offset = GET_BE_WORD(look->SubTable[j]);
743 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
744 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
746 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
749 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
751 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
754 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
758 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
759 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
760 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
761 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
762 int newIndex = glyph_index;
764 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
766 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
768 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
770 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
771 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
774 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
776 TRACE("Matched Backtrack\n");
778 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
780 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
781 for (k = 0; k < indexGlyphs; k++)
783 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
784 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
787 if (k != indexGlyphs)
789 TRACE("Matched IndexGlyphs\n");
791 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
793 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
795 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
796 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
799 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
801 TRACE("Matched LookAhead\n");
803 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
805 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
807 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
808 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
810 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
811 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
814 ERR("Chain failed to generate a glyph\n");
824 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
827 const GSUB_LookupTable *look;
829 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
830 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
831 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
832 switch(GET_BE_WORD(look->LookupType))
835 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
837 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
839 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
841 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
843 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
845 return GSUB_E_NOGLYPH;
848 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
851 int out_index = GSUB_E_NOGLYPH;
852 const GSUB_LookupList *lookup;
854 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
856 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
857 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
859 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
860 if (out_index != GSUB_E_NOGLYPH)
863 if (out_index == GSUB_E_NOGLYPH)
864 TRACE("lookups found no glyphs\n");
868 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
869 if (out2!=GSUB_E_NOGLYPH)
875 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, BOOL tryNew)
879 if (psc->userScript != 0)
881 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0 && strncmp((char*)&psc->userScript,ShapingData[psa->eScript].otTag,4)==0)
882 return ShapingData[psa->eScript].newOtTag;
884 return (char*)&psc->userScript;
887 if (tryNew && ShapingData[psa->eScript].newOtTag[0] != 0)
888 return ShapingData[psa->eScript].newOtTag;
890 if (ShapingData[psa->eScript].otTag[0] != 0)
891 return ShapingData[psa->eScript].otTag;
894 * fall back to the font charset
896 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
899 case ANSI_CHARSET: return "latn";
900 case BALTIC_CHARSET: return "latn"; /* ?? */
901 case CHINESEBIG5_CHARSET: return "hani";
902 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
903 case GB2312_CHARSET: return "hani";
904 case GREEK_CHARSET: return "grek";
905 case HANGUL_CHARSET: return "hang";
906 case RUSSIAN_CHARSET: return "cyrl";
907 case SHIFTJIS_CHARSET: return "kana";
908 case TURKISH_CHARSET: return "latn"; /* ?? */
909 case VIETNAMESE_CHARSET: return "latn";
910 case JOHAB_CHARSET: return "latn"; /* ?? */
911 case ARABIC_CHARSET: return "arab";
912 case HEBREW_CHARSET: return "hebr";
913 case THAI_CHARSET: return "thai";
914 default: return "latn";
918 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
920 const GSUB_Feature *feature;
923 for (i = 0; i < psc->feature_count; i++)
924 if (strncmp(psc->features[i].tag,feat,4)==0)
925 return psc->features[i].feature;
931 const GSUB_Script *script;
932 const GSUB_LangSys *language;
937 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc,(attempt==2)));
941 if (psc->userLang != 0)
942 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
944 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
946 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
948 } while(attempt && !feature);
950 /* try in the default (latin) table */
953 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
956 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
958 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
963 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
965 psc->feature_count++;
968 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
970 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
972 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
973 psc->features[psc->feature_count - 1].feature = feature;
977 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)
979 const GSUB_Feature *feature;
981 feature = load_GSUB_feature(hdc, psa, psc, feat);
983 return GSUB_E_NOFEATURE;
985 TRACE("applying feature %s\n",feat);
986 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
989 static VOID *load_gsub_table(HDC hdc)
991 VOID* GSUB_Table = NULL;
992 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
993 if (length != GDI_ERROR)
995 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
996 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
997 TRACE("Loaded GSUB table of %i bytes\n",length);
1002 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
1006 const GDEF_ClassDefFormat1 *cf1;
1011 offset = GET_BE_WORD(header->GlyphClassDef);
1015 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
1016 if (GET_BE_WORD(cf1->ClassFormat) == 1)
1018 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
1020 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
1021 if (index < GET_BE_WORD(cf1->GlyphCount))
1022 class = GET_BE_WORD(cf1->ClassValueArray[index]);
1025 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
1027 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
1029 top = GET_BE_WORD(cf2->ClassRangeCount);
1030 for (i = 0; i < top; i++)
1032 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
1033 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
1035 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
1041 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
1046 static VOID *load_gdef_table(HDC hdc)
1048 VOID* GDEF_Table = NULL;
1049 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
1050 if (length != GDI_ERROR)
1052 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
1053 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
1054 TRACE("Loaded GDEF table of %i bytes\n",length);
1059 static void GDEF_UpdateGlyphProps(HDC hdc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1061 VOID* header = load_gdef_table(hdc);
1064 for (i = 0; i < cGlyphs; i++)
1068 class = GDEF_get_glyph_class(header, pwGlyphs[i]);
1074 pGlyphProp[i].sva.fClusterStart = 1;
1075 pGlyphProp[i].sva.fDiacritic = 0;
1076 pGlyphProp[i].sva.fZeroWidth = 0;
1079 pGlyphProp[i].sva.fClusterStart = 1;
1080 pGlyphProp[i].sva.fDiacritic = 0;
1081 pGlyphProp[i].sva.fZeroWidth = 0;
1084 pGlyphProp[i].sva.fClusterStart = 0;
1085 pGlyphProp[i].sva.fDiacritic = 1;
1086 pGlyphProp[i].sva.fZeroWidth = 1;
1088 case ComponentGlyph:
1089 pGlyphProp[i].sva.fClusterStart = 0;
1090 pGlyphProp[i].sva.fDiacritic = 0;
1091 pGlyphProp[i].sva.fZeroWidth = 0;
1094 ERR("Unknown glyph class %i\n",class);
1095 pGlyphProp[i].sva.fClusterStart = 1;
1096 pGlyphProp[i].sva.fDiacritic = 0;
1097 pGlyphProp[i].sva.fZeroWidth = 0;
1102 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1106 for (i = 0; i < cGlyphs; i++)
1108 if (!pGlyphProp[i].sva.fClusterStart)
1111 for (j = 0; j < cChars; j++)
1113 if (pwLogClust[j] == i)
1116 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1118 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1119 pwLogClust[j] = pwLogClust[k];
1126 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1128 if (changeCount == 0)
1133 int target_glyph = nextIndex - 1;
1134 int target_index = -1;
1135 int replacing_glyph = -1;
1139 for (i = 0; i < chars; i++)
1141 if (pwLogClust[i] == target_glyph)
1148 for (i = chars - 1; i >= 0; i--)
1150 if (pwLogClust[i] == target_glyph)
1156 if (target_index == -1)
1158 ERR("Unable to find target glyph\n");
1162 if (changeCount < 0)
1165 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1167 if (pwLogClust[i] == target_glyph)
1169 if(pwLogClust[i] == replacing_glyph)
1170 pwLogClust[i] = target_glyph;
1174 if (changed >= changeCount)
1176 replacing_glyph = pwLogClust[i];
1177 pwLogClust[i] = target_glyph;
1185 /* renumber trailing indexes*/
1186 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1188 if (pwLogClust[i] != target_glyph)
1189 pwLogClust[i] += changeCount;
1194 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 )
1198 if (psc->GSUB_Table)
1200 const GSUB_Feature *feature;
1202 feature = load_GSUB_feature(hdc, psa, psc, feat);
1204 return GSUB_E_NOFEATURE;
1207 TRACE("applying feature %s\n",debugstr_an(feat,4));
1208 while(i < *pcGlyphs)
1211 INT prevCount = *pcGlyphs;
1212 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1213 if (nextIndex > GSUB_E_NOGLYPH)
1215 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1223 return GSUB_E_NOFEATURE;
1226 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1230 if ( i+ delta >= cchLen)
1238 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1242 if (psa->fLinkBefore)
1247 if ( i+ delta >= cchLen)
1249 if (psa->fLinkAfter)
1257 if (context_type[i] == jtT)
1258 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1260 return context_type[i];
1263 static inline BOOL right_join_causing(CHAR joining_type)
1265 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1268 static inline BOOL left_join_causing(CHAR joining_type)
1270 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1273 static inline BOOL word_break_causing(WCHAR chr)
1275 /* we are working within a string of characters already guareented to
1276 be within one script, Syriac, so we do not worry about any characers
1277 other than the space character outside of that range */
1278 return (chr == 0 || chr == 0x20 );
1282 * ContextualShape_Arabic
1284 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1291 if (*pcGlyphs != cChars)
1293 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1297 if (!psa->fLogicalOrder && psa->fRTL)
1308 if (!psc->GSUB_Table)
1309 psc->GSUB_Table = load_gsub_table(hdc);
1311 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1312 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1314 for (i = 0; i < cChars; i++)
1315 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1317 for (i = 0; i < cChars; i++)
1319 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1320 context_shape[i] = Xr;
1321 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1322 context_shape[i] = Xl;
1323 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)))
1324 context_shape[i] = Xm;
1325 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1326 context_shape[i] = Xr;
1327 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1328 context_shape[i] = Xl;
1330 context_shape[i] = Xn;
1333 /* Contextual Shaping */
1335 while(i < *pcGlyphs)
1337 BOOL shaped = FALSE;
1339 if (psc->GSUB_Table)
1342 INT prevCount = *pcGlyphs;
1343 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1344 if (nextIndex > GSUB_E_NOGLYPH)
1347 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1349 shaped = (nextIndex > GSUB_E_NOGLYPH);
1354 WORD newGlyph = pwOutGlyphs[i];
1355 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1357 /* fall back to presentation form B */
1358 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1359 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1360 pwOutGlyphs[i] = newGlyph;
1366 HeapFree(GetProcessHeap(),0,context_shape);
1367 HeapFree(GetProcessHeap(),0,context_type);
1371 * ContextualShape_Syriac
1375 #define DALATH 0x715
1378 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1385 if (*pcGlyphs != cChars)
1387 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1391 if (!psa->fLogicalOrder && psa->fRTL)
1402 if (!psc->GSUB_Table)
1403 psc->GSUB_Table = load_gsub_table(hdc);
1405 if (!psc->GSUB_Table)
1408 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1409 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1411 for (i = 0; i < cChars; i++)
1412 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1414 for (i = 0; i < cChars; i++)
1416 if (pwcChars[i] == ALAPH)
1418 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1420 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1421 context_shape[i] = Afj;
1422 else if ( rchar != DALATH && rchar != RISH &&
1423 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1424 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1425 context_shape[i] = Afn;
1426 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1427 context_shape[i] = Afx;
1429 context_shape[i] = Xn;
1431 else if (context_type[i] == jtR &&
1432 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1433 context_shape[i] = Xr;
1434 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1435 context_shape[i] = Xl;
1436 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)))
1437 context_shape[i] = Xm;
1438 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1439 context_shape[i] = Xr;
1440 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1441 context_shape[i] = Xl;
1443 context_shape[i] = Xn;
1446 /* Contextual Shaping */
1448 while(i < *pcGlyphs)
1451 INT prevCount = *pcGlyphs;
1452 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1453 if (nextIndex > GSUB_E_NOGLYPH)
1455 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1462 HeapFree(GetProcessHeap(),0,context_shape);
1463 HeapFree(GetProcessHeap(),0,context_type);
1467 * ContextualShape_Phags_pa
1470 #define phags_pa_CANDRABINDU 0xA873
1471 #define phags_pa_START 0xA840
1472 #define phags_pa_END 0xA87F
1474 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1480 if (*pcGlyphs != cChars)
1482 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1486 if (!psa->fLogicalOrder && psa->fRTL)
1497 if (!psc->GSUB_Table)
1498 psc->GSUB_Table = load_gsub_table(hdc);
1500 if (!psc->GSUB_Table)
1503 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1505 for (i = 0; i < cChars; i++)
1507 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1509 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1510 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1511 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1512 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1514 if (jrchar && jlchar)
1515 context_shape[i] = Xm;
1517 context_shape[i] = Xr;
1519 context_shape[i] = Xl;
1521 context_shape[i] = Xn;
1524 context_shape[i] = -1;
1527 /* Contextual Shaping */
1529 while(i < *pcGlyphs)
1531 if (context_shape[i] >= 0)
1534 INT prevCount = *pcGlyphs;
1535 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1536 if (nextIndex > GSUB_E_NOGLYPH)
1538 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1548 HeapFree(GetProcessHeap(),0,context_shape);
1551 static void ReplaceInsertChars(HDC hdc, INT cWalk, INT* pcChars, WCHAR *pwOutChars, const WCHAR *replacements)
1556 pwOutChars[cWalk] = replacements[0];
1560 for (i = 1; replacements[i] != 0x0000 && i < 3; i++)
1563 for (j = *pcChars; j > cWalk; j--)
1564 pwOutChars[j] = pwOutChars[j-1];
1565 *pcChars= *pcChars+1;
1566 pwOutChars[cWalk] = replacements[i];
1571 static void DecomposeVowels(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const VowelComponents vowels[])
1576 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1578 for (i = 0; vowels[i].base != 0x0; i++)
1580 if (pwOutChars[cWalk] == vowels[i].base)
1582 ReplaceInsertChars(hdc, cWalk, pcChars, pwOutChars, vowels[i].parts);
1589 static void ComposeConsonants(HDC hdc, WCHAR *pwOutChars, INT *pcChars, const ConsonantComponents consonants[])
1594 for (cWalk = 0; cWalk < *pcChars; cWalk++)
1596 for (i = 0; consonants[i].output!= 0x0; i++)
1599 for (j = 0; j + cWalk < *pcChars && consonants[i].parts[j]!=0x0; j++)
1600 if (pwOutChars[cWalk+j] != consonants[i].parts[j])
1603 if (consonants[i].parts[j]==0x0) /* matched all */
1607 pwOutChars[cWalk] = consonants[i].output;
1608 for(k = cWalk+1; k < *pcChars - j; k++)
1609 pwOutChars[k] = pwOutChars[k+j];
1610 *pcChars = *pcChars - j;
1618 static void Reorder_Ra_follows_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1620 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1623 WORD Ra = pwChar[start];
1624 WORD H = pwChar[start+1];
1626 TRACE("Doing reorder of Ra to %i\n",main);
1627 for (j = start; j < main-1; j++)
1628 pwChar[j] = pwChar[j+2];
1629 pwChar[main-1] = Ra;
1634 static void Reorder_Ra_follows_mantra_post(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1636 if (start != main && end > start+1 && lexical(pwChar[start]) == lex_Ra && lexical(pwChar[start+1]) == lex_Halant)
1639 WORD Ra = pwChar[start];
1640 WORD H = pwChar[start+1];
1641 for (loc = main; loc > end; loc++)
1642 if (lexical(pwChar[loc]) == lex_Mantra_post)
1644 if (loc == end) loc = main;
1646 TRACE("Doing reorder of Ra to %i\n",loc);
1647 for (j = start; j < loc-1; j++)
1648 pwChar[j] = pwChar[j+2];
1654 static void Reorder_Mantra_precede_base(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1658 /* reorder Mantras */
1661 for (i = 1; i <= end-main; i++)
1663 if (lexical(pwChar[main+i]) == lex_Mantra_pre)
1666 WCHAR c = pwChar[main+i];
1667 TRACE("Doing reorder of %x %x\n",c,pwChar[main]);
1668 for (j = main+i; j > main; j--)
1669 pwChar[j] = pwChar[j-1];
1676 static void Reorder_Mantra_precede_syllable(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1680 /* reorder Mantras */
1683 for (i = 1; i <= end-main; i++)
1685 if (lexical(pwChar[main+i]) == lex_Mantra_pre)
1688 WCHAR c = pwChar[main+i];
1689 TRACE("Doing reorder of %x to %i\n",c,start);
1690 for (j = main+i; j > start; j--)
1691 pwChar[j] = pwChar[j-1];
1698 static void Reorder_Like_Sinhala(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1700 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1701 if (start == main && main == end) return;
1703 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1704 if (lexical(pwChar[main]) == lex_Vowel) return;
1706 Reorder_Ra_follows_base(pwChar, start, main, end, lexical);
1707 Reorder_Mantra_precede_base(pwChar, start, main, end, lexical);
1710 static void Reorder_Like_Devanagari(LPWSTR pwChar, INT start, INT main, INT end, lexical_function lexical)
1712 TRACE("Syllable (%i..%i..%i)\n",start,main,end);
1713 if (start == main && main == end) return;
1715 main = Indic_FindBaseConsonant(pwChar, start, main, end, lexical);
1716 if (lexical(pwChar[main]) == lex_Vowel) return;
1718 Reorder_Ra_follows_mantra_post(pwChar, start, main, end, lexical);
1719 Reorder_Mantra_precede_syllable(pwChar, start, main, end, lexical);
1722 static int sinhala_lex(WCHAR c)
1726 case 0x0DCA: return lex_Halant;
1729 case 0x0DD8: return lex_Mantra_post;
1731 case 0x0DDB: return lex_Mantra_pre;
1733 case 0x0DDC: return lex_Composed_Vowel;
1734 case 0x200D: return lex_ZWJ;
1735 case 0x200C: return lex_ZWNJ;
1736 case 0x00A0: return lex_NBSP;
1738 if (c>=0x0D82 && c <=0x0D83) return lex_Modifier;
1739 else if (c>=0x0D85 && c <=0x0D96) return lex_Vowel;
1740 else if (c>=0x0D96 && c <=0x0DC6) return lex_Consonant;
1741 else if (c>=0x0DD0 && c <=0x0DD1) return lex_Mantra_post;
1742 else if (c>=0x0DD2 && c <=0x0DD3) return lex_Mantra_above;
1743 else if (c>=0x0DD4 && c <=0x0DD6) return lex_Mantra_below;
1744 else if (c>=0x0DDD && c <=0x0DDE) return lex_Composed_Vowel;
1745 else if (c>=0x0DF2 && c <=0x0DF3) return lex_Mantra_post;
1746 else return lex_Generic;
1750 static const VowelComponents Sinhala_vowels[] = {
1751 {0x0DDA, {0x0DD9,0x0DCA,0x0}},
1752 {0x0DDC, {0x0DD9,0x0DCF,0x0}},
1753 {0x0DDD, {0x0DD9,0x0DCF,0x0DCA}},
1754 {0x0DDE, {0x0DD9,0x0DDF,0x0}},
1755 {0x0000, {0x0000,0x0000,0x0}}};
1757 static void ContextualShape_Sinhala(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1759 int cCount = cChars;
1762 if (*pcGlyphs != cChars)
1764 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1768 input = HeapAlloc(GetProcessHeap(),0,sizeof(WCHAR) * (cChars * 3));
1770 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1772 /* Step 1: Decompose multi part vowels */
1773 DecomposeVowels(hdc, input, &cCount, Sinhala_vowels);
1775 TRACE("New double vowel expanded string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1777 /* Step 2: Reorder within Syllables */
1778 Indic_ReorderCharacters( input, cCount, sinhala_lex, Reorder_Like_Sinhala);
1779 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1781 /* Step 3: Get glyphs */
1782 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1785 HeapFree(GetProcessHeap(),0,input);
1788 static int devanagari_lex(WCHAR c)
1794 case 0x0903: return lex_Modifier;
1795 case 0x0930: return lex_Ra;
1796 case 0x093C: return lex_Nukta;
1798 case 0x093E: return lex_Mantra_post;
1799 case 0x093F: return lex_Mantra_pre;
1800 case 0x094D: return lex_Halant;
1801 case 0x0972: return lex_Vowel;
1802 case 0x200C: return lex_ZWNJ;
1803 case 0x200D: return lex_ZWJ;
1805 if (c>=0x0901 && c<=0x0902) return lex_Mantra_above;
1806 else if (c>=0x0904 && c<=0x0914) return lex_Vowel;
1807 else if (c>=0x0915 && c<=0x0939) return lex_Consonant;
1808 else if (c>=0x0941 && c<=0x0944) return lex_Mantra_below;
1809 else if (c>=0x0945 && c<=0x0948) return lex_Mantra_above;
1810 else if (c>=0x0949 && c<=0x094C) return lex_Mantra_post;
1811 else if (c>=0x0953 && c<=0x0954) return lex_Modifier;
1812 else if (c>=0x0958 && c<=0x095F) return lex_Consonant;
1813 else if (c>=0x0960 && c<=0x0961) return lex_Vowel;
1814 else if (c>=0x0962 && c<=0x0963) return lex_Mantra_below;
1815 else if (c>=0x097B && c<=0x097C) return lex_Consonant;
1816 else if (c>=0x097E && c<=0x097F) return lex_Consonant;
1817 else return lex_Generic;
1821 static const ConsonantComponents Devanagari_consonants[] ={
1822 {{0x0928, 0x093C, 0x00000}, 0x0929},
1823 {{0x0930, 0x093C, 0x00000}, 0x0931},
1824 {{0x0933, 0x093C, 0x00000}, 0x0934},
1825 {{0x0915, 0x093C, 0x00000}, 0x0958},
1826 {{0x0916, 0x093C, 0x00000}, 0x0959},
1827 {{0x0917, 0x093C, 0x00000}, 0x095A},
1828 {{0x091C, 0x093C, 0x00000}, 0x095B},
1829 {{0x0921, 0x093C, 0x00000}, 0x095C},
1830 {{0x0922, 0x093C, 0x00000}, 0x095D},
1831 {{0x092B, 0x093C, 0x00000}, 0x095E},
1832 {{0x092F, 0x093C, 0x00000}, 0x095F}};
1834 static void ContextualShape_Devanagari(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1836 int cCount = cChars;
1839 if (*pcGlyphs != cChars)
1841 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1845 input = HeapAlloc(GetProcessHeap(), 0, cChars * sizeof(WCHAR));
1846 memcpy(input, pwcChars, cChars * sizeof(WCHAR));
1848 /* Step 1: Compose Consonant and Nukta */
1849 ComposeConsonants(hdc, input, &cCount, Devanagari_consonants);
1850 TRACE("New composed string %s (%i)\n",debugstr_wn(input,cCount),cCount);
1852 /* Step 2: Reorder within Syllables */
1853 Indic_ReorderCharacters( input, cCount, devanagari_lex, Reorder_Like_Devanagari);
1854 TRACE("reordered string %s\n",debugstr_wn(input,cCount));
1855 GetGlyphIndicesW(hdc, input, cCount, pwOutGlyphs, 0);
1858 HeapFree(GetProcessHeap(),0,input);
1861 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)
1865 for (i = 0; i < cGlyphs; i++)
1870 for (k = 0; k < cChars; k++)
1872 if (pwLogClust[k] == i)
1874 char_index[char_count] = k;
1879 if (char_count == 0)
1881 FIXME("No chars in this glyph? Must be an error\n");
1885 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
1887 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
1888 pCharProp[char_index[0]].fCanGlyphAlone = 1;
1891 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1894 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1895 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1898 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 )
1901 int initGlyph, finaGlyph;
1905 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
1906 memset(spaces,0,cGlyphs);
1908 if (!psa->fLogicalOrder && psa->fRTL)
1910 initGlyph = cGlyphs-1;
1918 finaGlyph = cGlyphs-1;
1923 for (i = 0; i < cGlyphs; i++)
1925 for (k = 0; k < cChars; k++)
1926 if (pwLogClust[k] == i)
1928 if (pwcChars[k] == 0x0020)
1933 for (i = 0; i < cGlyphs; i++)
1937 BOOL isInit, isFinal;
1939 for (k = 0; k < cChars; k++)
1941 if (pwLogClust[k] == i)
1943 char_index[char_count] = k;
1948 isInit = (i == initGlyph || (i+dirR > 0 && i+dirR < cGlyphs && spaces[i+dirR]));
1949 isFinal = (i == finaGlyph || (i+dirL > 0 && i+dirL < cGlyphs && spaces[i+dirL]));
1951 if (char_count == 0)
1953 FIXME("No chars in this glyph? Must be an error\n");
1957 if (char_count == 1)
1959 if (pwcChars[char_index[0]] == 0x0020) /* space */
1961 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BLANK;
1962 pCharProp[char_index[0]].fCanGlyphAlone = 1;
1964 else if (pwcChars[char_index[0]] == 0x0640) /* kashida */
1965 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_KASHIDA;
1966 else if (pwcChars[char_index[0]] == 0x0633) /* SEEN */
1968 if (!isInit && !isFinal)
1969 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN_M;
1971 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_SEEN;
1973 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1977 if (pwcChars[char_index[0]] == 0x0628 ) /* BA */
1978 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BA;
1979 else if (pwcChars[char_index[0]] == 0x0631 ) /* RA */
1980 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_RA;
1981 else if (pwcChars[char_index[0]] == 0x0647 ) /* HA */
1982 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_HA;
1983 else if ((pwcChars[char_index[0]] == 0x0627 || pwcChars[char_index[0]] == 0x0625 || pwcChars[char_index[0]] == 0x0623 || pwcChars[char_index[0]] == 0x0622) ) /* alef-like */
1984 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_ALEF;
1986 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1988 else if (!isInit && !isFinal)
1989 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
1991 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
1993 else if (char_count == 2)
1995 if ((pwcChars[char_index[0]] == 0x0628 && pwcChars[char_index[1]]== 0x0631) || (pwcChars[char_index[0]] == 0x0631 && pwcChars[char_index[1]]== 0x0628)) /* BA+RA */
1996 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_BARA;
1998 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2000 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2002 else if (!isInit && !isFinal)
2003 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_ARABIC_NORMAL;
2005 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2008 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2009 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2010 HeapFree(GetProcessHeap(),0,spaces);
2013 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 )
2020 spaces = HeapAlloc(GetProcessHeap(),0,cGlyphs);
2021 memset(spaces,0,cGlyphs);
2023 if (!psa->fLogicalOrder && psa->fRTL)
2030 finaGlyph = cGlyphs-1;
2034 for (i = 0; i < cGlyphs; i++)
2036 for (k = 0; k < cChars; k++)
2037 if (pwLogClust[k] == i)
2039 if (pwcChars[k] == 0x0020)
2044 for (i = 0; i < cGlyphs; i++)
2049 for (k = 0; k < cChars; k++)
2051 if (pwLogClust[k] == i)
2053 char_index[char_count] = k;
2058 if (char_count == 0)
2060 FIXME("No chars in this glyph? Must be an error\n");
2064 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2066 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2067 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2069 else if (i == finaGlyph)
2070 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2072 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2075 HeapFree(GetProcessHeap(),0,spaces);
2076 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2077 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2079 /* Do not allow justification between marks and their base */
2080 for (i = 0; i < cGlyphs; i++)
2082 if (!pGlyphProp[i].sva.fClusterStart)
2083 pGlyphProp[i-dirL].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2087 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)
2091 for (i = 0; i < cGlyphs; i++)
2096 for (k = 0; k < cChars; k++)
2098 if (pwLogClust[k] == i)
2100 char_index[char_count] = k;
2105 if (char_count == 0)
2107 FIXME("No chars in this glyph? Must be an error\n");
2111 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2113 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
2114 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2117 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2119 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2120 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2123 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)
2127 for (i = 0; i < cGlyphs; i++)
2132 for (k = 0; k < cChars; k++)
2134 if (pwLogClust[k] == i)
2136 char_index[char_count] = k;
2141 if (char_count == 0)
2143 FIXME("No chars in this glyph? Must be an error\n");
2147 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2149 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2150 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2153 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2155 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
2156 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2158 /* Tibeten script does not set sva.fDiacritic or sva.fZeroWidth */
2159 for (i = 0; i < cGlyphs; i++)
2161 if (!pGlyphProp[i].sva.fClusterStart)
2163 pGlyphProp[i].sva.fDiacritic = 0;
2164 pGlyphProp[i].sva.fZeroWidth = 0;
2169 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)
2173 for (i = 0; i < cGlyphs; i++)
2178 for (k = 0; k < cChars; k++)
2180 if (pwLogClust[k] == i)
2182 char_index[char_count] = k;
2187 if (char_count == 0)
2189 FIXME("No chars in this glyph? Must be an error\n");
2193 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
2195 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
2196 pCharProp[char_index[0]].fCanGlyphAlone = 1;
2199 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_NONE;
2201 pGlyphProp[i].sva.fClusterStart = 0;
2202 for (k = 0; k < char_count && !pGlyphProp[i].sva.fClusterStart; k++)
2203 switch (lexical(pwcChars[char_index[k]]))
2205 case lex_Mantra_pre:
2206 case lex_Mantra_post:
2207 case lex_Mantra_above:
2208 case lex_Mantra_below:
2212 pGlyphProp[i].sva.fClusterStart = 1;
2216 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
2219 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 )
2221 ShapeCharGlyphProp_BaseIndic(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp, devanagari_lex);
2224 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)
2226 if (ShapingData[psa->eScript].charGlyphPropProc)
2227 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2229 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
2232 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
2234 if (ShapingData[psa->eScript].contextProc)
2235 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
2238 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)
2243 if (!rpRangeProperties)
2246 if (!psc->GSUB_Table)
2247 psc->GSUB_Table = load_gsub_table(hdc);
2249 if (!psc->GSUB_Table)
2252 if (!psa->fLogicalOrder && psa->fRTL)
2257 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
2259 if (rpRangeProperties->potfRecords[i].lParameter > 0)
2260 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
2264 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
2266 const TEXTRANGE_PROPERTIES *rpRangeProperties;
2267 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
2269 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
2272 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
2274 const GSUB_Feature *feature;
2277 if (!ShapingData[psa->eScript].requiredFeatures)
2280 if (!psc->GSUB_Table)
2281 psc->GSUB_Table = load_gsub_table(hdc);
2283 /* we need to have at least one of the required features */
2285 while (ShapingData[psa->eScript].requiredFeatures[i])
2287 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
2293 return USP_E_SCRIPT_NOT_IN_FONT;