diff --git a/font/ptserif/OFL.txt b/font/ptserif/OFL.txt
new file mode 100644
index 000000000..3f70bfe03
--- /dev/null
+++ b/font/ptserif/OFL.txt
@@ -0,0 +1,94 @@
+Copyright (c) 2010, ParaType Ltd. (http://www.paratype.com/public),
+with Reserved Font Names "PT Sans", "PT Serif" and "ParaType".
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+http://scripts.sil.org/OFL
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/font/ptserif/PTSerif-Bold.ttf b/font/ptserif/PTSerif-Bold.ttf
new file mode 100644
index 000000000..b95573250
Binary files /dev/null and b/font/ptserif/PTSerif-Bold.ttf differ
diff --git a/font/ptserif/PTSerif-BoldItalic.ttf b/font/ptserif/PTSerif-BoldItalic.ttf
new file mode 100644
index 000000000..e933f845e
Binary files /dev/null and b/font/ptserif/PTSerif-BoldItalic.ttf differ
diff --git a/font/ptserif/PTSerif-Italic.ttf b/font/ptserif/PTSerif-Italic.ttf
new file mode 100644
index 000000000..e53ac86f5
Binary files /dev/null and b/font/ptserif/PTSerif-Italic.ttf differ
diff --git a/font/ptserif/PTSerif-Regular.ttf b/font/ptserif/PTSerif-Regular.ttf
new file mode 100644
index 000000000..24af47855
Binary files /dev/null and b/font/ptserif/PTSerif-Regular.ttf differ
diff --git a/font/roboto/LICENSE.txt b/font/roboto/LICENSE.txt
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/font/roboto/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/font/roboto/Roboto-Bold.ttf b/font/roboto/Roboto-Bold.ttf
new file mode 100644
index 000000000..d998cf5b4
Binary files /dev/null and b/font/roboto/Roboto-Bold.ttf differ
diff --git a/font/roboto/Roboto-BoldItalic.ttf b/font/roboto/Roboto-BoldItalic.ttf
new file mode 100644
index 000000000..b4e221039
Binary files /dev/null and b/font/roboto/Roboto-BoldItalic.ttf differ
diff --git a/font/roboto/Roboto-Italic.ttf b/font/roboto/Roboto-Italic.ttf
new file mode 100644
index 000000000..5b390ff95
Binary files /dev/null and b/font/roboto/Roboto-Italic.ttf differ
diff --git a/font/roboto/Roboto-Regular.ttf b/font/roboto/Roboto-Regular.ttf
new file mode 100644
index 000000000..2b6392ffe
Binary files /dev/null and b/font/roboto/Roboto-Regular.ttf differ
diff --git a/package-lock.json b/package-lock.json
index 2a993ec9a..4495c5159 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -102,6 +102,12 @@
}
}
},
+ "@types/css-font-loading-module": {
+ "version": "0.0.4",
+ "resolved": "https://registry.npmjs.org/@types/css-font-loading-module/-/css-font-loading-module-0.0.4.tgz",
+ "integrity": "sha512-ENdXf7MW4m9HeDojB2Ukbi7lYMIuQNBHVf98dbzaiG4EEJREBd6oleVAjrLRCrp7dm6CK1mmdmU9tcgF61acbw==",
+ "dev": true
+ },
"@types/estree": {
"version": "0.0.39",
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
diff --git a/package.json b/package.json
index b27bcd995..663713e17 100644
--- a/package.json
+++ b/package.json
@@ -47,6 +47,7 @@
},
"devDependencies": {
"@rollup/plugin-commonjs": "^17.0.0",
+ "@types/css-font-loading-module": "0.0.4",
"@types/jasmine": "^3.6.2",
"@types/resize-observer-browser": "^0.1.5",
"concurrently": "^5.3.0",
diff --git a/src.compiler/csharp/CSharpAstTransformer.ts b/src.compiler/csharp/CSharpAstTransformer.ts
index 0488936a0..524c154f2 100644
--- a/src.compiler/csharp/CSharpAstTransformer.ts
+++ b/src.compiler/csharp/CSharpAstTransformer.ts
@@ -1420,7 +1420,7 @@ export default class CSharpAstTransformer {
nodeType: cs.SyntaxKind.TypeReference,
parent: variableStatement,
tsNode: s,
- reference: this._context.makeTypeName('alphaTab.core.ecmaScript.Error')
+ reference: this._context.makeTypeName('system.Exception')
} as cs.TypeReference;
} else {
variableStatement.type = this.createUnresolvedTypeNode(variableStatement, s.type ?? s, type);
diff --git a/src.csharp/AlphaTab.Test/AlphaTab.Test.csproj b/src.csharp/AlphaTab.Test/AlphaTab.Test.csproj
index 74b41307b..589def3c9 100644
--- a/src.csharp/AlphaTab.Test/AlphaTab.Test.csproj
+++ b/src.csharp/AlphaTab.Test/AlphaTab.Test.csproj
@@ -25,6 +25,10 @@
test-data\%(RecursiveDir)\%(Filename)%(Extension)
PreserveNewest
+
+ font\%(RecursiveDir)\%(Filename)%(Extension)
+ PreserveNewest
+
diff --git a/src.csharp/AlphaTab.Test/VisualTests/VisualTestHelper.cs b/src.csharp/AlphaTab.Test/VisualTests/VisualTestHelper.cs
index b784de8e3..267ba0b5b 100644
--- a/src.csharp/AlphaTab.Test/VisualTests/VisualTestHelper.cs
+++ b/src.csharp/AlphaTab.Test/VisualTests/VisualTestHelper.cs
@@ -6,6 +6,7 @@
using AlphaTab.Importer;
using AlphaTab.Io;
using AlphaTab.Model;
+using AlphaTab.Platform.CSharp;
using AlphaTab.Rendering;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using SkiaSharp;
@@ -15,7 +16,7 @@ namespace AlphaTab.VisualTests
partial class VisualTestHelper
{
public static async Task RunVisualTest(string inputFile, Settings? settings = null,
- IList? tracks = null, string? message = null, int tolerancePercent = 1)
+ IList? tracks = null, string? message = null, double tolerancePercent = 1)
{
try
{
@@ -57,7 +58,7 @@ await RunVisualTestScore(score, referenceFileName, settings,
public static async Task RunVisualTestScore(Score score, string referenceFileName,
Settings? settings = null,
- IList? tracks = null, string? message = null, int tolerancePercent = 1)
+ IList? tracks = null, string? message = null, double tolerancePercent = 1)
{
settings ??= new Settings();
tracks ??= new Core.List {0};
@@ -66,6 +67,20 @@ public static async Task RunVisualTestScore(Score score, string referenceFileNam
settings.Core.EnableLazyLoading = false;
settings.Core.UseWorkers = false;
+ settings.Display.Resources.CopyrightFont.Family = "Roboto";
+ settings.Display.Resources.TitleFont.Family = "PT Serif";
+ settings.Display.Resources.SubTitleFont.Family = "PT Serif";
+ settings.Display.Resources.WordsFont.Family = "PT Serif";
+ settings.Display.Resources.EffectFont.Family = "PT Serif";
+ settings.Display.Resources.FretboardNumberFont.Family = "Roboto";
+ settings.Display.Resources.TablatureFont.Family = "Roboto";
+ settings.Display.Resources.GraceFont.Family = "Roboto";
+ settings.Display.Resources.BarNumberFont.Family = "Roboto";
+ settings.Display.Resources.FingeringFont.Family = "PT Serif";
+ settings.Display.Resources.MarkerFont.Family = "PT Serif";
+
+ LoadFonts();
+
if (!referenceFileName.StartsWith("test-data/"))
{
referenceFileName = $"test-data/visual-tests/{referenceFileName}";
@@ -122,9 +137,36 @@ public static async Task RunVisualTestScore(Score score, string referenceFileNam
}
}
+ private static bool _fontsLoaded;
+ private static void LoadFonts()
+ {
+ if (_fontsLoaded)
+ {
+ return;
+ }
+
+ _fontsLoaded = true;
+ var fonts = new[]
+ {
+ "font/roboto/Roboto-Regular.ttf",
+ "font/roboto/Roboto-Italic.ttf",
+ "font/roboto/Roboto-Bold.ttf",
+ "font/roboto/Roboto-BoldItalic.ttf",
+ "font/ptserif/PTSerif-Regular.ttf",
+ "font/ptserif/PTSerif-Italic.ttf",
+ "font/ptserif/PTSerif-Bold.ttf",
+ "font/ptserif/PTSerif-BoldItalic.ttf"
+ };
+ foreach (var font in fonts)
+ {
+ var data = File.ReadAllBytes(font);
+ SkiaCanvas.RegisterCustomFont(data);
+ }
+ }
+
private static void CompareVisualResult(double totalWidth, double totalHeight,
AlphaTab.Core.List result, string referenceFileName,
- Uint8Array referenceFileData, string? message, int tolerancePercent = 1)
+ Uint8Array referenceFileData, string? message, double tolerancePercent = 1)
{
SKBitmap finalBitmap;
diff --git a/src.csharp/AlphaTab/Platform/CSharp/GdiCanvas.cs b/src.csharp/AlphaTab/Platform/CSharp/GdiCanvas.cs
index 47412b162..7dd99a156 100644
--- a/src.csharp/AlphaTab/Platform/CSharp/GdiCanvas.cs
+++ b/src.csharp/AlphaTab/Platform/CSharp/GdiCanvas.cs
@@ -19,9 +19,32 @@ internal sealed class GdiCanvas : ICanvas
{
private static readonly Graphics MeasurementGraphics;
private static readonly PrivateFontCollection MusicFontCollection;
+ private static readonly PrivateFontCollection CustomFontCollection = new PrivateFontCollection();
+ private static readonly IDictionary CustomFontFamilies =
+ new Dictionary(StringComparer.OrdinalIgnoreCase);
private static readonly StringFormat MusicFontFormat;
private static readonly StringFormat MusicFontFormatCenter;
+ public static void RegisterCustomFont(byte[] data)
+ {
+ var dataPtr = Marshal.AllocCoTaskMem(data.Length);
+ try
+ {
+ Marshal.Copy(data, 0, dataPtr, data.Length);
+ CustomFontCollection.AddMemoryFont(dataPtr, data.Length);
+
+ CustomFontFamilies.Clear();
+ foreach (var family in CustomFontCollection.Families)
+ {
+ CustomFontFamilies[family.Name] = family;
+ }
+ }
+ finally
+ {
+ Marshal.FreeCoTaskMem(dataPtr);
+ }
+ }
+
static GdiCanvas()
{
var measurementImage = new Bitmap(1, 1);
@@ -136,7 +159,7 @@ public Model.Font Font
{
var fw = _font.Bold ? Model.FontWeight.Bold : Model.FontWeight.Regular;
var fs = _font.Italic ? Model.FontStyle.Italic : Model.FontStyle.Plain;
-
+
return new Model.Font(_font.FontFamily.Name, _font.Size * Settings.Display.Scale,
fs, fw);
}
@@ -153,9 +176,19 @@ public Model.Font Font
fontStyle = GdiFontStyle.Italic;
}
- _font = new GdiFont(value.Family, (float) (value.Size * Settings.Display.Scale),
- fontStyle,
- GraphicsUnit.Pixel);
+ if (CustomFontFamilies.TryGetValue(value.Family, out var gdiFamily))
+ {
+ _font = new GdiFont(gdiFamily, (float) (value.Size * Settings.Display.Scale),
+ fontStyle,
+ GraphicsUnit.Pixel);
+
+ }
+ else
+ {
+ _font = new GdiFont(value.Family, (float) (value.Size * Settings.Display.Scale),
+ fontStyle,
+ GraphicsUnit.Pixel);
+ }
}
}
@@ -348,7 +381,7 @@ public void FillCircle(double x, double y, double radius)
_currentY = y;
Fill();
}
-
+
public void StrokeCircle(double x, double y, double radius)
{
_currentPath.StartFigure();
diff --git a/src.csharp/AlphaTab/Platform/CSharp/SkiaCanvas.cs b/src.csharp/AlphaTab/Platform/CSharp/SkiaCanvas.cs
index 62cba500d..81da4619b 100644
--- a/src.csharp/AlphaTab/Platform/CSharp/SkiaCanvas.cs
+++ b/src.csharp/AlphaTab/Platform/CSharp/SkiaCanvas.cs
@@ -3,6 +3,7 @@
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
+using System.Runtime.ExceptionServices;
using System.Runtime.InteropServices;
using AlphaTab.Model;
using HarfBuzzSharp;
@@ -62,9 +63,30 @@ static SkiaCanvas()
MusicFont = SKTypeface.FromStream(bravura);
}
+ private static readonly IDictionary CustomTypeFaces =
+ new Dictionary(StringComparer.OrdinalIgnoreCase);
+ public static void RegisterCustomFont(byte[] data)
+ {
+ using var skData = SKData.CreateCopy(data);
+ var face = SKTypeface.FromData(skData);
+ CustomTypeFaces[CustomTypeFaceKey(face)] = face;
+ }
+
+ private static string CustomTypeFaceKey(SKTypeface typeface)
+ {
+ return CustomTypeFaceKey(typeface.FamilyName, typeface.FontWeight > 400,
+ typeface.FontSlant == SKFontStyleSlant.Italic);
+ }
+
+ private static string CustomTypeFaceKey(string fontFamily, bool isBold, bool isItalic)
+ {
+ return fontFamily.ToLowerInvariant() + "_" + isBold + "_" + isItalic;
+ }
+
private SKSurface? _surface;
private SKPath? _path;
private string _typeFaceCache = "";
+ private bool _typeFaceIsSystem = false;
private SKTypeface? _typeFace;
public Color Color { get; set; }
@@ -77,14 +99,26 @@ private SKTypeface TypeFace
{
if (_typeFaceCache != Font.ToCssString(Settings.Display.Scale))
{
- _typeFace?.Dispose();
-
+ if (_typeFaceIsSystem)
+ {
+ _typeFace?.Dispose();
+ }
_typeFaceCache = Font.ToCssString(Settings.Display.Scale);
- _typeFace = SKTypeface.FromFamilyName(Font.Family,
- Font.IsBold ? SKFontStyleWeight.Bold : SKFontStyleWeight.Normal,
- SKFontStyleWidth.Normal,
- Font.IsItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright
- );
+
+ var key = CustomTypeFaceKey(Font.Family, Font.IsBold, Font.IsItalic);
+ if (!CustomTypeFaces.TryGetValue(key, out _typeFace))
+ {
+ _typeFaceIsSystem = true;
+ _typeFace = SKTypeface.FromFamilyName(Font.Family,
+ Font.IsBold ? SKFontStyleWeight.Bold : SKFontStyleWeight.Normal,
+ SKFontStyleWidth.Normal,
+ Font.IsItalic ? SKFontStyleSlant.Italic : SKFontStyleSlant.Upright
+ );
+ }
+ else
+ {
+ _typeFaceIsSystem = false;
+ }
}
return _typeFace;
@@ -247,26 +281,34 @@ public void EndGroup()
private const int SkiaToHarfBuzzFontSize = 1 << 16;
private const float HarfBuzzToSkiaFontSize = 1f / SkiaToHarfBuzzFontSize;
+ [HandleProcessCorruptedStateExceptions]
private static HarfBuzzSharp.Font MakeHarfBuzzFont(SKTypeface typeface, int size)
{
- using var stream = typeface.OpenStream(out var ttcIndex);
- var data = Marshal.AllocCoTaskMem(stream.Length);
- stream.Read(data, stream.Length);
- using var blob = new Blob(data, stream.Length, MemoryMode.ReadOnly,
- () => { Marshal.FreeCoTaskMem(data); });
- blob.MakeImmutable();
-
- using var face = new Face(blob, ttcIndex)
+ try
{
- Index = ttcIndex,
- UnitsPerEm = typeface.UnitsPerEm
- };
-
- var font = new HarfBuzzSharp.Font(face);
- var scale = size * SkiaToHarfBuzzFontSize;
- font.SetScale(scale, scale);
- font.SetFunctionsOpenType();
- return font;
+ using var stream = typeface.OpenStream(out var ttcIndex);
+ var data = Marshal.AllocCoTaskMem(stream.Length);
+ stream.Read(data, stream.Length);
+ using var blob = new Blob(data, stream.Length, MemoryMode.ReadOnly,
+ () => { Marshal.FreeCoTaskMem(data); });
+ blob.MakeImmutable();
+
+ using var face = new Face(blob, ttcIndex)
+ {
+ Index = ttcIndex,
+ UnitsPerEm = typeface.UnitsPerEm
+ };
+
+ var font = new HarfBuzzSharp.Font(face);
+ var scale = size * SkiaToHarfBuzzFontSize;
+ font.SetScale(scale, scale);
+ font.SetFunctionsOpenType();
+ return font;
+ }
+ catch (AccessViolationException e)
+ {
+ throw;
+ }
}
diff --git a/src.kotlin/alphaTab/src/commonMain/kotlin/system/Exception.kt b/src.kotlin/alphaTab/src/commonMain/kotlin/system/Exception.kt
new file mode 100644
index 000000000..194d127fa
--- /dev/null
+++ b/src.kotlin/alphaTab/src/commonMain/kotlin/system/Exception.kt
@@ -0,0 +1,3 @@
+package system
+
+typealias Exception = kotlin.Throwable
diff --git a/src.kotlin/alphaTab/src/jvmMain/kotlin/alphaTab/platform/jvm/SkiaCanvas.kt b/src.kotlin/alphaTab/src/jvmMain/kotlin/alphaTab/platform/jvm/SkiaCanvas.kt
index 0f9851bb6..b1ecf2384 100644
--- a/src.kotlin/alphaTab/src/jvmMain/kotlin/alphaTab/platform/jvm/SkiaCanvas.kt
+++ b/src.kotlin/alphaTab/src/jvmMain/kotlin/alphaTab/platform/jvm/SkiaCanvas.kt
@@ -9,14 +9,12 @@ import alphaTab.platform.ICanvas
import alphaTab.platform.TextAlign
import alphaTab.platform.TextBaseline
import org.jetbrains.skija.*
-import org.jetbrains.skija.shaper.RunHandler
-import org.jetbrains.skija.shaper.RunInfo
import org.jetbrains.skija.shaper.Shaper
-import org.jetbrains.skija.shaper.TextBlobBuilderRunHandler
import java.lang.IllegalStateException
import kotlin.contracts.ExperimentalContracts
import kotlin.math.floor
+
@ExperimentalUnsignedTypes
@ExperimentalContracts
val bravuraTtf = SkiaCanvas::class.java.getResource("/bravura/Bravura.ttf").readBytes()
@@ -28,14 +26,40 @@ const val MusicFontSize = 34
const val HangingAsPercentOfAscent = 80
+val CustomTypeFaces = HashMap();
+
// https://github.com/chromium/chromium/blob/99314be8152e688bafbbf9a615536bdbb289ea87/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
@ExperimentalUnsignedTypes
@ExperimentalContracts
-class SkiaCanvas : ICanvas {
+public class SkiaCanvas : ICanvas {
+ companion object {
+ public fun registerCustomFont(data: UByteArray) {
+ val skData = Data.makeFromBytes(data.asByteArray())
+ skData.use {
+ val face = Typeface.makeFromData(skData)
+ CustomTypeFaces[customTypeFaceKey(face)] = face;
+ }
+ }
+
+ private fun customTypeFaceKey(typeface: Typeface): String {
+ return customTypeFaceKey(typeface.familyName, typeface.isBold, typeface.isItalic)
+ }
+
+ private fun customTypeFaceKey(
+ fontFamily: String,
+ isBold: Boolean,
+ isItalic: Boolean
+ ): String {
+ return fontFamily.toLowerCase() + "_" + isBold + "_" + isItalic;
+ }
+
+ }
+
private lateinit var _surface: Surface
private var _path: Path? = null
private var _typeFaceCache: String = ""
+ private var _typeFaceIsSystem: Boolean = false
private var _typeFace: Typeface? = null
public override var color: Color = Color(255.0, 255.0, 255.0)
@@ -44,16 +68,28 @@ class SkiaCanvas : ICanvas {
private val typeFace: Typeface
get() {
if (_typeFaceCache != font.toCssString(settings.display.scale)) {
- _typeFace?.close()
+ if (_typeFaceIsSystem) {
+ _typeFace?.close()
+ }
_typeFaceCache = font.toCssString(settings.display.scale)
- _typeFace = Typeface.makeFromName(
- font.family,
- FontStyle(
- if (font.isBold) FontStyle.BOLD.weight else FontStyle.NORMAL.weight,
- FontStyle.NORMAL.width,
- if (font.isItalic) FontStyle.ITALIC.slant else FontStyle.NORMAL.slant
+
+ val key = customTypeFaceKey(font.family, font.isBold, font.isItalic)
+ if(!CustomTypeFaces.containsKey(key)) {
+ _typeFaceIsSystem = true
+ _typeFace = Typeface.makeFromName(
+ font.family,
+ FontStyle(
+ if (font.isBold) FontStyle.BOLD.weight else FontStyle.NORMAL.weight,
+ FontStyle.NORMAL.width,
+ if (font.isItalic) FontStyle.ITALIC.slant else FontStyle.NORMAL.slant
+ )
)
- )
+ }
+ else {
+ _typeFaceIsSystem = false
+ _typeFace = CustomTypeFaces[key]!!
+ }
+
}
return _typeFace!!
}
@@ -232,7 +268,7 @@ class SkiaCanvas : ICanvas {
private fun textRun(
text: String,
typeFace: Typeface,
- size:Double,
+ size: Double,
action: (blob: TextBlob, font: org.jetbrains.skija.Font, paint: Paint) -> Unit
) {
val paint = createPaint()
@@ -248,7 +284,7 @@ class SkiaCanvas : ICanvas {
val metrics = font.metrics
// SkShaper seems to add a negative ascent to the Y-position, we have to correct this
// https://source.chromium.org/chromium/chromium/src/+/master:third_party/skia/modules/skshaper/src/SkShaper.cpp;l=206;drc=c21c001893e2dd8229ab321465e4408798ff7289;bpv=1;bpt=1
- val yMetricsOffset = - metrics.ascent
+ val yMetricsOffset = -metrics.ascent
font.use {
val blob = shaper.shape(
text, font
@@ -257,7 +293,7 @@ class SkiaCanvas : ICanvas {
val blobBuilder = TextBlobBuilder()
val pos = arrayListOf()
- for(i in blob.glyphs.indices) {
+ for (i in blob.glyphs.indices) {
val xOffset = blob.positions[i * 2]
val yOffset = blob.positions[(i * 2) + 1] - yMetricsOffset
pos.add(Point(xOffset, yOffset))
diff --git a/src.kotlin/alphaTab/src/jvmTest/kotlin/alphaTab/visualTests/VisualTestHelperPartials.kt b/src.kotlin/alphaTab/src/jvmTest/kotlin/alphaTab/visualTests/VisualTestHelperPartials.kt
index 5b7a2591c..a06ba17be 100644
--- a/src.kotlin/alphaTab/src/jvmTest/kotlin/alphaTab/visualTests/VisualTestHelperPartials.kt
+++ b/src.kotlin/alphaTab/src/jvmTest/kotlin/alphaTab/visualTests/VisualTestHelperPartials.kt
@@ -10,6 +10,7 @@ import alphaTab.importer.ScoreLoader
import alphaTab.io.ByteBuffer
import alphaTab.model.JsonConverter
import alphaTab.model.Score
+import alphaTab.platform.jvm.SkiaCanvas
import alphaTab.rendering.RenderFinishedEventArgs
import alphaTab.rendering.ScoreRenderer
import kotlinx.coroutines.GlobalScope
@@ -94,6 +95,20 @@ class VisualTestHelperPartials {
actualSettings.core.enableLazyLoading = false
actualSettings.core.useWorkers = false
+ actualSettings.display.resources.copyrightFont.family = "Roboto"
+ actualSettings.display.resources.titleFont.family = "PT Serif"
+ actualSettings.display.resources.subTitleFont.family = "PT Serif"
+ actualSettings.display.resources.wordsFont.family = "PT Serif"
+ actualSettings.display.resources.effectFont.family = "PT Serif"
+ actualSettings.display.resources.fretboardNumberFont.family = "Roboto"
+ actualSettings.display.resources.tablatureFont.family = "Roboto"
+ actualSettings.display.resources.graceFont.family = "Roboto"
+ actualSettings.display.resources.barNumberFont.family = "Roboto"
+ actualSettings.display.resources.fingeringFont.family = "PT Serif"
+ actualSettings.display.resources.markerFont.family = "PT Serif"
+
+ loadFonts()
+
var actualReferenceFileName = referenceFileName
if (!actualReferenceFileName.startsWith("test-data/")) {
actualReferenceFileName = "test-data/visual-tests/$actualReferenceFileName"
@@ -158,6 +173,34 @@ class VisualTestHelperPartials {
}
}
+ private var _fontsLoaded = false
+ private fun loadFonts()
+ {
+ if (_fontsLoaded)
+ {
+ return;
+ }
+
+ _fontsLoaded = true;
+ val fonts = arrayOf(
+ "font/roboto/Roboto-Regular.ttf",
+ "font/roboto/Roboto-Italic.ttf",
+ "font/roboto/Roboto-Bold.ttf",
+ "font/roboto/Roboto-BoldItalic.ttf",
+ "font/ptserif/PTSerif-Regular.ttf",
+ "font/ptserif/PTSerif-Italic.ttf",
+ "font/ptserif/PTSerif-Bold.ttf",
+ "font/ptserif/PTSerif-BoldItalic.ttf"
+ )
+
+ for (font in fonts)
+ {
+ val data = TestPlatformPartials.loadFile(font)
+ SkiaCanvas.registerCustomFont(data.buffer.raw)
+ }
+ }
+
+
private fun compareVisualResult(
totalWidth: Double,
totalHeight: Double,
diff --git a/src/model/Font.ts b/src/model/Font.ts
index 0c7ed57bf..f4f26beb7 100644
--- a/src/model/Font.ts
+++ b/src/model/Font.ts
@@ -298,26 +298,74 @@ export enum FontWeight {
export class Font {
private _css: string;
private _cssScale: number = 0.0;
+ private _family: string;
+ private _style: FontStyle;
+ private _weight: FontWeight;
+ private _size: number;
+
+ private reset() {
+ this._cssScale = 0;
+ this._css = this.toCssString();
+ }
+
+ /**
+ * Gets the font family name.
+ */
+ public get family(): string {
+ return this._family;
+ }
+
+ /**
+ * Sets the font family name.
+ */
+ public set family(value: string) {
+ this._family = value;
+ this.reset();
+ }
+
+ /**
+ * Gets the font size in pixels.
+ */
+ public get size(): number {
+ return this._size;
+ }
/**
- * Gets or sets the font family name.
+ * Sets the font size in pixels.
*/
- public family: string;
+ public set size(value: number) {
+ this._size = value;
+ this.reset();
+ }
/**
- * Gets or sets the font size in pixels.
+ * Gets the font style.
*/
- public size: number;
+ public get style(): FontStyle {
+ return this._style;
+ }
+ /**
+ * Sets the font style.
+ */
+ public set style(value: FontStyle) {
+ this._style = value;
+ this.reset();
+ }
/**
- * Gets or sets the font style.
+ * Gets the font weight.
*/
- public style: FontStyle;
+ public get weight(): FontWeight {
+ return this._weight;
+ }
/**
* Gets or sets the font weight.
*/
- public weight: FontWeight;
+ public set weight(value: FontWeight) {
+ this._weight = value;
+ this.reset();
+ }
public get isBold(): boolean {
return this.weight === FontWeight.Bold;
@@ -340,14 +388,14 @@ export class Font {
style: FontStyle = FontStyle.Plain,
weight: FontWeight = FontWeight.Regular
) {
- this.family = family;
- this.size = size;
- this.style = style;
- this.weight = weight;
- this._css = this.toCssString(1);
+ this._family = family;
+ this._size = size;
+ this._style = style;
+ this._weight = weight;
+ this._css = this.toCssString();
}
- public toCssString(scale: number): string {
+ public toCssString(scale: number = 1): string {
if (!this._css || !(Math.abs(scale - this._cssScale) < 0.01)) {
let buf: string = '';
if (this.isBold) {
diff --git a/test-data/visual-tests/effects-and-annotations/bends.png b/test-data/visual-tests/effects-and-annotations/bends.png
index 94c4a8a61..70f09a5ad 100644
Binary files a/test-data/visual-tests/effects-and-annotations/bends.png and b/test-data/visual-tests/effects-and-annotations/bends.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/brush.png b/test-data/visual-tests/effects-and-annotations/brush.png
index ba9d061c9..95b189d5e 100644
Binary files a/test-data/visual-tests/effects-and-annotations/brush.png and b/test-data/visual-tests/effects-and-annotations/brush.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/chords.png b/test-data/visual-tests/effects-and-annotations/chords.png
index ae32860b0..e94eeaafe 100644
Binary files a/test-data/visual-tests/effects-and-annotations/chords.png and b/test-data/visual-tests/effects-and-annotations/chords.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/dynamics.png b/test-data/visual-tests/effects-and-annotations/dynamics.png
index af35075b9..7ede3f4ef 100644
Binary files a/test-data/visual-tests/effects-and-annotations/dynamics.png and b/test-data/visual-tests/effects-and-annotations/dynamics.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/fade-in.png b/test-data/visual-tests/effects-and-annotations/fade-in.png
index cdab327ed..41fa51867 100644
Binary files a/test-data/visual-tests/effects-and-annotations/fade-in.png and b/test-data/visual-tests/effects-and-annotations/fade-in.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/fingering.png b/test-data/visual-tests/effects-and-annotations/fingering.png
index 553410566..d23186b14 100644
Binary files a/test-data/visual-tests/effects-and-annotations/fingering.png and b/test-data/visual-tests/effects-and-annotations/fingering.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/let-ring.png b/test-data/visual-tests/effects-and-annotations/let-ring.png
index 047e8583f..ae177726d 100644
Binary files a/test-data/visual-tests/effects-and-annotations/let-ring.png and b/test-data/visual-tests/effects-and-annotations/let-ring.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/markers.png b/test-data/visual-tests/effects-and-annotations/markers.png
index 5e522ab61..539fcc51c 100644
Binary files a/test-data/visual-tests/effects-and-annotations/markers.png and b/test-data/visual-tests/effects-and-annotations/markers.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/palm-mute.png b/test-data/visual-tests/effects-and-annotations/palm-mute.png
index b60feb2fb..9bb1a974a 100644
Binary files a/test-data/visual-tests/effects-and-annotations/palm-mute.png and b/test-data/visual-tests/effects-and-annotations/palm-mute.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/pick-stroke.png b/test-data/visual-tests/effects-and-annotations/pick-stroke.png
index e69645325..91a46063d 100644
Binary files a/test-data/visual-tests/effects-and-annotations/pick-stroke.png and b/test-data/visual-tests/effects-and-annotations/pick-stroke.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/slides.png b/test-data/visual-tests/effects-and-annotations/slides.png
index 5aec430bb..ba77cc563 100644
Binary files a/test-data/visual-tests/effects-and-annotations/slides.png and b/test-data/visual-tests/effects-and-annotations/slides.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/tap.png b/test-data/visual-tests/effects-and-annotations/tap.png
index 5cfacc969..a311070de 100644
Binary files a/test-data/visual-tests/effects-and-annotations/tap.png and b/test-data/visual-tests/effects-and-annotations/tap.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/tempo.png b/test-data/visual-tests/effects-and-annotations/tempo.png
index 7e60a576d..6abd184ce 100644
Binary files a/test-data/visual-tests/effects-and-annotations/tempo.png and b/test-data/visual-tests/effects-and-annotations/tempo.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/text.png b/test-data/visual-tests/effects-and-annotations/text.png
index 03bc4d75b..3ccd6594a 100644
Binary files a/test-data/visual-tests/effects-and-annotations/text.png and b/test-data/visual-tests/effects-and-annotations/text.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/tremolo-bar.png b/test-data/visual-tests/effects-and-annotations/tremolo-bar.png
index 0683ad8e8..2b253ec18 100644
Binary files a/test-data/visual-tests/effects-and-annotations/tremolo-bar.png and b/test-data/visual-tests/effects-and-annotations/tremolo-bar.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/tremolo-picking.png b/test-data/visual-tests/effects-and-annotations/tremolo-picking.png
index 69bc7d089..14983aed8 100644
Binary files a/test-data/visual-tests/effects-and-annotations/tremolo-picking.png and b/test-data/visual-tests/effects-and-annotations/tremolo-picking.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/trill.png b/test-data/visual-tests/effects-and-annotations/trill.png
index d732eb665..323602896 100644
Binary files a/test-data/visual-tests/effects-and-annotations/trill.png and b/test-data/visual-tests/effects-and-annotations/trill.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/triplet-feel.png b/test-data/visual-tests/effects-and-annotations/triplet-feel.png
index b8fbedc60..8c5d9179f 100644
Binary files a/test-data/visual-tests/effects-and-annotations/triplet-feel.png and b/test-data/visual-tests/effects-and-annotations/triplet-feel.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/tuplets-advanced.png b/test-data/visual-tests/effects-and-annotations/tuplets-advanced.png
index 38fa214e3..571c0a4f3 100644
Binary files a/test-data/visual-tests/effects-and-annotations/tuplets-advanced.png and b/test-data/visual-tests/effects-and-annotations/tuplets-advanced.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/tuplets.png b/test-data/visual-tests/effects-and-annotations/tuplets.png
index f244ae0f1..9b4d0cedf 100644
Binary files a/test-data/visual-tests/effects-and-annotations/tuplets.png and b/test-data/visual-tests/effects-and-annotations/tuplets.png differ
diff --git a/test-data/visual-tests/effects-and-annotations/vibrato.png b/test-data/visual-tests/effects-and-annotations/vibrato.png
index 2958e7dd9..8ac33bac7 100644
Binary files a/test-data/visual-tests/effects-and-annotations/vibrato.png and b/test-data/visual-tests/effects-and-annotations/vibrato.png differ
diff --git a/test-data/visual-tests/general/alternate-endings.png b/test-data/visual-tests/general/alternate-endings.png
index 1dc614aed..b4761acee 100644
Binary files a/test-data/visual-tests/general/alternate-endings.png and b/test-data/visual-tests/general/alternate-endings.png differ
diff --git a/test-data/visual-tests/general/repeats.png b/test-data/visual-tests/general/repeats.png
index 77b353314..7c4a34a8e 100644
Binary files a/test-data/visual-tests/general/repeats.png and b/test-data/visual-tests/general/repeats.png differ
diff --git a/test-data/visual-tests/general/song-details.png b/test-data/visual-tests/general/song-details.png
index 34351c12e..7db77e4ed 100644
Binary files a/test-data/visual-tests/general/song-details.png and b/test-data/visual-tests/general/song-details.png differ
diff --git a/test-data/visual-tests/general/tuning.png b/test-data/visual-tests/general/tuning.png
index d68946ed9..b257ef349 100644
Binary files a/test-data/visual-tests/general/tuning.png and b/test-data/visual-tests/general/tuning.png differ
diff --git a/test-data/visual-tests/guitar-tabs/rhythm-with-beams.png b/test-data/visual-tests/guitar-tabs/rhythm-with-beams.png
index a6ee9d39b..07f77140d 100644
Binary files a/test-data/visual-tests/guitar-tabs/rhythm-with-beams.png and b/test-data/visual-tests/guitar-tabs/rhythm-with-beams.png differ
diff --git a/test-data/visual-tests/guitar-tabs/rhythm.png b/test-data/visual-tests/guitar-tabs/rhythm.png
index c46f0c7dc..6ffc948be 100644
Binary files a/test-data/visual-tests/guitar-tabs/rhythm.png and b/test-data/visual-tests/guitar-tabs/rhythm.png differ
diff --git a/test-data/visual-tests/guitar-tabs/string-variations.png b/test-data/visual-tests/guitar-tabs/string-variations.png
index cc7e495ec..d20261b5d 100644
Binary files a/test-data/visual-tests/guitar-tabs/string-variations.png and b/test-data/visual-tests/guitar-tabs/string-variations.png differ
diff --git a/test-data/visual-tests/layout/grace-notes-advanced.png b/test-data/visual-tests/layout/grace-notes-advanced.png
deleted file mode 100644
index 21b441d59..000000000
Binary files a/test-data/visual-tests/layout/grace-notes-advanced.png and /dev/null differ
diff --git a/test-data/visual-tests/layout/horizontal-layout-5to8.png b/test-data/visual-tests/layout/horizontal-layout-5to8.png
index 608dceabe..df970bd9c 100644
Binary files a/test-data/visual-tests/layout/horizontal-layout-5to8.png and b/test-data/visual-tests/layout/horizontal-layout-5to8.png differ
diff --git a/test-data/visual-tests/layout/horizontal-layout.png b/test-data/visual-tests/layout/horizontal-layout.png
index e7ec0fd08..401567c25 100644
Binary files a/test-data/visual-tests/layout/horizontal-layout.png and b/test-data/visual-tests/layout/horizontal-layout.png differ
diff --git a/test-data/visual-tests/layout/multi-track.png b/test-data/visual-tests/layout/multi-track.png
index bb8e6ecb1..80a33e0b6 100644
Binary files a/test-data/visual-tests/layout/multi-track.png and b/test-data/visual-tests/layout/multi-track.png differ
diff --git a/test-data/visual-tests/layout/multi-voice.png b/test-data/visual-tests/layout/multi-voice.png
index 2337ab9ba..9199ef887 100644
Binary files a/test-data/visual-tests/layout/multi-voice.png and b/test-data/visual-tests/layout/multi-voice.png differ
diff --git a/test-data/visual-tests/layout/page-layout-5barsperrow.png b/test-data/visual-tests/layout/page-layout-5barsperrow.png
index db05cdee1..00ba4eafd 100644
Binary files a/test-data/visual-tests/layout/page-layout-5barsperrow.png and b/test-data/visual-tests/layout/page-layout-5barsperrow.png differ
diff --git a/test-data/visual-tests/layout/page-layout-5to8.png b/test-data/visual-tests/layout/page-layout-5to8.png
index 5974e512a..23c35a961 100644
Binary files a/test-data/visual-tests/layout/page-layout-5to8.png and b/test-data/visual-tests/layout/page-layout-5to8.png differ
diff --git a/test-data/visual-tests/layout/page-layout.png b/test-data/visual-tests/layout/page-layout.png
index f81f229ef..4339588d1 100644
Binary files a/test-data/visual-tests/layout/page-layout.png and b/test-data/visual-tests/layout/page-layout.png differ
diff --git a/test-data/visual-tests/layout/tied-notes.png b/test-data/visual-tests/layout/tied-notes.png
deleted file mode 100644
index 407995f9f..000000000
Binary files a/test-data/visual-tests/layout/tied-notes.png and /dev/null differ
diff --git a/test-data/visual-tests/music-notation/accidentals.png b/test-data/visual-tests/music-notation/accidentals.png
index 932c39e0c..2326237b3 100644
Binary files a/test-data/visual-tests/music-notation/accidentals.png and b/test-data/visual-tests/music-notation/accidentals.png differ
diff --git a/test-data/visual-tests/music-notation/beams-advanced.png b/test-data/visual-tests/music-notation/beams-advanced.png
index 65dff890c..af34fc4aa 100644
Binary files a/test-data/visual-tests/music-notation/beams-advanced.png and b/test-data/visual-tests/music-notation/beams-advanced.png differ
diff --git a/test-data/visual-tests/music-notation/clefs.png b/test-data/visual-tests/music-notation/clefs.png
index d50a62309..361bf0724 100644
Binary files a/test-data/visual-tests/music-notation/clefs.png and b/test-data/visual-tests/music-notation/clefs.png differ
diff --git a/test-data/visual-tests/music-notation/forced-accidentals.png b/test-data/visual-tests/music-notation/forced-accidentals.png
index e0bad7799..cf0294d03 100644
Binary files a/test-data/visual-tests/music-notation/forced-accidentals.png and b/test-data/visual-tests/music-notation/forced-accidentals.png differ
diff --git a/test-data/visual-tests/music-notation/key-signatures.png b/test-data/visual-tests/music-notation/key-signatures.png
index 171fdc02f..0b17bd39a 100644
Binary files a/test-data/visual-tests/music-notation/key-signatures.png and b/test-data/visual-tests/music-notation/key-signatures.png differ
diff --git a/test-data/visual-tests/music-notation/notes-rests-beams.png b/test-data/visual-tests/music-notation/notes-rests-beams.png
index c092ea22f..92f29fbc4 100644
Binary files a/test-data/visual-tests/music-notation/notes-rests-beams.png and b/test-data/visual-tests/music-notation/notes-rests-beams.png differ
diff --git a/test-data/visual-tests/music-notation/rest-collisions.png b/test-data/visual-tests/music-notation/rest-collisions.png
index d771a3622..da144a3e9 100644
Binary files a/test-data/visual-tests/music-notation/rest-collisions.png and b/test-data/visual-tests/music-notation/rest-collisions.png differ
diff --git a/test-data/visual-tests/music-notation/time-signatures.png b/test-data/visual-tests/music-notation/time-signatures.png
index 5a9b9d7df..5f3d7e5a3 100644
Binary files a/test-data/visual-tests/music-notation/time-signatures.png and b/test-data/visual-tests/music-notation/time-signatures.png differ
diff --git a/test-data/visual-tests/notation-elements/chord-diagrams-off.png b/test-data/visual-tests/notation-elements/chord-diagrams-off.png
index 1065acbba..2b56b27ab 100644
Binary files a/test-data/visual-tests/notation-elements/chord-diagrams-off.png and b/test-data/visual-tests/notation-elements/chord-diagrams-off.png differ
diff --git a/test-data/visual-tests/notation-elements/chord-diagrams-on.png b/test-data/visual-tests/notation-elements/chord-diagrams-on.png
index 8bacfa5d0..dff71f089 100644
Binary files a/test-data/visual-tests/notation-elements/chord-diagrams-on.png and b/test-data/visual-tests/notation-elements/chord-diagrams-on.png differ
diff --git a/test-data/visual-tests/notation-elements/effects-off.png b/test-data/visual-tests/notation-elements/effects-off.png
index 07d23a3a6..55e6e5596 100644
Binary files a/test-data/visual-tests/notation-elements/effects-off.png and b/test-data/visual-tests/notation-elements/effects-off.png differ
diff --git a/test-data/visual-tests/notation-elements/effects-on.png b/test-data/visual-tests/notation-elements/effects-on.png
index 4df736e21..f4ad5d762 100644
Binary files a/test-data/visual-tests/notation-elements/effects-on.png and b/test-data/visual-tests/notation-elements/effects-on.png differ
diff --git a/test-data/visual-tests/notation-elements/guitar-tuning-off.png b/test-data/visual-tests/notation-elements/guitar-tuning-off.png
index 3a73dc96f..1210f0663 100644
Binary files a/test-data/visual-tests/notation-elements/guitar-tuning-off.png and b/test-data/visual-tests/notation-elements/guitar-tuning-off.png differ
diff --git a/test-data/visual-tests/notation-elements/guitar-tuning-on.png b/test-data/visual-tests/notation-elements/guitar-tuning-on.png
index 06c13ce81..e0b25e2ef 100644
Binary files a/test-data/visual-tests/notation-elements/guitar-tuning-on.png and b/test-data/visual-tests/notation-elements/guitar-tuning-on.png differ
diff --git a/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-off.png b/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-off.png
index 2a81724ab..5817b1270 100644
Binary files a/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-off.png and b/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-off.png differ
diff --git a/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-on.png b/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-on.png
index 97b63799b..8314ed139 100644
Binary files a/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-on.png and b/test-data/visual-tests/notation-elements/parenthesis-on-tied-bends-on.png differ
diff --git a/test-data/visual-tests/notation-elements/score-info-album.png b/test-data/visual-tests/notation-elements/score-info-album.png
index 9905339e1..f93aef1dd 100644
Binary files a/test-data/visual-tests/notation-elements/score-info-album.png and b/test-data/visual-tests/notation-elements/score-info-album.png differ
diff --git a/test-data/visual-tests/notation-elements/score-info-all.png b/test-data/visual-tests/notation-elements/score-info-all.png
index 52e2726a6..c903e3460 100644
Binary files a/test-data/visual-tests/notation-elements/score-info-all.png and b/test-data/visual-tests/notation-elements/score-info-all.png differ
diff --git a/test-data/visual-tests/notation-elements/score-info-artist.png b/test-data/visual-tests/notation-elements/score-info-artist.png
index e5bcca2ea..48ce8c40f 100644
Binary files a/test-data/visual-tests/notation-elements/score-info-artist.png and b/test-data/visual-tests/notation-elements/score-info-artist.png differ
diff --git a/test-data/visual-tests/notation-elements/score-info-copyright.png b/test-data/visual-tests/notation-elements/score-info-copyright.png
index 74d8f5820..842e45e80 100644
Binary files a/test-data/visual-tests/notation-elements/score-info-copyright.png and b/test-data/visual-tests/notation-elements/score-info-copyright.png differ
diff --git a/test-data/visual-tests/notation-elements/score-info-music.png b/test-data/visual-tests/notation-elements/score-info-music.png
index d96b51751..fad9ef657 100644
Binary files a/test-data/visual-tests/notation-elements/score-info-music.png and b/test-data/visual-tests/notation-elements/score-info-music.png differ
diff --git a/test-data/visual-tests/notation-elements/score-info-subtitle.png b/test-data/visual-tests/notation-elements/score-info-subtitle.png
index ae7945c55..79c29431a 100644
Binary files a/test-data/visual-tests/notation-elements/score-info-subtitle.png and b/test-data/visual-tests/notation-elements/score-info-subtitle.png differ
diff --git a/test-data/visual-tests/notation-elements/score-info-title.png b/test-data/visual-tests/notation-elements/score-info-title.png
index 46e70557b..80081de0f 100644
Binary files a/test-data/visual-tests/notation-elements/score-info-title.png and b/test-data/visual-tests/notation-elements/score-info-title.png differ
diff --git a/test-data/visual-tests/notation-elements/score-info-words-and-music.png b/test-data/visual-tests/notation-elements/score-info-words-and-music.png
index 8214bdd69..2e6d5add5 100644
Binary files a/test-data/visual-tests/notation-elements/score-info-words-and-music.png and b/test-data/visual-tests/notation-elements/score-info-words-and-music.png differ
diff --git a/test-data/visual-tests/notation-elements/score-info-words.png b/test-data/visual-tests/notation-elements/score-info-words.png
index ff1c13ddd..ee69fdbc1 100644
Binary files a/test-data/visual-tests/notation-elements/score-info-words.png and b/test-data/visual-tests/notation-elements/score-info-words.png differ
diff --git a/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-off.png b/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-off.png
index f3b5cbfe6..5e73b28db 100644
Binary files a/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-off.png and b/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-off.png differ
diff --git a/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-on.png b/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-on.png
index f3d18e663..a21bd26a7 100644
Binary files a/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-on.png and b/test-data/visual-tests/notation-elements/tab-notes-on-tied-bends-on.png differ
diff --git a/test-data/visual-tests/notation-elements/track-names-off.png b/test-data/visual-tests/notation-elements/track-names-off.png
index 4d0272a10..47b6befdb 100644
Binary files a/test-data/visual-tests/notation-elements/track-names-off.png and b/test-data/visual-tests/notation-elements/track-names-off.png differ
diff --git a/test-data/visual-tests/notation-elements/track-names-on.png b/test-data/visual-tests/notation-elements/track-names-on.png
index 09dc7a753..6255fc601 100644
Binary files a/test-data/visual-tests/notation-elements/track-names-on.png and b/test-data/visual-tests/notation-elements/track-names-on.png differ
diff --git a/test-data/visual-tests/notation-elements/zeros-on-dive-whammys-off.png b/test-data/visual-tests/notation-elements/zeros-on-dive-whammys-off.png
index b4cfa372f..b69700ce9 100644
Binary files a/test-data/visual-tests/notation-elements/zeros-on-dive-whammys-off.png and b/test-data/visual-tests/notation-elements/zeros-on-dive-whammys-off.png differ
diff --git a/test-data/visual-tests/notation-elements/zeros-on-dive-whammys-on.png b/test-data/visual-tests/notation-elements/zeros-on-dive-whammys-on.png
index 1b9089ab8..30d98e73e 100644
Binary files a/test-data/visual-tests/notation-elements/zeros-on-dive-whammys-on.png and b/test-data/visual-tests/notation-elements/zeros-on-dive-whammys-on.png differ
diff --git a/test-data/visual-tests/notation-legend/accentuations-default.png b/test-data/visual-tests/notation-legend/accentuations-default.png
index d5c9ab56a..c755b21ed 100644
Binary files a/test-data/visual-tests/notation-legend/accentuations-default.png and b/test-data/visual-tests/notation-legend/accentuations-default.png differ
diff --git a/test-data/visual-tests/notation-legend/accentuations-songbook.png b/test-data/visual-tests/notation-legend/accentuations-songbook.png
index 24d4aafcf..17b5c6cf2 100644
Binary files a/test-data/visual-tests/notation-legend/accentuations-songbook.png and b/test-data/visual-tests/notation-legend/accentuations-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/arpeggio-default.png b/test-data/visual-tests/notation-legend/arpeggio-default.png
index f149ae8e9..391d932ff 100644
Binary files a/test-data/visual-tests/notation-legend/arpeggio-default.png and b/test-data/visual-tests/notation-legend/arpeggio-default.png differ
diff --git a/test-data/visual-tests/notation-legend/arpeggio-songbook.png b/test-data/visual-tests/notation-legend/arpeggio-songbook.png
index f149ae8e9..391d932ff 100644
Binary files a/test-data/visual-tests/notation-legend/arpeggio-songbook.png and b/test-data/visual-tests/notation-legend/arpeggio-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/bends-default.png b/test-data/visual-tests/notation-legend/bends-default.png
index 88c8d651b..49bf6ffdf 100644
Binary files a/test-data/visual-tests/notation-legend/bends-default.png and b/test-data/visual-tests/notation-legend/bends-default.png differ
diff --git a/test-data/visual-tests/notation-legend/bends-songbook.png b/test-data/visual-tests/notation-legend/bends-songbook.png
index 5c4af2463..893fc07b6 100644
Binary files a/test-data/visual-tests/notation-legend/bends-songbook.png and b/test-data/visual-tests/notation-legend/bends-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/chords-default.png b/test-data/visual-tests/notation-legend/chords-default.png
index 6bfd5fe23..a34efa1d5 100644
Binary files a/test-data/visual-tests/notation-legend/chords-default.png and b/test-data/visual-tests/notation-legend/chords-default.png differ
diff --git a/test-data/visual-tests/notation-legend/chords-songbook.png b/test-data/visual-tests/notation-legend/chords-songbook.png
index 6bfd5fe23..a34efa1d5 100644
Binary files a/test-data/visual-tests/notation-legend/chords-songbook.png and b/test-data/visual-tests/notation-legend/chords-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/crescendo-default.png b/test-data/visual-tests/notation-legend/crescendo-default.png
index 0613f28c8..c2499e87e 100644
Binary files a/test-data/visual-tests/notation-legend/crescendo-default.png and b/test-data/visual-tests/notation-legend/crescendo-default.png differ
diff --git a/test-data/visual-tests/notation-legend/crescendo-songbook.png b/test-data/visual-tests/notation-legend/crescendo-songbook.png
index 0613f28c8..c2499e87e 100644
Binary files a/test-data/visual-tests/notation-legend/crescendo-songbook.png and b/test-data/visual-tests/notation-legend/crescendo-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/dead-default.png b/test-data/visual-tests/notation-legend/dead-default.png
index b089aa7f1..0c61f6249 100644
Binary files a/test-data/visual-tests/notation-legend/dead-default.png and b/test-data/visual-tests/notation-legend/dead-default.png differ
diff --git a/test-data/visual-tests/notation-legend/dead-songbook.png b/test-data/visual-tests/notation-legend/dead-songbook.png
index b089aa7f1..0c61f6249 100644
Binary files a/test-data/visual-tests/notation-legend/dead-songbook.png and b/test-data/visual-tests/notation-legend/dead-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/dynamics-default.png b/test-data/visual-tests/notation-legend/dynamics-default.png
index 229069642..0b7bcb5b6 100644
Binary files a/test-data/visual-tests/notation-legend/dynamics-default.png and b/test-data/visual-tests/notation-legend/dynamics-default.png differ
diff --git a/test-data/visual-tests/notation-legend/dynamics-songbook.png b/test-data/visual-tests/notation-legend/dynamics-songbook.png
index 229069642..0b7bcb5b6 100644
Binary files a/test-data/visual-tests/notation-legend/dynamics-songbook.png and b/test-data/visual-tests/notation-legend/dynamics-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/fingering-default.png b/test-data/visual-tests/notation-legend/fingering-default.png
index d50d7acd5..acbb1a2f8 100644
Binary files a/test-data/visual-tests/notation-legend/fingering-default.png and b/test-data/visual-tests/notation-legend/fingering-default.png differ
diff --git a/test-data/visual-tests/notation-legend/fingering-songbook.png b/test-data/visual-tests/notation-legend/fingering-songbook.png
index 6513e4cde..bc55f676f 100644
Binary files a/test-data/visual-tests/notation-legend/fingering-songbook.png and b/test-data/visual-tests/notation-legend/fingering-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/full-default.png b/test-data/visual-tests/notation-legend/full-default.png
index 6c00c312b..b660963de 100644
Binary files a/test-data/visual-tests/notation-legend/full-default.png and b/test-data/visual-tests/notation-legend/full-default.png differ
diff --git a/test-data/visual-tests/notation-legend/full-songbook.png b/test-data/visual-tests/notation-legend/full-songbook.png
index 8ab7eca77..be29615aa 100644
Binary files a/test-data/visual-tests/notation-legend/full-songbook.png and b/test-data/visual-tests/notation-legend/full-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/grace-default.png b/test-data/visual-tests/notation-legend/grace-default.png
index 4cfbc09e4..bee702449 100644
Binary files a/test-data/visual-tests/notation-legend/grace-default.png and b/test-data/visual-tests/notation-legend/grace-default.png differ
diff --git a/test-data/visual-tests/notation-legend/grace-songbook.png b/test-data/visual-tests/notation-legend/grace-songbook.png
index c12e0c013..ef4f9274a 100644
Binary files a/test-data/visual-tests/notation-legend/grace-songbook.png and b/test-data/visual-tests/notation-legend/grace-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/hammer-default.png b/test-data/visual-tests/notation-legend/hammer-default.png
index 2d735918d..53298f100 100644
Binary files a/test-data/visual-tests/notation-legend/hammer-default.png and b/test-data/visual-tests/notation-legend/hammer-default.png differ
diff --git a/test-data/visual-tests/notation-legend/hammer-songbook.png b/test-data/visual-tests/notation-legend/hammer-songbook.png
index 2d735918d..53298f100 100644
Binary files a/test-data/visual-tests/notation-legend/hammer-songbook.png and b/test-data/visual-tests/notation-legend/hammer-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/harmonics-default.png b/test-data/visual-tests/notation-legend/harmonics-default.png
index a4770a083..8d3a918ba 100644
Binary files a/test-data/visual-tests/notation-legend/harmonics-default.png and b/test-data/visual-tests/notation-legend/harmonics-default.png differ
diff --git a/test-data/visual-tests/notation-legend/harmonics-songbook.png b/test-data/visual-tests/notation-legend/harmonics-songbook.png
index a4770a083..8d3a918ba 100644
Binary files a/test-data/visual-tests/notation-legend/harmonics-songbook.png and b/test-data/visual-tests/notation-legend/harmonics-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/let-ring-default.png b/test-data/visual-tests/notation-legend/let-ring-default.png
index 0aa915292..12d660d12 100644
Binary files a/test-data/visual-tests/notation-legend/let-ring-default.png and b/test-data/visual-tests/notation-legend/let-ring-default.png differ
diff --git a/test-data/visual-tests/notation-legend/let-ring-songbook.png b/test-data/visual-tests/notation-legend/let-ring-songbook.png
index 01ae57353..d4a144545 100644
Binary files a/test-data/visual-tests/notation-legend/let-ring-songbook.png and b/test-data/visual-tests/notation-legend/let-ring-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/mixed-default.png b/test-data/visual-tests/notation-legend/mixed-default.png
index 2c32d019f..507ddfc37 100644
Binary files a/test-data/visual-tests/notation-legend/mixed-default.png and b/test-data/visual-tests/notation-legend/mixed-default.png differ
diff --git a/test-data/visual-tests/notation-legend/mixed-songbook.png b/test-data/visual-tests/notation-legend/mixed-songbook.png
index b80fa71ca..45e44d232 100644
Binary files a/test-data/visual-tests/notation-legend/mixed-songbook.png and b/test-data/visual-tests/notation-legend/mixed-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/multi-grace-default.png b/test-data/visual-tests/notation-legend/multi-grace-default.png
index 52052e4c6..406a75ac8 100644
Binary files a/test-data/visual-tests/notation-legend/multi-grace-default.png and b/test-data/visual-tests/notation-legend/multi-grace-default.png differ
diff --git a/test-data/visual-tests/notation-legend/multi-grace-songbook.png b/test-data/visual-tests/notation-legend/multi-grace-songbook.png
index 18aa8974f..bd1d0cedd 100644
Binary files a/test-data/visual-tests/notation-legend/multi-grace-songbook.png and b/test-data/visual-tests/notation-legend/multi-grace-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/multi-voice-default.png b/test-data/visual-tests/notation-legend/multi-voice-default.png
index 1988b4f29..e6853d544 100644
Binary files a/test-data/visual-tests/notation-legend/multi-voice-default.png and b/test-data/visual-tests/notation-legend/multi-voice-default.png differ
diff --git a/test-data/visual-tests/notation-legend/multi-voice-songbook.png b/test-data/visual-tests/notation-legend/multi-voice-songbook.png
index 1988b4f29..e6853d544 100644
Binary files a/test-data/visual-tests/notation-legend/multi-voice-songbook.png and b/test-data/visual-tests/notation-legend/multi-voice-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/ottavia-default.png b/test-data/visual-tests/notation-legend/ottavia-default.png
index d017f3a31..590ca0e5f 100644
Binary files a/test-data/visual-tests/notation-legend/ottavia-default.png and b/test-data/visual-tests/notation-legend/ottavia-default.png differ
diff --git a/test-data/visual-tests/notation-legend/ottavia-songbook.png b/test-data/visual-tests/notation-legend/ottavia-songbook.png
index d017f3a31..590ca0e5f 100644
Binary files a/test-data/visual-tests/notation-legend/ottavia-songbook.png and b/test-data/visual-tests/notation-legend/ottavia-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/pick-stroke-default.png b/test-data/visual-tests/notation-legend/pick-stroke-default.png
index 617fcf880..4840d5d0f 100644
Binary files a/test-data/visual-tests/notation-legend/pick-stroke-default.png and b/test-data/visual-tests/notation-legend/pick-stroke-default.png differ
diff --git a/test-data/visual-tests/notation-legend/pick-stroke-songbook.png b/test-data/visual-tests/notation-legend/pick-stroke-songbook.png
index 617fcf880..4840d5d0f 100644
Binary files a/test-data/visual-tests/notation-legend/pick-stroke-songbook.png and b/test-data/visual-tests/notation-legend/pick-stroke-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/slash-default.png b/test-data/visual-tests/notation-legend/slash-default.png
index 7b5ce7c79..229c26ba2 100644
Binary files a/test-data/visual-tests/notation-legend/slash-default.png and b/test-data/visual-tests/notation-legend/slash-default.png differ
diff --git a/test-data/visual-tests/notation-legend/slash-songbook.png b/test-data/visual-tests/notation-legend/slash-songbook.png
index 7b5ce7c79..229c26ba2 100644
Binary files a/test-data/visual-tests/notation-legend/slash-songbook.png and b/test-data/visual-tests/notation-legend/slash-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/slides-default.png b/test-data/visual-tests/notation-legend/slides-default.png
index 10ef1045c..3de475432 100644
Binary files a/test-data/visual-tests/notation-legend/slides-default.png and b/test-data/visual-tests/notation-legend/slides-default.png differ
diff --git a/test-data/visual-tests/notation-legend/slides-songbook.png b/test-data/visual-tests/notation-legend/slides-songbook.png
index 10ef1045c..3de475432 100644
Binary files a/test-data/visual-tests/notation-legend/slides-songbook.png and b/test-data/visual-tests/notation-legend/slides-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/staccatissimo-default.png b/test-data/visual-tests/notation-legend/staccatissimo-default.png
index bd9ce7bb5..b8273643b 100644
Binary files a/test-data/visual-tests/notation-legend/staccatissimo-default.png and b/test-data/visual-tests/notation-legend/staccatissimo-default.png differ
diff --git a/test-data/visual-tests/notation-legend/staccatissimo-songbook.png b/test-data/visual-tests/notation-legend/staccatissimo-songbook.png
index bd9ce7bb5..b8273643b 100644
Binary files a/test-data/visual-tests/notation-legend/staccatissimo-songbook.png and b/test-data/visual-tests/notation-legend/staccatissimo-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/sweep-default.png b/test-data/visual-tests/notation-legend/sweep-default.png
index 1eb930b9e..7d2ea078e 100644
Binary files a/test-data/visual-tests/notation-legend/sweep-default.png and b/test-data/visual-tests/notation-legend/sweep-default.png differ
diff --git a/test-data/visual-tests/notation-legend/sweep-songbook.png b/test-data/visual-tests/notation-legend/sweep-songbook.png
index 229069642..0b7bcb5b6 100644
Binary files a/test-data/visual-tests/notation-legend/sweep-songbook.png and b/test-data/visual-tests/notation-legend/sweep-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/tap-riff-default.png b/test-data/visual-tests/notation-legend/tap-riff-default.png
index a927a4fb6..9401f7487 100644
Binary files a/test-data/visual-tests/notation-legend/tap-riff-default.png and b/test-data/visual-tests/notation-legend/tap-riff-default.png differ
diff --git a/test-data/visual-tests/notation-legend/tap-riff-songbook.png b/test-data/visual-tests/notation-legend/tap-riff-songbook.png
index a927a4fb6..9401f7487 100644
Binary files a/test-data/visual-tests/notation-legend/tap-riff-songbook.png and b/test-data/visual-tests/notation-legend/tap-riff-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/tempo-change-default.png b/test-data/visual-tests/notation-legend/tempo-change-default.png
index a1f138b8c..6e5549df5 100644
Binary files a/test-data/visual-tests/notation-legend/tempo-change-default.png and b/test-data/visual-tests/notation-legend/tempo-change-default.png differ
diff --git a/test-data/visual-tests/notation-legend/tempo-change-songbook.png b/test-data/visual-tests/notation-legend/tempo-change-songbook.png
index 09d788505..353cdb60b 100644
Binary files a/test-data/visual-tests/notation-legend/tempo-change-songbook.png and b/test-data/visual-tests/notation-legend/tempo-change-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/text-default.png b/test-data/visual-tests/notation-legend/text-default.png
index af5603a68..cd85945ce 100644
Binary files a/test-data/visual-tests/notation-legend/text-default.png and b/test-data/visual-tests/notation-legend/text-default.png differ
diff --git a/test-data/visual-tests/notation-legend/text-songbook.png b/test-data/visual-tests/notation-legend/text-songbook.png
index af5603a68..cd85945ce 100644
Binary files a/test-data/visual-tests/notation-legend/text-songbook.png and b/test-data/visual-tests/notation-legend/text-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/tied-note-accidentals-default.png b/test-data/visual-tests/notation-legend/tied-note-accidentals-default.png
index 80e4dd77c..6c373b0d8 100644
Binary files a/test-data/visual-tests/notation-legend/tied-note-accidentals-default.png and b/test-data/visual-tests/notation-legend/tied-note-accidentals-default.png differ
diff --git a/test-data/visual-tests/notation-legend/tied-note-accidentals-songbook.png b/test-data/visual-tests/notation-legend/tied-note-accidentals-songbook.png
index 356c60b6d..0be6f80ee 100644
Binary files a/test-data/visual-tests/notation-legend/tied-note-accidentals-songbook.png and b/test-data/visual-tests/notation-legend/tied-note-accidentals-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/trill-default.png b/test-data/visual-tests/notation-legend/trill-default.png
index efc00b867..5e14edc0d 100644
Binary files a/test-data/visual-tests/notation-legend/trill-default.png and b/test-data/visual-tests/notation-legend/trill-default.png differ
diff --git a/test-data/visual-tests/notation-legend/trill-songbook.png b/test-data/visual-tests/notation-legend/trill-songbook.png
index efc00b867..5e14edc0d 100644
Binary files a/test-data/visual-tests/notation-legend/trill-songbook.png and b/test-data/visual-tests/notation-legend/trill-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/triplet-feel-default.png b/test-data/visual-tests/notation-legend/triplet-feel-default.png
index 6a14f54e5..08be93b37 100644
Binary files a/test-data/visual-tests/notation-legend/triplet-feel-default.png and b/test-data/visual-tests/notation-legend/triplet-feel-default.png differ
diff --git a/test-data/visual-tests/notation-legend/triplet-feel-songbook.png b/test-data/visual-tests/notation-legend/triplet-feel-songbook.png
index 6a14f54e5..08be93b37 100644
Binary files a/test-data/visual-tests/notation-legend/triplet-feel-songbook.png and b/test-data/visual-tests/notation-legend/triplet-feel-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/vibrato-default.png b/test-data/visual-tests/notation-legend/vibrato-default.png
index 80ea0be7c..39a656b97 100644
Binary files a/test-data/visual-tests/notation-legend/vibrato-default.png and b/test-data/visual-tests/notation-legend/vibrato-default.png differ
diff --git a/test-data/visual-tests/notation-legend/vibrato-songbook.png b/test-data/visual-tests/notation-legend/vibrato-songbook.png
index 80ea0be7c..39a656b97 100644
Binary files a/test-data/visual-tests/notation-legend/vibrato-songbook.png and b/test-data/visual-tests/notation-legend/vibrato-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/wah-default.png b/test-data/visual-tests/notation-legend/wah-default.png
index 3af7a70ea..bf0e0e29a 100644
Binary files a/test-data/visual-tests/notation-legend/wah-default.png and b/test-data/visual-tests/notation-legend/wah-default.png differ
diff --git a/test-data/visual-tests/notation-legend/wah-songbook.png b/test-data/visual-tests/notation-legend/wah-songbook.png
index 3af7a70ea..bf0e0e29a 100644
Binary files a/test-data/visual-tests/notation-legend/wah-songbook.png and b/test-data/visual-tests/notation-legend/wah-songbook.png differ
diff --git a/test-data/visual-tests/notation-legend/whammy-default.png b/test-data/visual-tests/notation-legend/whammy-default.png
index fa784903d..afe4e9eeb 100644
Binary files a/test-data/visual-tests/notation-legend/whammy-default.png and b/test-data/visual-tests/notation-legend/whammy-default.png differ
diff --git a/test-data/visual-tests/notation-legend/whammy-songbook.png b/test-data/visual-tests/notation-legend/whammy-songbook.png
index da9b8d0c3..0a895dca1 100644
Binary files a/test-data/visual-tests/notation-legend/whammy-songbook.png and b/test-data/visual-tests/notation-legend/whammy-songbook.png differ
diff --git a/test-data/visual-tests/special-notes/dead-notes.png b/test-data/visual-tests/special-notes/dead-notes.png
index 03f296688..1b2a649f2 100644
Binary files a/test-data/visual-tests/special-notes/dead-notes.png and b/test-data/visual-tests/special-notes/dead-notes.png differ
diff --git a/test-data/visual-tests/special-notes/ghost-notes.png b/test-data/visual-tests/special-notes/ghost-notes.png
index 2df9ba80d..3976b1504 100644
Binary files a/test-data/visual-tests/special-notes/ghost-notes.png and b/test-data/visual-tests/special-notes/ghost-notes.png differ
diff --git a/test-data/visual-tests/special-notes/grace-notes-advanced.png b/test-data/visual-tests/special-notes/grace-notes-advanced.png
index 49bd20212..52a6f3cf5 100644
Binary files a/test-data/visual-tests/special-notes/grace-notes-advanced.png and b/test-data/visual-tests/special-notes/grace-notes-advanced.png differ
diff --git a/test-data/visual-tests/special-notes/grace-notes.png b/test-data/visual-tests/special-notes/grace-notes.png
index 176856b08..d5cdd2b05 100644
Binary files a/test-data/visual-tests/special-notes/grace-notes.png and b/test-data/visual-tests/special-notes/grace-notes.png differ
diff --git a/test-data/visual-tests/special-notes/tied-notes.png b/test-data/visual-tests/special-notes/tied-notes.png
index 5691a57a5..8aeaf8f4b 100644
Binary files a/test-data/visual-tests/special-notes/tied-notes.png and b/test-data/visual-tests/special-notes/tied-notes.png differ
diff --git a/test-data/visual-tests/special-tracks/drum-tabs.png b/test-data/visual-tests/special-tracks/drum-tabs.png
index f86e0138d..1472a88c2 100644
Binary files a/test-data/visual-tests/special-tracks/drum-tabs.png and b/test-data/visual-tests/special-tracks/drum-tabs.png differ
diff --git a/test-data/visual-tests/special-tracks/grand-staff.png b/test-data/visual-tests/special-tracks/grand-staff.png
index 68d8bb7e5..6ba6e4a4a 100644
Binary files a/test-data/visual-tests/special-tracks/grand-staff.png and b/test-data/visual-tests/special-tracks/grand-staff.png differ
diff --git a/test-data/visual-tests/special-tracks/percussion.png b/test-data/visual-tests/special-tracks/percussion.png
index 53d112b64..8f386fd4c 100644
Binary files a/test-data/visual-tests/special-tracks/percussion.png and b/test-data/visual-tests/special-tracks/percussion.png differ
diff --git a/test/visualTests/VisualTestHelper.ts b/test/visualTests/VisualTestHelper.ts
index d9528a3ae..a28e99c13 100644
--- a/test/visualTests/VisualTestHelper.ts
+++ b/test/visualTests/VisualTestHelper.ts
@@ -31,7 +31,14 @@ export class VisualTestHelper {
const referenceFileName = TestPlatform.changeExtension(inputFile, '.png');
let score: Score = ScoreLoader.loadScoreFromBytes(inputFileData, settings);
- await VisualTestHelper.runVisualTestScore(score, referenceFileName, settings, tracks, message, tolerancePercent);
+ await VisualTestHelper.runVisualTestScore(
+ score,
+ referenceFileName,
+ settings,
+ tracks,
+ message,
+ tolerancePercent
+ );
} catch (e) {
fail(`Failed to run visual test ${e}`);
}
@@ -64,6 +71,80 @@ export class VisualTestHelper {
}
}
+ /**
+ * @target web
+ * @partial
+ */
+ private static _fontsLoaded = false;
+
+ /**
+ * @target web
+ * @partial
+ */
+ private static async loadFonts(): Promise {
+ if(VisualTestHelper._fontsLoaded) {
+ return;
+ }
+ VisualTestHelper._fontsLoaded = true;
+ const allFonts: FontFace[] = [];
+
+ const robotoRegular = new FontFace('Roboto', 'url(/base/font/roboto/Roboto-Regular.ttf)', {
+ weight: '400',
+ style: 'normal'
+ });
+ allFonts.push(robotoRegular);
+
+ const robotoItalic = new FontFace('Roboto', 'url(/base/font/roboto/Roboto-Italic.ttf)', {
+ weight: '400',
+ style: 'italic'
+ });
+ allFonts.push(robotoItalic);
+
+ const robotoBold = new FontFace('Roboto', 'url(/base/font/roboto/Roboto-Bold.ttf)', {
+ weight: '700',
+ style: 'normal'
+ });
+ allFonts.push(robotoBold);
+
+ const robotoBoldItalic = new FontFace('Roboto', 'url(/base/font/roboto/Roboto-BoldItalic.ttf)', {
+ weight: '700',
+ style: 'italic'
+ });
+ allFonts.push(robotoBoldItalic);
+
+ const ptserifRegular = new FontFace('PT Serif', 'url(/base/font/ptserif/PTSerif-Regular.ttf)', {
+ weight: '400',
+ style: 'normal'
+ });
+ allFonts.push(ptserifRegular);
+
+ const ptserifItalic = new FontFace('PT Serif', 'url(/base/font/ptserif/PTSerif-Italic.ttf)', {
+ weight: '400',
+ style: 'italic'
+ });
+ allFonts.push(ptserifItalic);
+
+ const ptserifBold = new FontFace('PT Serif', 'url(/base/font/ptserif/PTSerif-Bold.ttf)', {
+ weight: '700',
+ style: 'normal'
+ });
+ allFonts.push(ptserifBold);
+
+ const ptserifBoldItalic = new FontFace('PT Serif', 'url(/base/font/ptserif/PTSerif-BoldItalic.ttf)', {
+ weight: '700',
+ style: 'italic'
+ });
+ allFonts.push(ptserifBoldItalic);
+
+ const promises = allFonts.map(f => f.load());
+
+ await Promise.all(promises);
+
+ for(const font of allFonts) {
+ document.fonts.add(font);
+ }
+ }
+
/**
* @target web
* @partial
@@ -89,6 +170,20 @@ export class VisualTestHelper {
Environment.HighDpiFactor = 1; // test data is in scale 1
settings.core.enableLazyLoading = false;
+ settings.display.resources.copyrightFont.family = 'Roboto';
+ settings.display.resources.titleFont.family = 'PT Serif';
+ settings.display.resources.subTitleFont.family = 'PT Serif';
+ settings.display.resources.wordsFont.family = 'PT Serif';
+ settings.display.resources.effectFont.family = 'PT Serif';
+ settings.display.resources.fretboardNumberFont.family = 'Roboto';
+ settings.display.resources.tablatureFont.family = 'Roboto';
+ settings.display.resources.graceFont.family = 'Roboto';
+ settings.display.resources.barNumberFont.family = 'Roboto';
+ settings.display.resources.fingeringFont.family = 'PT Serif';
+ settings.display.resources.markerFont.family = 'PT Serif';
+
+ await VisualTestHelper.loadFonts();
+
let referenceFileData: Uint8Array;
try {
referenceFileData = await TestPlatform.loadFile(`test-data/visual-tests/${referenceFileName}`);
@@ -407,7 +502,7 @@ export class VisualTestHelper {
(dom as any).toString = function () {
return errorMessage;
};
- (dom as any)[Symbol.toPrimitive] = function() {
+ (dom as any)[Symbol.toPrimitive] = function () {
return errorMessage;
};
diff --git a/test/visualTests/features/General.test.ts b/test/visualTests/features/General.test.ts
index 372071912..4be0e0471 100644
--- a/test/visualTests/features/General.test.ts
+++ b/test/visualTests/features/General.test.ts
@@ -16,7 +16,7 @@ describe('GeneralTests', () => {
it('alternate-endings', async () => {
let settings: Settings = new Settings();
settings.display.staveProfile = StaveProfile.Score;
- await VisualTestHelper.runVisualTest('general/alternate-endings.gp', settings);
+ await VisualTestHelper.runVisualTest('general/alternate-endings.gp', settings, undefined, undefined, 1.5);
});
it('tuning', async () => {
diff --git a/test/visualTests/features/Layout.test.ts b/test/visualTests/features/Layout.test.ts
index 04dc42b72..8e35e83dc 100644
--- a/test/visualTests/features/Layout.test.ts
+++ b/test/visualTests/features/Layout.test.ts
@@ -27,7 +27,7 @@ describe('LayoutTests', () => {
settings.display.layoutMode = LayoutMode.Page;
settings.display.startBar = 5;
settings.display.barCount = 4;
- await VisualTestHelper.runVisualTest('layout/page-layout-5to8.gp', settings);
+ await VisualTestHelper.runVisualTest('layout/page-layout-5to8.gp', settings, undefined, undefined, 1.5);
});
it('horizontal-layout', async () => {
diff --git a/test/visualTests/features/MusicNotation.test.ts b/test/visualTests/features/MusicNotation.test.ts
index 597a40dcc..b98ba1e50 100644
--- a/test/visualTests/features/MusicNotation.test.ts
+++ b/test/visualTests/features/MusicNotation.test.ts
@@ -40,7 +40,7 @@ describe('MusicNotationTests', () => {
it('accidentals', async () => {
let settings: Settings = new Settings();
settings.display.staveProfile = StaveProfile.Score;
- await VisualTestHelper.runVisualTest('music-notation/accidentals.gp', settings);
+ await VisualTestHelper.runVisualTest('music-notation/accidentals.gp', settings, undefined, undefined, 2.5);
});
it('forced-accidentals', async () => {
diff --git a/test/visualTests/features/NotationLegend.test.ts b/test/visualTests/features/NotationLegend.test.ts
index 97bfd5106..c565e0459 100644
--- a/test/visualTests/features/NotationLegend.test.ts
+++ b/test/visualTests/features/NotationLegend.test.ts
@@ -84,8 +84,8 @@ describe('NotationLegend', () => {
it('sweep-default', async () => { await runNotationLegendTest(`sweep-default.png`, 93, 1, false); });
it('sweep-songbook', async () => { await runNotationLegendTest(`sweep-songbook.png`, 92, 1, true); });
- it('fingering-default', async () => { await runNotationLegendTest(`fingering-default.png`, 94, 2, false); });
- it('fingering-songbook', async () => { await runNotationLegendTest(`fingering-songbook.png`, 94, 2, true); });
+ it('fingering-default', async () => { await runNotationLegendTest(`fingering-default.png`, 94, 2, false, 'notation-legend.gp', 1.5); });
+ it('fingering-songbook', async () => { await runNotationLegendTest(`fingering-songbook.png`, 94, 2, true, 'notation-legend.gp', 1.5); });
it('whammy-default', async () => { await runNotationLegendTest(`whammy-default.png`, 96, 15, false); });
it('whammy-songbook', async () => { await runNotationLegendTest(`whammy-songbook.png`, 96, 15, true); });
@@ -99,7 +99,7 @@ describe('NotationLegend', () => {
it('tied-note-accidentals-default', async () => { await runNotationLegendTest(`tied-note-accidentals-default.png`, 1, -1, false, 'tied-note-accidentals.gp'); });
it('tied-note-accidentals-songbook', async () => { await runNotationLegendTest(`tied-note-accidentals-songbook.png`, 1, -1, true, 'tied-note-accidentals.gp'); });
- async function runNotationLegendTest(referenceFileName: string, startBar: number, barCount: number, songBook: boolean, fileName: string = 'notation-legend.gp'): Promise {
+ async function runNotationLegendTest(referenceFileName: string, startBar: number, barCount: number, songBook: boolean, fileName: string = 'notation-legend.gp', tolerance:number=1): Promise {
let settings: Settings = new Settings();
settings.display.layoutMode = LayoutMode.Horizontal;
settings.display.startBar = startBar;
@@ -109,6 +109,6 @@ describe('NotationLegend', () => {
}
const inputFileData = await TestPlatform.loadFile(`test-data/visual-tests/notation-legend/${fileName}`);
let score: Score = ScoreLoader.loadScoreFromBytes(inputFileData, settings);
- await VisualTestHelper.runVisualTestScore(score, `notation-legend/${referenceFileName}`, settings, [0]);
+ await VisualTestHelper.runVisualTestScore(score, `notation-legend/${referenceFileName}`, settings, [0], undefined, tolerance);
}
});