Explorar el Código

refactored css-rules-matcher

Gildas hace 7 años
padre
commit
f728c52b3f

+ 54 - 55
lib/single-file/css-rules-matcher.js

@@ -112,11 +112,11 @@ this.RulesMatcher = this.RulesMatcher || (() => {
 					}
 					if (selectors) {
 						const selectorsText = selectors.map(selector => cssWhat.stringify([selector]));
+						const ruleInfo = { cssRule, mediaInfo, ruleIndex, sheetIndex, matchedSelectors: new Set(), style: new Map(), selectors, selectorsText };
 						selectors.forEach((selector, selectorIndex) => {
 							const selectorText = selectorsText[selectorIndex];
-							getMatchedElementsSelector(doc,
-								{ cssRule, mediaInfo, ruleIndex, sheetIndex, selectors, selectorsText, selector, selectorText },
-								matchedElementsCache);
+							const selectorInfo = { selector, selectorIndex, selectorText, ruleInfo };
+							getMatchedElementsSelector(doc, selectorInfo, matchedElementsCache);
 						});
 					}
 				}
@@ -127,13 +127,13 @@ this.RulesMatcher = this.RulesMatcher || (() => {
 		}
 	}
 
-	function getMatchedElementsSelector(doc, ruleData, matchedElementsCache) {
+	function getMatchedElementsSelector(doc, selectorInfo, matchedElementsCache) {
 		let selectorText;
-		const filteredSelectorText = getFilteredSelector(ruleData.selectorText);
-		if (filteredSelectorText != ruleData.selectorText) {
+		const filteredSelectorText = getFilteredSelector(selectorInfo.selectorText);
+		if (filteredSelectorText != selectorInfo.selectorText) {
 			selectorText = filteredSelectorText;
 		} else {
-			selectorText = ruleData.selectorText;
+			selectorText = selectorInfo.selectorText;
 		}
 		const cachedMatchedElements = matchedElementsCache.get(selectorText);
 		const matchedElements = cachedMatchedElements || doc.querySelectorAll(selectorText);
@@ -141,90 +141,89 @@ this.RulesMatcher = this.RulesMatcher || (() => {
 			matchedElementsCache.set(selectorText, matchedElements);
 		}
 		if (matchedElements.length) {
-			if (filteredSelectorText != ruleData.selectorText) {
-				ruleData.mediaInfo.pseudoSelectors.add(ruleData.cssRule.selectorText);
-				matchedElements.forEach(element => addPseudoRule(element, ruleData));
+			if (filteredSelectorText != selectorInfo.selectorText) {
+				selectorInfo.ruleInfo.mediaInfo.pseudoSelectors.add(selectorInfo.ruleInfo.cssRule.selectorText);
+				matchedElements.forEach(element => addPseudoRule(element, selectorInfo));
 			} else {
-				matchedElements.forEach(element => addRule(element, ruleData));
+				matchedElements.forEach(element => addRule(element, selectorInfo));
 			}
 		}
 	}
 
-	function addRule(element, ruleData) {
-		let elementInfo = ruleData.mediaInfo.elements.get(element);
+	function addRule(element, selectorInfo) {
+		const mediaInfo = selectorInfo.ruleInfo.mediaInfo;
+		let elementInfo = mediaInfo.elements.get(element);
 		if (!elementInfo) {
 			elementInfo = [];
 			const elementStyle = element.style;
 			if (elementStyle && elementStyle.length) {
-				elementInfo.push({ cssStyle: elementStyle });
+				elementInfo.push({ styleInfo: { cssStyle: elementStyle, style: new Map() } });
 			}
-			ruleData.mediaInfo.elements.set(element, elementInfo);
+			mediaInfo.elements.set(element, elementInfo);
 		}
-		const specificity = computeSpecificity(ruleData.selector);
-		specificity.ruleIndex = ruleData.ruleIndex;
-		specificity.sheetIndex = ruleData.sheetIndex;
-		ruleData.specificity = specificity;
-		elementInfo.push(ruleData);
+		const specificity = computeSpecificity(selectorInfo.selector);
+		specificity.ruleIndex = selectorInfo.ruleInfo.ruleIndex;
+		specificity.sheetIndex = selectorInfo.ruleInfo.sheetIndex;
+		selectorInfo.specificity = specificity;
+		elementInfo.push(selectorInfo);
 	}
 
-	function addPseudoRule(element, ruleData) {
-		let elementInfo = ruleData.mediaInfo.pseudos.get(element);
+	function addPseudoRule(element, selectorInfo) {
+		let elementInfo = selectorInfo.ruleInfo.mediaInfo.pseudos.get(element);
 		if (!elementInfo) {
 			elementInfo = [];
-			ruleData.mediaInfo.pseudos.set(element, elementInfo);
+			selectorInfo.ruleInfo.mediaInfo.pseudos.set(element, elementInfo);
 		}
-		elementInfo.push(ruleData);
+		elementInfo.push(selectorInfo);
 	}
 
 	function computeCascade(mediaInfo, parentMediaInfos, mediaAllInfo) {
 		mediaInfo.elements.forEach(elementInfo => getStylesInfo(elementInfo).forEach((elementStyleInfo, styleName) => {
-			let ruleInfo, ascendantMedia;
-			if (elementStyleInfo.cssRule) {
-				ascendantMedia = [mediaInfo, ...parentMediaInfos].find(media => media.rules.get(elementStyleInfo.cssRule)) || mediaInfo;
-				ruleInfo = ascendantMedia.rules.get(elementStyleInfo.cssRule);
-			} else if (mediaInfo == mediaAllInfo) {
-				ruleInfo = mediaAllInfo.styles.get(elementStyleInfo.cssStyle);
-			}
-			if (!ruleInfo) {
-				ruleInfo = { style: new Map(), matchedSelectors: new Set(), selectorsText: elementStyleInfo.selectorsText };
-			}
-			if (elementStyleInfo.cssRule) {
-				ascendantMedia.rules.set(elementStyleInfo.cssRule, ruleInfo);
-			} else if (mediaInfo == mediaAllInfo) {
-				mediaAllInfo.styles.set(elementStyleInfo.cssStyle, ruleInfo);
-			}
-			if (elementStyleInfo.selectorText) {
-				ruleInfo.matchedSelectors.add(elementStyleInfo.selectorText);
-			}
-			const styleValue = ruleInfo.style.get(styleName);
-			if (!styleValue) {
-				ruleInfo.style.set(styleName, elementStyleInfo.styleValue);
+			if (elementStyleInfo.selectorInfo.ruleInfo) {
+				const ruleInfo = elementStyleInfo.selectorInfo.ruleInfo;
+				const cssRule = ruleInfo.cssRule;
+				const ascendantMedia = [mediaInfo, ...parentMediaInfos].find(media => media.rules.get(cssRule)) || mediaInfo;
+				ascendantMedia.rules.set(cssRule, ruleInfo);
+				if (cssRule) {
+					ruleInfo.matchedSelectors.add(elementStyleInfo.selectorInfo.selectorText);
+				}
+				const styleValue = ruleInfo.style.get(styleName);
+				if (!styleValue) {
+					ruleInfo.style.set(styleName, elementStyleInfo.styleValue);
+				}
+			} else {
+				const styleInfo = elementStyleInfo.selectorInfo.styleInfo;
+				const cssStyle = styleInfo.cssStyle;
+				mediaAllInfo.styles.set(cssStyle, styleInfo);
+				const styleValue = styleInfo.style.get(styleName);
+				if (!styleValue) {
+					styleInfo.style.set(styleName, elementStyleInfo.styleValue);
+				}
 			}
 		}));
-		mediaInfo.medias.forEach(childMediaInfo => computeCascade(childMediaInfo, [mediaInfo, ...parentMediaInfos]));
+		mediaInfo.medias.forEach(childMediaInfo => computeCascade(childMediaInfo, [mediaInfo, ...parentMediaInfos], mediaAllInfo));
 	}
 
 	function getStylesInfo(elementInfo) {
 		const elementStylesInfo = new Map();
-		elementInfo.forEach(ruleInfo => {
-			if (ruleInfo.cssStyle) {
-				const cssStyle = ruleInfo.cssStyle;
+		elementInfo.forEach(selectorInfo => {
+			if (selectorInfo.styleInfo) {
+				const cssStyle = selectorInfo.styleInfo.cssStyle;
 				const stylesInfo = parseCss.parseAListOfDeclarations(cssStyle.cssText);
 				stylesInfo.forEach(styleInfo => {
 					const important = cssStyle.getPropertyPriority(styleInfo.name);
 					const styleValue = cssStyle.getPropertyValue(styleInfo.name) + (important && "!" + important);
-					elementStylesInfo.set(styleInfo.name, { styleValue, cssStyle, important });
+					elementStylesInfo.set(styleInfo.name, { selectorInfo, styleValue, important });
 				});
 			} else {
-				const cssRule = ruleInfo.cssRule;
-				const cssStyle = cssRule.style;
+				const cssStyle = selectorInfo.ruleInfo.cssRule.style;
 				const stylesInfo = parseCss.parseAListOfDeclarations(cssStyle.cssText);
 				stylesInfo.forEach(styleInfo => {
 					const important = cssStyle.getPropertyPriority(styleInfo.name);
 					const styleValue = cssStyle.getPropertyValue(styleInfo.name) + (important && "!" + important);
 					let elementStyleInfo = elementStylesInfo.get(styleInfo.name);
 					if (!elementStyleInfo || (important && !elementStyleInfo.important)) {
-						elementStylesInfo.set(styleInfo.name, { styleValue, cssRule, selectorText: ruleInfo.selectorText, selectorsText: ruleInfo.selectorsText, important });
+						elementStylesInfo.set(styleInfo.name, { selectorInfo, styleValue, important });
 					}
 				});
 			}
@@ -242,8 +241,8 @@ this.RulesMatcher = this.RulesMatcher || (() => {
 
 	function sortRules(media) {
 		media.elements.forEach(elementRules => elementRules.sort((ruleInfo1, ruleInfo2) =>
-			ruleInfo1.cssStyle && !ruleInfo2.cssStyle ? -1 :
-				!ruleInfo1.cssStyle && ruleInfo2.cssStyle ? 1 :
+			ruleInfo1.styleInfo && !ruleInfo2.styleInfo ? -1 :
+				!ruleInfo1.styleInfo && ruleInfo2.styleInfo ? 1 :
 					compareSpecificity(ruleInfo1.specificity, ruleInfo2.specificity)));
 		media.medias.forEach(sortRules);
 	}

+ 23 - 19
lib/single-file/css-rules-minifier.js

@@ -94,30 +94,34 @@ this.cssMinifier = this.cssMinifier || (() => {
 
 	function processRuleInfo(cssRule, ruleInfo) {
 		let selectorText = "", styleCssText = "";
-		if (ruleInfo) {
-			const stylesInfo = parseCss.parseAListOfDeclarations(cssRule.style.cssText);
-			for (let styleIndex = 0; styleIndex < stylesInfo.length; styleIndex++) {
-				const style = stylesInfo[styleIndex];
-				if (ruleInfo.style.get(style.name)) {
-					if (styleCssText) {
-						styleCssText += ";";
-					}
-					const priority = cssRule.style.getPropertyPriority(style.name);
-					styleCssText += style.name + ":" + cssRule.style.getPropertyValue(style.name) + (priority && ("!" + priority));
+		const stylesInfo = parseCss.parseAListOfDeclarations(cssRule.style.cssText);
+		for (let styleIndex = 0; styleIndex < stylesInfo.length; styleIndex++) {
+			const style = stylesInfo[styleIndex];
+			if (ruleInfo.style.get(style.name)) {
+				if (styleCssText) {
+					styleCssText += ";";
 				}
+				const priority = cssRule.style.getPropertyPriority(style.name);
+				styleCssText += style.name + ":" + cssRule.style.getPropertyValue(style.name) + (priority && ("!" + priority));
 			}
-			if (ruleInfo.matchedSelectors.size < ruleInfo.selectorsText.length) {
-				for (let selectorTextIndex = 0; selectorTextIndex < ruleInfo.selectorsText.length; selectorTextIndex++) {
-					const ruleSelectorText = ruleInfo.selectorsText[selectorTextIndex];
-					if (ruleInfo.matchedSelectors.has(ruleSelectorText)) {
-						if (selectorText) {
-							selectorText += ", ";
-						}
-						selectorText += ruleSelectorText;
+		}
+		if (ruleInfo.matchedSelectors.size < ruleInfo.selectorsText.length) {
+			const newSelectors = [];
+			const newSelectorsText = [];
+			for (let selectorTextIndex = 0; selectorTextIndex < ruleInfo.selectorsText.length; selectorTextIndex++) {
+				const ruleSelectorText = ruleInfo.selectorsText[selectorTextIndex];
+				if (ruleInfo.matchedSelectors.has(ruleSelectorText)) {
+					if (selectorText) {
+						selectorText += ", ";
 					}
+					newSelectors.push(ruleInfo.selectors[selectorTextIndex]);
+					newSelectorsText.push(ruleSelectorText);
+					selectorText += ruleSelectorText;
 				}
-				cssRule.selectorText = selectorText;
 			}
+			cssRule.selectorText = selectorText; // needed for images minifier
+			ruleInfo.selectorsText = newSelectorsText;
+			ruleInfo.selectors = newSelectors;
 		}
 		return (selectorText || cssRule.selectorText) + "{" + (styleCssText || cssRule.style.cssText) + "}";
 	}

+ 4 - 9
lib/single-file/doc-helper.js

@@ -193,26 +193,21 @@ this.docHelper = this.docHelper || (() => {
 
 	function getSize(imageElement) {
 		const computedStyle = getComputedStyle(imageElement);
-		let width, height, paddingLeft, paddingRight, paddingTop, paddingBottom, borderLeftWidth, borderRightWidth, borderTopWidth, borderBottomWidth;
+		let width, height, paddingLeft, paddingRight, paddingTop, paddingBottom;
 		if (computedStyle.getPropertyValue("box-sizing") == "border-box") {
 			paddingLeft = paddingRight = paddingTop = paddingBottom = 0;
-			borderLeftWidth = borderRightWidth = borderTopWidth = borderBottomWidth = 0;
 		} else {
 			paddingLeft = getWidth("padding-left", computedStyle);
 			paddingRight = getWidth("padding-right", computedStyle);
 			paddingTop = getWidth("padding-top", computedStyle);
 			paddingBottom = getWidth("padding-bottom", computedStyle);
-			borderLeftWidth = getWidth("border-left-width", computedStyle);
-			borderRightWidth = getWidth("border-right-width", computedStyle);
-			borderTopWidth = getWidth("border-top-width", computedStyle);
-			borderBottomWidth = getWidth("border-bottom-width", computedStyle);
 		}
 		width = imageElement.clientWidth;
 		height = imageElement.clientHeight;
-		if (width >= 0 && height >= 0 && paddingLeft >= 0 && paddingRight >= 0 && paddingTop >= 0 && paddingBottom >= 0 && borderLeftWidth >= 0 && borderRightWidth >= 0 && borderTopWidth >= 0 && borderBottomWidth >= 0) {
+		if (width >= 0 && height >= 0 && paddingLeft >= 0 && paddingRight >= 0 && paddingTop >= 0 && paddingBottom >= 0) {
 			return {
-				width: width - paddingLeft - paddingRight - borderLeftWidth - borderRightWidth,
-				height: height - paddingTop - paddingBottom - borderTopWidth - borderBottomWidth
+				width: width - paddingLeft - paddingRight,
+				height: height - paddingTop - paddingBottom
 			};
 		}
 	}

+ 81 - 36
lib/single-file/html-images-minifier.js

@@ -25,11 +25,20 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 	const DEBUG = false;
 	const SVG_NS = "http://www.w3.org/2000/svg";
 	const PREFIX_DATA_URI_IMAGE_SVG = "data:image/svg+xml";
-	const TRANSFORMED_IMAGE_ATTRIBUTE = "data-single-file-image-transform";
-	const IGNORED_ATTRIBUTES = ["src", "viewBox", "preserveAspectRatio", "xlink:href"];
+	const SINGLE_FILE_IMAGE_ATTRIBUTE = "single-file-ref";
+	const IGNORED_ATTRIBUTES = ["src", "viewBox", "preserveAspectRatio", "xlink:href", "title", "class"];
+	const SINGLE_FILE_SELECTOR = {
+		type: "attribute",
+		action: "exists",
+		ignoreCase: false,
+		name: SINGLE_FILE_IMAGE_ATTRIBUTE,
+		value: ""
+	};
 
 	return {
 		process: (doc, mediaAllInfo, options) => {
+			const matchedImageSelectors = new Map();
+			getImageRuleInfos(mediaAllInfo, matchedImageSelectors);
 			const imageGroups = getImageGroups(doc);
 			let duplicates = new Set();
 			const duplicateURLs = [];
@@ -40,12 +49,12 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 				}
 			});
 			if (duplicateURLs.length) {
-				processStyleSheets(doc, duplicates, mediaAllInfo);
+				processStyleSheets(doc, duplicates, mediaAllInfo, matchedImageSelectors);
 				processImages(doc, duplicates, duplicateURLs, options);
 			}
 		},
 		postProcess(doc) {
-			doc.querySelectorAll("svg[" + TRANSFORMED_IMAGE_ATTRIBUTE + "]").forEach(svgElement => {
+			doc.querySelectorAll("svg[" + SINGLE_FILE_IMAGE_ATTRIBUTE + "]").forEach(svgElement => {
 				const useElement = svgElement.childNodes[0];
 				if (useElement) {
 					const refImageId = useElement.getAttribute("xlink:href").substring(1);
@@ -54,13 +63,37 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 						if (refImageElement && refImageElement.getAttribute("xlink:href").startsWith(PREFIX_DATA_URI_IMAGE_SVG)) {
 							svgElement.removeAttributeNS(SVG_NS, "preserveAspectRatio");
 						}
-						svgElement.removeAttribute(TRANSFORMED_IMAGE_ATTRIBUTE);
 					}
 				}
 			});
 		}
 	};
 
+	function getImageRuleInfos(parentMediaInfo, matchedImageSelectors) {
+		parentMediaInfo.elements.forEach((elementInfo, element) => {
+			const tagName = element.tagName.toLowerCase();
+			if (tagName == "img" || tagName == "svg") {
+				elementInfo.forEach(selectorInfo => {
+					if (selectorInfo.selector) {
+						let selector = JSON.parse(JSON.stringify(selectorInfo.selector));
+						selector.push({
+							type: "pseudo",
+							name: "not",
+							data: [[SINGLE_FILE_SELECTOR]]
+						});
+						const selectors = matchedImageSelectors.get(selectorInfo.ruleInfo.cssRule.selectorText) || JSON.parse(JSON.stringify(selectorInfo.ruleInfo.selectors));
+						selectors[selectorInfo.selectorIndex] = selector;
+						selector = JSON.parse(JSON.stringify(selectorInfo.selector));
+						selector.push(SINGLE_FILE_SELECTOR);
+						selectors.push(selector);
+						matchedImageSelectors.set(selectorInfo.ruleInfo.cssRule.selectorText, selectors);
+					}
+				});
+			}
+		});
+		parentMediaInfo.medias.forEach(mediaInfo => getImageRuleInfos(mediaInfo, matchedImageSelectors));
+	}
+
 	function getImageGroups(doc) {
 		const imageGroups = new Map();
 		doc.querySelectorAll("img[src]:not([srcset])").forEach(imageElement => {
@@ -76,7 +109,7 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 		return imageGroups;
 	}
 
-	function processStyleSheets(doc, duplicates, mediaAllInfo) {
+	function processStyleSheets(doc, duplicates, mediaAllInfo, matchedImageSelectors) {
 		const matchedSelectors = getMatchedSelectors(duplicates, mediaAllInfo);
 		doc.querySelectorAll("style").forEach((styleElement, sheetIndex) => {
 			if (styleElement.sheet) {
@@ -87,7 +120,7 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 				} else {
 					mediaInfo = mediaAllInfo;
 				}
-				styleElement.textContent = processRules(doc, cssRules, sheetIndex, mediaInfo, matchedSelectors);
+				styleElement.textContent = processRules(doc, cssRules, sheetIndex, mediaInfo, matchedSelectors, matchedImageSelectors);
 			}
 		});
 	}
@@ -123,21 +156,22 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 						const useElement = doc.createElementNS(SVG_NS, "use");
 						svgElement.appendChild(useElement);
 						imgElement.getAttributeNames().forEach(attributeName => {
-							try {
-								if (!IGNORED_ATTRIBUTES.includes(attributeName)) {
-									svgElement.setAttribute(attributeName, imgElement.getAttribute(attributeName));
-								}
-							} catch (error) {
-								if (!IGNORED_ATTRIBUTES.includes(attributeName)) {
-									try {
-										svgElement.setAttributeNS(SVG_NS, attributeName, imgElement.getAttribute(attributeName));
-									} catch (error) {
-										/* ignored */
-									}
+							if (!IGNORED_ATTRIBUTES.concat([docHelper.imagesAttributeName(options.sessionId)]).includes(attributeName)) {
+								try {
+									svgElement.setAttributeNS(SVG_NS, attributeName, imgElement.getAttribute(attributeName));
+								} catch (error) {
+									/* ignored */
 								}
 							}
 						});
-						svgElement.setAttribute(TRANSFORMED_IMAGE_ATTRIBUTE, "");
+						svgElement.setAttribute("class", imgElement.getAttribute("class"));
+						const title = imgElement.getAttribute("title");
+						if (title) {
+							const titleElement = doc.createElementNS(SVG_NS, "title");
+							titleElement.textContent = title;
+							svgElement.appendChild(titleElement);
+						}
+						svgElement.setAttribute(SINGLE_FILE_IMAGE_ATTRIBUTE, "");
 						svgElement.setAttributeNS(SVG_NS, "viewBox", "0 0 " + width + " " + height);
 						svgElement.setAttributeNS(SVG_NS, "width", imageData.clientWidth);
 						svgElement.setAttributeNS(SVG_NS, "height", imageData.clientHeight);
@@ -165,16 +199,16 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 
 	function getMatchedSelectors(duplicates, parentMediaInfo, matchedRules = new Map()) {
 		duplicates.forEach(imageElement => {
-			let elementInfos = parentMediaInfo.elements.get(imageElement);
-			if (!elementInfos) {
-				elementInfos = parentMediaInfo.pseudos.get(imageElement);
+			let elementInfo = parentMediaInfo.elements.get(imageElement);
+			if (!elementInfo) {
+				elementInfo = parentMediaInfo.pseudos.get(imageElement);
 			}
-			if (elementInfos) {
-				elementInfos.forEach(elementInfo => {
-					if (elementInfo.cssRule) {
-						let selectorInfo = matchedRules.get(elementInfo.cssRule.selectorText);
-						if (!selectorInfo) {
-							matchedRules.set(elementInfo.cssRule.selectorText, elementInfo.selectors);
+			if (elementInfo) {
+				elementInfo.forEach(elementInfo => {
+					if (elementInfo.ruleInfo) {
+						let selectors = matchedRules.get(elementInfo.selectorText);
+						if (!selectors) {
+							matchedRules.set(elementInfo.ruleInfo.cssRule.selectorText, elementInfo.ruleInfo.selectors);
 						}
 					}
 				});
@@ -184,7 +218,7 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 		return matchedRules;
 	}
 
-	function processRules(doc, cssRules, sheetIndex, mediaInfo, matchedSelectors) {
+	function processRules(doc, cssRules, sheetIndex, mediaInfo, matchedSelectors, matchedImageSelectors) {
 		let sheetContent = "", mediaRuleIndex = 0;
 		let startTime;
 		if (DEBUG && cssRules.length > 1) {
@@ -194,14 +228,16 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 		Array.from(cssRules).forEach(cssRule => {
 			if (cssRule.type == CSSRule.MEDIA_RULE) {
 				sheetContent += "@media " + Array.from(cssRule.media).join(",") + "{";
-				sheetContent += processRules(doc, cssRule.cssRules, sheetIndex, mediaInfo.medias.get("rule-" + sheetIndex + "-" + mediaRuleIndex + "-" + cssRule.media.mediaText), matchedSelectors);
+				sheetContent += processRules(doc, cssRule.cssRules, sheetIndex, mediaInfo.medias.get("rule-" + sheetIndex + "-" + mediaRuleIndex + "-" + cssRule.media.mediaText), matchedSelectors, matchedImageSelectors);
 				mediaRuleIndex++;
 				sheetContent += "}";
 			} else if (cssRule.type == CSSRule.STYLE_RULE) {
-				const selectors = matchedSelectors.get(cssRule.selectorText);
-				if (selectors) {
+				const imageSelectors = matchedImageSelectors.get(cssRule.selectorText);
+				let selectors = matchedSelectors.get(cssRule.selectorText);
+				if (imageSelectors || selectors) {
+					selectors = imageSelectors || selectors;
 					selectors.forEach(selector => {
-						const newSelector = transformSelector(selector);
+						const newSelector = getSVGSelector(selector);
 						if (newSelector) {
 							selectors.push(newSelector);
 						}
@@ -220,18 +256,27 @@ this.imagesMinifier = this.imagesMinifier || (() => {
 		return sheetContent;
 	}
 
-	function transformSelector(selector) {
+	function getSVGSelector(selector) {
 		selector = JSON.parse(JSON.stringify(selector));
 		let simpleSelector, selectorIndex = selector.length - 1, imageTagFound;
 		while (selectorIndex >= 0 && !imageTagFound) {
 			simpleSelector = selector[selectorIndex];
-			imageTagFound = simpleSelector.type == "tag" && simpleSelector.name == "img";
-			if (!imageTagFound) {
+			if (simpleSelector.type == "pseudo" && simpleSelector.name == "not") {
+				const negatedSelector = simpleSelector.data[0][0];
+				if (negatedSelector.type == SINGLE_FILE_SELECTOR.type && negatedSelector.action == SINGLE_FILE_SELECTOR.action && negatedSelector.name == SINGLE_FILE_SELECTOR.name) {
+					selector.splice(selectorIndex, 1);
+				}
 				selectorIndex--;
+			} else {
+				imageTagFound = simpleSelector.type == "tag" && simpleSelector.name == "img";
+				if (!imageTagFound) {
+					selectorIndex--;
+				}
 			}
 		}
 		if (imageTagFound) {
 			simpleSelector.name = "svg";
+			selector.splice(selectorIndex + 1, 0, SINGLE_FILE_SELECTOR);
 			return selector;
 		}
 	}