Avalonia
Avalonia copied to clipboard
Symbol font glyphs rendered thicker in avalonia
Describe the bug Glyphs in symbol fonts (Segoe Fluent Icons, Segoe MDL2 Assets, etc.) are rendering thicker than they should be in Avalonia (TextBlock/TextLayout and FormattedText). Using Skia in a custom draw op renders them correctly to appear much closer to how they should. SkiaSharp version is whatever ships with Avalonia (I'm not using my own ref here). This also isn't new to the new text engine for 11.0, but I just discovered it's not just an issue with my custom font (based on the open source Fluent UI Icons) but also with the other MS fonts.
1920x1080 display, normal 100% scaling
The glyph is \uE8BB
from either of the Segoe icon fonts (same as the native close button everywhere on Windows)
Xaml
<Viewbox Width="10"
Height="10"
Grid.Column="1">
<TextBlock Name="ButtonIcon"
FontFamily="Segoe Fluent Icons"
FontSize="12"
Text=""
Foreground="White"/>
</Viewbox>
<Viewbox Width="10"
Height="10"
Grid.Column="1" Grid.Row="1">
<local:SkiaTextBlock />
</Viewbox>
The Skia CustomDrawOp (SkiaTextBlock)
var tf = SKTypeface.FromFamilyName("Segoe Fluent Icons");
Font = new SKFont
{
Subpixel = true,
Edging = SKFontEdging.SubpixelAntialias,
Hinting = SKFontHinting.Full,
LinearMetrics = true,
Typeface = tf,
Size = 12
};
public void Render(IDrawingContextImpl context)
{
var api = context.GetFeature<ISkiaSharpApiLeaseFeature>();
using var lease = api.Lease();
var dc = lease.SkCanvas;
var txt = "\uE8BB";
using var paint = new SKPaint(Font);
paint.Style = SKPaintStyle.StrokeAndFill;
paint.Color = SKColors.White;
SKRect bnds = default;
paint.MeasureText(txt, ref bnds);
var cx = (float)Bounds.Center.X;
var cy = (float)Bounds.Center.Y;
dc.DrawText(txt, cx - (bnds.Width / 2), cy - (bnds.Height / 2) + bnds.Height, paint);
}
To Reproduce Steps to reproduce the behavior:
- Go to '...'
- Click on '....'
- Scroll down to '....'
- See error
Expected behavior A clear and concise description of what you expected to happen.
Screenshots If applicable, add screenshots to help explain your problem.
Desktop (please complete the following information):
- OS: Windows
- Version 11.0
Additional context Add any other context about the problem here.
I would blame the font metrics in the FluentAvalonia.ttf font except you tested others. Very strange. If it does turn out to be something we need to adjust with the font though just let me know. I can take another look at it.
I had a deeper look at this and it looks like this is a bug with the SKCanvas.DrawText implementation. If you pass in a string the edging settings are not respected and you don't get a grayscale rendering. If you call this function with a SKTextBlob all settings are respected and you get grayscale rendering etc.
dc.DrawText(glyphRun.TextBlob, cx - (bnds.Width / 2), cy - (bnds.Height / 2) + bnds.Height, paint)
//Edging is respected
dc.DrawText(txt, cx - (bnds.Width / 2), cy - (bnds.Height / 2) + bnds.Height, paint)
//No edging setting is respected
If I set Edging.Alias both produce the same results
But the expected result is the thinner one with DrawText(string).
But based on what you said I did a quick test and I'm wondering if these symbol fonts aren't meant to be rendered with anti-aliasing, or Skia's anti-aliasing is too much? DirectWrite renders more correctly and I've also noticed that certain foreground-background contrasts can make the glyph appear correct too:
WPF has the ClearTypeHint property in RenderOptions
and the TextOptions class for customizing this behavior. Could this be added (or something similar) to support scenarios like this where aliasing is better?
I think I can disable anti-aliasing for symbol fonts
Looking closely at the images I think this is just a difference in anti-aliasing too. DirectWrite simply has a better algorithm in this case but it still looks slightly anti-aliased to me. I wouldn't necessarily just disable antialiasing for Skia in this case... that might create other issues.
I think I can disable anti-aliasing for symbol fonts
How would you detect these? Those fonts that only have glyphs in the private use area?
Because some Microsoft symbol fonts don't follow this rule, others include real characters along with symbol glyphs.
Y that is the only option to somehow reliably detect such font. The other option is to provide TextRenderOptions that allow you to disable anti-aliasing in some context. I might just go for implementing TextRenderOptions.