r71692 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r71691‎ | r71692 | r71693 >
Date:03:21, 26 August 2010
Author:tparscal
Status:ok
Tags:
Comment:
Replaced rubbish Minify_CSS with a new CSSMin class which can minify extremely fast and automatically embed images as data-uris.
Modified paths:
  • /branches/resourceloader/phase3/includes/AutoLoader.php (modified) (history)
  • /branches/resourceloader/phase3/includes/CSSMin.php (added) (history)
  • /branches/resourceloader/phase3/includes/Minify_CSS.php (deleted) (history)
  • /branches/resourceloader/phase3/includes/ResourceLoader.php (modified) (history)
  • /branches/resourceloader/phase3/includes/ResourceLoaderModule.php (modified) (history)
  • /branches/resourceloader/phase3/skins/vector/main-ltr.css (modified) (history)

Diff [purge]

Index: branches/resourceloader/phase3/skins/vector/main-ltr.css
@@ -25,12 +25,14 @@
2626 }
2727 body {
2828 background-color: #f3f3f3;
 29+ /* @embed */
2930 background-image: url(images/page-base.png?1);
3031 }
3132 /* Content */
3233 div#content {
3334 margin-left: 10em;
3435 padding: 1em;
 36+ /* @embed */
3537 background-image: url(images/border.png?1);
3638 background-position: top left;
3739 background-repeat: repeat-y;
@@ -41,7 +43,8 @@
4244 #mw-page-base {
4345 height: 5em;
4446 background-color: white;
45 - background-image: url(images/page-fade.png?1);
 47+ /* @embed */
 48+ background-image: url("images/page-fade.png?1");
4649 background-position: bottom left;
4750 background-repeat: repeat-x;
4851 }
@@ -49,7 +52,8 @@
5053 margin-top: -5em;
5154 margin-left: 10em;
5255 height: 5em;
53 - background-image: url(images/border.png?1);
 56+ /* @embed */
 57+ background-image: url('images/border.png?1');
5458 background-position: bottom left;
5559 background-repeat: repeat-x;
5660 }
@@ -116,6 +120,7 @@
117121 height: 2.5em;
118122 }
119123 div.vectorTabs {
 124+ /* @embed */
120125 background-image: url(images/tab-break.png?1);
121126 background-position: bottom left;
122127 background-repeat: no-repeat;
@@ -143,6 +148,7 @@
144149 margin: 0;
145150 padding: 0;
146151 background-color: #f3f3f3;
 152+ /* @embed */
147153 background-image: url(images/tab-normal-fade.png?1);
148154 background-position: bottom left;
149155 background-repeat: repeat-x;
@@ -153,6 +159,7 @@
154160 display: block;
155161 }
156162 div.vectorTabs li.selected {
 163+ /* @embed */
157164 background-image: url(images/tab-current-fade.png?1);
158165 }
159166 /* OVERRIDDEN BY COMPLIANT BROWSERS */
@@ -161,6 +168,7 @@
162169 height: 1.9em;
163170 padding-left: 0.5em;
164171 padding-right: 0.5em;
 172+ /* @embed */
165173 background-image: url(images/tab-break.png?1);
166174 background-position: bottom right;
167175 background-repeat: no-repeat;
@@ -201,6 +209,7 @@
202210 div.vectorMenu {
203211 direction: ltr;
204212 float: left;
 213+ /* @embed */
205214 background-image: url(images/arrow-down-icon.png?1);
206215 background-position: 100% 60%;
207216 background-repeat: no-repeat;
@@ -214,6 +223,7 @@
215224 /* @noflip */
216225 div#mw-head div.vectorMenu h5 {
217226 float: left;
 227+ /* @embed */
218228 background-image: url(images/tab-break.png?1);
219229 background-repeat: no-repeat;
220230 }
@@ -241,6 +251,7 @@
242252 width: 24px;
243253 height: 2.5em;
244254 text-decoration: none;
 255+ /* @embed */
245256 background-image: url(images/tab-break.png?1);
246257 background-repeat: no-repeat;
247258 }
@@ -349,6 +360,7 @@
350361 min-height: 1px; /* Gotta trigger hasLayout for IE7 */
351362 border: solid 1px #AAAAAA;
352363 background-color: white;
 364+ /* @embed */
353365 background-image: url(images/search-fade.png?1);
354366 background-position: top left;
355367 background-repeat: repeat-x;
@@ -421,6 +433,7 @@
422434 margin: 0;
423435 padding-top: 0.5em;
424436 margin-left: 1.25em;
 437+ /* @embed */
425438 background-image: url(images/portal-break.png?1);
426439 background-repeat: no-repeat;
427440 background-position: top left;
@@ -451,7 +464,8 @@
452465 margin-left: 10em;
453466 margin-top: 0;
454467 padding: 0.75em;
455 - background-image: url(images/border.png?1);
 468+ /* @embed */
 469+ background-image: url("images/border.png?1");
456470 background-position: top left;
457471 background-repeat: repeat-x;
458472 direction: ltr;
@@ -523,6 +537,7 @@
524538 clear: both;
525539 margin: 0 !important;
526540 padding: 0 !important;
 541+ /* @embed */
527542 background-image: url(images/preferences-break.png?1);
528543 background-position: bottom left;
529544 background-repeat: no-repeat;
@@ -537,6 +552,7 @@
538553 white-space: nowrap;
539554 list-style-type: none;
540555 list-style-image: none;
 556+ /* @embed */
