Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 23 additions & 17 deletions src/Svg.Skia/SkiaSvgAssetLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public ShimSkiaSharp.SKImage LoadImage(System.IO.Stream stream)

var preferredTypeface = paintPreferredTypeface.Typeface;
var weight = _skiaModel.ToSKFontStyleWeight(preferredTypeface?.FontWeight ?? ShimSkiaSharp.SKFontStyleWeight.Normal);
var requestedWeight = preferredTypeface is null ? default(SkiaSharp.SKFontStyleWeight?) : weight;
var width = _skiaModel.ToSKFontStyleWidth(preferredTypeface?.FontWidth ?? ShimSkiaSharp.SKFontStyleWidth.Normal);
var slant = _skiaModel.ToSKFontStyleSlant(preferredTypeface?.FontSlant ?? ShimSkiaSharp.SKFontStyleSlant.Upright);
var preferredFamily = preferredTypeface?.FamilyName;
Expand All @@ -73,13 +74,7 @@ void YieldCurrentTypefaceText()
ret.Add(new(currentTypefaceText, _skiaModel.GetTextAdvance(currentTypefaceText, runningPaint),
runningPaint.Typeface is null
? null
: ShimSkiaSharp.SKTypeface.FromFamilyName(
runningPaint.Typeface.FamilyName,
// SkiaSharp provides int properties here. Let's just assume our
// ShimSkiaSharp defines the same values as SkiaSharp and convert directly
(ShimSkiaSharp.SKFontStyleWeight)runningPaint.Typeface.FontWeight,
(ShimSkiaSharp.SKFontStyleWidth)runningPaint.Typeface.FontWidth,
(ShimSkiaSharp.SKFontStyleSlant)runningPaint.Typeface.FontSlant)
: ToShimTypeface(runningPaint.Typeface, requestedWeight)
));
}

Expand Down Expand Up @@ -131,14 +126,15 @@ runningPaint.Typeface is null

EnsureTypefaceProviderCaches();

var codepoints = CollectDistinctRenderableCodepoints(text);
var codepoints = CollectDistinctRenderableCodepoints(text!);
if (codepoints.Count == 0)
{
return paintPreferredTypeface.Typeface;
}

var preferredTypeface = paintPreferredTypeface.Typeface;
var preferredWeight = _skiaModel.ToSKFontStyleWeight(preferredTypeface?.FontWeight ?? ShimSkiaSharp.SKFontStyleWeight.Normal);
var requestedWeight = preferredTypeface is null ? default(SkiaSharp.SKFontStyleWeight?) : preferredWeight;
var preferredWidth = _skiaModel.ToSKFontStyleWidth(preferredTypeface?.FontWidth ?? ShimSkiaSharp.SKFontStyleWidth.Normal);
var preferredSlant = _skiaModel.ToSKFontStyleSlant(preferredTypeface?.FontSlant ?? ShimSkiaSharp.SKFontStyleSlant.Upright);
var preferredFamily = preferredTypeface?.FamilyName;
Expand Down Expand Up @@ -185,7 +181,7 @@ void AddCandidate(SkiaSharp.SKTypeface? candidate)
var candidate = candidates[i];
if (CanRenderAllCodepoints(candidate, codepoints))
{
return ToShimTypeface(candidate);
return ToShimTypeface(candidate, requestedWeight);
}
}

Expand Down Expand Up @@ -564,15 +560,25 @@ private static bool CanRenderAllCodepoints(SkiaSharp.SKTypeface? typeface, IRead
return true;
}

private static ShimSkiaSharp.SKTypeface? ToShimTypeface(SkiaSharp.SKTypeface? typeface)
private static ShimSkiaSharp.SKTypeface? ToShimTypeface(
SkiaSharp.SKTypeface? typeface,
SkiaSharp.SKFontStyleWeight? requestedWeight)
{
return typeface is null || typeface.Handle == IntPtr.Zero
? null
: ShimSkiaSharp.SKTypeface.FromFamilyName(
typeface.FamilyName,
(ShimSkiaSharp.SKFontStyleWeight)typeface.FontWeight,
(ShimSkiaSharp.SKFontStyleWidth)typeface.FontWidth,
(ShimSkiaSharp.SKFontStyleSlant)typeface.FontSlant);
if (typeface is null || typeface.Handle == IntPtr.Zero)
{
return null;
}

var resolvedWeight = (SkiaSharp.SKFontStyleWeight)typeface.FontWeight;
var shimWeight = requestedWeight is { } weight && resolvedWeight < weight
? (ShimSkiaSharp.SKFontStyleWeight)weight
: (ShimSkiaSharp.SKFontStyleWeight)resolvedWeight;

return ShimSkiaSharp.SKTypeface.FromFamilyName(
typeface.FamilyName,
shimWeight,
(ShimSkiaSharp.SKFontStyleWidth)typeface.FontWidth,
(ShimSkiaSharp.SKFontStyleSlant)typeface.FontSlant);
}

