Explorar o código

Merge pull request #9276 from Gillibald/feature/textCompat

Text rendering compat
Max Katz %!s(int64=3) %!d(string=hai) anos
pai
achega
0c301dffb5

+ 27 - 0
src/Avalonia.Base/Media/FontSimulations.cs

@@ -0,0 +1,27 @@
+using System;
+
+namespace Avalonia.Media
+{
+    /// <summary>
+    ///     Specifies algorithmic style simulations to be applied to the typeface.
+    ///     Bold and oblique simulations can be combined via bitwise OR operation.
+    /// </summary>
+    [Flags]
+    public enum FontSimulations : byte
+    {
+        /// <summary>
+        /// No simulations are performed.
+        /// </summary>
+        None = 0x0000,
+
+        /// <summary>
+        /// Algorithmic emboldening is performed.
+        /// </summary>
+        Bold = 0x0001,
+
+        /// <summary>
+        /// Algorithmic italicization is performed.
+        /// </summary>
+        Oblique = 0x0002
+    }
+}

+ 24 - 0
src/Avalonia.Base/Media/GlyphMetrics.cs

@@ -0,0 +1,24 @@
+namespace Avalonia.Media;
+
+public readonly struct GlyphMetrics
+{
+    /// <summary>
+    /// Distance from the x-origin to the left extremum of the glyph.
+    /// </summary>
+    public int XBearing { get; init; }
+
+    /// <summary>
+    /// Distance from the top extremum of the glyph to the y-origin.
+    /// </summary>
+    public int YBearing{ get; init; }
+
+    /// <summary>
+    /// Distance from the left extremum of the glyph to the right extremum.
+    /// </summary>
+    public int Width{ get; init; }
+
+    /// <summary>
+    /// Distance from the top extremum of the glyph to the bottom extremum.
+    /// </summary>
+    public int Height{ get; init; }
+}

+ 15 - 0
src/Avalonia.Base/Media/IGlyphTypeface.cs

@@ -19,6 +19,21 @@ namespace Avalonia.Media
         /// </returns>
         FontMetrics Metrics { get; }
 
+        /// <summary>
+        ///     Gets the algorithmic style simulations applied to this glyph typeface.
+        /// </summary>
+        FontSimulations FontSimulations { get; }
+
+        /// <summary>
+        ///     Tries to get a glyph's metrics in em units.
+        /// </summary>
+        /// <param name="glyph">The glyph id.</param>
+        /// <param name="metrics">The glyph metrics.</param>
+        /// <returns>
+        ///   <c>true</c> if an glyph's metrics was found, <c>false</c> otherwise.
+        /// </returns>
+        bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics);
+        
         /// <summary>
         ///     Returns an glyph index for the specified codepoint.
         /// </summary>

+ 13 - 0
src/Avalonia.Headless/HeadlessPlatformStubs.cs

@@ -102,6 +102,8 @@ namespace Avalonia.Headless
 
         public int GlyphCount => 1337;
 
+        public FontSimulations FontSimulations { get; }
+
         public void Dispose()
         {
         }
@@ -138,6 +140,17 @@ namespace Avalonia.Headless
             table = null;
             return false;
         }
+
+        public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+        {
+            metrics = new GlyphMetrics
+            {
+                Height = 10,
+                Width = 10
+            };
+
+            return true;
+        }
     }
 
     class HeadlessTextShaperStub : ITextShaperImpl

+ 12 - 4
src/Skia/Avalonia.Skia/FontManagerImpl.cs

@@ -148,11 +148,19 @@ namespace Avalonia.Skia
                     $"Could not create glyph typeface for: {typeface.FontFamily.Name}.");
             }
 
-            var isFakeBold = (int)typeface.Weight >= 600 && !skTypeface.IsBold;
+            var fontSimulations = FontSimulations.None;
 
-            var isFakeItalic = typeface.Style == FontStyle.Italic && !skTypeface.IsItalic;
-            
-            return new GlyphTypefaceImpl(skTypeface, isFakeBold, isFakeItalic);
+            if((int)typeface.Weight >= 600 && !skTypeface.IsBold)
+            {
+                fontSimulations |= FontSimulations.Bold;
+            }
+
+            if(typeface.Style == FontStyle.Italic && !skTypeface.IsItalic)
+            {
+                fontSimulations |= FontSimulations.Oblique;
+            }
+
+            return new GlyphTypefaceImpl(skTypeface, fontSimulations);
         }
     }
 }

+ 24 - 4
src/Skia/Avalonia.Skia/GlyphTypefaceImpl.cs

