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); } });