using System.Security.Cryptography;
using System.Text.Json;
using AngleSharp.Dom;
using AngleSharp.Html.Parser;
using XFESystem.Browser;
using XFESystem.Platform;
namespace XFESystem.Platform.Tests;
public sealed class ArialFallbackTests
{
[Theory]
[InlineData("Arial", 400, "Liberation Sans")]
[InlineData("Helvetica, sans-serif", 700, "Liberation Sans Bold")]
[InlineData("'Unavailable Font', 'Arial', monospace", 400, "Liberation Sans")]
[InlineData("Consolas, Arial", 400, "Cascadia Mono")]
[InlineData("system-ui, Arial", 400, "Lato")]
[InlineData("sans-serif", 700, "Lato Bold")]
public void SelectsTheFirstSupportedFamilyWithoutRenamingBundledFonts(string family, int weight, string expected)
{
var fonts = PlatformFonts.CreateBundled();
Assert.Equal(expected, fonts.DescribeFace(family, weight));
Assert.Equal(expected, fonts.CreateIndependent().DescribeFace(family, weight));
}
[Theory]
[InlineData("Arial")]
[InlineData("Helvetica, sans-serif")]
public void NarrowResultWithTranslationKeepsTheCitationAboveItsTitle(string family)
{
var page = new HtmlParser().ParseDocument("<style>body{margin:0}#outer{width:416px;display:flex}#link{display:flex;padding-bottom:8px}#icon{width:28px;height:28px;margin-right:8px}.site{font:14px/18px " + family + "}.meta,.attribution{display:flex}.attribution{height:20px;font:16px/22px " + family + "}cite{font:14px/22px " + family + "}strong{font-weight:normal}span{margin-top:1px;margin-left:8px;position:relative}h2{margin:0}</style>" +
"<div id=outer><a id=link><div id=icon></div><div class=site><div>Site</div><div class=meta><div class=attribution><cite id=url>https://dot<strong>net</strong>.<strong>microsoft</strong>.com › en-us › <strong>download</strong></cite><span>翻译此结果</span></div></div></div></a></div><h2 id=title>Result title</h2>");
var list = new BrowserLayoutEngine().Layout(page, new(500, 200), textMetrics: new Metrics());
var runs = list.Commands.Where(c => c.Kind == BrowserDrawKind.Text && c.Node?.ParentElement?.Closest("cite") is not null).ToArray();
Assert.NotEmpty(runs);
Assert.Single(runs.Select(c => c.Bounds.Y).Distinct());
Assert.True(runs.Max(c => c.Bounds.Bottom) <= list.GetBoundingClientRect(page.GetElementById("title")!).Top);
Assert.InRange(list.GetBoundingClientRect(page.GetElementById("url")!).Width, 291.7, 292);
Assert.True(list.GetBoundingClientRect(page.GetElementById("link")!).Right <= 416.000001);
}
[Fact]
public void EmbeddedFacesAndFullLicenseMatchThePinnedDistribution()
{
var root = new DirectoryInfo(AppContext.BaseDirectory);
while (root is not null && !Directory.Exists(Path.Combine(root.FullName, "assets", "fonts", "liberation-sans-2.1.5"))) root = root.Parent;
Assert.NotNull(root);
string path = Path.Combine(root.FullName, "assets", "fonts", "liberation-sans-2.1.5");
using var manifest = JsonDocument.Parse(File.ReadAllBytes(Path.Combine(path, "Manifest.json")));
Assert.Equal("35ffaa54f117e633e89a5da89af235a073b34dbe582726fbf6989568f7fd9bda", manifest.RootElement.GetProperty("BinaryPackageSha256").GetString());
foreach (var file in manifest.RootElement.GetProperty("Files").EnumerateArray())
Assert.Equal(file.GetProperty("Sha256").GetString(), Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(Path.Combine(path, file.GetProperty("Path").GetString()!)))));
foreach (var pair in new[] { ("LiberationSans.ttf", "LiberationSans-Regular.ttf"), ("LiberationSansBold.ttf", "LiberationSans-Bold.ttf") })
{
using var stream = typeof(PlatformFonts).Assembly.GetManifestResourceStream("PlatformFonts/" + pair.Item1);
Assert.NotNull(stream);
Assert.Equal(SHA256.HashData(File.ReadAllBytes(Path.Combine(path, pair.Item2))), SHA256.HashData(stream));
}
string license = File.ReadAllText(Path.Combine(path, "OFL.txt"));
Assert.Contains("Copyright (c) 2012 Red Hat, Inc.", license);
Assert.Contains("SIL OPEN FONT LICENSE Version 1.1", license);
}
private sealed class Metrics : IBrowserTextMetrics
{
private readonly PlatformFonts fonts = PlatformFonts.CreateBundled();
public double Measure(string text, BrowserFont font) => fonts.Measure(text, font.Size, font.Family, font.Weight);
}
}
using System.Security.Cryptography;
using System.Text.Json;
using AngleSharp.Dom;
using AngleSharp.Html.Parser;
using XFESystem.Browser;
using XFESystem.Platform;
namespace XFESystem.Platform.Tests;
public sealed class ArialFallbackTests
{
[Theory]
[InlineData("Arial", 400, "Liberation Sans")]
[InlineData("Helvetica, sans-serif", 700, "Liberation Sans Bold")]
[InlineData("'Unavailable Font', 'Arial', monospace", 400, "Liberation Sans")]
[InlineData("Consolas, Arial", 400, "Cascadia Mono")]
[InlineData("system-ui, Arial", 400, "Lato")]
[InlineData("sans-serif", 700, "Lato Bold")]
public void SelectsTheFirstSupportedFamilyWithoutRenamingBundledFonts(string family, int weight, string expected)
{
var fonts = PlatformFonts.CreateBundled();
Assert.Equal(expected, fonts.DescribeFace(family, weight));
Assert.Equal(expected, fonts.CreateIndependent().DescribeFace(family, weight));
}
[Theory]
[InlineData("Arial")]
[InlineData("Helvetica, sans-serif")]
public void NarrowResultWithTranslationKeepsTheCitationAboveItsTitle(string family)
{
var page = new HtmlParser().ParseDocument("<style>body{margin:0}#outer{width:416px;display:flex}#link{display:flex;padding-bottom:8px}#icon{width:28px;height:28px;margin-right:8px}.site{font:14px/18px " + family + "}.meta,.attribution{display:flex}.attribution{height:20px;font:16px/22px " + family + "}cite{font:14px/22px " + family + "}strong{font-weight:normal}span{margin-top:1px;margin-left:8px;position:relative}h2{margin:0}</style>" +
"<div id=outer><a id=link><div id=icon></div><div class=site><div>Site</div><div class=meta><div class=attribution><cite id=url>https://dot<strong>net</strong>.<strong>microsoft</strong>.com › en-us › <strong>download</strong></cite><span>翻译此结果</span></div></div></div></a></div><h2 id=title>Result title</h2>");
var list = new BrowserLayoutEngine().Layout(page, new(500, 200), textMetrics: new Metrics());
var runs = list.Commands.Where(c => c.Kind == BrowserDrawKind.Text && c.Node?.ParentElement?.Closest("cite") is not null).ToArray();
Assert.NotEmpty(runs);
Assert.Single(runs.Select(c => c.Bounds.Y).Distinct());
Assert.True(runs.Max(c => c.Bounds.Bottom) <= list.GetBoundingClientRect(page.GetElementById("title")!).Top);
Assert.InRange(list.GetBoundingClientRect(page.GetElementById("url")!).Width, 291.7, 292);
Assert.True(list.GetBoundingClientRect(page.GetElementById("link")!).Right <= 416.000001);
}
[Fact]
public void EmbeddedFacesAndFullLicenseMatchThePinnedDistribution()
{
var root = new DirectoryInfo(AppContext.BaseDirectory);
while (root is not null && !Directory.Exists(Path.Combine(root.FullName, "assets", "fonts", "liberation-sans-2.1.5"))) root = root.Parent;
Assert.NotNull(root);
string path = Path.Combine(root.FullName, "assets", "fonts", "liberation-sans-2.1.5");
using var manifest = JsonDocument.Parse(File.ReadAllBytes(Path.Combine(path, "Manifest.json")));
Assert.Equal("35ffaa54f117e633e89a5da89af235a073b34dbe582726fbf6989568f7fd9bda", manifest.RootElement.GetProperty("BinaryPackageSha256").GetString());
foreach (var file in manifest.RootElement.GetProperty("Files").EnumerateArray())
Assert.Equal(file.GetProperty("Sha256").GetString(), Convert.ToHexStringLower(SHA256.HashData(File.ReadAllBytes(Path.Combine(path, file.GetProperty("Path").GetString()!)))));
foreach (var pair in new[] { ("LiberationSans.ttf", "LiberationSans-Regular.ttf"), ("LiberationSansBold.ttf", "LiberationSans-Bold.ttf") })
{
using var stream = typeof(PlatformFonts).Assembly.GetManifestResourceStream("PlatformFonts/" + pair.Item1);
Assert.NotNull(stream);
Assert.Equal(SHA256.HashData(File.ReadAllBytes(Path.Combine(path, pair.Item2))), SHA256.HashData(stream));
}
string license = File.ReadAllText(Path.Combine(path, "OFL.txt"));
Assert.Contains("Copyright (c) 2012 Red Hat, Inc.", license);
Assert.Contains("SIL OPEN FONT LICENSE Version 1.1", license);
}
private sealed class Metrics : IBrowserTextMetrics
{
private readonly PlatformFonts fonts = PlatformFonts.CreateBundled();
public double Measure(string text, BrowserFont font) => fonts.Measure(text, font.Size, font.Family, font.Weight);
}
}