diff --git a/src.csharp/AlphaTab/Core/TypeHelper.cs b/src.csharp/AlphaTab/Core/TypeHelper.cs index e161067b5..95adcf86f 100644 --- a/src.csharp/AlphaTab/Core/TypeHelper.cs +++ b/src.csharp/AlphaTab/Core/TypeHelper.cs @@ -340,6 +340,12 @@ public static string SubstringIndex(this string s, double startIndex, double end return s.Substring((int) startIndex, (int) (endIndex - startIndex)); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string ReplaceAll(this string s, string before, string after) + { + return s.Replace(before, after); + } + public static string TypeOf(object? actual) { switch (actual) diff --git a/src.kotlin/alphaTab/alphaTab/src/commonMain/kotlin/alphaTab/core/Globals.kt b/src.kotlin/alphaTab/alphaTab/src/commonMain/kotlin/alphaTab/core/Globals.kt index 1b0b718c0..e412245f0 100644 --- a/src.kotlin/alphaTab/alphaTab/src/commonMain/kotlin/alphaTab/core/Globals.kt +++ b/src.kotlin/alphaTab/alphaTab/src/commonMain/kotlin/alphaTab/core/Globals.kt @@ -83,6 +83,10 @@ internal fun String.substring(startIndex: Double): String { return this.substring(startIndex.toInt()) } +internal fun String.replaceAll(before:String, after:String): String { + return this.replace(before, after) +} + internal fun IAlphaTabEnum.toDouble(): Double { return this.value.toDouble() } diff --git a/src/Environment.ts b/src/Environment.ts index e77aa9fd6..9dc99eb59 100644 --- a/src/Environment.ts +++ b/src/Environment.ts @@ -202,7 +202,7 @@ export class Environment { /** * @target web */ - public static bravuraFontChecker: FontLoadingChecker = new FontLoadingChecker('alphaTab'); + public static bravuraFontChecker: FontLoadingChecker = new FontLoadingChecker(['alphaTab']); /** * @target web @@ -549,7 +549,7 @@ export class Environment { (Environment.globalThis as any).IntersectionObserver = IntersectionObserverPolyfill; } - if(!('replaceChildren' in Element.prototype)) { + if (!('replaceChildren' in Element.prototype)) { Element.prototype.replaceChildren = function (...nodes: (Node | string)[]) { this.innerHTML = ''; this.append(...nodes); @@ -557,6 +557,11 @@ export class Environment { Document.prototype.replaceChildren = Element.prototype.replaceChildren; DocumentFragment.prototype.replaceChildren = Element.prototype.replaceChildren; } + if (!('replaceAll' in String.prototype)) { + (String.prototype as any).replaceAll = function (str: string, newStr: string) { + return this.replace(new RegExp(str, 'g'), newStr); + }; + } } } diff --git a/src/RenderingResources.ts b/src/RenderingResources.ts index c3bbc4081..a6089de99 100644 --- a/src/RenderingResources.ts +++ b/src/RenderingResources.ts @@ -6,8 +6,8 @@ import { Font, FontStyle, FontWeight } from '@src/model/Font'; * @json */ export class RenderingResources { - private static sansFont: string = 'Arial'; - private static serifFont: string = 'Georgia'; + private static sansFont: string = 'Arial, sans-serif'; + private static serifFont: string = 'Georgia, serif'; /** * Gets or sets the font to use for displaying the songs copyright information in the header of the music sheet. diff --git a/src/model/Font.ts b/src/model/Font.ts index c62cfd664..7df966f5e 100644 --- a/src/model/Font.ts +++ b/src/model/Font.ts @@ -23,6 +23,7 @@ class FontParser { public lineHeight: string = 'normal'; public size: string = '1rem'; public families: string[] = []; + public parseOnlyFamilies: boolean = false; private _tokens: FontParserToken[]; private _currentTokenIndex: number = -1; @@ -70,14 +71,27 @@ class FontParser { } } - this.fontStyleVariantWeight(); - this.fontSizeLineHeight(); + if (!this.parseOnlyFamilies) { + this.fontStyleVariantWeight(); + this.fontSizeLineHeight(); + } this.fontFamily(); } + public static parseFamilies(value: string): string[] { + const parser = new FontParser(value); + parser.parseOnlyFamilies = true; + parser.parse(); + return parser.families; + } + private fontFamily() { if (!this._currentToken) { - throw new Error(`Missing font list`); + if(this.parseOnlyFamilies) { + return; + } else { + throw new Error(`Missing font list`); + } } const familyListInput = this._input.substr(this._currentToken.startPos).trim(); @@ -263,6 +277,15 @@ class FontParser { this._currentTokenIndex = -1; this.nextToken(); } + + public static quoteFont(f: string): string { + if(f.indexOf(' ') === -1) { + return f; + } + + const escapedQuotes = f.replaceAll('"', '\\"'); + return `"${escapedQuotes}"`; + } } /** @@ -299,7 +322,7 @@ export enum FontWeight { export class Font { private _css: string; private _cssScale: number = 0.0; - private _family: string; + private _families: string[]; private _style: FontStyle; private _weight: FontWeight; private _size: number; @@ -310,17 +333,33 @@ export class Font { } /** - * Gets the font family name. + * Gets the first font family name. + * @deprecated Consider using {@link families} for multi font family support. */ public get family(): string { - return this._family; + return this._families[0]; } /** - * Sets the font family name. + * Sets the font family list. + * @deprecated Consider using {@link families} for multi font family support. */ public set family(value: string) { - this._family = value; + this.families = FontParser.parseFamilies(value); + } + + /** + * Gets the font family name. + */ + public get families(): string[] { + return this._families; + } + + /** + * Sets the font family name. + */ + public set families(value: string[]) { + this._families = value; this.reset(); } @@ -389,13 +428,31 @@ export class Font { style: FontStyle = FontStyle.Plain, weight: FontWeight = FontWeight.Regular ) { - this._family = family; + this._families = FontParser.parseFamilies(family); this._size = size; this._style = style; this._weight = weight; this._css = this.toCssString(); } + /** + * Initializes a new instance of the {@link Font} class. + * @param families The families. + * @param size The size. + * @param style The style. + * @param weight The weight. + */ + public static withFamilyList( + families: string[], + size: number, + style: FontStyle = FontStyle.Plain, + weight: FontWeight = FontWeight.Regular + ) { + const f = new Font("", size, style, weight); + f.families = families; + return f; + } + public toCssString(scale: number = 1): string { if (!this._css || !(Math.abs(scale - this._cssScale) < 0.01)) { let buf: string = ''; @@ -407,9 +464,7 @@ export class Font { } buf += this.size * scale; buf += 'px '; - buf += "'"; - buf += this.family; - buf += "'"; + buf += this.families.map(f => FontParser.quoteFont(f)).join(', '); this._css = buf; this._cssScale = scale; } @@ -422,25 +477,18 @@ export class Font { return null; case 'object': { const m = v as Map; - let family = m.get('family') as string; + let families = m.get('families') as string[]; // tslint:disable-next-line: no-unnecessary-type-assertion let size = m.get('size')! as number; let style = JsonHelper.parseEnum(m.get('style'), FontStyle)!; let weight = JsonHelper.parseEnum(m.get('weight'), FontWeight)!; - return new Font(family, size, style, weight); + return Font.withFamilyList(families, size, style, weight); } case 'string': { const parser = new FontParser(v as string); parser.parse(); - let family: string = parser.families[0]; - if ( - (family.startsWith("'") && family.endsWith("'")) || - (family.startsWith('"') && family.endsWith('"')) - ) { - family = family.substr(1, family.length - 2); - } - + let families: string[] = parser.families; let fontSizeString: string = parser.size.toLowerCase(); let fontSize: number = 0; // as per https://websemantics.uk/articles/font-size-conversion/ @@ -502,7 +550,7 @@ export class Font { break; } - return new Font(family, fontSize, fontStyle, fontWeight); + return Font.withFamilyList(families, fontSize, fontStyle, fontWeight); } default: return null; @@ -511,7 +559,7 @@ export class Font { public static toJson(font: Font): Map { const o = new Map(); - o.set('family', font.family); + o.set('families', font.families); o.set('size', font.size); o.set('style', font.style as number); o.set('weight', font.weight as number); diff --git a/src/platform/javascript/BrowserUiFacade.ts b/src/platform/javascript/BrowserUiFacade.ts index 853a2e29f..e29e6c300 100644 --- a/src/platform/javascript/BrowserUiFacade.ts +++ b/src/platform/javascript/BrowserUiFacade.ts @@ -202,9 +202,9 @@ export class BrowserUiFacade implements IUiFacade { } private registerFontChecker(font: Font): void { - if (!this._fontCheckers.has(font.family)) { - let checker: FontLoadingChecker = new FontLoadingChecker(font.family); - this._fontCheckers.set(font.family, checker); + if (!this._fontCheckers.has(font.families.join(', '))) { + let checker: FontLoadingChecker = new FontLoadingChecker(font.families); + this._fontCheckers.set(font.families.join(', '), checker); checker.fontLoaded.on(this.onFontLoaded.bind(this)); checker.checkForFontAvailability(); } diff --git a/src/platform/svg/FontSizes.ts b/src/platform/svg/FontSizes.ts index e5d1fdfb7..ac2ba3f8a 100644 --- a/src/platform/svg/FontSizes.ts +++ b/src/platform/svg/FontSizes.ts @@ -67,9 +67,19 @@ export class FontSizes { } } - public static measureString(s: string, family: string, size: number, style: FontStyle, weight:FontWeight): number { + public static measureString(s: string, families: string[], size: number, style: FontStyle, weight:FontWeight): number { let data: Uint8Array; let dataSize: number = 11; + let family = families[0]; // default to first font + + // find a font which is maybe registered already + for(let i = 0; i < families.length; i++) { + if(FontSizes.FontSizeLookupTables.has(families[i])) { + family = families[i]; + break; + } + } + if (!FontSizes.FontSizeLookupTables.has(family)) { FontSizes.generateFontLookup(family); } diff --git a/src/platform/svg/SvgCanvas.ts b/src/platform/svg/SvgCanvas.ts index 5f53abe6d..e227f6920 100644 --- a/src/platform/svg/SvgCanvas.ts +++ b/src/platform/svg/SvgCanvas.ts @@ -179,7 +179,7 @@ export abstract class SvgCanvas implements ICanvas { if (!text) { return 0; } - return FontSizes.measureString(text, this.font.family, this.font.size, this.font.style, this.font.weight); + return FontSizes.measureString(text, this.font.families, this.font.size, this.font.style, this.font.weight); } public abstract fillMusicFontSymbol( diff --git a/src/rendering/glyphs/TripletFeelGlyph.ts b/src/rendering/glyphs/TripletFeelGlyph.ts index be6b7839e..97e0a1304 100644 --- a/src/rendering/glyphs/TripletFeelGlyph.ts +++ b/src/rendering/glyphs/TripletFeelGlyph.ts @@ -148,7 +148,7 @@ export class TripletFeelGlyph extends EffectGlyph { private renderTriplet(cx: number, cy: number, canvas: ICanvas): void { cy += 2 * this.scale; let font: Font = this.renderer.resources.effectFont; - canvas.font = new Font(font.family, font.size * 0.8, font.style); + canvas.font = Font.withFamilyList(font.families, font.size * 0.8, font.style); let rightX: number = cx + TripletFeelGlyph.NoteSeparation * this.scale + 3 * this.scale; canvas.beginPath(); canvas.moveTo(cx, cy + 3 * this.scale); diff --git a/src/rendering/layout/ScoreLayout.ts b/src/rendering/layout/ScoreLayout.ts index b1824ced8..f093cea80 100644 --- a/src/rendering/layout/ScoreLayout.ts +++ b/src/rendering/layout/ScoreLayout.ts @@ -284,7 +284,7 @@ export abstract class ScoreLayout { let height: number = Math.floor(size * 2); const e = new RenderFinishedEventArgs(); - const font = new Font(resources.copyrightFont.family, size, FontStyle.Plain, FontWeight.Bold); + const font = Font.withFamilyList(resources.copyrightFont.families, size, FontStyle.Plain, FontWeight.Bold); this.renderer.canvas!.font = font; diff --git a/src/util/FontLoadingChecker.ts b/src/util/FontLoadingChecker.ts index 7c68e3dc3..f36465b16 100644 --- a/src/util/FontLoadingChecker.ts +++ b/src/util/FontLoadingChecker.ts @@ -7,14 +7,17 @@ import { Environment } from '@src/Environment'; * @target web */ export class FontLoadingChecker { - private _family: string; + private _originalFamilies: string[]; + private _families: string[]; + private _isStarted: boolean = false; public isFontLoaded: boolean = false; public fontLoaded: IEventEmitterOfT = new EventEmitterOfT(); - public constructor(family: string) { - this._family = family; + public constructor(families: string[]) { + this._originalFamilies = families; + this._families = families; } public checkForFontAvailability(): void { @@ -31,40 +34,74 @@ export class FontLoadingChecker { this._isStarted = true; let failCounter: number = 0; let failCounterId: number = window.setInterval(() => { - failCounter++; Logger.warning( 'Rendering', - `Could not load font '${this._family}' within ${failCounter * 5} seconds`, + `Could not load font '${this._families[0]}' within ${(failCounter + 1) * 5} seconds`, null ); + + // try loading next font if there are more than 1 left + if (this._families.length > 1) { + this._families.shift(); + failCounter = 0; + } else { + failCounter++; + } + }, 5000); - Logger.debug('Font', `Start checking for font availablility: ${this._family}`); + Logger.debug('Font', `Start checking for font availablility: ${this._families.join(', ')}`); - Logger.debug('Font', `[${this._family}] Font API available`); + let errorHandler = () => { + if (this._families.length > 1) { + Logger.debug('Font', `[${this._families[0]}] Loading Failed, switching to ${this._families[1]}`); + this._families.shift(); + window.setTimeout(() => { + checkFont(); + }, 0); + } + else { + Logger.error('Font', `[${this._originalFamilies.join(',')}] Loading Failed, rendering cannot start`); + window.clearInterval(failCounterId); + } + }; + + let successHandler = (font:string) => { + Logger.debug('Rendering', `[${font}] Font API signaled available`); + this.isFontLoaded = true; + window.clearInterval(failCounterId); + (this.fontLoaded as EventEmitterOfT).trigger(this._families[0]); + }; let checkFont = () => { - (document as any).fonts.load(`1em ${this._family}`).then(() => { - Logger.debug('Font', `[${this._family}] Font API signaled loaded`); - - if ((document as any).fonts.check('1em ' + this._family)) { - Logger.debug('Rendering', `[${this._family}] Font API signaled available`); - this.isFontLoaded = true; - window.clearInterval(failCounterId); - (this.fontLoaded as EventEmitterOfT).trigger(this._family); - } else { - Logger.debug( - 'Font', - `[${this._family}] Font API loaded reported, but font not available, checking later again`, - null - ); - window.setTimeout(() => { - checkFont(); - }, 250); + // Fast Path: check if one of the specified fonts is already available. + for (const font of this._families) { + if ((document as any).fonts.check('1em ' + font)) { + successHandler(font); + return; } - return true; - }); + } + + // Slow path: Wait for fonts to be loaded sequentially + const promise: Promise = (document as any).fonts.load(`1em ${this._families[0]}`); + promise.then( + () => { + Logger.debug('Font', `[${this._families[0]}] Font API signaled loaded`); + if ((document as any).fonts.check('1em ' + this._families[0])) { + successHandler(this._families[0]); + } else { + errorHandler(); + } + return true; + }, + reason => { + errorHandler(); + }); }; - checkFont(); + + + (document as any).fonts.ready.then(() => { + checkFont(); + }); } } diff --git a/test/model/Font.test.ts b/test/model/Font.test.ts index 54b7d5f6b..c23e59471 100644 --- a/test/model/Font.test.ts +++ b/test/model/Font.test.ts @@ -3,7 +3,7 @@ import { Font, FontStyle, FontWeight } from "@src/model/Font"; describe('FontTests', () => { function parseText(text: string, expected: Font) { const font = Font.fromJson(text); - expect(font!.family).toEqual(expected.family); + expect(font!.families.join(', ')).toEqual(expected.families.join(', ')); expect(font!.isBold).toEqual(expected.isBold); expect(font!.isItalic).toEqual(expected.isItalic); expect(font!.size).toEqual(expected.size); @@ -12,38 +12,55 @@ describe('FontTests', () => { } it('parses-full', function () { - parseText('italic small-caps bold 12px/1.5em "Arial"', new Font("Arial", 12, FontStyle.Italic, FontWeight.Bold)) + parseText('italic small-caps bold 12px/1.5em "Arial"', Font.withFamilyList(["Arial"], 12, FontStyle.Italic, FontWeight.Bold)) }); it('parses-partial-options', function () { - parseText('italic bold 12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Italic, FontWeight.Bold)) - parseText('bold italic 12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Italic, FontWeight.Bold)) - parseText('bold 12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain, FontWeight.Bold)) - parseText('italic 12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Italic)) + parseText('italic bold 12px/1.5em "Arial", sans', Font.withFamilyList(["Arial", "sans"], 12, FontStyle.Italic, FontWeight.Bold)) + parseText('bold italic 12px/1.5em "Arial", sans', Font.withFamilyList(["Arial", "sans"], 12, FontStyle.Italic, FontWeight.Bold)) + parseText('bold 12px/1.5em "Arial", sans', Font.withFamilyList(["Arial", "sans"], 12, FontStyle.Plain, FontWeight.Bold)) + parseText('italic 12px/1.5em "Arial", sans', Font.withFamilyList(["Arial", "sans"], 12, FontStyle.Italic)) }); it('parses-no-options', function () { - parseText('12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) + parseText('12px/1.5em "Arial", sans', Font.withFamilyList(["Arial", "sans"], 12, FontStyle.Plain)) }); it('parses-line-height-spaces', function () { - parseText('12px/1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) - parseText('12px /1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) - parseText('12px / 1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) - parseText('12px / 1.5em "Arial", sans', new Font("Arial", 12, FontStyle.Plain)) + parseText('12px/1.5em "Arial", sans', Font.withFamilyList(["Arial", "sans"], 12, FontStyle.Plain)) + parseText('12px /1.5em "Arial", sans', Font.withFamilyList(["Arial", "sans"], 12, FontStyle.Plain)) + parseText('12px / 1.5em "Arial", sans', Font.withFamilyList(["Arial", "sans"], 12, FontStyle.Plain)) + parseText('12px / 1.5em "Arial", sans', Font.withFamilyList(["Arial", "sans"], 12, FontStyle.Plain)) }); it('parses-multiple-families', function () { - parseText('12px/1.5em Arial, Verdana, sans', new Font("Arial", 12, FontStyle.Plain)) - parseText("12px/1.5em 'Arial', 'Verdana', 'sans'", new Font("Arial", 12, FontStyle.Plain)) - parseText('12px/1.5em "Arial", "Verdana", "sans"', new Font("Arial", 12, FontStyle.Plain)) - parseText('12px/1.5em Arial, "Verdana", sans', new Font("Arial", 12, FontStyle.Plain)) - parseText('12px/1.5em Arial, \'Verdana\', "sans"', new Font("Arial", 12, FontStyle.Plain)) + parseText('12px/1.5em Arial, Verdana, sans', Font.withFamilyList(["Arial", "Verdana", "sans"], 12, FontStyle.Plain)) + parseText("12px/1.5em 'Arial', 'Verdana', 'sans'", Font.withFamilyList(["Arial", "Verdana", "sans"], 12, FontStyle.Plain)) + parseText('12px/1.5em "Arial", "Verdana", "sans"', Font.withFamilyList(["Arial", "Verdana", "sans"], 12, FontStyle.Plain)) + parseText('12px/1.5em Arial, "Verdana", sans', Font.withFamilyList(["Arial", "Verdana", "sans"], 12, FontStyle.Plain)) + parseText('12px/1.5em Arial, \'Verdana\', "sans"', Font.withFamilyList(["Arial", "Verdana", "sans"], 12, FontStyle.Plain)) }); it('parses-escaped-quotes', function () { - parseText("12px/1.5em \"Ari\\\"al\"", new Font("Ari\"al", 12, FontStyle.Plain)) - parseText('12px/1.5em \'Ari\\\'al\'', new Font("Ari'al", 12, FontStyle.Plain)) - parseText('12px/1.5em \'Ari\\\'\'', new Font('Ari\'', 12, FontStyle.Plain)) - parseText("12px/1.5em 'Ari\\al'", new Font("Ari\\al", 12, FontStyle.Plain)) + parseText("12px/1.5em \"Ari\\\"al\"", Font.withFamilyList(["Ari\"al"], 12, FontStyle.Plain)) + parseText('12px/1.5em \'Ari\\\'al\'', Font.withFamilyList(["Ari'al"], 12, FontStyle.Plain)) + parseText('12px/1.5em \'Ari\\\'\'', Font.withFamilyList(['Ari\''], 12, FontStyle.Plain)) + parseText("12px/1.5em 'Ari\\al'", Font.withFamilyList(["Ari\\al"], 12, FontStyle.Plain)) + }); + it('parses-with-spaces-and-quotes', function () { + parseText("12px/1.5em \"Times New Roman\"", Font.withFamilyList(["Times New Roman"], 12, FontStyle.Plain)) + parseText("12px/1.5em \"Times New Roman\", Arial, 'Open Sans'", Font.withFamilyList(["Times New Roman", "Arial", "Open Sans"], 12, FontStyle.Plain)) + }); + + function toCssStringTest(f:Font, expected:string){ + expect(f.toCssString()).toEqual(expected) + } + + it('css-string-tests', function () { + toCssStringTest(Font.withFamilyList(["Arial"], 12, FontStyle.Plain), "12px Arial") + toCssStringTest(Font.withFamilyList(["Arial"], 12, FontStyle.Italic), "italic 12px Arial") + toCssStringTest(Font.withFamilyList(["Arial"], 12, FontStyle.Italic, FontWeight.Bold), "bold italic 12px Arial") + toCssStringTest(Font.withFamilyList(["Times New Roman"], 12, FontStyle.Plain), "12px \"Times New Roman\"") + toCssStringTest(Font.withFamilyList(["Times New Roman", "Arial"], 12, FontStyle.Plain), "12px \"Times New Roman\", Arial") + toCssStringTest(Font.withFamilyList(["With 'SingleQuote'", 'With "DoubleQuote"', "Arial"], 12, FontStyle.Plain), "12px \"With 'SingleQuote'\", \"With \\\"DoubleQuote\\\"\", Arial") }); }); \ No newline at end of file diff --git a/test/model/JsonConverter.test.ts b/test/model/JsonConverter.test.ts index 75223ba79..e427113c8 100644 --- a/test/model/JsonConverter.test.ts +++ b/test/model/JsonConverter.test.ts @@ -169,7 +169,7 @@ describe('JsonConverterTest', () => { expect(settings.display.layoutMode).toEqual(LayoutMode.Horizontal); expect(settings.display.scale).toEqual(5); expect(settings.notation.rhythmMode).toEqual(TabRhythmMode.ShowWithBars); - expect(settings.display.resources.copyrightFont.family).toEqual('Roboto'); + expect(settings.display.resources.copyrightFont.families[0]).toEqual('Roboto'); expect(settings.display.resources.copyrightFont.size).toEqual(18); expect(settings.display.resources.copyrightFont.style).toEqual(FontStyle.Italic); }); @@ -202,7 +202,7 @@ describe('JsonConverterTest', () => { expect(settings.display.layoutMode).toEqual(LayoutMode.Horizontal); expect(settings.display.scale).toEqual(5); expect(settings.notation.rhythmMode).toEqual(TabRhythmMode.ShowWithBars); - expect(settings.display.resources.copyrightFont.family).toEqual('Roboto'); + expect(settings.display.resources.copyrightFont.families[0]).toEqual('Roboto'); expect(settings.display.resources.copyrightFont.size).toEqual(18); expect(settings.display.resources.copyrightFont.style).toEqual(FontStyle.Italic); }); diff --git a/test/visualTests/VisualTestHelper.ts b/test/visualTests/VisualTestHelper.ts index 2a913605d..6e812bcd2 100644 --- a/test/visualTests/VisualTestHelper.ts +++ b/test/visualTests/VisualTestHelper.ts @@ -173,17 +173,17 @@ 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'; + settings.display.resources.copyrightFont.families = ['Roboto']; + settings.display.resources.titleFont.families = ['PT Serif']; + settings.display.resources.subTitleFont.families = ['PT Serif']; + settings.display.resources.wordsFont.families = ['PT Serif']; + settings.display.resources.effectFont.families = ['PT Serif']; + settings.display.resources.fretboardNumberFont.families = ['Roboto']; + settings.display.resources.tablatureFont.families = ['Roboto']; + settings.display.resources.graceFont.families = ['Roboto']; + settings.display.resources.barNumberFont.families = ['Roboto']; + settings.display.resources.fingeringFont.families = ['PT Serif']; + settings.display.resources.markerFont.families = ['PT Serif']; await VisualTestHelper.loadFonts(); @@ -245,7 +245,7 @@ export class VisualTestHelper { if (!triggerResize || isResizeRender) { resolve(); - } else if(triggerResize) { + } else if (triggerResize) { isResizeRender = true; // @ts-ignore api.triggerResize(); @@ -463,8 +463,8 @@ export class VisualTestHelper { let percentDifferenceText = percentDifference.toFixed(2); result.message = `Difference between original and new image is too big: ${match.differentPixels}/${totalPixels} (${percentDifferenceText}%)`; // await VisualTestHelper.saveFiles(expectedFileName, expected, oldActual, diff); - } - + } + if (sizeMismatch) { result.message += `Image sizes do not match: expected ${expected.width}x${expected.height} but got ${oldActual.width}x${oldActual.height}`; result.pass = false; diff --git a/tsconfig.base.json b/tsconfig.base.json index 3faf0ed5f..4ef27ce4f 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -7,6 +7,7 @@ "es2015", "es2016", "es2017", + "es2021", "dom" ], "strict": true,