PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.7.0
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.7.0
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / mrclay / minify / lib / Minify / CSS / Compressor.php

Compressor.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.7.0, at vendor/mrclay/minify/lib/Minify/CSS/Compressor.php

276 lines 8.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class Minify_CSS_Compressor
4 * @package Minify
5 */
6
7 /**
8 * Compress CSS
9 *
10 * This is a heavy regex-based removal of whitespace, unnecessary
11 * comments and tokens, and some CSS value minimization, where practical.
12 * Many steps have been taken to avoid breaking comment-based hacks,
13 * including the ie5/mac filter (and its inversion), but expect tricky
14 * hacks involving comment tokens in 'content' value strings to break
15 * minimization badly. A test suite is available.
16 *
17 * Note: This replaces a lot of spaces with line breaks. It's rumored
18 * (https://github.com/yui/yuicompressor/blob/master/README.md#global-options)
19 * that some source control tools and old browsers don't like very long lines.
20 * Compressed files with shorter lines are also easier to diff. If this is
21 * unacceptable please use CSSmin instead.
22 *
23 * @package Minify
24 * @author Stephen Clay <[email protected]>
25 * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
26 *
27 * @deprecated Use CSSmin (tubalmartin/cssmin)
28 */
29 class Minify_CSS_Compressor
30 {
31
32 /**
33 * Minify a CSS string
34 *
35 * @param string $css
36 *
37 * @param array $options (currently ignored)
38 *
39 * @return string
40 */
41 public static function process($css, $options = array())
42 {
43 $obj = new Minify_CSS_Compressor($options);
44
45 return $obj->_process($css);
46 }
47
48 /**
49 * @var array
50 */
51 protected $_options = null;
52
53 /**
54 * Are we "in" a hack? I.e. are some browsers targetted until the next comment?
55 *
56 * @var bool
57 */
58 protected $_inHack = false;
59
60 /**
61 * Constructor
62 *
63 * @param array $options (currently ignored)
64 */
65 private function __construct($options)
66 {
67 $this->_options = $options;
68 }
69
70 /**
71 * Minify a CSS string
72 *
73 * @param string $css
74 *
75 * @return string
76 */
77 protected function _process($css)
78 {
79 $css = str_replace("\r\n", "\n", $css);
80
81 // preserve empty comment after '>'
82 // http://www.webdevout.net/css-hacks#in_css-selectors
83 $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
84
85 // preserve empty comment between property and value
86 // http://css-discuss.incutio.com/?page=BoxModelHack
87 $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
88 $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
89
90 // apply callback to all valid comments (and strip out surrounding ws
91 $pattern = '@\\s*/\\*([\\s\\S]*?)\\*/\\s*@';
92 $css = preg_replace_callback($pattern, array($this, '_commentCB'), $css);
93
94 // remove ws around { } and last semicolon in declaration block
95 $css = preg_replace('/\\s*{\\s*/', '{', $css);
96 $css = preg_replace('/;?\\s*}\\s*/', '}', $css);
97
98 // remove ws surrounding semicolons
99 $css = preg_replace('/\\s*;\\s*/', ';', $css);
100
101 // remove ws around urls
102 $pattern = '/
103 url\\( # url(
104 \\s*
105 ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
106 \\s*
107 \\) # )
108 /x';
109 $css = preg_replace($pattern, 'url($1)', $css);
110
111 // remove ws between rules and colons
112 $pattern = '/
113 \\s*
114 ([{;]) # 1 = beginning of block or rule separator
115 \\s*
116 ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
117 \\s*
118 :
119 \\s*
120 (\\b|[#\'"-]) # 3 = first character of a value
121 /x';
122 $css = preg_replace($pattern, '$1$2:$3', $css);
123
124 // remove ws in selectors
125 $pattern = '/
126 (?: # non-capture
127 \\s*
128 [^~>+,\\s]+ # selector part
129 \\s*
130 [,>+~] # combinators
131 )+
132 \\s*
133 [^~>+,\\s]+ # selector part
134 { # open declaration block
135 /x';
136 $css = preg_replace_callback($pattern, array($this, '_selectorsCB'), $css);
137
138 // minimize hex colors
139 $pattern = '/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i';
140 $css = preg_replace($pattern, '$1#$2$3$4$5', $css);
141
142 // remove spaces between font families
143 $pattern = '/font-family:([^;}]+)([;}])/';
144 $css = preg_replace_callback($pattern, array($this, '_fontFamilyCB'), $css);
145
146 $css = preg_replace('/@import\\s+url/', '@import url', $css);
147
148 // replace any ws involving newlines with a single newline
149 $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
150
151 // separate common descendent selectors w/ newlines (to limit line lengths)
152 $pattern = '/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/';
153 $css = preg_replace($pattern, "$1\n$2{", $css);
154
155 // Use newline after 1st numeric value (to limit line lengths).
156 $pattern = '/
157 ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
158 \\s+
159 /x';
160 $css = preg_replace($pattern, "$1\n", $css);
161
162 // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
163 $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
164
165 return trim($css);
166 }
167
168 /**
169 * Replace what looks like a set of selectors
170 *
171 * @param array $m regex matches
172 *
173 * @return string
174 */
175 protected function _selectorsCB($m)
176 {
177 // remove ws around the combinators
178 return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
179 }
180
181 /**
182 * Process a comment and return a replacement
183 *
184 * @param array $m regex matches
185 *
186 * @return string
187 */
188 protected function _commentCB($m)
189 {
190 $hasSurroundingWs = (trim($m[0]) !== $m[1]);
191 $m = $m[1];
192 // $m is the comment content w/o the surrounding tokens,
193 // but the return value will replace the entire comment.
194 if ($m === 'keep') {
195 return '/**/';
196 }
197
198 if ($m === '" "') {
199 // component of http://tantek.com/CSS/Examples/midpass.html
200 return '/*" "*/';
201 }
202
203 if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
204 // component of http://tantek.com/CSS/Examples/midpass.html
205 return '/*";}}/* */';
206 }
207
208 if ($this->_inHack) {
209 // inversion: feeding only to one browser
210 $pattern = '@
211 ^/ # comment started like /*/
212 \\s*
213 (\\S[\\s\\S]+?) # has at least some non-ws content
214 \\s*
215 /\\* # ends like /*/ or /**/
216 @x';
217 if (preg_match($pattern, $m, $n)) {
218 // end hack mode after this comment, but preserve the hack and comment content
219 $this->_inHack = false;
220
221 return "/*/{$n[1]}/**/";
222 }
223 }
224
225 if (substr($m, -1) === '\\') { // comment ends like \*/
226 // begin hack mode and preserve hack
227 $this->_inHack = true;
228
229 return '/*\\*/';
230 }
231
232 if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
233 // begin hack mode and preserve hack
234 $this->_inHack = true;
235
236 return '/*/*/';
237 }
238
239 if ($this->_inHack) {
240 // a regular comment ends hack mode but should be preserved
241 $this->_inHack = false;
242
243 return '/**/';
244 }
245
246 // Issue 107: if there's any surrounding whitespace, it may be important, so
247 // replace the comment with a single space
248 return $hasSurroundingWs ? ' ' : ''; // remove all other comments
249 }
250
251 /**
252 * Process a font-family listing and return a replacement
253 *
254 * @param array $m regex matches
255 *
256 * @return string
257 */
258 protected function _fontFamilyCB($m)
259 {
260 // Issue 210: must not eliminate WS between words in unquoted families
261 $flags = PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY;
262 $pieces = preg_split('/(\'[^\']+\'|"[^"]+")/', $m[1], -1, $flags);
263 $out = 'font-family:';
264
265 while (null !== ($piece = array_shift($pieces))) {
266 if ($piece[0] !== '"' && $piece[0] !== "'") {
267 $piece = preg_replace('/\\s+/', ' ', $piece);
268 $piece = preg_replace('/\\s?,\\s?/', ',', $piece);
269 }
270 $out .= $piece;
271 }
272
273 return $out . $m[2];
274 }
275 }
276