541557 background-image: url(images/preferences-break.png?1);
542558 background-position: bottom right;
543559 background-repeat: no-repeat;
@@ -560,6 +576,7 @@
561577 text-decoration: underline;
562578 }
563579 #preftoc li.selected a {
 580+ /* @embed */
564581 background-image: url(images/preferences-fade.png?1);
565582 background-position: bottom;
566583 background-repeat: repeat-x;
@@ -574,6 +591,7 @@
575592 clear: both;
576593 border: solid 1px #cccccc;
577594 background-color: #f9f9f9;
 595+ /* @embed */
578596 background-image: url(images/preferences-base.png?1);
579597 }
580598 #preferences fieldset.prefsection {
@@ -754,6 +772,7 @@
755773 list-style-type: square;
756774 margin: .3em 0 0 1.5em;
757775 padding: 0;
 776+ /* @embed */
758777 list-style-image: url(images/bullet-icon.png?1);
759778 }
760779 ol {
@@ -1011,31 +1030,37 @@
10121031 }
10131032 div#content a.external,
10141033 div#content a[href ^="gopher://"] {
 1034+ /* @embed */
10151035 background: url(images/external-link-ltr-icon.png?2) center right no-repeat;
10161036 padding: 0 13px 0 0;
10171037 }
10181038 div#content a[href ^="https://"],
10191039 .link-https {
 1040+ /* @embed */
10201041 background: url(images/lock-icon.png?2) center right no-repeat;
10211042 padding: 0 13px 0 0;
10221043 }
10231044 div#content a[href ^="mailto:"],
10241045 .link-mailto {
 1046+ /* @embed */
10251047 background: url(images/mail-icon.png?2) center right no-repeat;
10261048 padding: 0 13px 0 0;
10271049 }
10281050 div#content a[href ^="news://"] {
 1051+ /* @embed */
10291052 background: url(images/news-icon.png?2) center right no-repeat;
10301053 padding: 0 13px 0 0;
10311054 }
10321055 div#content a[href ^="ftp://"],
10331056 .link-ftp {
 1057+ /* @embed */
10341058 background: url(images/file-icon.png?2) center right no-repeat;
10351059 padding: 0 13px 0 0;
10361060 }
10371061 div#content a[href ^="irc://"],
10381062 div#content a.extiw[href ^="irc://"],
10391063 .link-irc {
 1064+ /* @embed */
10401065 background: url(images/talk-icon.png?2) center right no-repeat;
10411066 padding: 0 13px 0 0;
10421067 }
@@ -1046,6 +1071,7 @@
10471072 div#content a.external[href $=".wav"], div#content a.external[href $=".WAV"],
10481073 div#content a.external[href $=".wma"], div#content a.external[href $=".WMA"],
10491074 .link-audio {
 1075+ /* @embed */
10501076 background: url("images/audio-icon.png?2") center right no-repeat;
10511077 padding: 0 13px 0 0;
10521078 }
@@ -1054,6 +1080,7 @@
10551081 div#content a.external[href $=".mpeg"], div#content a.external[href $=".MPEG"],
10561082 div#content a.external[href $=".mpg"], div#content a.external[href $=".MPG"],
10571083 .link-video {
 1084+ /* @embed */
10581085 background: url("images/video-icon.png?2") center right no-repeat;
10591086 padding: 0 13px 0 0;
10601087 }
@@ -1061,6 +1088,7 @@
10621089 div#content a.external[href *=".pdf#"], div#content a.external[href *=".PDF#"],
10631090 div#content a.external[href *=".pdf?"], div#content a.external[href *=".PDF?"],
10641091 .link-document {
 1092+ /* @embed */
10651093 background: url("images/document-icon.png?2") center right no-repeat;
10661094 padding: 0 13px 0 0;
10671095 }
@@ -1081,6 +1109,7 @@
10821110 #pt-userpage,
10831111 #pt-anonuserpage,
10841112 #pt-login {
 1113+ /* @embed */
10851114 background: url(images/user-icon.png?1) left top no-repeat;
10861115 padding-left: 15px !important;
10871116 text-transform: none;
@@ -1140,6 +1169,7 @@
11411170 }
11421171 #ca-unwatch.icon a.loading,
11431172 #ca-watch.icon a.loading {
 1173+ /* @embed */
