@@ -44,13 +44,15 @@ internal sealed class IndicShaper : DefaultShaper
4444 private const int DottedCircle = 0x25cc ;
4545
4646 private readonly TextOptions textOptions ;
47+ private readonly FontMetrics fontMetrics ;
4748 private ShapingConfiguration indicConfiguration ;
4849 private readonly bool isOldSpec ;
4950
50- public IndicShaper ( ScriptClass script , Tag unicodeScriptTag , TextOptions textOptions )
51+ public IndicShaper ( ScriptClass script , Tag unicodeScriptTag , TextOptions textOptions , FontMetrics fontMetrics )
5152 : base ( script , MarkZeroingMode . None , textOptions )
5253 {
5354 this . textOptions = textOptions ;
55+ this . fontMetrics = fontMetrics ;
5456
5557 if ( IndicConfigurations . TryGetValue ( script , out ShapingConfiguration value ) )
5658 {
@@ -101,23 +103,24 @@ protected override void AssignFeatures(IGlyphShapingCollection collection, int i
101103 return ;
102104 }
103105
106+ FontMetrics fontMetrics = this . fontMetrics ;
107+
104108 // Decompose split matras
105109 Span < ushort > buffer = stackalloc ushort [ 16 ] ;
106110 int end = index + count ;
107111 for ( int i = end - 1 ; i >= 0 ; i -- )
108112 {
109113 GlyphShapingData data = substitutionCollection [ i ] ;
110- FontMetrics fontMetrics = data . TextRun . Font ! . FontMetrics ;
111-
112114 if ( ( Decompositions . TryGetValue ( data . CodePoint . Value , out int [ ] ? decompositions ) ||
113115 UniversalShapingData . Decompositions . TryGetValue ( data . CodePoint . Value , out decompositions ) ) &&
114116 decompositions != null )
115117 {
116118 Span < ushort > ids = buffer [ ..decompositions . Length ] ;
117119 for ( int j = 0 ; j < decompositions . Length ; j ++ )
118120 {
119- // Font should always contain the decomposed glyph.
120- fontMetrics . TryGetGlyphId ( new CodePoint ( decompositions [ j ] ) , out ushort id ) ;
121+ // Font should always contain the decomposed glyph since the shaper
122+ // is assigned based on features supported by the font.
123+ _ = fontMetrics . TryGetGlyphId ( new CodePoint ( decompositions [ j ] ) , out ushort id ) ;
121124 ids [ j ] = id ;
122125 }
123126
@@ -207,23 +210,22 @@ private void InitialReorder(IGlyphShapingCollection collection, int index, int c
207210 Span < GlyphShapingData > tempBuffer = new GlyphShapingData [ 3 ] ;
208211
209212 ShapingConfiguration indicConfiguration = this . indicConfiguration ;
210- for ( int i = 0 ; i < count ; i ++ )
211- {
212- GlyphShapingData data = substitutionCollection [ i + index ] ;
213- FontMetrics fontMetrics = data . TextRun . Font ! . FontMetrics ;
213+ FontMetrics fontMetrics = this . fontMetrics ;
214+ CodePoint viramaPoint = new ( indicConfiguration . Virama ) ;
214215
215- fontMetrics . TryGetGlyphId ( new ( 0x0020 ) , out ushort spc ) ;
216-
217- IndicShapingEngineInfo ? info = data . IndicShapingEngineInfo ;
218- if ( info ? . Position == Positions . Base_C )
216+ if ( fontMetrics . TryGetGlyphId ( viramaPoint , out ushort viramaId ) )
217+ {
218+ for ( int i = 0 ; i < count ; i ++ )
219219 {
220- CodePoint cp = new ( indicConfiguration . Virama ) ;
221- if ( fontMetrics . TryGetGlyphId ( cp , out ushort id ) )
220+ GlyphShapingData data = substitutionCollection [ i + index ] ;
221+ IndicShapingEngineInfo ? info = data . IndicShapingEngineInfo ;
222+
223+ if ( info ? . Position == Positions . Base_C )
222224 {
223225 GlyphShapingData virama = new ( data , false )
224226 {
225- GlyphId = id ,
226- CodePoint = cp
227+ GlyphId = viramaId ,
228+ CodePoint = viramaPoint
227229 } ;
228230
229231 tempBuffer [ 2 ] = virama ;
@@ -235,6 +237,8 @@ private void InitialReorder(IGlyphShapingCollection collection, int index, int c
235237 }
236238 }
237239
240+ bool hasDottedCircle = fontMetrics . TryGetGlyphId ( new ( DottedCircle ) , out ushort circleId ) ;
241+ _ = fontMetrics . TryGetGSubTable ( out GSubTable ? gSubTable ) ;
238242 int max = index + count ;
239243 int start = index ;
240244 int end = NextSyllable ( substitutionCollection , index , max ) ;
@@ -250,13 +254,7 @@ private void InitialReorder(IGlyphShapingCollection collection, int index, int c
250254 goto Increment ;
251255 }
252256
253- FontMetrics fontMetrics = data . TextRun . Font ! . FontMetrics ;
254- if ( ! fontMetrics . TryGetGSubTable ( out GSubTable ? gSubTable ) )
255- {
256- break ;
257- }
258-
259- if ( dataInfo != null && type == "broken_cluster" && fontMetrics . TryGetGlyphId ( new ( DottedCircle ) , out ushort id ) )
257+ if ( dataInfo != null && hasDottedCircle && type == "broken_cluster" )
260258 {
261259 // Insert after possible Repha.
262260 int i = start ;
@@ -272,7 +270,7 @@ private void InitialReorder(IGlyphShapingCollection collection, int index, int c
272270 }
273271
274272 glyphs [ 0 ] = current . GlyphId ;
275- glyphs [ 1 ] = id ;
273+ glyphs [ 1 ] = circleId ;
276274
277275 substitutionCollection . Replace ( i , glyphs , FeatureTags . GlyphCompositionDecomposition ) ;
278276
@@ -303,7 +301,7 @@ private void InitialReorder(IGlyphShapingCollection collection, int index, int c
303301 // base consonants.
304302 if ( start + 3 <= end &&
305303 indicConfiguration . RephPosition != Positions . Ra_To_Become_Reph &&
306- gSubTable . TryGetFeatureLookups ( in RphfTag , this . ScriptClass , out _ ) &&
304+ gSubTable ? . TryGetFeatureLookups ( in RphfTag , this . ScriptClass , out _ ) == true &&
307305 ( ( indicConfiguration . RephMode == RephMode . Implicit && ! IsJoiner ( substitutionCollection [ start + 2 ] ) ) ||
308306 ( indicConfiguration . RephMode == RephMode . Explicit && substitutionCollection [ start + 2 ] . IndicShapingEngineInfo ? . Category == Categories . ZWJ ) ) )
309307 {
@@ -692,7 +690,7 @@ private void InitialReorder(IGlyphShapingCollection collection, int index, int c
692690
693691 const int prefLen = 2 ;
694692 if ( basePosition + prefLen < end &&
695- gSubTable . TryGetFeatureLookups ( in PrefTag , this . ScriptClass , out _ ) )
693+ gSubTable ? . TryGetFeatureLookups ( in PrefTag , this . ScriptClass , out _ ) == true )
696694 {
697695 // Find a Halant,Ra sequence and mark it for pre-base reordering processing.
698696 for ( int i = basePosition + 1 ; i + prefLen - 1 < end ; i ++ )
@@ -790,9 +788,7 @@ private bool WouldSubstitute(GlyphSubstitutionCollection collection, in Tag feat
790788 collection . EnableShapingFeature ( i , featureTag ) ;
791789 }
792790
793- GlyphShapingData data = buffer [ 0 ] ;
794- FontMetrics fontMetrics = data . TextRun . Font ! . FontMetrics ;
795-
791+ FontMetrics fontMetrics = this . fontMetrics ;
796792 if ( fontMetrics . TryGetGSubTable ( out GSubTable ? gSubTable ) )
797793 {
798794 const int index = 0 ;
@@ -865,6 +861,8 @@ private void FinalReorder(IGlyphShapingCollection collection, int index, int cou
865861 int max = index + count ;
866862 int start = index ;
867863 int end = NextSyllable ( substitutionCollection , index , max ) ;
864+ FontMetrics fontMetrics = this . fontMetrics ;
865+ _ = fontMetrics . TryGetGSubTable ( out GSubTable ? gSubTable ) ;
868866 while ( start < max )
869867 {
870868 // 4. Final reordering:
@@ -873,14 +871,7 @@ private void FinalReorder(IGlyphShapingCollection collection, int index, int cou
873871 // applied (see below), the shaping engine performs some final glyph
874872 // reordering before applying all the remaining font features to the entire
875873 // cluster.
876- GlyphShapingData data = substitutionCollection [ start ] ;
877- FontMetrics fontMetrics = data . TextRun . Font ! . FontMetrics ;
878- if ( ! fontMetrics . TryGetGSubTable ( out GSubTable ? gSubTable ) )
879- {
880- break ;
881- }
882-
883- bool tryPref = gSubTable . TryGetFeatureLookups ( in PrefTag , this . ScriptClass , out _ ) ;
874+ bool tryPref = gSubTable ? . TryGetFeatureLookups ( in PrefTag , this . ScriptClass , out _ ) == true ;
884875
885876 // Find base consonant again.
886877 int basePosition = start ;
0 commit comments