From 68c6dab5fd9088590ab76b84446bcb0627b256a1 Mon Sep 17 00:00:00 2001 From: Matt Karl Date: Fri, 16 Dec 2022 09:04:47 -0500 Subject: [PATCH] Workaround for Safari font loading bug (#32) --- src/HTMLText.ts | 40 +++++++++++++++++++++++----------------- src/HTMLTextStyle.ts | 34 +++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/HTMLText.ts b/src/HTMLText.ts index 9fe3172..208d621 100644 --- a/src/HTMLText.ts +++ b/src/HTMLText.ts @@ -186,7 +186,7 @@ export class HTMLText extends Sprite * @param {boolean} respectDirty - Whether to abort updating the * text if the Text isn't dirty and the function is called. */ - updateText(respectDirty = true): void + async updateText(respectDirty = true): Promise { const { style, canvas, context } = this; @@ -211,24 +211,30 @@ export class HTMLText extends Sprite if (!this._loading) { - const image = this._image; - const svgURL = new XMLSerializer().serializeToString(this._svgRoot); - this._loading = true; - image.src = `data:image/svg+xml;charset=utf8,${encodeURIComponent(svgURL)}`; - image.onload = () => + await new Promise((resolve) => { - context.clearRect(0, 0, canvas.width, canvas.height); - context.drawImage( - image, - 0, 0, width, height, - 0, 0, width, height, - ); - image.src = ''; - image.onload = null; - this._loading = false; - this.updateTexture(); - }; + const image = this._image; + + image.onload = async () => + { + await style.onBeforeDraw(); + context.clearRect(0, 0, canvas.width, canvas.height); + context.drawImage( + image, + 0, 0, width, height, + 0, 0, width, height, + ); + image.src = ''; + image.onload = null; + this._loading = false; + this.updateTexture(); + resolve(); + }; + const svgURL = new XMLSerializer().serializeToString(this._svgRoot); + + image.src = `data:image/svg+xml;charset=utf8,${encodeURIComponent(svgURL)}`; + }); } } diff --git a/src/HTMLTextStyle.ts b/src/HTMLTextStyle.ts index 0b920a6..f2c0db0 100644 --- a/src/HTMLTextStyle.ts +++ b/src/HTMLTextStyle.ts @@ -98,6 +98,9 @@ class HTMLTextStyle extends TextStyle /** Global rules or stylesheet, useful for creating rules for rendering */ private _stylesheet = ''; + /** Track font changes internally */ + private fontsDirty = false; + /** * Convert a TextStyle to HTMLTextStyle * @example @@ -134,6 +137,7 @@ class HTMLTextStyle extends TextStyle this.fontFamily = 'Arial'; this._fonts.length = 0; this.styleID++; + this.fontsDirty = true; } } @@ -150,6 +154,7 @@ class HTMLTextStyle extends TextStyle this._fonts.push(font); font.refs++; this.styleID++; + this.fontsDirty = true; return Promise.resolve(); } @@ -196,6 +201,7 @@ class HTMLTextStyle extends TextStyle await document.fonts.ready; this.styleID++; + this.fontsDirty = true; }); } @@ -351,7 +357,33 @@ class HTMLTextStyle extends TextStyle Object.assign(this, HTMLTextStyle.defaultOptions); } - /** Proving that Safari is the new IE */ + /** + * Called after the image is loaded but before drawing to the canvas. + * Mostly used to handle Safari's font loading bug. + * @ignore + */ + public onBeforeDraw() + { + const { fontsDirty: prevFontsDirty } = this; + + this.fontsDirty = false; + + // Safari has a known bug where embedded fonts are not available + // immediately after the image loads, to compensate we wait an + // arbitrary amount of time + // @see https://bugs.webkit.org/show_bug.cgi?id=219770 + if (this.isSafari && this._fonts.length > 0 && prevFontsDirty) + { + return new Promise((resolve) => setTimeout(resolve, 100)); + } + + return Promise.resolve(); + } + + /** + * Proving that Safari is the new IE + * @ignore + */ private get isSafari(): boolean { const { userAgent } = settings.ADAPTER.getNavigator();