Explorar o código

test font URL if necessary (e.g. CSP error)

Gildas %!s(int64=6) %!d(string=hai) anos
pai
achega
ef24ef8927

+ 27 - 18
lib/single-file/modules/css-fonts-alt-minifier.js

@@ -60,7 +60,7 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 	};
 
 	return {
-		process: async (doc, stylesheets) => {
+		process: async (doc, stylesheets, fontURLs) => {
 			const fontsDetails = {
 				fonts: new Map(),
 				medias: new Map(),
@@ -89,9 +89,9 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 				const media = stylesheetInfo.mediaText;
 				if (cssRules) {
 					if (media && media != MEDIA_ALL) {
-						await processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + media), stats);
+						await processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + media), fontURLs, stats);
 					} else {
-						await processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats);
+						await processFontFaceRules(cssRules, sheetIndex, fontsDetails, fontURLs, stats);
 					}
 					stats.rules.discarded -= cssRules.getSize();
 				}
@@ -169,7 +169,7 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 		fontsDetails.medias.forEach(mediaFontsDetails => processFontDetails(mediaFontsDetails));
 	}
 
-	async function processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats) {
+	async function processFontFaceRules(cssRules, sheetIndex, fontsDetails, fontURLs, stats) {
 		const cssTree = singlefile.lib.vendor.cssTree;
 		const removedRules = [];
 		let mediaIndex = 0, supportsIndex = 0;
@@ -177,17 +177,17 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 			const ruleData = cssRule.data;
 			if (ruleData.type == "Atrule" && ruleData.name == "media" && ruleData.block && ruleData.block.children && ruleData.prelude) {
 				const mediaText = cssTree.generate(ruleData.prelude);
-				await processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + mediaIndex + "-" + mediaText), stats);
+				await processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + mediaIndex + "-" + mediaText), fontURLs, stats);
 				mediaIndex++;
 			} else if (ruleData.type == "Atrule" && ruleData.name == "supports" && ruleData.block && ruleData.block.children && ruleData.prelude) {
 				const supportsText = cssTree.generate(ruleData.prelude);
-				await processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.supports.get("supports-" + sheetIndex + "-" + supportsIndex + "-" + supportsText), stats);
+				await processFontFaceRules(ruleData.block.children, sheetIndex, fontsDetails.supports.get("supports-" + sheetIndex + "-" + supportsIndex + "-" + supportsText), fontURLs, stats);
 				supportsIndex++;
 			} else if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
 				const fontInfo = fontsDetails.fonts.get(getFontKey(ruleData));
 				if (fontInfo) {
 					fontsDetails.fonts.delete(getFontKey(ruleData));
-					await processFontFaceRule(ruleData, fontInfo, stats);
+					await processFontFaceRule(ruleData, fontInfo, fontURLs, stats);
 				} else {
 					removedRules.push(cssRule);
 				}
@@ -196,8 +196,18 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 		removedRules.forEach(cssRule => cssRules.remove(cssRule));
 	}
 
