Improved font matching and exception message. Refactored tests.

This commit is contained in:
MarcinZiabek 2022-02-27 15:19:50 +01:00
Родитель 8db283d559
Коммит a92cc25fb1
3 изменённых файлов: 109 добавлений и 77 удалений

Просмотреть файл

@ -1,123 +1,146 @@
using NUnit.Framework;
using FluentAssertions;
using NUnit.Framework;
using QuestPDF.Drawing;
using SkiaSharp;
using static SkiaSharp.SKFontStyleSlant;
namespace QuestPDF.UnitTests
{
[TestFixture]
public class FontStyleSetTests
{
private void ExpectComparisonOrder(SKFontStyle target, params SKFontStyle[] styles)
private void ExpectComparisonOrder(SKFontStyle target, SKFontStyle[] styles)
{
for (int i = 0; i < styles.Length - 1; i++)
for (var i = 0; i < styles.Length - 1; i++)
{
Assert.True(FontStyleSet.IsBetterMatch(target, styles[i], styles[i + 1]));
Assert.False(FontStyleSet.IsBetterMatch(target, styles[i + 1], styles[i]));
var currentStyle = styles[i];
var nextStyle = styles[i + 1];
FontStyleSet.IsBetterMatch(target, currentStyle, nextStyle).Should().BeTrue();
FontStyleSet.IsBetterMatch(target, nextStyle, currentStyle).Should().BeFalse();
}
}
[Test]
public void FontStyleSet_IsBetterMatch_CondensedWidth()
{
ExpectComparisonOrder(
new SKFontStyle(500, 5, SKFontStyleSlant.Upright),
new SKFontStyle(500, 5, SKFontStyleSlant.Upright),
new SKFontStyle(500, 4, SKFontStyleSlant.Upright),
new SKFontStyle(500, 3, SKFontStyleSlant.Upright),
new SKFontStyle(500, 6, SKFontStyleSlant.Upright)
);
var styles = new[]
{
new SKFontStyle(500, 5, Upright),
new SKFontStyle(500, 4, Upright),
new SKFontStyle(500, 3, Upright),
new SKFontStyle(500, 6, Upright)
};
ExpectComparisonOrder(new SKFontStyle(500, 5, Upright), styles);
}
[Test]
public void FontStyleSet_IsBetterMatch_ExpandedWidth()
{
ExpectComparisonOrder(
new SKFontStyle(500, 6, SKFontStyleSlant.Upright),
new SKFontStyle(500, 6, SKFontStyleSlant.Upright),
new SKFontStyle(500, 7, SKFontStyleSlant.Upright),
new SKFontStyle(500, 8, SKFontStyleSlant.Upright),
new SKFontStyle(500, 5, SKFontStyleSlant.Upright)
);
var styles = new[]
{
new SKFontStyle(500, 6, Upright),
new SKFontStyle(500, 7, Upright),
new SKFontStyle(500, 8, Upright),
new SKFontStyle(500, 5, Upright)
};
ExpectComparisonOrder(new SKFontStyle(500, 6, Upright), styles);
}
[Test]
public void FontStyleSet_IsBetterMatch_ItalicSlant()
{
ExpectComparisonOrder(
new SKFontStyle(500, 5, SKFontStyleSlant.Italic),
new SKFontStyle(500, 5, SKFontStyleSlant.Italic),
new SKFontStyle(500, 5, SKFontStyleSlant.Oblique),
new SKFontStyle(500, 5, SKFontStyleSlant.Upright)
);
var styles = new[]
{
new SKFontStyle(500, 5, Italic),
new SKFontStyle(500, 5, Oblique),
new SKFontStyle(500, 5, Upright)
};
ExpectComparisonOrder(new SKFontStyle(500, 5, Italic), styles);
}
[Test]
public void FontStyleSet_IsBetterMatch_ObliqueSlant()
{
ExpectComparisonOrder(
new SKFontStyle(500, 5, SKFontStyleSlant.Oblique),
new SKFontStyle(500, 5, SKFontStyleSlant.Oblique),
new SKFontStyle(500, 5, SKFontStyleSlant.Italic),
new SKFontStyle(500, 5, SKFontStyleSlant.Upright)
);
var styles = new[]
{
new SKFontStyle(500, 5, Oblique),
new SKFontStyle(500, 5, Italic),
new SKFontStyle(500, 5, Upright)
};
ExpectComparisonOrder(new SKFontStyle(500, 5, Oblique), styles);
}
[Test]
public void FontStyleSet_IsBetterMatch_UprightSlant()
{
ExpectComparisonOrder(
new SKFontStyle(500, 5, SKFontStyleSlant.Upright),
new SKFontStyle(500, 5, SKFontStyleSlant.Upright),
new SKFontStyle(500, 5, SKFontStyleSlant.Oblique),
new SKFontStyle(500, 5, SKFontStyleSlant.Italic)
);
var styles = new[]
{
new SKFontStyle(500, 5, Upright),
new SKFontStyle(500, 5, Oblique),
new SKFontStyle(500, 5, Italic)
};
ExpectComparisonOrder(new SKFontStyle(500, 5, Upright), styles);
}
[Test]
public void FontStyleSet_IsBetterMatch_ThinWeight()
{
ExpectComparisonOrder(
new SKFontStyle(300, 5, SKFontStyleSlant.Upright),
new SKFontStyle(300, 5, SKFontStyleSlant.Upright),
new SKFontStyle(200, 5, SKFontStyleSlant.Upright),
new SKFontStyle(100, 5, SKFontStyleSlant.Upright),
new SKFontStyle(400, 5, SKFontStyleSlant.Upright)
);
var styles = new[]
{
new SKFontStyle(300, 5, Upright),
new SKFontStyle(200, 5, Upright),
new SKFontStyle(100, 5, Upright),
new SKFontStyle(400, 5, Upright)
};
ExpectComparisonOrder(new SKFontStyle(300, 5, Upright), styles);
}
[Test]
public void FontStyleSet_IsBetterMatch_RegularWeight()
{
ExpectComparisonOrder(
new SKFontStyle(400, 5, SKFontStyleSlant.Upright),
new SKFontStyle(500, 5, SKFontStyleSlant.Upright),
new SKFontStyle(300, 5, SKFontStyleSlant.Upright),
new SKFontStyle(100, 5, SKFontStyleSlant.Upright),
new SKFontStyle(600, 5, SKFontStyleSlant.Upright)
);
var styles = new[]
{
new SKFontStyle(500, 5, Upright),
new SKFontStyle(300, 5, Upright),
new SKFontStyle(100, 5, Upright),
new SKFontStyle(600, 5, Upright)
};
ExpectComparisonOrder(new SKFontStyle(400, 5, Upright), styles);
}
[Test]
public void FontStyleSet_IsBetterMatch_BoldWeight()
{
ExpectComparisonOrder(
new SKFontStyle(600, 5, SKFontStyleSlant.Upright),
new SKFontStyle(600, 5, SKFontStyleSlant.Upright),
new SKFontStyle(700, 5, SKFontStyleSlant.Upright),
new SKFontStyle(800, 5, SKFontStyleSlant.Upright),
new SKFontStyle(500, 5, SKFontStyleSlant.Upright)
);
var styles = new[]
{
new SKFontStyle(600, 5, Upright),
new SKFontStyle(700, 5, Upright),
new SKFontStyle(800, 5, Upright),
new SKFontStyle(500, 5, Upright)
};
ExpectComparisonOrder(new SKFontStyle(600, 5, Upright), styles);
}
[Test]
public void FontStyleSet_RespectsPriority()
{
ExpectComparisonOrder(
new SKFontStyle(500, 5, SKFontStyleSlant.Upright),
new SKFontStyle(600, 5, SKFontStyleSlant.Italic),
new SKFontStyle(600, 6, SKFontStyleSlant.Upright),
new SKFontStyle(500, 6, SKFontStyleSlant.Italic)
);
var styles = new[]
{
new SKFontStyle(600, 5, Italic),
new SKFontStyle(600, 6, Upright),
new SKFontStyle(500, 6, Italic)
};
ExpectComparisonOrder(new SKFontStyle(500, 5, Upright), styles);
}
}
}