11441174 background-image: url(images/watch-icon-loading.gif?1);
11451175 background-position: center 60%;
11461176 }
@@ -1148,6 +1178,7 @@
11491179 display: none;
11501180 }
11511181 div.vectorTabs ul {
 1182+ /* @embed */
11521183 background-image:url(images/tab-break.png?1);
11531184 background-position:right bottom;
11541185 background-repeat:no-repeat;
Index: branches/resourceloader/phase3/includes/Minify_CSS.php
@@ -1,699 +0,0 @@
2 -<?php
3 -/**
4 - * Minify_CSS class and its dependencies, copied from Minfiy r416 <http://code.google.com/p/minify/source/browse/>
5 - *
6 - * Minify is distributed with the following license:
7 - * Copyright (c) 2008 Ryan Grove <ryan@wonko.com>
8 - * Copyright (c) 2008 Steve Clay <steve@mrclay.org>
9 - * All rights reserved.
10 - *
11 - * Redistribution and use in source and binary forms, with or without
12 - * modification, are permitted provided that the following conditions are met:
13 - *
14 - * * Redistributions of source code must retain the above copyright notice,
15 - * this list of conditions and the following disclaimer.
16 - * * Redistributions in binary form must reproduce the above copyright notice,
17 - * this list of conditions and the following disclaimer in the documentation
18 - * and/or other materials provided with the distribution.
19 - * * Neither the name of this project nor the names of its contributors may be
20 - * used to endorse or promote products derived from this software without
21 - * specific prior written permission.
22 - *
23 - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
27 - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
30 - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 - */
34 -
35 -/**
36 - * Minify CSS
37 - *
38 - * This class uses Minify_CSS_Compressor and Minify_CSS_UriRewriter to
39 - * minify CSS and rewrite relative URIs.
40 - *
41 - * @author Stephen Clay <steve@mrclay.org>
42 - * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
43 - */
44 -class Minify_CSS {
45 -
46 - /**
47 - * Minify a CSS string
48 - *
49 - * @param string $css
50 - *
51 - * @param array $options available options:
52 - *
53 - * 'preserveComments': (default true) multi-line comments that begin
54 - * with "/*!" will be preserved with newlines before and after to
55 - * enhance readability.
56 - *
57 - * 'prependRelativePath': (default null) if given, this string will be
58 - * prepended to all relative URIs in import/url declarations
59 - *
60 - * 'currentDir': (default null) if given, this is assumed to be the
61 - * directory of the current CSS file. Using this, minify will rewrite
62 - * all relative URIs in import/url declarations to correctly point to
63 - * the desired files. For this to work, the files *must* exist and be
64 - * visible by the PHP process.
65 - *
66 - * 'symlinks': (default = array()) If the CSS file is stored in
67 - * a symlink-ed directory, provide an array of link paths to
68 - * target paths, where the link paths are within the document root. Because
69 - * paths need to be normalized for this to work, use "//" to substitute
70 - * the doc root in the link paths (the array keys). E.g.:
71 - * <code>
72 - * array('//symlink' => '/real/target/path') // unix
73 - * array('//static' => 'D:\\staticStorage') // Windows
74 - * </code>
75 - *
76 - * @return string
77 - */
78 - public static function minify($css, $options = array())
79 - {
80 - if (isset($options['preserveComments'])
81 - && !$options['preserveComments']) {
82 - $css = Minify_CSS_Compressor::process($css, $options);
83 - } else {
84 - $css = Minify_CommentPreserver::process(
85 - $css
86 - ,array('Minify_CSS_Compressor', 'process')
87 - ,array($options)
88 - );
89 - }
90 - if (! isset($options['currentDir']) && ! isset($options['prependRelativePath'])) {
91 - return $css;
92 - }
93 - if (isset($options['currentDir'])) {
94 - return Minify_CSS_UriRewriter::rewrite(
95 - $css
96 - ,$options['currentDir']
97 - ,isset($options['docRoot']) ? $options['docRoot'] : $_SERVER['DOCUMENT_ROOT']
98 - ,isset($options['symlinks']) ? $options['symlinks'] : array()
99 - );
100 - } else {
101 - return Minify_CSS_UriRewriter::prepend(
102 - $css
103 - ,$options['prependRelativePath']
104 - );
105 - }
106 - }
107 -}
108 -
109 -/**
110 - * Compress CSS
111 - *
112 - * This is a heavy regex-based removal of whitespace, unnecessary
113 - * comments and tokens, and some CSS value minimization, where practical.
114 - * Many steps have been taken to avoid breaking comment-based hacks,
115 - * including the ie5/mac filter (and its inversion), but expect tricky
116 - * hacks involving comment tokens in 'content' value strings to break
117 - * minimization badly. A test suite is available.
118 - *
119 - * @author Stephen Clay <steve@mrclay.org>
120 - * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
121 - */
122 -class Minify_CSS_Compressor {
123 -
124 - /**
125 - * Minify a CSS string
126 - *
127 - * @param string $css
128 - *
129 - * @param array $options (currently ignored)
130 - *
131 - * @return string
132 - */
133 - public static function process($css, $options = array())
134 - {
135 - $obj = new Minify_CSS_Compressor($options);
136 - return $obj->_process($css);
137 - }
138 -
139 - /**
140 - * @var array options
141 - */
142 - protected $_options = null;
143 -
144 - /**
145 - * @var bool Are we "in" a hack?
146 - *
147 - * I.e. are some browsers targetted until the next comment?
148 - */
149 - protected $_inHack = false;
150 -
151 -
152 - /**
153 - * Constructor
154 - *
155 - * @param array $options (currently ignored)
156 - *
157 - * @return null
158 - */
159 - private function __construct($options) {
160 - $this->_options = $options;
161 - }
162 -
163 - /**
164 - * Minify a CSS string
165 - *
166 - * @param string $css
167 - *
168 - * @return string
169 - */
170 - protected function _process($css)
171 - {
172 - $css = str_replace("\r\n", "\n", $css);
173 -
174 - // preserve empty comment after '>'
175 - // http://www.webdevout.net/css-hacks#in_css-selectors
176 - $css = preg_replace('@>/\\*\\s*\\*/@', '>/*keep*/', $css);
177 -
178 - // preserve empty comment between property and value
179 - // http://css-discuss.incutio.com/?page=BoxModelHack
180 - $css = preg_replace('@/\\*\\s*\\*/\\s*:@', '/*keep*/:', $css);
181 - $css = preg_replace('@:\\s*/\\*\\s*\\*/@', ':/*keep*/', $css);
182 -
183 - // apply callback to all valid comments (and strip out surrounding ws
184 - $css = preg_replace_callback('@\\s*/\\*([\\s\\S]*?)\\*/\\s*@'
185 - ,array($this, '_commentCB'), $css);
186 -
187 - // remove ws around { } and last semicolon in declaration block
188 - $css = preg_replace('/\\s*{\\s*/', '{', $css);
189 - $css = preg_replace('/;?\\s*}\\s*/', '}', $css);
190 -
191 - // remove ws surrounding semicolons
192 - $css = preg_replace('/\\s*;\\s*/', ';', $css);
193 -
194 - // remove ws around urls
195 - $css = preg_replace('/
196 - url\\( # url(
197 - \\s*
198 - ([^\\)]+?) # 1 = the URL (really just a bunch of non right parenthesis)
199 - \\s*
200 - \\) # )
201 - /x', 'url($1)', $css);
202 -
203 - // remove ws between rules and colons
204 - $css = preg_replace('/
205 - \\s*
206 - ([{;]) # 1 = beginning of block or rule separator
207 - \\s*
208 - ([\\*_]?[\\w\\-]+) # 2 = property (and maybe IE filter)
209 - \\s*
210 - :
211 - \\s*
212 - (\\b|[#\'"]) # 3 = first character of a value
213 - /x', '$1$2:$3', $css);
214 -
215 - // remove ws in selectors
216 - $css = preg_replace_callback('/
217 - (?: # non-capture
218 - \\s*
219 - [^~>+,\\s]+ # selector part
220 - \\s*
221 - [,>+~] # combinators
222 - )+
223 - \\s*
224 - [^~>+,\\s]+ # selector part
225 - { # open declaration block
226 - /x'
227 - ,array($this, '_selectorsCB'), $css);
228 -
229 - // minimize hex colors
230 - $css = preg_replace('/([^=])#([a-f\\d])\\2([a-f\\d])\\3([a-f\\d])\\4([\\s;\\}])/i'
231 - , '$1#$2$3$4$5', $css);
232 -
233 - // remove spaces between font families
234 - $css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
235 - ,array($this, '_fontFamilyCB'), $css);
236 -
237 - $css = preg_replace('/@import\\s+url/', '@import url', $css);
238 -
239 - // replace any ws involving newlines with a single newline
240 - $css = preg_replace('/[ \\t]*\\n+\\s*/', "\n", $css);
241 -
242 - // separate common descendent selectors w/ newlines (to limit line lengths)
243 - $css = preg_replace('/([\\w#\\.\\*]+)\\s+([\\w#\\.\\*]+){/', "$1\n$2{", $css);
244 -
245 - // Use newline after 1st numeric value (to limit line lengths).
246 - $css = preg_replace('/
247 - ((?:padding|margin|border|outline):\\d+(?:px|em)?) # 1 = prop : 1st numeric value
248 - \\s+
249 - /x'
250 - ,"$1\n", $css);
251 -
252 - // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
253 - $css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
254 -
255 - return trim($css);
256 - }
257 -
258 - /**
259 - * Replace what looks like a set of selectors
260 - *
261 - * @param array $m regex matches
262 - *
263 - * @return string
264 - */
265 - protected function _selectorsCB($m)
266 - {
267 - // remove ws around the combinators
268 - return preg_replace('/\\s*([,>+~])\\s*/', '$1', $m[0]);
269 - }
270 -
271 - /**
272 - * Process a comment and return a replacement
273 - *
274 - * @param array $m regex matches
275 - *
276 - * @return string
277 - */
278 - protected function _commentCB($m)
279 - {
280 - $hasSurroundingWs = (trim($m[0]) !== $m[1]);
281 - $m = $m[1];
282 - // $m is the comment content w/o the surrounding tokens,
283 - // but the return value will replace the entire comment.
284 - if ($m === 'keep') {
285 - return '/**/';
286 - }
287 - if ($m === '" "') {
288 - // component of http://tantek.com/CSS/Examples/midpass.html
289 - return '/*" "*/';
290 - }
291 - if (preg_match('@";\\}\\s*\\}/\\*\\s+@', $m)) {
292 - // component of http://tantek.com/CSS/Examples/midpass.html
293 - return '/*";}}/* */';
294 - }
295 - if ($this->_inHack) {
296 - // inversion: feeding only to one browser
297 - if (preg_match('@
298 - ^/ # comment started like /*/
299 - \\s*
300 - (\\S[\\s\\S]+?) # has at least some non-ws content
301 - \\s*
302 - /\\* # ends like /*/ or /**/
303 - @x', $m, $n)) {
304 - // end hack mode after this comment, but preserve the hack and comment content
305 - $this->_inHack = false;
306 - return "/*/{$n[1]}/**/";
307 - }
308 - }
309 - if (substr($m, -1) === '\\') { // comment ends like \*/
310 - // begin hack mode and preserve hack
311 - $this->_inHack = true;
312 - return '/*\\*/';
313 - }
314 - if ($m !== '' && $m[0] === '/') { // comment looks like /*/ foo */
315 - // begin hack mode and preserve hack
316 - $this->_inHack = true;
317 - return '/*/*/';
318 - }
319 - if ($this->_inHack) {
320 - // a regular comment ends hack mode but should be preserved
321 - $this->_inHack = false;
322 - return '/**/';
323 - }
324 - // Issue 107: if there's any surrounding whitespace, it may be important, so
325 - // replace the comment with a single space
326 - return $hasSurroundingWs // remove all other comments
327 - ? ' '
328 - : '';
329 - }
330 -
331 - /**
332 - * Process a font-family listing and return a replacement
333 - *
334 - * @param array $m regex matches
335 - *
336 - * @return string
337 - */
338 - protected function _fontFamilyCB($m)
339 - {
340 - $m[1] = preg_replace('/
341 - \\s*
342 - (
343 - "[^"]+" # 1 = family in double qutoes
344 - |\'[^\']+\' # or 1 = family in single quotes
345 - |[\\w\\-]+ # or 1 = unquoted family
346 - )
347 - \\s*
348 - /x', '$1', $m[1]);
349 - return 'font-family:' . $m[1] . $m[2];
350 - }
351 -}
352 -
353 -/**
354 - * Rewrite file-relative URIs as root-relative in CSS files
355 - *
356 - * @author Stephen Clay <steve@mrclay.org>
357 - */
358 -class Minify_CSS_UriRewriter {
359 -
360 - /**
361 - * Defines which class to call as part of callbacks, change this
362 - * if you extend Minify_CSS_UriRewriter
363 - * @var string
364 - */
365 - protected static $className = 'Minify_CSS_UriRewriter';
366 -
367 - /**
368 - * rewrite() and rewriteRelative() append debugging information here
369 - * @var string
370 - */
371 - public static $debugText = '';
372 -
373 - /**
374 - * Rewrite file relative URIs as root relative in CSS files
375 - *
376 - * @param string $css
377 - *
378 - * @param string $currentDir The directory of the current CSS file.
379 - *
380 - * @param string $docRoot The document root of the web site in which
381 - * the CSS file resides (default = $_SERVER['DOCUMENT_ROOT']).
382 - *
383 - * @param array $symlinks (default = array()) If the CSS file is stored in
384 - * a symlink-ed directory, provide an array of link paths to
385 - * target paths, where the link paths are within the document root. Because
386 - * paths need to be normalized for this to work, use "//" to substitute
387 - * the doc root in the link paths (the array keys). E.g.:
388 - * <code>
389 - * array('//symlink' => '/real/target/path') // unix
390 - * array('//static' => 'D:\\staticStorage') // Windows
391 - * </code>
392 - *
393 - * @return string
394 - */
395 - public static function rewrite($css, $currentDir, $docRoot = null, $symlinks = array())
396 - {
397 - self::$_docRoot = self::_realpath(
398 - $docRoot ? $docRoot : $_SERVER['DOCUMENT_ROOT']
399 - );
400 - self::$_currentDir = self::_realpath($currentDir);
401 - self::$_symlinks = array();
402 -
403 - // normalize symlinks
404 - foreach ($symlinks as $link => $target) {
405 - $link = ($link === '//')
406 - ? self::$_docRoot
407 - : str_replace('//', self::$_docRoot . '/', $link);
408 - $link = strtr($link, '/', DIRECTORY_SEPARATOR);
409 - self::$_symlinks[$link] = self::_realpath($target);
410 - }
411 -
412 - self::$debugText .= "docRoot : " . self::$_docRoot . "\n"
413 - . "currentDir : " . self::$_currentDir . "\n";
414 - if (self::$_symlinks) {
415 - self::$debugText .= "symlinks : " . var_export(self::$_symlinks, 1) . "\n";
416 - }
417 - self::$debugText .= "\n";
418 -
419 - $css = self::_trimUrls($css);
420 -
421 - // rewrite
422 - $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
423 - ,array(self::$className, '_processUriCB'), $css);
424 - $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
425 - ,array(self::$className, '_processUriCB'), $css);
426 -
427 - return $css;
428 - }
429 -
430 - /**
431 - * Prepend a path to relative URIs in CSS files
432 - *
433 - * @param string $css
434 - *
435 - * @param string $path The path to prepend.
436 - *
437 - * @return string
438 - */
439 - public static function prepend($css, $path)
440 - {
441 - self::$_prependPath = $path;
442 -
443 - $css = self::_trimUrls($css);
444 -
445 - // append
446 - $css = preg_replace_callback('/@import\\s+([\'"])(.*?)[\'"]/'
447 - ,array(self::$className, '_processUriCB'), $css);
448 - $css = preg_replace_callback('/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
449 - ,array(self::$className, '_processUriCB'), $css);
450 -
451 - self::$_prependPath = null;
452 - return $css;
453 - }
454 -
455 -
456 - /**
457 - * @var string directory of this stylesheet
458 - */
459 - private static $_currentDir = '';
460 -
461 - /**
462 - * @var string DOC_ROOT
463 - */
464 - private static $_docRoot = '';
465 -
466 - /**
467 - * @var array directory replacements to map symlink targets back to their
468 - * source (within the document root) E.g. '/var/www/symlink' => '/var/realpath'
469 - */
470 - private static $_symlinks = array();
471 -
472 - /**
473 - * @var string path to prepend
474 - */
475 - private static $_prependPath = null;
476 -
477 - private static function _trimUrls($css)
478 - {
479 - return preg_replace('/
480 - url\\( # url(
481 - \\s*
482 - ([^\\)]+?) # 1 = URI (assuming does not contain ")")
483 - \\s*
484 - \\) # )
485 - /x', 'url($1)', $css);
486 - }
487 -
488 - private static function _processUriCB($m)
489 - {
490 - // $m matched either '/@import\\s+([\'"])(.*?)[\'"]/' or '/url\\(\\s*([^\\)\\s]+)\\s*\\)/'
491 - $isImport = ($m[0][0] === '@');
492 - // determine URI and the quote character (if any)
493 - if ($isImport) {
494 - $quoteChar = $m[1];
495 - $uri = $m[2];
496 - } else {
497 - // $m[1] is either quoted or not
498 - $quoteChar = ($m[1][0] === "'" || $m[1][0] === '"')
499 - ? $m[1][0]
500 - : '';
501 - $uri = ($quoteChar === '')
502 - ? $m[1]
503 - : substr($m[1], 1, strlen($m[1]) - 2);
504 - }
505 - // analyze URI
506 - if ('/' !== $uri[0] // root-relative
507 - && false === strpos($uri, '//') // protocol (non-data)
508 - && 0 !== strpos($uri, 'data:') // data protocol
509 - ) {
510 - // URI is file-relative: rewrite depending on options
511 - $uri = (self::$_prependPath !== null)
512 - ? (self::$_prependPath . $uri)
513 - : self::rewriteRelative($uri, self::$_currentDir, self::$_docRoot, self::$_symlinks);
514 - }
515 - return $isImport
516 - ? "@import {$quoteChar}{$uri}{$quoteChar}"
517 - : "url({$quoteChar}{$uri}{$quoteChar})";
518 - }
519 -
520 - /**
521 - * Rewrite a file relative URI as root relative
522 - *
523 - * <code>
524 - * Minify_CSS_UriRewriter::rewriteRelative(
525 - * '../img/hello.gif'
526 - * , '/home/user/www/css' // path of CSS file
527 - * , '/home/user/www' // doc root
528 - * );
529 - * // returns '/img/hello.gif'
530 - *
531 - * // example where static files are stored in a symlinked directory
532 - * Minify_CSS_UriRewriter::rewriteRelative(
533 - * 'hello.gif'
534 - * , '/var/staticFiles/theme'
535 - * , '/home/user/www'
536 - * , array('/home/user/www/static' => '/var/staticFiles')
537 - * );
538 - * // returns '/static/theme/hello.gif'
539 - * </code>
540 - *
541 - * @param string $uri file relative URI
542 - *
543 - * @param string $realCurrentDir realpath of the current file's directory.
544 - *
545 - * @param string $realDocRoot realpath of the site document root.
546 - *
547 - * @param array $symlinks (default = array()) If the file is stored in
548 - * a symlink-ed directory, provide an array of link paths to
549 - * real target paths, where the link paths "appear" to be within the document
550 - * root. E.g.:
551 - * <code>
552 - * array('/home/foo/www/not/real/path' => '/real/target/path') // unix
553 - * array('C:\\htdocs\\not\\real' => 'D:\\real\\target\\path') // Windows
554 - * </code>
555 - *
556 - * @return string
557 - */
558 - public static function rewriteRelative($uri, $realCurrentDir, $realDocRoot, $symlinks = array())
559 - {
560 - // prepend path with current dir separator (OS-independent)
561 - $path = strtr($realCurrentDir, '/', DIRECTORY_SEPARATOR)
562 - . DIRECTORY_SEPARATOR . strtr($uri, '/', DIRECTORY_SEPARATOR);
563 -
564 - self::$debugText .= "file-relative URI : {$uri}\n"
565 - . "path prepended : {$path}\n";
566 -
567 - // "unresolve" a symlink back to doc root
568 - foreach ($symlinks as $link => $target) {
569 - if (0 === strpos($path, $target)) {
570 - // replace $target with $link
571 - $path = $link . substr($path, strlen($target));
572 -
573 - self::$debugText .= "symlink unresolved : {$path}\n";
574 -
575 - break;
576 - }
577 - }
578 - // strip doc root
579 - $path = substr($path, strlen($realDocRoot));
580 -
581 - self::$debugText .= "docroot stripped : {$path}\n";
582 -
583 - // fix to root-relative URI
584 -
585 -
586 - $uri = strtr($path, '/\\', '//');
587 -
588 - // remove /./ and /../ where possible
589 - $uri = str_replace('/./', '/', $uri);
590 - // inspired by patch from Oleg Cherniy
591 - do {
592 - $uri = preg_replace('@/[^/]+/\\.\\./@', '/', $uri, 1, $changed);
593 - } while ($changed);
594 -
595 - self::$debugText .= "traversals removed : {$uri}\n\n";
596 -
597 - return $uri;
598 - }
599 -
600 - /**
601 - * Get realpath with any trailing slash removed. If realpath() fails,
602 - * just remove the trailing slash.
603 - *
604 - * @param string $path
605 - *
606 - * @return mixed path with no trailing slash
607 - */
608 - protected static function _realpath($path)
609 - {
610 - $realPath = realpath($path);
611 - if ($realPath !== false) {
612 - $path = $realPath;
613 - }
614 - return rtrim($path, '/\\');
615 - }
616 -}
617 -
618 -/**
619 - * Process a string in pieces preserving C-style comments that begin with "/*!"
620 - *
621 - * @author Stephen Clay <steve@mrclay.org>
622 - */
623 -class Minify_CommentPreserver {
624 -
625 - /**
626 - * String to be prepended to each preserved comment
627 - *
628 - * @var string
629 - */
630 - public static $prepend = "\n";
631 -
632 - /**
633 - * String to be appended to each preserved comment
634 - *
635 - * @var string
636 - */
637 - public static $append = "\n";
638 -
639 - /**
640 - * Process a string outside of C-style comments that begin with "/*!"
641 - *
642 - * On each non-empty string outside these comments, the given processor
643 - * function will be called. The first "!" will be removed from the
644 - * preserved comments, and the comments will be surrounded by
645 - * Minify_CommentPreserver::$preprend and Minify_CommentPreserver::$append.
646 - *
647 - * @param string $content
648 - * @param callback $processor function
649 - * @param array $args array of extra arguments to pass to the processor
650 - * function (default = array())
651 - * @return string
652 - */
653 - public static function process($content, $processor, $args = array())
654 - {
655 - $ret = '';
656 - while (true) {
657 - list($beforeComment, $comment, $afterComment) = self::_nextComment($content);
658 - if ('' !== $beforeComment) {
659 - $callArgs = $args;
660 - array_unshift($callArgs, $beforeComment);
661 - $ret .= call_user_func_array($processor, $callArgs);
662 - }
663 - if (false === $comment) {
664 - break;
665 - }
666 - $ret .= $comment;
667 - $content = $afterComment;
668 - }
669 - return $ret;
670 - }
671 -
672 - /**
673 - * Extract comments that YUI Compressor preserves.
674 - *
675 - * @param string $in input
676 - *
677 - * @return array 3 elements are returned. If a YUI comment is found, the
678 - * 2nd element is the comment and the 1st and 2nd are the surrounding
679 - * strings. If no comment is found, the entire string is returned as the
680 - * 1st element and the other two are false.
681 - */
682 - private static function _nextComment($in)
683 - {
684 - if (
685 - false === ($start = strpos($in, '/*!'))
686 - || false === ($end = strpos($in, '*/', $start + 3))
687 - ) {
688 - return array($in, false, false);
689 - }
690 - $ret = array(
691 - substr($in, 0, $start)
692 - ,self::$prepend . '/*' . substr($in, $start + 3, $end - $start - 1) . self::$append
693 - );
694 - $endChars = (strlen($in) - $end - 2);
695 - $ret[] = (0 === $endChars)
696 - ? ''
697 - : substr($in, -$endChars);
698 - return $ret;
699 - }
700 -}
Index: branches/resourceloader/phase3/includes/CSSMin.php
@@ -0,0 +1,55 @@
 2+<?php
 3+
 4+class CSSMin {
 5+
 6+ /* Constants */
 7+
 8+ const MAX_EMBED_SIZE = 1024;
 9+
 10+ /* Static Methods */
 11+
 12+ /*
 13+ * Remaps CSS URL paths and automatically embeds data URIs for URL rules preceded by an /* @embed * / comment
 14+ */
 15+ public static function remap( $source, $path ) {
 16+ // Pre-process for URL rewriting
 17+ $offset = 0;
 18+ while ( preg_match(
 19+ '/((?<embed>\s*\/\*\s*\@embed\s*\*\/)(?<rule>[^\;\}]*))?url\((?<file>[^)]*)\)(?<extra>[^;]*)[\;]?/',
 20+ $source, $match, PREG_OFFSET_CAPTURE, $offset
 21+ ) ) {
 22+ $url = $path . '/' . trim( $match['file'][0], "'\"" );
 23+ $file = preg_replace( '/([^\?]*)(.*)/', '$1', $url );
 24+ $embed = $match['embed'][0];
 25+ $rule = $match['rule'][0];
 26+ $extra = $match['extra'][0];
 27+ if ( $match['embed'][1] > 0 && file_exists( $file ) && filesize( $file ) <= self::MAX_EMBED_SIZE ) {
 28+ // If we ever get to PHP 5.3, we should use the Fileinfo extension instead of mime_content_type
 29+ $type = mime_content_type( $file );
 30+ $data = rtrim( base64_encode( file_get_contents( $file ) ), '=' );
 31+ $replacement = "{$rule}url(data:{$type};base64,{$data}){$extra};{$rule}url({$url}){$extra}!ie;";
 32+ } else {
 33+ $replacement = "{$embed}{$rule}url({$url}){$extra};";
 34+ }
 35+ $source = substr_replace( $source, $replacement, $match[0][1], strlen( $match[0][0] ) );
 36+ $offset = $match[0][1] + strlen( $replacement );
 37+ }
 38+ return $source;
 39+ }
 40+
 41+ /*
 42+ * As seen at http://www.lateralcode.com/css-minifier/
 43+ */
 44+ public static function minify( $css ) {
 45+ $css = preg_replace( '#\s+#', ' ', $css );
 46+ $css = preg_replace( '#/\*.*?\*/#s', '', $css );
 47+ $css = str_replace( '; ', ';', $css );
 48+ $css = str_replace( ': ', ':', $css );
 49+ $css = str_replace( ' {', '{', $css );
 50+ $css = str_replace( '{ ', '{', $css );
 51+ $css = str_replace( ', ', ',', $css );
 52+ $css = str_replace( '} ', '}', $css );
 53+ $css = str_replace( ';}', '}', $css );
 54+ return trim( $css );
 55+ }
 56+}
\ No newline at end of file
Property changes on: branches/resourceloader/phase3/includes/CSSMin.php
___________________________________________________________________
Added: svn:eol-style
157 + native
Index: branches/resourceloader/phase3/includes/ResourceLoader.php
@@ -79,7 +79,7 @@
8080 * @param {string} $file path to file being filtered, (optional: only required for CSS to resolve paths)
8181 * @return {string} filtered data
8282 */
83 - protected static function filter( $filter, $data, $file = null ) {
 83+ protected static function filter( $filter, $data ) {
8484 // FIXME: $file is not used by any callers as path rewriting is currently kinda broken
8585 global $wgMemc;
8686 $key = wfMemcKey( 'resourceloader', $filter, md5( $data ) );
@@ -93,7 +93,8 @@
9494 $result = JSMin::minify( $data );
9595 break;
9696 case 'minify-css':
97 - $result = Minify_CSS::minify( $data, array( 'currentDir' => dirname( $file ), 'docRoot' => '.' ) );
 97+ $result = CSSMin::minify( $data );
 98+ //$result = $data;
9899 break;
99100 case 'flip-css':
100101 $result = CSSJanus::transform( $data, true, false );
Index: branches/resourceloader/phase3/includes/AutoLoader.php
@@ -46,6 +46,7 @@
4747 'CreativeCommonsRdf' => 'includes/Metadata.php',
4848 'Credits' => 'includes/Credits.php',
4949 'CSSJanus' => 'includes/CSSJanus.php',
 50+ 'CSSMin' => 'includes/CSSMin.php',
5051 'DBABagOStuff' => 'includes/BagOStuff.php',
5152 'DependencyWrapper' => 'includes/CacheDependency.php',
5253 'DiffHistoryBlob' => 'includes/HistoryBlob.php',
@@ -158,7 +159,6 @@
159160 'MessageBlobStore' => 'includes/MessageBlobStore.php',
160161 'MessageCache' => 'includes/MessageCache.php',
161162 'MimeMagic' => 'includes/MimeMagic.php',
162 - 'Minify_CSS' => 'includes/Minify_CSS.php',
163163 'MWException' => 'includes/Exception.php',
164164 'MWMemcached' => 'includes/memcached-client.php',
165165 'MWNamespace' => 'includes/Namespace.php',
Index: branches/resourceloader/phase3/includes/ResourceLoaderModule.php
@@ -212,7 +212,7 @@
213213 * @return string JS
214214 */
215215 public function getScript() {
216 - return self::concatFiles( $this->scripts );
 216+ return self::concatScripts( $this->scripts );
217217 }
218218
219219 /**
@@ -221,7 +221,7 @@
222222 * @return string JS
223223 */
224224 public function getStyle() {
225 - return self::concatFiles( $this->styles );
 225+ return self::concatStyles( $this->styles );
226226 }
227227
228228 /**
@@ -248,7 +248,7 @@
249249 * @return string JS
250250 */
251251 public function getDebugScript() {
252 - return self::concatFiles( $this->debugScripts );
 252+ return self::concatScripts( $this->debugScripts );
253253 }
254254
255255 /**
@@ -260,7 +260,7 @@
261261 if ( !isset( $this->languageScripts[$lang] ) ) {
262262 return '';
263263 }
264 - return self::concatFiles( $this->languageScripts[$lang] );
 264+ return self::concatScripts( $this->languageScripts[$lang] );
265265 }
266266
267267 /**
@@ -275,7 +275,7 @@
276276 } else if ( isset( $this->skinScripts['default'] ) ) {
277277 $scripts = $this->skinScripts['default'];
278278 }
279 - return self::concatFiles( $scripts );
 279+ return self::concatScripts( $scripts );
280280 }
281281
282282 /**
@@ -290,7 +290,7 @@
291291 } else if ( isset( $this->skinStyles['default'] ) ) {
292292 $styles = $this->skinStyles['default'];
293293 }
294 - return self::concatFiles( $styles );
 294+ return self::concatStyles( $styles );
295295 }
296296
297297 /**
@@ -302,7 +302,7 @@
303303 if ( count( $this->loaders ) == 0 ) {
304304 return false;
305305 }
306 - return self::concatFiles( $this->loaders );
 306+ return self::concatScripts( $this->loaders );
307307 }
308308
309309 /**
@@ -311,10 +311,17 @@
312312 * @param $files array Array of file names
313313 * @return string Concatenated contents of $files
314314 */
315 - protected static function concatFiles( $files ) {
 315+ protected static function concatScripts( $files ) {
316316 return implode( "\n", array_map( 'file_get_contents', array_unique( (array) $files ) ) );
317317 }
318 -
 318+
 319+ protected static function concatStyles( $files ) {
 320+ return implode( "\n", array_map( array( 'ResourceLoaderModule', 'remapStyle' ), array_unique( (array) $files ) ) );
 321+ }
 322+
 323+ protected static function remapStyle( $file ) {
 324+ return CSSMin::remap( file_get_contents( $file ), dirname( $file ) );
 325+ }
319326 }
320327
321328 class ResourceLoaderSiteJSModule extends ResourceLoaderModule {

Status & tagging log