diff --git a/src/Minifier.php b/src/Minifier.php index 9e58577..ad7aecc 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->restoreUnquotedFontTokens($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 restoreUnquotedFontTokens($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