Просмотр исходного кода

take unicode ranges into account when removing unused fonts

Gildas 7 лет назад
Родитель
Сommit
91f68825ab

+ 44 - 5
lib/single-file/fonts-minifier.js

@@ -27,7 +27,7 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 	const REGEXP_URL_NO_QUOTES_FN = /url\s*\(\s*(.*?)\s*\)/i;
 
 	return {
-		process: (doc, removeUnusedCSSRules) => {
+		process: (doc, removeUnusedCSSRules, secondPass) => {
 			const declaredFonts = new Set();
 			const usedFonts = new Set();
 			const stats = {
@@ -44,7 +44,7 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 				if (style.sheet) {
 					const processedRules = style.sheet.cssRules.length;
 					stats.rules.processed += processedRules;
-					style.textContent = processRules(doc, style.sheet.cssRules, declaredFonts, usedFonts, removeUnusedCSSRules, stats);
+					style.textContent = processRules(doc, style.sheet.cssRules, declaredFonts, usedFonts, removeUnusedCSSRules, stats, secondPass);
 					stats.rules.discarded += processedRules - style.sheet.cssRules.length;
 				}
 			});
@@ -67,13 +67,13 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 		}
 	};
 
-	function processRules(doc, rules, declaredFonts, usedFonts, removeUnusedCSSRules, stats) {
+	function processRules(doc, rules, declaredFonts, usedFonts, removeUnusedCSSRules, stats, secondPass) {
 		let stylesheetContent = "";
 		if (rules) {
 			Array.from(rules).forEach(rule => {
 				if (rule.type == CSSRule.MEDIA_RULE) {
 					stylesheetContent += "@media " + Array.prototype.join.call(rule.media, ",") + " {";
-					stylesheetContent += processRules(doc, rule.cssRules, declaredFonts, usedFonts, removeUnusedCSSRules, stats);
+					stylesheetContent += processRules(doc, rule.cssRules, declaredFonts, usedFonts, removeUnusedCSSRules, stats, secondPass);
 					stylesheetContent += "}";
 				} else if (removeUnusedCSSRules && rule.type == CSSRule.STYLE_RULE) {
 					if (rule.style && rule.style.fontFamily) {
@@ -91,7 +91,11 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 						if (src) {
 							const fontSources = src.match(/url\(.*?\)\s*(,|$)/g);
 							if (fontSources) {
-								cssText = processFontFaceRule(rule, fontSources, stats);
+								if (secondPass || testUnicodeRange(doc, rule)) {
+									cssText = processFontFaceRule(rule, fontSources, stats);
+								} else {
+									cssText = "";
+								}
 							}
 						}
 					}
@@ -102,6 +106,41 @@ this.fontsMinifier = this.fontsMinifier || (() => {
 		return stylesheetContent;
 	}
 
+	function testUnicodeRange(doc, rule) {
+		const unicodeRange = rule.style.getPropertyValue("unicode-range");
+		const docContent = doc.body.outerText;
+		if (unicodeRange) {
+			const unicodeRanges = unicodeRange.split(/\s*,\s*/);
+			const result = unicodeRanges.filter(rangeValue => {
+				const range = rangeValue.split(/-/);
+				if (range.length == 2) {
+					range[0] = transformRange(range[0]);
+					const regExpString = "[" + range[0] + "-\\u" + range[1] + "]";
+					return (new RegExp(regExpString)).test(docContent);
+				}
+				if (range.length == 1) {
+					if (range[0].includes("?")) {
+						const firstRange = transformRange(range[0]);
+						const secondRange = firstRange;
+						const regExpString = "[" + firstRange.replace(/\?/g, "0") + "-" + secondRange.replace(/\?/g, "F") + "]";
+						return (new RegExp(regExpString)).test(docContent);
+
+					} else {
+						const regExpString = "[" + transformRange(range[0]) + "]";
+						return (new RegExp(regExpString)).test(docContent);
+					}
+				}
+				return true;
+			});
+			return result.length;
+		}
+		return true;
+	}
+
+	function transformRange(range) {
+		return range.replace(/^U\+/i, "\\u");
+	}
+
 	function processFontFaceRule(rule, fontSources, stats) {
 		fontSources = fontSources.map(fontSrc => {
 			const fontFormatMatch = fontSrc.match(/format\((.*?)\)\s*,?$/);

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

@@ -129,8 +129,8 @@ this.SingleFile = this.SingleFile || (() => {
 			return rulesMinifier.process(doc);
 		}
 
-		static fontsMinifier(doc, removeUnusedCSSRules) {
-			return fontsMinifier.process(doc, removeUnusedCSSRules);
+		static fontsMinifier(doc, removeUnusedCSSRules, secondPass) {
+			return fontsMinifier.process(doc, removeUnusedCSSRules, secondPass);
 		}
 
 		static uglifycss(content, options) {

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

@@ -157,7 +157,7 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 				this.processor.lazyLoadImages();
 			}
 			if (this.options.removeAlternativeFonts) {
-				this.processor.removeAlternativeFonts();
+				this.processor.removeAlternativeFonts(true);
 			}
 			if (!this.options.removeFrames) {
 				await this.processor.frames();
@@ -398,8 +398,8 @@ this.SingleFileCore = this.SingleFileCore || (() => {
 			this.stats.set("discarded", "cssRules", removedRules.discarded);
 		}
 
-		removeAlternativeFonts() {
-			DOM.fontsMinifier(this.doc, this.options.removeUnusedCSSRules);
+		removeAlternativeFonts(secondPass) {
+			DOM.fontsMinifier(this.doc, this.options.removeUnusedCSSRules, secondPass);
 		}
 
 		removeHiddenElements(sessionId) {