@@ -12,7 +12,7 @@ namespace Avalonia.Skia
     {
         private bool _isDisposed;
 
-        public GlyphTypefaceImpl(SKTypeface typeface, bool isFakeBold = false, bool isFakeItalic = false)
+        public GlyphTypefaceImpl(SKTypeface typeface, FontSimulations fontSimulations)
         {
             Typeface = typeface ?? throw new ArgumentNullException(nameof(typeface));
 
@@ -52,9 +52,7 @@ namespace Avalonia.Skia
 
             GlyphCount = Typeface.GlyphCount;
 
-            IsFakeBold = isFakeBold;
-
-            IsFakeItalic = isFakeItalic;
+            FontSimulations = fontSimulations;
         }
 
         public Face Face { get; }
@@ -63,6 +61,8 @@ namespace Avalonia.Skia
 
         public SKTypeface Typeface { get; }
 
+        public FontSimulations FontSimulations { get; }
+
         public int ReplacementCodepoint { get; }
 
         public FontMetrics Metrics { get; }
@@ -73,6 +73,26 @@ namespace Avalonia.Skia
 
         public bool IsFakeItalic { get; }
 
+        public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+        {
+            metrics = default;
+
+            if (!Font.TryGetGlyphExtents(glyph, out var extents))
+            {
+                return false;
+            }
+            
+            metrics = new GlyphMetrics
+            {
+                XBearing = extents.XBearing,
+                YBearing = extents.YBearing,
+                Width = extents.Width,
+                Height = extents.Height
+            };
+                
+            return true;
+        }
+
         /// <inheritdoc cref="IGlyphTypeface"/>
         public ushort GetGlyph(uint codepoint)
         {

+ 24 - 1
src/Windows/Avalonia.Direct2D1/Media/GlyphTypefaceImpl.cs

@@ -1,10 +1,11 @@
 using System;
-using System.Drawing.Drawing2D;
 using Avalonia.Media;
 using Avalonia.Metadata;
 using HarfBuzzSharp;
 using SharpDX.DirectWrite;
 using FontMetrics = Avalonia.Media.FontMetrics;
+using FontSimulations = Avalonia.Media.FontSimulations;
+using GlyphMetrics = Avalonia.Media.GlyphMetrics;
 
 namespace Avalonia.Direct2D1.Media
 {
@@ -82,6 +83,8 @@ namespace Avalonia.Direct2D1.Media
 
         public int GlyphCount { get; set; }
 
+        public FontSimulations FontSimulations => FontSimulations.None;
+
         /// <inheritdoc cref="IGlyphTypeface"/>
         public ushort GetGlyph(uint codepoint)
         {
@@ -135,6 +138,26 @@ namespace Avalonia.Direct2D1.Media
             return Font.GetHorizontalGlyphAdvances(glyphIndices);
         }
 
+        public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+        {
+            metrics = default;
+
+            if (!Font.TryGetGlyphExtents(glyph, out var extents))
+            {
+                return false;
+            }
+
+            metrics = new GlyphMetrics
+            {
+                XBearing = extents.XBearing,
+                YBearing = extents.YBearing,
+                Width = extents.Width,
+                Height = extents.Height
+            };
+
+            return true;
+        }
+
         private void Dispose(bool disposing)
         {
             if (_isDisposed)

+ 1 - 1
tests/Avalonia.Skia.UnitTests/Media/CustomFontManagerImpl.cs

@@ -103,7 +103,7 @@ namespace Avalonia.Skia.UnitTests.Media
                     }
             }
 
-            return new GlyphTypefaceImpl(skTypeface);
+            return new GlyphTypefaceImpl(skTypeface, FontSimulations.None);
         }
     }
 }

+ 23 - 9
tests/Avalonia.UnitTests/HarfBuzzGlyphTypefaceImpl.cs

@@ -10,7 +10,7 @@ namespace Avalonia.UnitTests
         private bool _isDisposed;
         private Blob _blob;
 
-        public HarfBuzzGlyphTypefaceImpl(Stream data, bool isFakeBold = false, bool isFakeItalic = false)
+        public HarfBuzzGlyphTypefaceImpl(Stream data)
         {
             _blob = Blob.FromStream(data);
             
@@ -45,10 +45,6 @@ namespace Avalonia.UnitTests
             };           
 
             GlyphCount = Face.GlyphCount;
-
-            IsFakeBold = isFakeBold;
-
-            IsFakeItalic = isFakeItalic;
         }
 
         public FontMetrics Metrics { get; }
@@ -58,10 +54,8 @@ namespace Avalonia.UnitTests
         public Font Font { get; }
 
         public int GlyphCount { get; set; }
-        
-        public bool IsFakeBold { get; }
-        
-        public bool IsFakeItalic { get; }
+
+        public FontSimulations FontSimulations { get; }
 
         /// <inheritdoc cref="IGlyphTypeface"/>
         public ushort GetGlyph(uint codepoint)
@@ -162,5 +156,25 @@ namespace Avalonia.UnitTests
             Dispose(true);
             GC.SuppressFinalize(this);
         }
+
+        public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+        {
+            metrics = default;
+
+            if (!Font.TryGetGlyphExtents(glyph, out var extents))
+            {
+                return false;
+            }
+
+            metrics = new GlyphMetrics
+            {
+                XBearing = extents.XBearing,
+                YBearing = extents.YBearing,
+                Width = extents.Width,
+                Height = extents.Height
+            };
+
+            return true;
+        }
     }
 }

+ 13 - 0
tests/Avalonia.UnitTests/MockGlyphTypeface.cs

@@ -15,6 +15,8 @@ namespace Avalonia.UnitTests
 
         public int GlyphCount => 1337;
 
+        public FontSimulations FontSimulations => throw new NotImplementedException();
+
         public ushort GetGlyph(uint codepoint)
         {
             return (ushort)codepoint;
@@ -56,5 +58,16 @@ namespace Avalonia.UnitTests
             table = null;
             return false;
         }
+
+        public bool TryGetGlyphMetrics(ushort glyph, out GlyphMetrics metrics)
+        {
+            metrics = new GlyphMetrics
+            {
+                Width = 10,
+                Height = 10
+            };
+
+            return true;
+        }
     }
 }