private SkiaSharp.SKTypeface? GetProviderTypeface(
Expand Down
119 changes: 119 additions & 0 deletions tests/Svg.Skia.UnitTests/Issue462Tests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
#pragma warning disable CS0618 // FakeBoldText is deprecated on SKPaint; shim keeps the legacy surface for compatibility

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using ShimSkiaSharp;
using Svg.Skia.TypefaceProviders;
using Svg.Skia.UnitTests.Common;
using Xunit;
using NativeTypeface = SkiaSharp.SKTypeface;

namespace Svg.Skia.UnitTests;

public class Issue462Tests : SvgUnitTest
{
[Fact]
public void FindTypefaces_PreservesRequestedBoldForRegularOnlyResolvedFace()
{
using var provider = new RegularOnlyTypefaceProvider(GetFontsPath("SourceSansPro-Regular.ttf"));
var settings = new SKSvgSettings
{
TypefaceProviders = new List<ITypefaceProvider> { provider }
};
var model = new SkiaModel(settings);
var assetLoader = new SkiaSvgAssetLoader(model);
var paint = CreateRequestedBoldPaint(provider.FamilyName);

var span = Assert.Single(assetLoader.FindTypefaces("Bold Text", paint));

Assert.NotNull(span.Typeface);
Assert.Equal(SKFontStyleWeight.Bold, span.Typeface!.FontWeight);
AssertUsesSyntheticBold(model, span.Typeface);
}

[Fact]
public void FindRunTypeface_PreservesRequestedBoldForRegularOnlyResolvedFace()
{
using var provider = new RegularOnlyTypefaceProvider(GetFontsPath("SourceSansPro-Regular.ttf"));
var settings = new SKSvgSettings
{
TypefaceProviders = new List<ITypefaceProvider> { provider }
};
var model = new SkiaModel(settings);
var assetLoader = new SkiaSvgAssetLoader(model);
var paint = CreateRequestedBoldPaint(provider.FamilyName);

var typeface = assetLoader.FindRunTypeface("Bold Text", paint);

Assert.NotNull(typeface);
Assert.Equal(SKFontStyleWeight.Bold, typeface!.FontWeight);
AssertUsesSyntheticBold(model, typeface);
}

private static SKPaint CreateRequestedBoldPaint(string familyName)
{
return new SKPaint
{
TextSize = 48f,
Typeface = SKTypeface.FromFamilyName(
familyName,
SKFontStyleWeight.Bold,
SKFontStyleWidth.Normal,
SKFontStyleSlant.Upright)
};
}

private static void AssertUsesSyntheticBold(SkiaModel model, SKTypeface typeface)
{
using var localPaint = model.ToSKPaint(new SKPaint
{
TextSize = 48f,
Typeface = typeface
});

Assert.NotNull(localPaint);
Assert.True(localPaint!.FakeBoldText);
}

private sealed class RegularOnlyTypefaceProvider : ITypefaceProvider, IDisposable
{
private readonly NativeTypeface _typeface;

public RegularOnlyTypefaceProvider(string path)
{
if (!File.Exists(path))
{
throw new FileNotFoundException("Test font was not found.", path);
}

_typeface = NativeTypeface.FromFile(path);
FamilyName = _typeface.FamilyName;
}

public string FamilyName { get; }

public NativeTypeface? FromFamilyName(
string fontFamily,
SkiaSharp.SKFontStyleWeight fontWeight,
SkiaSharp.SKFontStyleWidth fontWidth,
SkiaSharp.SKFontStyleSlant fontStyle)
{
var requestedFamilies = fontFamily
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(static family => family.Trim().Trim('"', '\''));

return requestedFamilies.Contains(FamilyName, StringComparer.OrdinalIgnoreCase)
? _typeface
: null;
}

public void Dispose()
{
_typeface.Dispose();
}
}
}

#pragma warning restore CS0618
Loading