Procházet zdrojové kódy

validate fonts when removing alternate ones

Former-commit-id: a2bf8de7200243452adead026fdaa0982dc60fde
Gildas před 6 roky
rodič
revize
8203518c0f

+ 31 - 15
lib/single-file/modules/css-fonts-alt-minifier.js

@@ -21,10 +21,14 @@
  *   Source.
  */
 
+/* global window */
+
 this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fontsAltMinifier || (() => {
 
 	const singlefile = this.singlefile;
 
+	const FontFace = window.FontFace;
+
 	const REGEXP_URL_SIMPLE_QUOTES_FN = /url\s*\(\s*'(.*?)'\s*\)/i;
 	const REGEXP_URL_DOUBLE_QUOTES_FN = /url\s*\(\s*"(.*?)"\s*\)/i;
 	const REGEXP_URL_NO_QUOTES_FN = /url\s*\(\s*(.*?)\s*\)/i;
@@ -57,7 +61,7 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 	};
 
 	return {
-		process: (doc, stylesheets) => {
+		process: async (doc, stylesheets) => {
 			const fontsDetails = {
 				fonts: new Map(),
 				medias: new Map(),
@@ -81,20 +85,18 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 				sheetIndex++;
 			});
 			processFontDetails(fontsDetails);
-			sheetIndex = 0;
-			stylesheets.forEach(stylesheetInfo => {
+			await Promise.all([...stylesheets].map(async ([, stylesheetInfo], sheetIndex) => {
 				const cssRules = stylesheetInfo.stylesheet.children;
 				const media = stylesheetInfo.mediaText;
 				if (cssRules) {
 					if (media && media != MEDIA_ALL) {
-						processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + media), stats);
+						await processFontFaceRules(cssRules, sheetIndex, fontsDetails.medias.get("media-" + sheetIndex + "-" + media), stats);
 					} else {
-						processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats);
+						await processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats);
 					}
 					stats.rules.discarded -= cssRules.getSize();
 				}
-				sheetIndex++;
-			});
+			}));
 			return stats;
 		}
 	};
@@ -168,7 +170,7 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 		fontsDetails.medias.forEach(mediaFontsDetails => processFontDetails(mediaFontsDetails));
 	}
 
-	function processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats) {
+	async function processFontFaceRules(cssRules, sheetIndex, fontsDetails, stats) {
 		const cssTree = singlefile.lib.vendor.cssTree;
 		const removedRules = [];
 		let mediaIndex = 0, supportsIndex = 0;
@@ -176,17 +178,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);
-				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), stats);
 				mediaIndex++;
 			} else if (ruleData.type == "Atrule" && ruleData.name == "supports" && ruleData.block && ruleData.block.children && ruleData.prelude) {
 				const supportsText = cssTree.generate(ruleData.prelude);
-				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), 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));
-					processFontFaceRule(ruleData, fontInfo, stats);
+					await processFontFaceRule(ruleData, fontInfo, stats);
 				} else {
 					removedRules.push(cssRule);
 				}
@@ -195,17 +197,31 @@ this.singlefile.lib.modules.fontsAltMinifier = this.singlefile.lib.modules.fonts
 		removedRules.forEach(cssRule => cssRules.remove(cssRule));
 	}
 
-	function processFontFaceRule(ruleData, fontInfo, stats) {
+	async function processFontFaceRule(ruleData, fontInfo, stats) {
 		const cssTree = singlefile.lib.vendor.cssTree;
-		const findSource = fontFormat => fontInfo.find(source => !source.src.match(EMPTY_URL_SOURCE) && !source.src.match(TEXT_CONTENT_URL_SOURCE) && source.format == fontFormat);
+		await Promise.all(fontInfo.map(async source => {
+			if (FontFace) {
+				const fontFace = new FontFace("test-font", source.src);
+				try {
+					await fontFace.load();
+					await fontFace.loaded;
+					source.valid = true;
+				} catch (error) {
+					// ignored
+				}
+			} else {
+				source.valid = true;
+			}
+		}));
+		const findSource = (fontFormat, testValidity) => fontInfo.find(source => !source.src.match(EMPTY_URL_SOURCE) && !source.src.match(TEXT_CONTENT_URL_SOURCE) && source.format == fontFormat && (!testValidity || source.valid));
 		const filterSource = fontSource => fontInfo.filter(source => source == fontSource || source.src.startsWith(LOCAL_SOURCE));
 		stats.fonts.processed += fontInfo.length;
 		stats.fonts.discarded += fontInfo.length;
-		const woffFontFound = findSource("woff2-variations") || findSource("woff2") || findSource("woff");
+		const woffFontFound = findSource("woff2-variations", true) || findSource("woff2", true) || findSource("woff", true);
 		if (woffFontFound) {
 			fontInfo = filterSource(woffFontFound);
 		} else {
-			const ttfFontFound = findSource("truetype-variations") || findSource("truetype");
+			const ttfFontFound = findSource("truetype-variations", true) || findSource("truetype", true);
 			if (ttfFontFound) {
 				fontInfo = filterSource(ttfFontFound);
 			} else {

+ 4 - 4
lib/single-file/single-file-core.js

@@ -125,10 +125,10 @@ this.singlefile.lib.core = this.singlefile.lib.core || (() => {
 		]
 	}, {
 		sequential: [
-			{ option: "removeAlternativeImages", action: "removeAlternativeImages" },
-			{ option: "removeAlternativeFonts", action: "removeAlternativeFonts" }
+			{ option: "removeAlternativeImages", action: "removeAlternativeImages" }			
 		],
 		parallel: [
+			{ option: "removeAlternativeFonts", action: "removeAlternativeFonts" },
 			{ option: "!removeFrames", action: "processFrames" },
 			{ option: "!removeImports", action: "processHtmlImports" },
 		]
@@ -1136,8 +1136,8 @@ this.singlefile.lib.core = this.singlefile.lib.core || (() => {
 			util.removeAlternativeImages(this.doc);
 		}
 
-		removeAlternativeFonts() {
-			util.removeAlternativeFonts(this.doc, this.stylesheets);
+		async removeAlternativeFonts() {
+			await util.removeAlternativeFonts(this.doc, this.stylesheets);
 		}
 
 		async processFrames() {