Esempio n. 1
0
        public FTVector GetKerning(uint leftGlyph, uint rightGlyph, KerningMode mode)
        {
            if (disposed)
                throw new ObjectDisposedException("face", "Cannot access a disposed object.");

            FTVector kern;
            Error err = FT.FT_Get_Kerning(Reference, leftGlyph, rightGlyph, mode, out kern);

            if (err != Error.Ok)
                throw new FreeTypeException(err);

            return kern;
        }
Esempio n. 2
0
 /// <summary>
 /// Applies any available substitutions to the collection of glyphs.
 /// </summary>
 /// <param name="collection">The glyph substitution collection.</param>
 /// <param name="kerningMode">The kerning mode.</param>
 internal abstract void ApplySubstitution(GlyphSubstitutionCollection collection, KerningMode kerningMode);
Esempio n. 3
0
 /// <summary>
 /// Applies any available positioning updates to the collection of glyphs.
 /// </summary>
 /// <param name="collection">The glyph positioning collection.</param>
 /// <param name="kerningMode">The kerning mode.</param>
 internal abstract void UpdatePositions(GlyphPositioningCollection collection, KerningMode kerningMode);
Esempio n. 4
0
 internal static extern Error FT_Get_Kerning(IntPtr face, uint left_glyph, uint right_glyph, KerningMode kern_mode, out FTVector akerning);
Esempio n. 5
0
 public static extern Error FT_Get_Kerning(Face *face, uint left_glyph, uint right_glyph, KerningMode kern_mode, out FTVector26Dot6 akerning);
Esempio n. 6
0
 /// <inheritdoc/>
 internal override void ApplySubstitution(GlyphSubstitutionCollection collection, KerningMode kerningMode)
 => this.metrics.Value.ApplySubstitution(collection, kerningMode);
Esempio n. 7
0
 /// <inheritdoc/>
 internal override void UpdatePositions(GlyphPositioningCollection collection, KerningMode kerningMode)
 => this.metrics.Value.UpdatePositions(collection, kerningMode);
        public bool TryUpdatePositions(FontMetrics fontMetrics, GlyphPositioningCollection collection, KerningMode kerningMode, out bool kerned)
        {
            kerned = false;
            bool updated = false;

            for (ushort i = 0; i < collection.Count; i++)
            {
                if (!collection.ShouldProcess(fontMetrics, i))
                {
                    continue;
                }

                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++;
                }

                if (shaper.MarkZeroingMode == MarkZeroingMode.PreGPos)
                {
                    ZeroMarkAdvances(fontMetrics, collection, index, count);
                }

                // Assign Substitution features to each glyph.
                shaper.AssignFeatures(collection, index, count);
                IEnumerable <Tag>     stageFeatures = shaper.GetShapingStageFeatures();
                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;
                            }

                            bool success = featureLookup.LookupTable.TryUpdatePosition(fontMetrics, this, collection, featureLookup.Feature, iterator.Index, count - (iterator.Index - index));
                            kerned  |= success && (feature == KernTag || feature == VKernTag);
                            updated |= success;
                            iterator.Next();
                        }
                    }
                }

                if (shaper.MarkZeroingMode == MarkZeroingMode.PostGpos)
                {
                    ZeroMarkAdvances(fontMetrics, collection, index, count);
                }

                FixCursiveAttachment(collection, index, count);
                FixMarkAttachment(collection, index, count);
                if (updated)
                {
                    UpdatePositions(fontMetrics, collection, index, count);
                }
            }

            return(updated);
        }
        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;
                            }
                        }
                    }
                }
            }
        }
Esempio n. 10
0
 internal static extern Error FT_Get_Kerning(IntPtr face, uint left_glyph, uint right_glyph, KerningMode kern_mode, out FTVector akerning);
 public ArabicShaper(KerningMode kerningMode)
     : base(MarkZeroingMode.PostGpos, kerningMode)
 {
 }
 /// <summary>
 /// Creates a Shaper based on the given script language.
 /// </summary>
 /// <param name="script">The script language.</param>
 /// <param name="kerningMode">The kerning mode.</param>
 /// <returns>A shaper for the given script.</returns>
 public static BaseShaper Create(ScriptClass script, KerningMode kerningMode)
 => script switch
 {