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);
48 typedef VOID (*ShapeCharGlyphPropProc)( HDC , ScriptCache*, SCRIPT_ANALYSIS*, const WCHAR*, const INT, const WORD*, const INT, WORD*, SCRIPT_CHARPROP*, SCRIPT_GLYPHPROP*);
50 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);
52 extern const unsigned short wine_shaping_table[];
53 extern const unsigned short wine_shaping_forms[LAST_ARABIC_CHAR - FIRST_ARABIC_CHAR + 1][4];
75 #ifdef WORDS_BIGENDIAN
76 #define GET_BE_WORD(x) (x)
78 #define GET_BE_WORD(x) RtlUshortByteSwap(x)
81 /* These are all structures needed for the GSUB table */
82 #define GSUB_TAG MS_MAKE_TAG('G', 'S', 'U', 'B')
83 #define GSUB_E_NOFEATURE -2
84 #define GSUB_E_NOGLYPH -1
100 GSUB_ScriptRecord ScriptRecord[1];
106 } GSUB_LangSysRecord;
111 GSUB_LangSysRecord LangSysRecord[1];
115 WORD LookupOrder; /* Reserved */
116 WORD ReqFeatureIndex;
118 WORD FeatureIndex[1];
124 } GSUB_FeatureRecord;
128 GSUB_FeatureRecord FeatureRecord[1];
132 WORD FeatureParams; /* Reserved */
134 WORD LookupListIndex[1];
153 } GSUB_CoverageFormat1;
158 WORD StartCoverageIndex;
164 GSUB_RangeRecord RangeRecord[1];
165 } GSUB_CoverageFormat2;
168 WORD SubstFormat; /* = 1 */
171 } GSUB_SingleSubstFormat1;
174 WORD SubstFormat; /* = 2 */
178 }GSUB_SingleSubstFormat2;
181 WORD SubstFormat; /* = 1 */
185 }GSUB_LigatureSubstFormat1;
200 WORD LookupListIndex;
202 }GSUB_SubstLookupRecord;
205 WORD SubstFormat; /* = 1 */
207 WORD ChainSubRuleSetCount;
208 WORD ChainSubRuleSet[1];
209 }GSUB_ChainContextSubstFormat1;
212 WORD SubstFormat; /* = 3 */
213 WORD BacktrackGlyphCount;
215 }GSUB_ChainContextSubstFormat3_1;
218 WORD InputGlyphCount;
220 }GSUB_ChainContextSubstFormat3_2;
223 WORD LookaheadGlyphCount;
225 }GSUB_ChainContextSubstFormat3_3;
229 GSUB_SubstLookupRecord SubstLookupRecord[1];
230 }GSUB_ChainContextSubstFormat3_4;
233 WORD SubstFormat; /* = 1 */
235 WORD AlternateSetCount;
236 WORD AlternateSet[1];
237 } GSUB_AlternateSubstFormat1;
244 /* These are all structures needed for the GDEF table */
245 #define GDEF_TAG MS_MAKE_TAG('G', 'D', 'E', 'F')
247 enum {BaseGlyph=1, LigatureGlyph, MarkGlyph, ComponentGlyph};
254 WORD MarkAttachClassDef;
261 WORD ClassValueArray[1];
262 } GDEF_ClassDefFormat1;
268 } GDEF_ClassRangeRecord;
272 WORD ClassRangeCount;
273 GDEF_ClassRangeRecord ClassRangeRecord[1];
274 } GDEF_ClassDefFormat2;
276 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count);
278 /* the orders of joined_forms and contextual_features need to line up */
279 static const char* contextual_features[] =
291 static OPENTYPE_FEATURE_RECORD standard_features[] =
293 { MS_MAKE_TAG('l','i','g','a'), 1},
294 { MS_MAKE_TAG('c','l','i','g'), 1},
297 static OPENTYPE_FEATURE_RECORD arabic_features[] =
299 { MS_MAKE_TAG('r','l','i','g'), 1},
300 { MS_MAKE_TAG('c','a','l','t'), 1},
301 { MS_MAKE_TAG('l','i','g','a'), 1},
302 { MS_MAKE_TAG('d','l','i','g'), 1},
303 { MS_MAKE_TAG('c','s','w','h'), 1},
304 { MS_MAKE_TAG('m','s','e','t'), 1},
307 static const char* required_arabic_features[] =
316 static OPENTYPE_FEATURE_RECORD hebrew_features[] =
318 { MS_MAKE_TAG('d','l','i','g'), 1},
321 static OPENTYPE_FEATURE_RECORD syriac_features[] =
323 { MS_MAKE_TAG('r','l','i','g'), 1},
324 { MS_MAKE_TAG('c','a','l','t'), 1},
325 { MS_MAKE_TAG('l','i','g','a'), 1},
326 { MS_MAKE_TAG('d','l','i','g'), 1},
329 static const char* required_syriac_features[] =
341 static OPENTYPE_FEATURE_RECORD sinhala_features[] =
344 { MS_MAKE_TAG('a','k','h','n'), 1},
345 { MS_MAKE_TAG('r','p','h','f'), 1},
346 { MS_MAKE_TAG('v','a','t','u'), 1},
347 { MS_MAKE_TAG('p','s','t','f'), 1},
348 /* Presentation forms */
349 { MS_MAKE_TAG('b','l','w','s'), 1},
350 { MS_MAKE_TAG('a','b','v','s'), 1},
351 { MS_MAKE_TAG('p','s','t','s'), 1},
354 static OPENTYPE_FEATURE_RECORD tibetan_features[] =
356 { MS_MAKE_TAG('a','b','v','s'), 1},
357 { MS_MAKE_TAG('b','l','w','s'), 1},
360 static OPENTYPE_FEATURE_RECORD thai_features[] =
362 { MS_MAKE_TAG('c','c','m','p'), 1},
365 static const char* required_lao_features[] =
371 typedef struct ScriptShapeDataTag {
372 TEXTRANGE_PROPERTIES defaultTextRange;
373 const char** requiredFeatures;
375 ContextualShapingProc contextProc;
376 ShapeCharGlyphPropProc charGlyphPropProc;
379 /* in order of scripts */
380 static const ScriptShapeData ShapingData[] =
382 {{ standard_features, 2}, NULL, "", NULL, NULL},
383 {{ standard_features, 2}, NULL, "latn", NULL, NULL},
384 {{ standard_features, 2}, NULL, "latn", NULL, NULL},
385 {{ standard_features, 2}, NULL, "latn", NULL, NULL},
386 {{ standard_features, 2}, NULL, "" , NULL, NULL},
387 {{ standard_features, 2}, NULL, "latn", NULL, NULL},
388 {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic, NULL},
389 {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic, NULL},
390 {{ hebrew_features, 1}, NULL, "hebr", NULL, NULL},
391 {{ syriac_features, 4}, required_syriac_features, "syrc", ContextualShape_Syriac, NULL},
392 {{ arabic_features, 6}, required_arabic_features, "arab", ContextualShape_Arabic, NULL},
393 {{ NULL, 0}, NULL, "thaa", NULL, NULL},
394 {{ standard_features, 2}, NULL, "grek", NULL, NULL},
395 {{ standard_features, 2}, NULL, "cyrl", NULL, NULL},
396 {{ standard_features, 2}, NULL, "armn", NULL, NULL},
397 {{ standard_features, 2}, NULL, "geor", NULL, NULL},
398 {{ sinhala_features, 7}, NULL, "sinh", NULL, NULL},
399 {{ tibetan_features, 2}, NULL, "tibt", NULL, NULL},
400 {{ tibetan_features, 2}, NULL, "tibt", NULL, NULL},
401 {{ tibetan_features, 2}, NULL, "phag", ContextualShape_Phags_pa, NULL},
402 {{ thai_features, 1}, NULL, "thai", NULL, NULL},
403 {{ thai_features, 1}, NULL, "thai", NULL, NULL},
404 {{ thai_features, 1}, required_lao_features, "lao", NULL, NULL},
405 {{ thai_features, 1}, required_lao_features, "lao", NULL, NULL},
408 static INT GSUB_is_glyph_covered(LPCVOID table , UINT glyph)
410 const GSUB_CoverageFormat1* cf1;
414 if (GET_BE_WORD(cf1->CoverageFormat) == 1)
416 int count = GET_BE_WORD(cf1->GlyphCount);
418 TRACE("Coverage Format 1, %i glyphs\n",count);
419 for (i = 0; i < count; i++)
420 if (glyph == GET_BE_WORD(cf1->GlyphArray[i]))
424 else if (GET_BE_WORD(cf1->CoverageFormat) == 2)
426 const GSUB_CoverageFormat2* cf2;
429 cf2 = (const GSUB_CoverageFormat2*)cf1;
431 count = GET_BE_WORD(cf2->RangeCount);
432 TRACE("Coverage Format 2, %i ranges\n",count);
433 for (i = 0; i < count; i++)
435 if (glyph < GET_BE_WORD(cf2->RangeRecord[i].Start))
437 if ((glyph >= GET_BE_WORD(cf2->RangeRecord[i].Start)) &&
438 (glyph <= GET_BE_WORD(cf2->RangeRecord[i].End)))
440 return (GET_BE_WORD(cf2->RangeRecord[i].StartCoverageIndex) +
441 glyph - GET_BE_WORD(cf2->RangeRecord[i].Start));
447 ERR("Unknown CoverageFormat %i\n",GET_BE_WORD(cf1->CoverageFormat));
452 static const GSUB_Script* GSUB_get_script_table( const GSUB_Header* header, const char* tag)
454 const GSUB_ScriptList *script;
455 const GSUB_Script *deflt = NULL;
457 script = (const GSUB_ScriptList*)((const BYTE*)header + GET_BE_WORD(header->ScriptList));
459 TRACE("%i scripts in this font\n",GET_BE_WORD(script->ScriptCount));
460 for (i = 0; i < GET_BE_WORD(script->ScriptCount); i++)
462 const GSUB_Script *scr;
465 offset = GET_BE_WORD(script->ScriptRecord[i].Script);
466 scr = (const GSUB_Script*)((const BYTE*)script + offset);
468 if (strncmp(script->ScriptRecord[i].ScriptTag, tag,4)==0)
470 if (strncmp(script->ScriptRecord[i].ScriptTag, "dflt",4)==0)
476 static const GSUB_LangSys* GSUB_get_lang_table( const GSUB_Script* script, const char* tag)
480 const GSUB_LangSys *Lang;
482 TRACE("Deflang %x, LangCount %i\n",GET_BE_WORD(script->DefaultLangSys), GET_BE_WORD(script->LangSysCount));
484 for (i = 0; i < GET_BE_WORD(script->LangSysCount) ; i++)
486 offset = GET_BE_WORD(script->LangSysRecord[i].LangSys);
487 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
489 if ( strncmp(script->LangSysRecord[i].LangSysTag,tag,4)==0)
492 offset = GET_BE_WORD(script->DefaultLangSys);
495 Lang = (const GSUB_LangSys*)((const BYTE*)script + offset);
501 static const GSUB_Feature * GSUB_get_feature(const GSUB_Header *header, const GSUB_LangSys *lang, const char* tag)
504 const GSUB_FeatureList *feature;
505 feature = (const GSUB_FeatureList*)((const BYTE*)header + GET_BE_WORD(header->FeatureList));
507 TRACE("%i features\n",GET_BE_WORD(lang->FeatureCount));
508 for (i = 0; i < GET_BE_WORD(lang->FeatureCount); i++)
510 int index = GET_BE_WORD(lang->FeatureIndex[i]);
511 if (strncmp(feature->FeatureRecord[index].FeatureTag,tag,4)==0)
513 const GSUB_Feature *feat;
514 feat = (const GSUB_Feature*)((const BYTE*)feature + GET_BE_WORD(feature->FeatureRecord[index].Feature));
521 static INT GSUB_apply_SingleSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
524 TRACE("Single Substitution Subtable\n");
526 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
529 const GSUB_SingleSubstFormat1 *ssf1;
530 offset = GET_BE_WORD(look->SubTable[j]);
531 ssf1 = (const GSUB_SingleSubstFormat1*)((const BYTE*)look+offset);
532 if (GET_BE_WORD(ssf1->SubstFormat) == 1)
534 int offset = GET_BE_WORD(ssf1->Coverage);
535 TRACE(" subtype 1, delta %i\n", GET_BE_WORD(ssf1->DeltaGlyphID));
536 if (GSUB_is_glyph_covered((const BYTE*)ssf1+offset, glyphs[glyph_index]) != -1)
538 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
539 glyphs[glyph_index] = glyphs[glyph_index] + GET_BE_WORD(ssf1->DeltaGlyphID);
540 TRACE(" 0x%x\n",glyphs[glyph_index]);
541 return glyph_index + 1;
546 const GSUB_SingleSubstFormat2 *ssf2;
550 ssf2 = (const GSUB_SingleSubstFormat2 *)ssf1;
551 offset = GET_BE_WORD(ssf1->Coverage);
552 TRACE(" subtype 2, glyph count %i\n", GET_BE_WORD(ssf2->GlyphCount));
553 index = GSUB_is_glyph_covered((const BYTE*)ssf2+offset, glyphs[glyph_index]);
554 TRACE(" Coverage index %i\n",index);
557 if (glyphs[glyph_index] == GET_BE_WORD(ssf2->Substitute[index]))
558 return GSUB_E_NOGLYPH;
560 TRACE(" Glyph is 0x%x ->",glyphs[glyph_index]);
561 glyphs[glyph_index] = GET_BE_WORD(ssf2->Substitute[index]);
562 TRACE("0x%x\n",glyphs[glyph_index]);
563 return glyph_index + 1;
567 return GSUB_E_NOGLYPH;
570 static INT GSUB_apply_AlternateSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
573 TRACE("Alternate Substitution Subtable\n");
575 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
578 const GSUB_AlternateSubstFormat1 *asf1;
581 offset = GET_BE_WORD(look->SubTable[j]);
582 asf1 = (const GSUB_AlternateSubstFormat1*)((const BYTE*)look+offset);
583 offset = GET_BE_WORD(asf1->Coverage);
585 index = GSUB_is_glyph_covered((const BYTE*)asf1+offset, glyphs[glyph_index]);
588 const GSUB_AlternateSet *as;
589 offset = GET_BE_WORD(asf1->AlternateSet[index]);
590 as = (const GSUB_AlternateSet*)((const BYTE*)asf1+offset);
591 FIXME("%i alternates, picking index 0\n",GET_BE_WORD(as->GlyphCount));
592 if (glyphs[glyph_index] == GET_BE_WORD(as->Alternate[0]))
593 return GSUB_E_NOGLYPH;
595 TRACE(" Glyph 0x%x ->",glyphs[glyph_index]);
596 glyphs[glyph_index] = GET_BE_WORD(as->Alternate[0]);
597 TRACE(" 0x%x\n",glyphs[glyph_index]);
598 return glyph_index + 1;
601 return GSUB_E_NOGLYPH;
604 static INT GSUB_apply_LigatureSubst(const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
608 TRACE("Ligature Substitution Subtable\n");
609 for (j = 0; j < GET_BE_WORD(look->SubTableCount); j++)
611 const GSUB_LigatureSubstFormat1 *lsf1;
614 offset = GET_BE_WORD(look->SubTable[j]);
615 lsf1 = (const GSUB_LigatureSubstFormat1*)((const BYTE*)look+offset);
616 offset = GET_BE_WORD(lsf1->Coverage);
617 index = GSUB_is_glyph_covered((const BYTE*)lsf1+offset, glyphs[glyph_index]);
618 TRACE(" Coverage index %i\n",index);
621 const GSUB_LigatureSet *ls;
624 offset = GET_BE_WORD(lsf1->LigatureSet[index]);
625 ls = (const GSUB_LigatureSet*)((const BYTE*)lsf1+offset);
626 count = GET_BE_WORD(ls->LigatureCount);
627 TRACE(" LigatureSet has %i members\n",count);
628 for (k = 0; k < count; k++)
630 const GSUB_Ligature *lig;
631 int CompCount,l,CompIndex;
633 offset = GET_BE_WORD(ls->Ligature[k]);
634 lig = (const GSUB_Ligature*)((const BYTE*)ls+offset);
635 CompCount = GET_BE_WORD(lig->CompCount) - 1;
636 CompIndex = glyph_index+write_dir;
637 for (l = 0; l < CompCount && CompIndex >= 0 && CompIndex < *glyph_count; l++)
640 CompGlyph = GET_BE_WORD(lig->Component[l]);
641 if (CompGlyph != glyphs[CompIndex])
643 CompIndex += write_dir;
647 int replaceIdx = glyph_index;
649 replaceIdx = glyph_index - CompCount;
651 TRACE(" Glyph is 0x%x (+%i) ->",glyphs[glyph_index],CompCount);
652 glyphs[replaceIdx] = GET_BE_WORD(lig->LigGlyph);
653 TRACE("0x%x\n",glyphs[replaceIdx]);
657 for (j = replaceIdx + 1; j < *glyph_count; j++)
658 glyphs[j] =glyphs[j+CompCount];
659 *glyph_count = *glyph_count - CompCount;
661 return replaceIdx + 1;
666 return GSUB_E_NOGLYPH;
669 static INT GSUB_apply_ChainContextSubst(const GSUB_LookupList* lookup, const GSUB_LookupTable *look, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
674 TRACE("Chaining Contextual Substitution Subtable\n");
675 for (j = 0; j < GET_BE_WORD(look->SubTableCount) && !done; j++)
677 const GSUB_ChainContextSubstFormat1 *ccsf1;
679 int dirLookahead = write_dir;
680 int dirBacktrack = -1 * write_dir;
682 offset = GET_BE_WORD(look->SubTable[j]);
683 ccsf1 = (const GSUB_ChainContextSubstFormat1*)((const BYTE*)look+offset);
684 if (GET_BE_WORD(ccsf1->SubstFormat) == 1)
686 FIXME(" TODO: subtype 1 (Simple context glyph substitution)\n");
689 else if (GET_BE_WORD(ccsf1->SubstFormat) == 2)
691 FIXME(" TODO: subtype 2 (Class-based Chaining Context Glyph Substitution)\n");
694 else if (GET_BE_WORD(ccsf1->SubstFormat) == 3)
698 const GSUB_ChainContextSubstFormat3_1 *ccsf3_1;
699 const GSUB_ChainContextSubstFormat3_2 *ccsf3_2;
700 const GSUB_ChainContextSubstFormat3_3 *ccsf3_3;
701 const GSUB_ChainContextSubstFormat3_4 *ccsf3_4;
702 int newIndex = glyph_index;
704 ccsf3_1 = (const GSUB_ChainContextSubstFormat3_1 *)ccsf1;
706 TRACE(" subtype 3 (Coverage-based Chaining Context Glyph Substitution)\n");
708 for (k = 0; k < GET_BE_WORD(ccsf3_1->BacktrackGlyphCount); k++)
710 offset = GET_BE_WORD(ccsf3_1->Coverage[k]);
711 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirBacktrack * (k+1))]) == -1)
714 if (k != GET_BE_WORD(ccsf3_1->BacktrackGlyphCount))
716 TRACE("Matched Backtrack\n");
718 ccsf3_2 = (const GSUB_ChainContextSubstFormat3_2 *)(((LPBYTE)ccsf1)+sizeof(GSUB_ChainContextSubstFormat3_1) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_1->BacktrackGlyphCount)-1)));
720 indexGlyphs = GET_BE_WORD(ccsf3_2->InputGlyphCount);
721 for (k = 0; k < indexGlyphs; k++)
723 offset = GET_BE_WORD(ccsf3_2->Coverage[k]);
724 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (write_dir * k)]) == -1)
727 if (k != indexGlyphs)
729 TRACE("Matched IndexGlyphs\n");
731 ccsf3_3 = (const GSUB_ChainContextSubstFormat3_3 *)(((LPBYTE)ccsf3_2)+sizeof(GSUB_ChainContextSubstFormat3_2) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_2->InputGlyphCount)-1)));
733 for (k = 0; k < GET_BE_WORD(ccsf3_3->LookaheadGlyphCount); k++)
735 offset = GET_BE_WORD(ccsf3_3->Coverage[k]);
736 if (GSUB_is_glyph_covered((const BYTE*)ccsf3_1+offset, glyphs[glyph_index + (dirLookahead * (indexGlyphs + k))]) == -1)
739 if (k != GET_BE_WORD(ccsf3_3->LookaheadGlyphCount))
741 TRACE("Matched LookAhead\n");
743 ccsf3_4 = (const GSUB_ChainContextSubstFormat3_4 *)(((LPBYTE)ccsf3_3)+sizeof(GSUB_ChainContextSubstFormat3_3) + (sizeof(WORD) * (GET_BE_WORD(ccsf3_3->LookaheadGlyphCount)-1)));
745 for (k = 0; k < GET_BE_WORD(ccsf3_4->SubstCount); k++)
747 int lookupIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].LookupListIndex);
748 int SequenceIndex = GET_BE_WORD(ccsf3_4->SubstLookupRecord[k].SequenceIndex) * write_dir;
750 TRACE("SUBST: %i -> %i %i\n",k, SequenceIndex, lookupIndex);
751 newIndex = GSUB_apply_lookup(lookup, lookupIndex, glyphs, glyph_index + SequenceIndex, write_dir, glyph_count);
754 ERR("Chain failed to generate a glyph\n");
764 static INT GSUB_apply_lookup(const GSUB_LookupList* lookup, INT lookup_index, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
767 const GSUB_LookupTable *look;
769 offset = GET_BE_WORD(lookup->Lookup[lookup_index]);
770 look = (const GSUB_LookupTable*)((const BYTE*)lookup + offset);
771 TRACE("type %i, flag %x, subtables %i\n",GET_BE_WORD(look->LookupType),GET_BE_WORD(look->LookupFlag),GET_BE_WORD(look->SubTableCount));
772 switch(GET_BE_WORD(look->LookupType))
775 return GSUB_apply_SingleSubst(look, glyphs, glyph_index, write_dir, glyph_count);
777 return GSUB_apply_AlternateSubst(look, glyphs, glyph_index, write_dir, glyph_count);
779 return GSUB_apply_LigatureSubst(look, glyphs, glyph_index, write_dir, glyph_count);
781 return GSUB_apply_ChainContextSubst(lookup, look, glyphs, glyph_index, write_dir, glyph_count);
783 FIXME("We do not handle SubType %i\n",GET_BE_WORD(look->LookupType));
785 return GSUB_E_NOGLYPH;
788 static INT GSUB_apply_feature(const GSUB_Header * header, const GSUB_Feature* feature, WORD *glyphs, INT glyph_index, INT write_dir, INT *glyph_count)
791 int out_index = GSUB_E_NOGLYPH;
792 const GSUB_LookupList *lookup;
794 lookup = (const GSUB_LookupList*)((const BYTE*)header + GET_BE_WORD(header->LookupList));
796 TRACE("%i lookups\n", GET_BE_WORD(feature->LookupCount));
797 for (i = 0; i < GET_BE_WORD(feature->LookupCount); i++)
799 out_index = GSUB_apply_lookup(lookup, GET_BE_WORD(feature->LookupListIndex[i]), glyphs, glyph_index, write_dir, glyph_count);
800 if (out_index != GSUB_E_NOGLYPH)
803 if (out_index == GSUB_E_NOGLYPH)
804 TRACE("lookups found no glyphs\n");
808 out2 = GSUB_apply_feature(header, feature, glyphs, glyph_index, write_dir, glyph_count);
809 if (out2!=GSUB_E_NOGLYPH)
815 static const char* get_opentype_script(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc)
819 if (psc->userScript != 0)
820 return (char*)&psc->userScript;
822 if (ShapingData[psa->eScript].otTag[0] != 0)
823 return ShapingData[psa->eScript].otTag;
826 * fall back to the font charset
828 charset = GetTextCharsetInfo(hdc, NULL, 0x0);
831 case ANSI_CHARSET: return "latn";
832 case BALTIC_CHARSET: return "latn"; /* ?? */
833 case CHINESEBIG5_CHARSET: return "hani";
834 case EASTEUROPE_CHARSET: return "latn"; /* ?? */
835 case GB2312_CHARSET: return "hani";
836 case GREEK_CHARSET: return "grek";
837 case HANGUL_CHARSET: return "hang";
838 case RUSSIAN_CHARSET: return "cyrl";
839 case SHIFTJIS_CHARSET: return "kana";
840 case TURKISH_CHARSET: return "latn"; /* ?? */
841 case VIETNAMESE_CHARSET: return "latn";
842 case JOHAB_CHARSET: return "latn"; /* ?? */
843 case ARABIC_CHARSET: return "arab";
844 case HEBREW_CHARSET: return "hebr";
845 case THAI_CHARSET: return "thai";
846 default: return "latn";
850 static LPCVOID load_GSUB_feature(HDC hdc, SCRIPT_ANALYSIS *psa, ScriptCache *psc, const char* feat)
852 const GSUB_Feature *feature;
855 for (i = 0; i < psc->feature_count; i++)
856 if (strncmp(psc->features[i].tag,feat,4)==0)
857 return psc->features[i].feature;
863 const GSUB_Script *script;
864 const GSUB_LangSys *language;
866 script = GSUB_get_script_table(psc->GSUB_Table, get_opentype_script(hdc,psa,psc));
869 if (psc->userLang != 0)
870 language = GSUB_get_lang_table(script,(char*)&psc->userLang);
872 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
874 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
877 /* try in the default (latin) table */
880 script = GSUB_get_script_table(psc->GSUB_Table, "latn");
883 language = GSUB_get_lang_table(script, "xxxx"); /* Need to get Lang tag */
885 feature = GSUB_get_feature(psc->GSUB_Table, language, feat);
890 TRACE("Feature %s located at %p\n",debugstr_an(feat,4),feature);
892 psc->feature_count++;
895 psc->features = HeapReAlloc(GetProcessHeap(), 0, psc->features, psc->feature_count * sizeof(LoadedFeature));
897 psc->features = HeapAlloc(GetProcessHeap(), 0, psc->feature_count * sizeof(LoadedFeature));
899 lstrcpynA(psc->features[psc->feature_count - 1].tag, feat, 5);
900 psc->features[psc->feature_count - 1].feature = feature;
904 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)
906 const GSUB_Feature *feature;
908 feature = load_GSUB_feature(hdc, psa, psc, feat);
910 return GSUB_E_NOFEATURE;
912 TRACE("applying feature %s\n",feat);
913 return GSUB_apply_feature(psc->GSUB_Table, feature, glyphs, index, write_dir, glyph_count);
916 static VOID *load_gsub_table(HDC hdc)
918 VOID* GSUB_Table = NULL;
919 int length = GetFontData(hdc, GSUB_TAG , 0, NULL, 0);
920 if (length != GDI_ERROR)
922 GSUB_Table = HeapAlloc(GetProcessHeap(),0,length);
923 GetFontData(hdc, GSUB_TAG , 0, GSUB_Table, length);
924 TRACE("Loaded GSUB table of %i bytes\n",length);
929 static WORD GDEF_get_glyph_class(const GDEF_Header *header, WORD glyph)
933 const GDEF_ClassDefFormat1 *cf1;
938 offset = GET_BE_WORD(header->GlyphClassDef);
942 cf1 = (GDEF_ClassDefFormat1*)(((BYTE*)header)+offset);
943 if (GET_BE_WORD(cf1->ClassFormat) == 1)
945 if (glyph >= GET_BE_WORD(cf1->StartGlyph))
947 int index = glyph - GET_BE_WORD(cf1->StartGlyph);
948 if (index < GET_BE_WORD(cf1->GlyphCount))
949 class = GET_BE_WORD(cf1->ClassValueArray[index]);
952 else if (GET_BE_WORD(cf1->ClassFormat) == 2)
954 const GDEF_ClassDefFormat2 *cf2 = (GDEF_ClassDefFormat2*)cf1;
956 top = GET_BE_WORD(cf2->ClassRangeCount);
957 for (i = 0; i < top; i++)
959 if (glyph >= GET_BE_WORD(cf2->ClassRangeRecord[i].Start) &&
960 glyph <= GET_BE_WORD(cf2->ClassRangeRecord[i].End))
962 class = GET_BE_WORD(cf2->ClassRangeRecord[i].Class);
968 ERR("Unknown Class Format %i\n",GET_BE_WORD(cf1->ClassFormat));
973 static VOID *load_gdef_table(HDC hdc)
975 VOID* GDEF_Table = NULL;
976 int length = GetFontData(hdc, GDEF_TAG , 0, NULL, 0);
977 if (length != GDI_ERROR)
979 GDEF_Table = HeapAlloc(GetProcessHeap(),0,length);
980 GetFontData(hdc, GDEF_TAG , 0, GDEF_Table, length);
981 TRACE("Loaded GDEF table of %i bytes\n",length);
986 static void GDEF_UpdateGlyphProps(HDC hdc, const WORD *pwGlyphs, const WORD cGlyphs, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
988 VOID* header = load_gdef_table(hdc);
991 for (i = 0; i < cGlyphs; i++)
995 class = GDEF_get_glyph_class(header, pwGlyphs[i]);
1001 pGlyphProp[i].sva.fClusterStart = 1;
1002 pGlyphProp[i].sva.fDiacritic = 0;
1003 pGlyphProp[i].sva.fZeroWidth = 0;
1006 pGlyphProp[i].sva.fClusterStart = 1;
1007 pGlyphProp[i].sva.fDiacritic = 0;
1008 pGlyphProp[i].sva.fZeroWidth = 0;
1011 pGlyphProp[i].sva.fClusterStart = 0;
1012 pGlyphProp[i].sva.fDiacritic = 1;
1013 pGlyphProp[i].sva.fZeroWidth = 1;
1015 case ComponentGlyph:
1016 pGlyphProp[i].sva.fClusterStart = 0;
1017 pGlyphProp[i].sva.fDiacritic = 0;
1018 pGlyphProp[i].sva.fZeroWidth = 0;
1021 ERR("Unknown glyph class %i\n",class);
1022 pGlyphProp[i].sva.fClusterStart = 1;
1023 pGlyphProp[i].sva.fDiacritic = 0;
1024 pGlyphProp[i].sva.fZeroWidth = 0;
1029 static void UpdateClustersFromGlyphProp(const int cGlyphs, const int cChars, WORD* pwLogClust, SCRIPT_GLYPHPROP *pGlyphProp)
1033 for (i = 0; i < cGlyphs; i++)
1035 if (!pGlyphProp[i].sva.fClusterStart)
1038 for (j = 0; j < cChars; j++)
1040 if (pwLogClust[j] == i)
1043 while (!pGlyphProp[pwLogClust[k]].sva.fClusterStart && k >= 0 && k <cChars)
1045 if (pGlyphProp[pwLogClust[k]].sva.fClusterStart)
1046 pwLogClust[j] = pwLogClust[k];
1053 static void UpdateClusters(int nextIndex, int changeCount, int write_dir, int chars, WORD* pwLogClust )
1055 if (changeCount == 0)
1060 int target_glyph = nextIndex - 1;
1061 int target_index = -1;
1062 int replacing_glyph = -1;
1066 for (i = 0; i < chars; i++)
1068 if (pwLogClust[i] == target_glyph)
1075 for (i = chars - 1; i >= 0; i--)
1077 if (pwLogClust[i] == target_glyph)
1083 if (target_index == -1)
1085 ERR("Unable to find target glyph\n");
1089 if (changeCount < 0)
1092 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1094 if (pwLogClust[i] == target_glyph)
1096 if(pwLogClust[i] == replacing_glyph)
1097 pwLogClust[i] = target_glyph;
1101 if (changed >= changeCount)
1103 replacing_glyph = pwLogClust[i];
1104 pwLogClust[i] = target_glyph;
1112 /* renumber trailing indexes*/
1113 for(i = target_index; i < chars && i >= 0; i+=write_dir)
1115 if (pwLogClust[i] != target_glyph)
1116 pwLogClust[i] += changeCount;
1121 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 )
1125 if (psc->GSUB_Table)
1127 const GSUB_Feature *feature;
1129 feature = load_GSUB_feature(hdc, psa, psc, feat);
1131 return GSUB_E_NOFEATURE;
1134 TRACE("applying feature %s\n",debugstr_an(feat,4));
1135 while(i < *pcGlyphs)
1138 INT prevCount = *pcGlyphs;
1139 nextIndex = GSUB_apply_feature(psc->GSUB_Table, feature, pwOutGlyphs, i, write_dir, pcGlyphs);
1140 if (nextIndex > GSUB_E_NOGLYPH)
1142 UpdateClusters(nextIndex, *pcGlyphs - prevCount, write_dir, cChars, pwLogClust);
1150 return GSUB_E_NOFEATURE;
1153 static WCHAR neighbour_char(int i, int delta, const WCHAR* chars, INT cchLen)
1157 if ( i+ delta >= cchLen)
1165 static CHAR neighbour_joining_type(int i, int delta, const CHAR* context_type, INT cchLen, SCRIPT_ANALYSIS *psa)
1169 if (psa->fLinkBefore)
1174 if ( i+ delta >= cchLen)
1176 if (psa->fLinkAfter)
1184 if (context_type[i] == jtT)
1185 return neighbour_joining_type(i,delta,context_type,cchLen,psa);
1187 return context_type[i];
1190 static inline BOOL right_join_causing(CHAR joining_type)
1192 return (joining_type == jtL || joining_type == jtD || joining_type == jtC);
1195 static inline BOOL left_join_causing(CHAR joining_type)
1197 return (joining_type == jtR || joining_type == jtD || joining_type == jtC);
1200 static inline BOOL word_break_causing(WCHAR chr)
1202 /* we are working within a string of characters already guareented to
1203 be within one script, Syriac, so we do not worry about any characers
1204 other than the space character outside of that range */
1205 return (chr == 0 || chr == 0x20 );
1209 * ContextualShape_Arabic
1211 static void ContextualShape_Arabic(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1218 if (*pcGlyphs != cChars)
1220 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1224 if (!psa->fLogicalOrder && psa->fRTL)
1235 if (!psc->GSUB_Table)
1236 psc->GSUB_Table = load_gsub_table(hdc);
1238 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1239 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1241 for (i = 0; i < cChars; i++)
1242 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1244 for (i = 0; i < cChars; i++)
1246 if (context_type[i] == jtR && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1247 context_shape[i] = Xr;
1248 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1249 context_shape[i] = Xl;
1250 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)))
1251 context_shape[i] = Xm;
1252 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1253 context_shape[i] = Xr;
1254 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1255 context_shape[i] = Xl;
1257 context_shape[i] = Xn;
1260 /* Contextual Shaping */
1262 while(i < *pcGlyphs)
1264 BOOL shaped = FALSE;
1266 if (psc->GSUB_Table)
1269 INT prevCount = *pcGlyphs;
1270 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1271 if (nextIndex > GSUB_E_NOGLYPH)
1274 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1276 shaped = (nextIndex > GSUB_E_NOGLYPH);
1281 WORD newGlyph = pwOutGlyphs[i];
1282 if (pwcChars[i] >= FIRST_ARABIC_CHAR && pwcChars[i] <= LAST_ARABIC_CHAR)
1284 /* fall back to presentation form B */
1285 WCHAR context_char = wine_shaping_forms[pwcChars[i] - FIRST_ARABIC_CHAR][context_shape[i]];
1286 if (context_char != pwcChars[i] && GetGlyphIndicesW(hdc, &context_char, 1, &newGlyph, 0) != GDI_ERROR && newGlyph != 0x0000)
1287 pwOutGlyphs[i] = newGlyph;
1293 HeapFree(GetProcessHeap(),0,context_shape);
1294 HeapFree(GetProcessHeap(),0,context_type);
1298 * ContextualShape_Syriac
1302 #define DALATH 0x715
1305 static void ContextualShape_Syriac(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1312 if (*pcGlyphs != cChars)
1314 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1318 if (!psa->fLogicalOrder && psa->fRTL)
1329 if (!psc->GSUB_Table)
1330 psc->GSUB_Table = load_gsub_table(hdc);
1332 if (!psc->GSUB_Table)
1335 context_type = HeapAlloc(GetProcessHeap(),0,cChars);
1336 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1338 for (i = 0; i < cChars; i++)
1339 context_type[i] = wine_shaping_table[wine_shaping_table[pwcChars[i] >> 8] + (pwcChars[i] & 0xff)];
1341 for (i = 0; i < cChars; i++)
1343 if (pwcChars[i] == ALAPH)
1345 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1347 if (left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1348 context_shape[i] = Afj;
1349 else if ( rchar != DALATH && rchar != RISH &&
1350 !left_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)) &&
1351 word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1352 context_shape[i] = Afn;
1353 else if ( (rchar == DALATH || rchar == RISH) && word_break_causing(neighbour_char(i,dirL,pwcChars,cChars)))
1354 context_shape[i] = Afx;
1356 context_shape[i] = Xn;
1358 else if (context_type[i] == jtR &&
1359 right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1360 context_shape[i] = Xr;
1361 else if (context_type[i] == jtL && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1362 context_shape[i] = Xl;
1363 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)))
1364 context_shape[i] = Xm;
1365 else if (context_type[i] == jtD && right_join_causing(neighbour_joining_type(i,dirR,context_type,cChars,psa)))
1366 context_shape[i] = Xr;
1367 else if (context_type[i] == jtD && left_join_causing(neighbour_joining_type(i,dirL,context_type,cChars,psa)))
1368 context_shape[i] = Xl;
1370 context_shape[i] = Xn;
1373 /* Contextual Shaping */
1375 while(i < *pcGlyphs)
1378 INT prevCount = *pcGlyphs;
1379 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1380 if (nextIndex > GSUB_E_NOGLYPH)
1382 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1389 HeapFree(GetProcessHeap(),0,context_shape);
1390 HeapFree(GetProcessHeap(),0,context_type);
1394 * ContextualShape_Phags_pa
1397 #define phags_pa_CANDRABINDU 0xA873
1398 #define phags_pa_START 0xA840
1399 #define phags_pa_END 0xA87F
1401 static void ContextualShape_Phags_pa(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1407 if (*pcGlyphs != cChars)
1409 ERR("Number of Glyphs and Chars need to match at the beginning\n");
1413 if (!psa->fLogicalOrder && psa->fRTL)
1424 if (!psc->GSUB_Table)
1425 psc->GSUB_Table = load_gsub_table(hdc);
1427 if (!psc->GSUB_Table)
1430 context_shape = HeapAlloc(GetProcessHeap(),0,sizeof(INT) * cChars);
1432 for (i = 0; i < cChars; i++)
1434 if (pwcChars[i] >= phags_pa_START && pwcChars[i] <= phags_pa_END)
1436 WCHAR rchar = neighbour_char(i,dirR,pwcChars,cChars);
1437 WCHAR lchar = neighbour_char(i,dirL,pwcChars,cChars);
1438 BOOL jrchar = (rchar != phags_pa_CANDRABINDU && rchar >= phags_pa_START && rchar <= phags_pa_END);
1439 BOOL jlchar = (lchar != phags_pa_CANDRABINDU && lchar >= phags_pa_START && lchar <= phags_pa_END);
1441 if (jrchar && jlchar)
1442 context_shape[i] = Xm;
1444 context_shape[i] = Xr;
1446 context_shape[i] = Xl;
1448 context_shape[i] = Xn;
1451 context_shape[i] = -1;
1454 /* Contextual Shaping */
1456 while(i < *pcGlyphs)
1458 if (context_shape[i] >= 0)
1461 INT prevCount = *pcGlyphs;
1462 nextIndex = apply_GSUB_feature_to_glyph(hdc, psa, psc, pwOutGlyphs, i, dirL, pcGlyphs, contextual_features[context_shape[i]]);
1463 if (nextIndex > GSUB_E_NOGLYPH)
1465 UpdateClusters(nextIndex, *pcGlyphs - prevCount, dirL, cChars, pwLogClust);
1475 HeapFree(GetProcessHeap(),0,context_shape);
1478 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)
1482 for (i = 0; i < cGlyphs; i++)
1487 for (k = 0; k < cChars; k++)
1489 if (pwLogClust[k] == i)
1491 char_index[char_count] = k;
1496 if (char_count == 0)
1498 FIXME("No chars in this glyph? Must be an error\n");
1502 if (char_count ==1 && pwcChars[char_index[0]] == 0x0020) /* space */
1504 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_BLANK;
1505 pCharProp[char_index[0]].fCanGlyphAlone = 1;
1508 pGlyphProp[i].sva.uJustification = SCRIPT_JUSTIFY_CHARACTER;
1511 GDEF_UpdateGlyphProps(hdc, pwGlyphs, cGlyphs, pwLogClust, pGlyphProp);
1512 UpdateClustersFromGlyphProp(cGlyphs, cChars, pwLogClust, pGlyphProp);
1515 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)
1517 if (ShapingData[psa->eScript].charGlyphPropProc)
1518 ShapingData[psa->eScript].charGlyphPropProc(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
1520 ShapeCharGlyphProp_Default(hdc, psc, psa, pwcChars, cChars, pwGlyphs, cGlyphs, pwLogClust, pCharProp, pGlyphProp);
1523 void SHAPE_ContextualShaping(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WCHAR* pwcChars, INT cChars, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, WORD *pwLogClust)
1525 if (ShapingData[psa->eScript].contextProc)
1526 ShapingData[psa->eScript].contextProc(hdc, psc, psa, pwcChars, cChars, pwOutGlyphs, pcGlyphs, cMaxGlyphs, pwLogClust);
1529 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)
1534 if (!rpRangeProperties)
1537 if (!psc->GSUB_Table)
1538 psc->GSUB_Table = load_gsub_table(hdc);
1540 if (!psc->GSUB_Table)
1543 if (!psa->fLogicalOrder && psa->fRTL)
1548 for (i = 0; i < rpRangeProperties->cotfRecords; i++)
1550 if (rpRangeProperties->potfRecords[i].lParameter > 0)
1551 apply_GSUB_feature(hdc, psa, psc, pwOutGlyphs, dirL, pcGlyphs, cChars, (const char*)&rpRangeProperties->potfRecords[i].tagFeature, pwLogClust);
1555 void SHAPE_ApplyDefaultOpentypeFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa, WORD* pwOutGlyphs, INT* pcGlyphs, INT cMaxGlyphs, INT cChars, WORD *pwLogClust)
1557 const TEXTRANGE_PROPERTIES *rpRangeProperties;
1558 rpRangeProperties = &ShapingData[psa->eScript].defaultTextRange;
1560 SHAPE_ApplyOpenTypeFeatures(hdc, psc, psa, pwOutGlyphs, pcGlyphs, cMaxGlyphs, cChars, rpRangeProperties, pwLogClust);
1563 HRESULT SHAPE_CheckFontForRequiredFeatures(HDC hdc, ScriptCache *psc, SCRIPT_ANALYSIS *psa)
1565 const GSUB_Feature *feature;
1568 if (!ShapingData[psa->eScript].requiredFeatures)
1571 if (!psc->GSUB_Table)
1572 psc->GSUB_Table = load_gsub_table(hdc);
1574 /* we need to have at least one of the required features */
1576 while (ShapingData[psa->eScript].requiredFeatures[i])
1578 feature = load_GSUB_feature(hdc, psa, psc, ShapingData[psa->eScript].requiredFeatures[i]);
1584 return USP_E_SCRIPT_NOT_IN_FONT;