/// <summary> /// Position glyphs according to features defined in the font. /// </summary> /// <param name="Font">In: Font access interface</param> /// <param name="workspace">In: Workspace for layout engine</param> /// <param name="ScriptTag">In: Script tag</param> /// <param name="LangSysTag">In: LangSys tag</param> /// <param name="Metrics">In: LayoutMetrics</param> /// <param name="FeatureSet">In: List of features to apply</param> /// <param name="featureCount">In: Actual number of features in <paramref name="FeatureSet"/></param> /// <param name="featureSetOffset">In: offset of input characters inside FeatureSet</param> /// <param name="CharCount">In: Characters count (i.e. <paramref name="Charmap"/>.Length);</param> /// <param name="Charmap">In: Char to glyph mapping</param> /// <param name="Glyphs">In/out: List of GlyphInfo structs</param> /// <param name="Advances">In/out: Glyphs adv.widths</param> /// <param name="Offsets">In/out: Glyph offsets</param> /// <returns>Substitution result</returns> internal static OpenTypeLayoutResult PositionGlyphs( IOpenTypeFont Font, OpenTypeLayoutWorkspace workspace, uint ScriptTag, uint LangSysTag, LayoutMetrics Metrics, Feature[] FeatureSet, int featureCount, int featureSetOffset, int CharCount, UshortList Charmap, GlyphInfoList Glyphs, int *Advances, LayoutOffset *Offsets ) { try { FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS); if (!GposTable.IsPresent) { return(OpenTypeLayoutResult.ScriptNotFound); } GPOSHeader GposHeader = new GPOSHeader(0); ScriptList ScriptList = GposHeader.GetScriptList(GposTable); ScriptTable Script = ScriptList.FindScript(GposTable, ScriptTag); if (Script.IsNull) { return(OpenTypeLayoutResult.ScriptNotFound); } LangSysTable LangSys = Script.FindLangSys(GposTable, LangSysTag); if (LangSys.IsNull) { return(OpenTypeLayoutResult.LangSysNotFound); } FeatureList FeatureList = GposHeader.GetFeatureList(GposTable); LookupList LookupList = GposHeader.GetLookupList(GposTable); LayoutEngine.ApplyFeatures( Font, workspace, OpenTypeTags.GPOS, GposTable, Metrics, LangSys, FeatureList, LookupList, FeatureSet, featureCount, featureSetOffset, CharCount, Charmap, Glyphs, Advances, Offsets ); } catch (FileFormatException) { return(OpenTypeLayoutResult.BadFontTable); } return(OpenTypeLayoutResult.Success); }
/* This is unused code, but will be used later so it is just commented out for now. * * /// <summary> * /// Enumerates scripts in a font * /// </summary> * internal static OpenTypeLayoutResult GetScriptList ( * IOpenTypeFont Font, // In: Font access interface * out TagInfo[] Scripts // Out: Array of scripts supported * ) * { * ushort i; * ushort GposNewTags; * * Scripts=null; // Assignment required, because of out attribute. * // This value should be owerwritten later. * * try * { * FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB); * FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS); * * GSUBHeader GsubHeader = new GSUBHeader(0); * GPOSHeader GposHeader = new GPOSHeader(0); * * ScriptList GsubScriptList; * ScriptList GposScriptList; * ushort GsubScriptCount; * ushort GposScriptCount; * * if (GsubTable.IsNotPresent && GposTable.IsNotPresent) * { * Scripts = Array.Empty<TagInfo>(); * return OpenTypeLayoutResult.Success; * } * * if (GsubTable.IsPresent) * { * GsubScriptList = GsubHeader.GetScriptList(GsubTable); * GsubScriptCount = GsubScriptList.GetScriptCount(GsubTable); * } * else * { * GsubScriptList = new ScriptList(FontTable.InvalidOffset); * GsubScriptCount = 0; * } * * if (GposTable.IsPresent) * { * GposScriptList = GposHeader.GetScriptList(GposTable); * GposScriptCount = GposScriptList.GetScriptCount(GposTable); * } * else * { * GposScriptList = new ScriptList(FontTable.InvalidOffset); * GposScriptCount = 0; * } * * //This is true in most cases that there is no new tags in GPOS. * //So, we allocate this array then check GPOS for new tags * Scripts = new TagInfo[GsubScriptCount]; * * for(i=0; i<GsubScriptCount; i++) * { * Scripts[i].Tag = GsubScriptList.GetScriptTag(GsubTable,i); * Scripts[i].TagFlags = TagInfoFlags.Substitution; * } * * //Check GPOS for tags that is not in GSUB * GposNewTags=0; * * for(i=0;i<GposScriptCount;i++) * { * uint GposTag = GsubScriptList.GetScriptTag(GposTable,i); * if (TagInfo.IsNewTag(Scripts,GposTag)) GposNewTags++; * } * * //append new tags to ScriptTags if any exists * if (GposNewTags>0) * { * int CurrentScriptIndex=GposScriptCount; * * //Allocate new array to fit all tags * TagInfo[] tmp = Scripts; * Scripts = new TagInfo[GsubScriptCount+GposNewTags]; * Array.Copy(tmp,0,Scripts,0,tmp.Length); * * for(i=0;i<GposScriptCount;i++) * { * uint GposTag = GsubScriptList.GetScriptTag(GposTable,i); * if (TagInfo.IsNewTag(Scripts,GposTag)) * { * Scripts[CurrentScriptIndex].Tag=GposTag; * Scripts[CurrentScriptIndex].TagFlags * = TagInfoFlags.Positioning; ++CurrentScriptIndex; * } * else * { * int ScriptIndex = TagInfo.GetTagIndex(Scripts,GposTag); * Scripts[ScriptIndex].TagFlags |= TagInfoFlags.Positioning; * } * } * * Debug.Assert(CurrentScriptIndex==Scripts.Length); * } * } * catch (FileFormatException) * { * return OpenTypeLayoutResult.BadFontTable; * } * * return OpenTypeLayoutResult.Success; * } * * * ///<summary> * /// Enumerates language systems for script * /// </summary> * internal static OpenTypeLayoutResult GetLangSysList ( * IOpenTypeFont Font, // In: Font access interface * uint ScriptTag, // In: Script tag * out TagInfo[] LangSystems // Out: Array of LangSystems for Script * ) * { * ushort i; * ushort GposNewTags; * * LangSystems=null; // Assignment required, because of out attribute. * // This value should be owerwritten later. * * try * { * FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB); * FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS); * * GSUBHeader GsubHeader = new GSUBHeader(0); * GPOSHeader GposHeader = new GPOSHeader(0); * * ScriptList GsubScriptList; * ScriptList GposScriptList; * ScriptTable GsubScript; * ScriptTable GposScript; * ushort GsubLangSysCount; * ushort GposLangSysCount; * * if (GsubTable.IsNotPresent && GposTable.IsNotPresent) * { * return OpenTypeLayoutResult.ScriptNotFound; * } * * if (GsubTable.IsPresent) * { * GsubScriptList = GsubHeader.GetScriptList(GsubTable); * GsubScript = GsubScriptList.FindScript(GsubTable,ScriptTag); * } * else * { * GsubScript = new ScriptTable(FontTable.InvalidOffset); * } * * if (GposTable.IsPresent) * { * GposScriptList = GposHeader.GetScriptList(GposTable); * GposScript = GposScriptList.FindScript(GposTable,ScriptTag); * } * else * { * GposScript = new ScriptTable(FontTable.InvalidOffset); * } * * if (GsubScript.IsNull && GposScript.IsNull) * { * return OpenTypeLayoutResult.ScriptNotFound; * } * * if (!GsubScript.IsNull) * { * GsubLangSysCount = GsubScript.GetLangSysCount(GsubTable); * } * else * { * GsubLangSysCount = 0; * } * * if (!GposScript.IsNull) * { * GposLangSysCount = GposScript.GetLangSysCount(GposTable); * } * else * { * GposLangSysCount = 0; * } * * //This is true in most cases that there is no new tags in GPOS. * //So, we allocate this array then check GPOS for new tags * ushort CurrentLangSysIndex; * * if (GsubScript.IsDefaultLangSysExists(GsubTable)) * { * LangSystems = new TagInfo[GsubLangSysCount+1]; * LangSystems[0].Tag = (uint)OpenTypeTags.dflt; * LangSystems[0].TagFlags = TagInfoFlags.Substitution; * CurrentLangSysIndex = 1; * } * else * { * LangSystems = new TagInfo[GsubLangSysCount]; * CurrentLangSysIndex = 0; * } * * for(i=0; i<GsubLangSysCount; i++) * { * LangSystems[CurrentLangSysIndex].Tag = GsubScript.GetLangSysTag(GsubTable,i); * LangSystems[CurrentLangSysIndex].TagFlags = TagInfoFlags.Substitution; ++CurrentLangSysIndex; * } * * //Check GPOS for tags that is not in GSUB * GposNewTags=0; * * if (!GposScript.IsNull) * { * if (GposScript.IsDefaultLangSysExists(GposTable) && * TagInfo.IsNewTag(LangSystems,(uint)OpenTypeTags.dflt)) * { ++GposNewTags; * } * * for(i=0;i<GposLangSysCount;i++) * { * uint GposTag = GsubScript.GetLangSysTag(GposTable,i); * if (TagInfo.IsNewTag(LangSystems,GposTag)) * { ++GposNewTags; * } * } * } * * Debug.Assert(CurrentLangSysIndex==LangSystems.Length); * * //append new tags to ScriptTags if any exists * if (GposNewTags>0) * { * //Allocate new array to fit all tags * TagInfo[] tmp = LangSystems; * LangSystems = new TagInfo[GsubLangSysCount+GposNewTags]; * Array.Copy(tmp,0,LangSystems,0,tmp.Length); * * if (GposScript.IsDefaultLangSysExists(GposTable)) * { * if (TagInfo.IsNewTag(LangSystems,(uint)OpenTypeTags.dflt)) * { * LangSystems[CurrentLangSysIndex].Tag = (uint)OpenTypeTags.dflt; * LangSystems[CurrentLangSysIndex].TagFlags = TagInfoFlags.Positioning; ++CurrentLangSysIndex; * } * else * { * int LangSysIndex = TagInfo.GetTagIndex(LangSystems,(uint)OpenTypeTags.dflt); * LangSystems[LangSysIndex].TagFlags |= TagInfoFlags.Positioning; * } * } * * for(i=0;i<GposLangSysCount;i++) * { * uint GposTag = GposScript.GetLangSysTag(GposTable,i); * * if (TagInfo.IsNewTag(LangSystems,GposTag)) * { * LangSystems[CurrentLangSysIndex].Tag = GposTag; * LangSystems[CurrentLangSysIndex].TagFlags = TagInfoFlags.Positioning; ++CurrentLangSysIndex; * } * else * { * int LangSysIndex = TagInfo.GetTagIndex(LangSystems,GposTag); * LangSystems[LangSysIndex].TagFlags |= TagInfoFlags.Positioning; * } * } * * Debug.Assert(CurrentLangSysIndex==LangSystems.Length); * } * } * catch (FileFormatException) * { * return OpenTypeLayoutResult.BadFontTable; * } * * return OpenTypeLayoutResult.Success; * } * * * /// <summary> * /// Enumerates features in a language system * /// </summary> * internal static OpenTypeLayoutResult GetFeatureList ( * IOpenTypeFont Font, // In: Font access interface * uint ScriptTag, // In: Script tag * uint LangSysTag, // In: LangSys tag * out TagInfo[] Features // Out: Array of features * ) * { * ushort i; * ushort GposNewTags; * * Features=null; // Assignment required, because of out attribute. * // This value should be owerwritten later. * * try * { * FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB); * FontTable GposTable = Font.GetFontTable(OpenTypeTags.GPOS); * * GSUBHeader GsubHeader = new GSUBHeader(0); * GPOSHeader GposHeader = new GPOSHeader(0); * * ScriptList GsubScriptList; * ScriptList GposScriptList; * ScriptTable GsubScript; * ScriptTable GposScript; * LangSysTable GsubLangSys; * LangSysTable GposLangSys; * ushort GsubFeatureCount; * ushort GposFeatureCount; * FeatureList GsubFeatureList; * FeatureList GposFeatureList; * * * if (GsubTable.IsNotPresent && GposTable.IsNotPresent) * { * return OpenTypeLayoutResult.ScriptNotFound; * } * * if (GsubTable.IsPresent) * { * GsubScriptList = GsubHeader.GetScriptList(GsubTable); * GsubScript = GsubScriptList.FindScript(GsubTable,ScriptTag); * GsubLangSys = GsubScript.FindLangSys(GsubTable,LangSysTag); * GsubFeatureList = GsubHeader.GetFeatureList(GsubTable); * } * else * { * GsubScript = new ScriptTable(FontTable.InvalidOffset); * GsubLangSys = new LangSysTable(FontTable.InvalidOffset); * GsubFeatureList = new FeatureList(FontTable.InvalidOffset); * } * * if (GposTable.IsPresent) * { * GposScriptList = GposHeader.GetScriptList(GposTable); * GposScript = GposScriptList.FindScript(GposTable,ScriptTag); * GposLangSys = GposScript.FindLangSys(GposTable,LangSysTag); * GposFeatureList = GposHeader.GetFeatureList(GposTable); * } * else * { * GposScript = new ScriptTable(FontTable.InvalidOffset); * GposLangSys = new LangSysTable(FontTable.InvalidOffset); * GposFeatureList = new FeatureList(FontTable.InvalidOffset); * } * * if (GsubScript.IsNull && GposScript.IsNull) * { * return OpenTypeLayoutResult.ScriptNotFound; * } * * if (GsubLangSys.IsNull && GposLangSys.IsNull) * { * return OpenTypeLayoutResult.LangSysNotFound; * } * * if (!GsubLangSys.IsNull) * { * GsubFeatureCount = GsubLangSys.FeatureCount(GsubTable); * } * else * { * GsubFeatureCount = 0; * } * * if (!GposLangSys.IsNull) * { * GposFeatureCount = GposLangSys.FeatureCount(GposTable); * } * else * { * GposFeatureCount = 0; * } * * Features = new TagInfo[GsubFeatureCount]; * int CurrentFeatureIndex = 0; * * for(i=0; i<GsubFeatureCount; i++) * { * ushort FeatureIndex = GsubLangSys.GetFeatureIndex(GsubTable,i); * Features[CurrentFeatureIndex].Tag = GsubFeatureList.FeatureTag(GsubTable,FeatureIndex); * Features[CurrentFeatureIndex].TagFlags = TagInfoFlags.Substitution; ++CurrentFeatureIndex; * } * * Debug.Assert(CurrentFeatureIndex==Features.Length); * * //Check GPOS for tags that is not in GSUB * GposNewTags=0; * if (!GposLangSys.IsNull) * { * for(i=0;i<GposFeatureCount;i++) * { * ushort FeatureIndex = GposLangSys.GetFeatureIndex(GposTable,i); * uint GposTag = GposFeatureList.FeatureTag(GposTable,FeatureIndex); * if (TagInfo.IsNewTag(Features,GposTag)) * { ++GposNewTags; * } * } * } * * //append new tags to ScriptTags if any exists * if (GposNewTags>0) * { * //Allocate new array to fit all tags * TagInfo[] tmp = Features; * Features = new TagInfo[GsubFeatureCount+GposNewTags]; * Array.Copy(tmp,0,Features,0,tmp.Length); * * for(i=0;i<GposFeatureCount;i++) * { * ushort FeatureIndex = GposLangSys.GetFeatureIndex(GposTable,i); * uint GposTag = GposFeatureList.FeatureTag(GposTable,FeatureIndex); * * if (TagInfo.IsNewTag(Features,GposTag)) * { * Features[CurrentFeatureIndex].Tag = GposTag; * Features[CurrentFeatureIndex].TagFlags = TagInfoFlags.Positioning; ++CurrentFeatureIndex; * } * else * { * int Index = TagInfo.GetTagIndex(Features,GposTag); * Features[Index].TagFlags |= TagInfoFlags.Positioning; * } * } * * Debug.Assert(CurrentFeatureIndex==Features.Length); * } * * * } * catch (FileFormatException) * { * return OpenTypeLayoutResult.BadFontTable; * } * * return OpenTypeLayoutResult.Success; * } */ /// <summary> /// Substitutes glyphs according to features defined in the font. /// </summary> /// <param name="Font">In: Font access interface</param> /// <param name="workspace">In: Workspace for layout engine</param> /// <param name="ScriptTag">In: Script tag</param> /// <param name="LangSysTag">In: LangSys tag</param> /// <param name="FeatureSet">In: List of features to apply</param> /// <param name="featureCount">In: Actual number of features in <paramref name="FeatureSet"/></param> /// <param name="featureSetOffset">In: offset of input characters inside FeatureSet</param> /// <param name="CharCount">In: Characters count (i.e. <paramref name="Charmap"/>.Length);</param> /// <param name="Charmap">In/out: Char to glyph mapping</param> /// <param name="Glyphs">In/out: List of GlyphInfo structs</param> /// <returns>Substitution result</returns> internal static OpenTypeLayoutResult SubstituteGlyphs( IOpenTypeFont Font, // In: Font access interface OpenTypeLayoutWorkspace workspace, // In: Workspace for layout engine uint ScriptTag, // In: Script tag uint LangSysTag, // In: LangSys tag Feature[] FeatureSet, // In: List of features to apply int featureCount, // In: Actual number of features in FeatureSet int featureSetOffset, int CharCount, // In: Characters count (i.e. Charmap.Length); UshortList Charmap, // In/out: Char to glyph mapping GlyphInfoList Glyphs // In/out: List of GlyphInfo structs ) { try { FontTable GsubTable = Font.GetFontTable(OpenTypeTags.GSUB); if (!GsubTable.IsPresent) { return(OpenTypeLayoutResult.ScriptNotFound); } GSUBHeader GsubHeader = new GSUBHeader(0); ScriptList ScriptList = GsubHeader.GetScriptList(GsubTable); ScriptTable Script = ScriptList.FindScript(GsubTable, ScriptTag); if (Script.IsNull) { return(OpenTypeLayoutResult.ScriptNotFound); } LangSysTable LangSys = Script.FindLangSys(GsubTable, LangSysTag); if (LangSys.IsNull) { return(OpenTypeLayoutResult.LangSysNotFound); } FeatureList FeatureList = GsubHeader.GetFeatureList(GsubTable); LookupList LookupList = GsubHeader.GetLookupList(GsubTable); LayoutEngine.ApplyFeatures( Font, workspace, OpenTypeTags.GSUB, GsubTable, new LayoutMetrics(), //it is not needed for substitution LangSys, FeatureList, LookupList, FeatureSet, featureCount, featureSetOffset, CharCount, Charmap, Glyphs, null, null ); } catch (FileFormatException) { return(OpenTypeLayoutResult.BadFontTable); } return(OpenTypeLayoutResult.Success); }