Просмотреть файл

@ -10,8 +10,8 @@ namespace QuestPDF.Drawing
public static class FontManager
{
private static ConcurrentDictionary<string, FontStyleSet> StyleSets = new();
private static ConcurrentDictionary<string, SKFontMetrics> FontMetrics = new();
private static ConcurrentDictionary<string, SKPaint> Paints = new();
private static ConcurrentDictionary<object, SKFontMetrics> FontMetrics = new();
private static ConcurrentDictionary<object, SKPaint> Paints = new();
private static ConcurrentDictionary<string, SKPaint> ColorPaint = new();
private static void RegisterFontType(SKData fontData, string? customName = null)
@ -59,7 +59,7 @@ namespace QuestPDF.Drawing
internal static SKPaint ToPaint(this TextStyle style)
{
return Paints.GetOrAdd(style.Key, key => Convert(style));
return Paints.GetOrAdd(style.PaintKey, key => Convert(style));
static SKPaint Convert(TextStyle style)
{
@ -67,8 +67,7 @@ namespace QuestPDF.Drawing
{
Color = SKColor.Parse(style.Color),
Typeface = GetTypeface(style),
TextSize = style.Size ?? 12,
TextEncoding = SKTextEncoding.Utf32
TextSize = style.Size ?? 12
};
}
@ -77,19 +76,27 @@ namespace QuestPDF.Drawing
var weight = (SKFontStyleWeight)(style.FontWeight ?? FontWeight.Normal);
var slant = (style.IsItalic ?? false) ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright;
var skFontStyle = new SKFontStyle(weight, SKFontStyleWidth.Normal, slant);
var fontStyle = new SKFontStyle(weight, SKFontStyleWidth.Normal, slant);
if (StyleSets.TryGetValue(style.FontType, out var set))
return set.Match(skFontStyle);
if (StyleSets.TryGetValue(style.FontType, out var fontStyleSet))
return fontStyleSet.Match(fontStyle);
return SKTypeface.FromFamilyName(style.FontType, skFontStyle)
?? throw new ArgumentException($"The typeface {style.FontType} could not be found. Please consider installing the font file on your system or loading it from a file using the FontManager.RegisterFontType() static method.");
var fontFromDefaultSource = SKFontManager.Default.MatchFamily(style.FontType, fontStyle);
if (fontFromDefaultSource != null)
return fontFromDefaultSource;
throw new ArgumentException(
$"The typeface '{style.FontType}' could not be found. " +
$"Please consider the following options: " +
$"1) install the font on your operating system or execution environment. " +
$"2) load a font file specifically for QuestPDF usage via the QuestPDF.Drawing.FontManager.RegisterFontType(Stream fileContentStream) static method.");
}
}
internal static SKFontMetrics ToFontMetrics(this TextStyle style)
{
return FontMetrics.GetOrAdd(style.Key, key => style.ToPaint().FontMetrics);
return FontMetrics.GetOrAdd(style.FontMetricsKey, key => style.ToPaint().FontMetrics);
}
}
}

Просмотреть файл

@ -17,7 +17,8 @@ namespace QuestPDF.Infrastructure
internal bool? HasStrikethrough { get; set; }
internal bool? HasUnderline { get; set; }
internal string? Key { get; private set; }
internal object PaintKey { get; private set; }
internal object FontMetricsKey { get; private set; }
internal static TextStyle LibraryDefault => new TextStyle
{
@ -42,7 +43,8 @@ namespace QuestPDF.Infrastructure
HasGlobalStyleApplied = true;
ApplyParentStyle(globalStyle);
Key ??= $"{Color}|{BackgroundColor}|{FontType}|{Size}|{LineHeight}|{FontWeight}|{IsItalic}|{HasStrikethrough}|{HasUnderline}";
PaintKey ??= (FontType, Size, FontWeight, IsItalic, Color);
FontMetricsKey ??= (FontType, Size, FontWeight, IsItalic);
}
internal void ApplyParentStyle(TextStyle parentStyle)