예제 #1
0
        public static bool ApplyLookupList(
            FontMetrics fontMetrics,
            GSubTable table,
            Tag feature,
            LookupFlags lookupFlags,
            SequenceLookupRecord[] records,
            GlyphSubstitutionCollection collection,
            ushort index,
            int count)
        {
            bool hasChanged = false;
            SkippingGlyphIterator iterator = new(fontMetrics, collection, index, lookupFlags);
            int currentCount = collection.Count;

            foreach (SequenceLookupRecord lookupRecord in records)
            {
                ushort sequenceIndex = lookupRecord.SequenceIndex;
                ushort lookupIndex   = lookupRecord.LookupListIndex;
                iterator.Index = index;
                iterator.Increment(sequenceIndex);
                GSub.LookupTable lookup = table.LookupList.LookupTables[lookupIndex];
                hasChanged |= lookup.TrySubstitution(fontMetrics, table, collection, feature, iterator.Index, count - (iterator.Index - index));

                // Account for substitutions changing the length of the collection.
                if (collection.Count != currentCount)
                {
                    count       -= currentCount - collection.Count;
                    currentCount = collection.Count;
                }
            }

            return(hasChanged);
        }
 public override bool TrySubstitution(
     FontMetrics fontMetrics,
     GSubTable table,
     GlyphSubstitutionCollection collection,
     Tag feature,
     ushort index,
     int count)
 => false;
예제 #3
0
        public bool TrySubstitution(
            FontMetrics fontMetrics,
            GSubTable table,
            GlyphSubstitutionCollection collection,
            Tag feature,
            ushort index,
            int count)
        {
            foreach (LookupSubTable subTable in this.LookupSubTables)
            {
                if (subTable.TrySubstitution(fontMetrics, table, collection, feature, index, count))
                {
                    // A lookup is finished for a glyph after the client locates the target
                    // glyph or glyph context and performs a substitution, if specified.
                    return(true);
                }
            }

            return(false);
        }
        public void ApplySubstitution(FontMetrics fontMetrics, GlyphSubstitutionCollection collection, KerningMode kerningMode)
        {
            for (ushort i = 0; i < collection.Count; i++)
            {
                // Choose a shaper based on the script.
                // This determines which features to apply to which glyphs.
                ScriptClass current = CodePoint.GetScriptClass(collection.GetGlyphShapingData(i).CodePoint);
                BaseShaper  shaper  = ShaperFactory.Create(current, kerningMode);

                ushort index = i;
                ushort count = 1;
                while (i < collection.Count - 1)
                {
                    // We want to assign the same feature lookups to individual sections of the text rather
                    // than the text as a whole to ensure that different language shapers do not interfere
                    // with each other when the text contains multiple languages.
                    GlyphShapingData nextData = collection.GetGlyphShapingData(i + 1);
                    ScriptClass      next     = CodePoint.GetScriptClass(nextData.CodePoint);
                    if (next is not ScriptClass.Common and not ScriptClass.Unknown and not ScriptClass.Inherited && next != current)
                    {
                        break;
                    }

                    i++;
                    count++;
                }

                // Assign Substitution features to each glyph.
                shaper.AssignFeatures(collection, index, count);
                IEnumerable <Tag> stageFeatures = shaper.GetShapingStageFeatures();

                int currentCount = collection.Count;
                SkippingGlyphIterator iterator = new(fontMetrics, collection, index, default);
                foreach (Tag stageFeature in stageFeatures)
                {
                    List <(Tag Feature, ushort Index, LookupTable LookupTable)> lookups = this.GetFeatureLookups(in stageFeature, current);
                    if (lookups.Count == 0)
                    {
                        continue;
                    }

                    // Apply features in order.
                    foreach ((Tag Feature, ushort Index, LookupTable LookupTable)featureLookup in lookups)
                    {
                        Tag feature = featureLookup.Feature;
                        iterator.Reset(index, featureLookup.LookupTable.LookupFlags);

                        while (iterator.Index < index + count)
                        {
                            List <TagEntry> glyphFeatures = collection.GetGlyphShapingData(iterator.Index).Features;
                            if (!HasFeature(glyphFeatures, in feature))
                            {
                                iterator.Next();
                                continue;
                            }

                            featureLookup.LookupTable.TrySubstitution(fontMetrics, this, collection, featureLookup.Feature, iterator.Index, count - (iterator.Index - index));
                            iterator.Next();

                            // Account for substitutions changing the length of the collection.
                            if (collection.Count != currentCount)
                            {
                                count        = (ushort)(count - (currentCount - collection.Count));
                                currentCount = collection.Count;
                            }
                        }
                    }
                }
            }
        }