diff --git a/src/utils/FontManager.js b/src/utils/FontManager.js index b4123c6368..796018a497 100644 --- a/src/utils/FontManager.js +++ b/src/utils/FontManager.js @@ -21,18 +21,47 @@ limitations under the License. * MIT license */ -let colrFontSupported = undefined; +function safariVersionCheck(ua) { + console.log("Browser is Safari - checking version for COLR support"); + try { + const safariVersionMatch = ua.match(/Mac OS X ([\d|_]+).*Version\/([\d|.]+).*Safari/); + if (safariVersionMatch) { + const macOSVersionStr = safariVersionMatch[1]; + const safariVersionStr = safariVersionMatch[2]; + const macOSVersion = macOSVersionStr.split("_").map(n => parseInt(n, 10)); + const safariVersion = safariVersionStr.split(".").map(n => parseInt(n, 10)); + const colrFontSupported = macOSVersion[0] >= 10 && macOSVersion[1] >= 14 && safariVersion[0] >= 12; + // https://www.colorfonts.wtf/ states safari supports COLR fonts from this version on + console.log(`COLR support on Safari requires macOS 10.14 and Safari 12, ` + + `detected Safari ${safariVersionStr} on macOS ${macOSVersionStr}, ` + + `COLR supported: ${colrFontSupported}`); + return colrFontSupported; + } + } catch (err) { + console.error("Error in Safari COLR version check", err); + } + console.warn("Couldn't determine Safari version to check COLR font support, assuming no."); + return false; +} async function isColrFontSupported() { - if (colrFontSupported !== undefined) { - return colrFontSupported; - } + console.log("Checking for COLR support"); + const {userAgent} = navigator; // Firefox has supported COLR fonts since version 26 - // but doesn't support the check below with content blocking enabled. - if (navigator.userAgent.includes("Firefox")) { - colrFontSupported = true; - return colrFontSupported; + // but doesn't support the check below without + // "Extract canvas data" permissions + // when content blocking is enabled. + if (userAgent.includes("Firefox")) { + console.log("Browser is Firefox - assuming COLR is supported"); + return true; + } + // Safari doesn't wait for the font to load (if it doesn't have it in cache) + // to emit the load event on the image, so there is no way to not make the check + // reliable. Instead sniff the version. + // Excluding "Chrome", as it's user agent unhelpfully also contains Safari... + if (!userAgent.includes("Chrome") && userAgent.includes("Safari")) { + return safariVersionCheck(userAgent); } try { @@ -58,23 +87,25 @@ async function isColrFontSupported() { img.src = 'data:image/svg+xml;charset=utf-8,' + encodeURIComponent(svg); - // FIXME wait for safari load our colr font - const wait = ms => new Promise((r, j)=>setTimeout(r, ms)); - await wait(500); - + console.log("Waiting for COLR SVG to load"); + await new Promise(resolve => img.onload = resolve); + console.log("Drawing canvas to detect COLR support"); context.drawImage(img, 0, 0); - colrFontSupported = (context.getImageData(10, 10, 1, 1).data[0] === 200); + const colrFontSupported = (context.getImageData(10, 10, 1, 1).data[0] === 200); + console.log("Canvas check revealed COLR is supported? " + colrFontSupported); + return colrFontSupported; } catch (e) { - console.error("Couldn't load colr font", e); - colrFontSupported = false; + console.error("Couldn't load COLR font", e); + return false; } - return colrFontSupported; } +let colrFontCheckStarted = false; export async function fixupColorFonts() { - if (colrFontSupported !== undefined) { + if (colrFontCheckStarted) { return; } + colrFontCheckStarted = true; if (await isColrFontSupported()) { const path = `url('${require("../../res/fonts/Twemoji_Mozilla/TwemojiMozilla-colr.woff2")}')`;