From f9212997c94e835fa14f1dac3b31b48f0b3375c1 Mon Sep 17 00:00:00 2001 From: zyt Date: Mon, 1 Oct 2018 16:22:02 +0200 Subject: [PATCH 1/3] Prevent unquoted font family names that match color names from being replaced --- src/Minifier.php | 45 +++++++++++++++++++++--- tests/MinifierTest.php | 5 +++ tests/expectations/font-family-color.css | 1 + tests/fixtures/font-family-color.css | 2 ++ 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 tests/expectations/font-family-color.css create mode 100644 tests/fixtures/font-family-color.css diff --git a/src/Minifier.php b/src/Minifier.php index 9e58577..51f7911 100644 --- a/src/Minifier.php +++ b/src/Minifier.php @@ -29,28 +29,30 @@ class Minifier const COMMENT_TOKEN_START = '_CSSMIN_CMT_'; const RULE_BODY_TOKEN = '_CSSMIN_RBT_%d_'; const PRESERVED_TOKEN = '_CSSMIN_PTK_%d_'; - + const UNQUOTED_FONT_TOKEN = '_CSSMIN_UFT_%d_'; + // Token lists private $comments = array(); private $ruleBodies = array(); private $preservedTokens = array(); - + private $unquotedFontTokens = array(); + // Output options private $keepImportantComments = true; private $keepSourceMapComment = false; private $linebreakPosition = 0; - + // PHP ini limits private $raisePhpLimits; private $memoryLimit; private $maxExecutionTime = 60; // 1 min private $pcreBacktrackLimit; private $pcreRecursionLimit; - + // Color maps private $hexToNamedColorsMap; private $namedToHexColorsMap; - + // Regexes private $numRegex; private $charsetRegex = '/@charset [^;]+;/Si'; @@ -62,6 +64,7 @@ class Minifier private $shortenThreeZeroesRegex; private $shortenFourZeroesRegex; private $unitsGroupRegex = '(?:ch|cm|em|ex|gd|in|mm|px|pt|pc|q|rem|vh|vmax|vmin|vw|%)'; + private $unquotedFontsRegex = '/(font-family:|font:)([^ \'"]+?)[^}]*/Si'; /** * @param bool|int $raisePhpLimits If true, PHP settings will be raised if needed @@ -287,6 +290,17 @@ private function registerRuleBodyToken($body) return $tokenId; } + private function registerUnquotedFontToken($body) + { + if (empty($body)) { + return ''; + } + + $tokenId = sprintf(self::UNQUOTED_FONT_TOKEN, count($this->unquotedFontTokens)); + $this->unquotedFontTokens[$tokenId] = $body; + return $tokenId; + } + /** * Parses & minifies the given input CSS string * @param string $css @@ -600,6 +614,14 @@ private function processRuleBody($body) $body ); + // Tokenize unquoted font names in order to hide them from + // color name replacements. + $body = preg_replace_callback( + $this->unquotedFontsRegex, + array($this, 'preserveUnquotedFontTokens'), + $body + ); + // Shorten long named colors with a shorter HEX counterpart: white -> #fff. // Run at least 2 times to cover most cases $body = preg_replace_callback( @@ -608,6 +630,9 @@ private function processRuleBody($body) $body ); + // Restore unquoted font tokens now after colors have been changed. + $body = $this->restoreUnqoutedFontTokens($body); + // Replace positive sign from numbers before the leading space is removed. // +1.2em to 1.2em, +.8px to .8px, +2% to 2% $body = preg_replace('/([ :,(])\+(\.?\d+)/S', '$1$2', $body); @@ -695,6 +720,16 @@ private function processRuleBody($body) return $body; } + private function preserveUnquotedFontTokens($matches) + { + return $this->registerUnquotedFontToken($matches[0]); + } + + private function restoreUnqoutedFontTokens($body) + { + return strtr($body, $this->unquotedFontTokens); + } + /** * Compresses At-rules and selectors. * @param string $css the whole stylesheet with rule bodies tokenized. diff --git a/tests/MinifierTest.php b/tests/MinifierTest.php index 5ad31aa..4d37072 100644 --- a/tests/MinifierTest.php +++ b/tests/MinifierTest.php @@ -172,6 +172,11 @@ public function testFontWeightProperty() $this->execTest('font-weight'); } + public function testFontFamilyColor() + { + $this->execTest('font-family-color'); + } + public function testImportantRule() { $this->execTest('important'); diff --git a/tests/expectations/font-family-color.css b/tests/expectations/font-family-color.css new file mode 100644 index 0000000..8ac68e2 --- /dev/null +++ b/tests/expectations/font-family-color.css @@ -0,0 +1 @@ +.full-width-content .nectar-recent-posts-slider{font:italic 1.2em Fira White,serif}.recent-post-container .inner-wrap h2{font-family:Archivo Black;text-transform:capitalize;letter-spacing:0;font-size:60px;line-height:74px;font-weight:400} \ No newline at end of file diff --git a/tests/fixtures/font-family-color.css b/tests/fixtures/font-family-color.css new file mode 100644 index 0000000..70931f8 --- /dev/null +++ b/tests/fixtures/font-family-color.css @@ -0,0 +1,2 @@ +.full-width-content .nectar-recent-posts-slider{font: italic 1.2em Fira White, serif;} +.recent-post-container .inner-wrap h2{font-family:Archivo Black;text-transform:capitalize;letter-spacing:0;font-size:60px;line-height:74px;font-weight:400;} \ No newline at end of file From 6543779773721a98c0e180010a91c9a82c2218f1 Mon Sep 17 00:00:00 2001 From: zyt Date: Mon, 1 Oct 2018 16:49:35 +0200 Subject: [PATCH 2/3] minor tweak to the unquoted fonts regex to not grab too much stuff can probably be improved further... --- src/Minifier.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Minifier.php b/src/Minifier.php index 51f7911..aa19894 100644 --- a/src/Minifier.php +++ b/src/Minifier.php @@ -64,7 +64,7 @@ class Minifier private $shortenThreeZeroesRegex; private $shortenFourZeroesRegex; private $unitsGroupRegex = '(?:ch|cm|em|ex|gd|in|mm|px|pt|pc|q|rem|vh|vmax|vmin|vw|%)'; - private $unquotedFontsRegex = '/(font-family:|font:)([^ \'"]+?)[^}]*/Si'; + private $unquotedFontsRegex = '/(font-family:|font:)([^\'"]+?)[^};]*/Si'; /** * @param bool|int $raisePhpLimits If true, PHP settings will be raised if needed From 45b44e0d9cd306d17eae722cc888ad0f47b2949a Mon Sep 17 00:00:00 2001 From: zyt Date: Mon, 1 Oct 2018 17:13:34 +0200 Subject: [PATCH 3/3] fix typo in method name: restoreUnqoutedFontTokens -> restoreUnquotedFontTokens --- src/Minifier.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Minifier.php b/src/Minifier.php index aa19894..ad7aecc 100644 --- a/src/Minifier.php +++ b/src/Minifier.php @@ -631,7 +631,7 @@ private function processRuleBody($body) ); // Restore unquoted font tokens now after colors have been changed. - $body = $this->restoreUnqoutedFontTokens($body); + $body = $this->restoreUnquotedFontTokens($body); // Replace positive sign from numbers before the leading space is removed. // +1.2em to 1.2em, +.8px to .8px, +2% to 2% @@ -725,7 +725,7 @@ private function preserveUnquotedFontTokens($matches) return $this->registerUnquotedFontToken($matches[0]); } - private function restoreUnqoutedFontTokens($body) + private function restoreUnquotedFontTokens($body) { return strtr($body, $this->unquotedFontTokens); }