-	async function processFontFaceRule(ruleData, fontInfo, stats) {
+	async function processFontFaceRule(ruleData, fontInfo, fontURLs, stats) {
 		const cssTree = singlefile.lib.vendor.cssTree;
+
+		const removedNodes = [];
+		for (let node = ruleData.block.children.head; node; node = node.next) {
+			if (node.data.property == "src") {
+				removedNodes.push(node);
+			}
+		}
+		removedNodes.pop();
+		removedNodes.forEach(node => ruleData.block.children.remove(node));
+		const srcDeclaration = ruleData.block.children.filter(node => node.property == "src").tail;
 		await Promise.all(fontInfo.map(async source => {
 			if (FontFace) {
 				const fontFace = new FontFace("test-font", source.src);
@@ -206,7 +216,15 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 					await fontFace.loaded;
 					source.valid = true;
 				} catch (error) {
-					// ignored
+					const fontURL = fontURLs.get(srcDeclaration.data);
+					const fontFace = new FontFace("test-font", "url(" + fontURL + ")");
+					try {
+						await fontFace.load();
+						await fontFace.loaded;
+						source.valid = true;
+					} catch (error) {
+						// ignored
+					}
 				}
 			} else {
 				source.valid = true;
@@ -233,15 +251,6 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 			}
 		}
 		stats.fonts.discarded -= fontInfo.length;
-		const removedNodes = [];
-		for (let node = ruleData.block.children.head; node; node = node.next) {
-			if (node.data.property == "src") {
-				removedNodes.push(node);
-			}
-		}
-		removedNodes.pop();
-		removedNodes.forEach(node => ruleData.block.children.remove(node));
-		const srcDeclaration = ruleData.block.children.filter(node => node.property == "src").tail;
 		if (srcDeclaration) {
 			fontInfo.reverse();
 			try {

+ 5 - 3
lib/single-file/single-file-core.js

@@ -1107,6 +1107,7 @@ this.singlefile.lib.core = this.singlefile.lib.core || (() => {
 		}
 
 		async processStylesheets() {
+			this.options.fontURLs = new Map();
 			await Promise.all([...this.stylesheets].map(([, stylesheetInfo]) =>
 				ProcessorHelper.processStylesheet(stylesheetInfo.stylesheet.children, this.baseURI, this.options, this.cssVariables, this.batchRequest)
 			));
@@ -1195,7 +1196,7 @@ this.singlefile.lib.core = this.singlefile.lib.core || (() => {
 		}
 
 		async removeAlternativeFonts() {
-			await util.removeAlternativeFonts(this.doc, this.stylesheets);
+			await util.removeAlternativeFonts(this.doc, this.stylesheets, this.options.fontURLs);
 		}
 
 		async processFrames() {
@@ -1615,14 +1616,14 @@ this.singlefile.lib.core = this.singlefile.lib.core || (() => {
 					} else if (ruleData.type == "Atrule" && (ruleData.name == "media" || ruleData.name == "supports")) {
 						promises.push(this.processStylesheet(ruleData.block.children, baseURI, options, cssVariables, batchRequest));
 					} else if (ruleData.type == "Atrule" && ruleData.name == "font-face") {
-						promises.push(processFontFaceRule(ruleData));
+						promises.push(processFontFaceRule(ruleData, options.fontURLs));
 					}
 				}
 			}
 			removedRules.forEach(cssRule => cssRules.remove(cssRule));
 			await Promise.all(promises);
 
-			async function processFontFaceRule(ruleData) {
+			async function processFontFaceRule(ruleData, fontURLs) {
 				await Promise.all(ruleData.block.children.toArray().map(async declaration => {
 					if (declaration.type == "Declaration" && declaration.value.children) {
 						const urlFunctions = Util.getUrlFunctions(Util.getCSSValue(declaration.value), true);
@@ -1632,6 +1633,7 @@ this.singlefile.lib.core = this.singlefile.lib.core || (() => {
 							if (!Util.testIgnoredPath(resourceURL)) {
 								if (Util.testValidURL(resourceURL)) {
 									let { content } = await batchRequest.addURL(resourceURL, true);
+									fontURLs.set(declaration, resourceURL);
 									replaceURLs(declaration, originalResourceURL, content);
 								}
 							}

+ 2 - 2
lib/single-file/single-file-util.js

@@ -153,8 +153,8 @@ this.singlefile.lib.util = this.singlefile.lib.util || (() => {
 				removeUnusedFonts(doc, stylesheets, styles, options) {
 					return modules.fontsMinifier.process(doc, stylesheets, styles, options);
 				},
-				removeAlternativeFonts(doc, stylesheets) {
-					return modules.fontsAltMinifier.process(doc, stylesheets);
+				removeAlternativeFonts(doc, stylesheets, fontURLs) {
+					return modules.fontsAltMinifier.process(doc, stylesheets, fontURLs);
 				},
 				getMediaAllInfo(doc, stylesheets, styles) {
 					return modules.matchedRules.getMediaAllInfo(doc, stylesheets, styles);