http://www.mediawiki.org/wiki/Special:Code/MediaWiki/71767
Revision: 71767
Author: tparscal
Date: 2010-08-26 23:36:39 +0000 (Thu, 26 Aug 2010)
Log Message:
-----------
Improved performance of CSSMin::minify by using arrays with str_replace and
preg_replace, switched to using consistent delimiters for regex (/), added
modified time based versioning for CSS URLs of local files, and adjusted the
maximum size of a file to be embedded to push to the edge of IE's 32k limit.
Modified Paths:
--------------
branches/resourceloader/phase3/includes/CSSMin.php
Modified: branches/resourceloader/phase3/includes/CSSMin.php
===================================================================
--- branches/resourceloader/phase3/includes/CSSMin.php 2010-08-26 23:31:00 UTC
(rev 71766)
+++ branches/resourceloader/phase3/includes/CSSMin.php 2010-08-26 23:36:39 UTC
(rev 71767)
@@ -4,52 +4,79 @@
/* Constants */
- const MAX_EMBED_SIZE = 1024;
+ /**
+ * Maximum file size to still qualify for in-line embedding as a
data-URI
+ *
+ * 24,576 is used because Internet Explorer has a 32,768 byte limit for
data URIs, which when base64 encoded will
+ * result in a 1/4 increase in size.
+ */
+ const EMBED_SIZE_LIMIT = 24576;
/* Static Methods */
/*
* Remaps CSS URL paths and automatically embeds data URIs for URL
rules preceded by an /* @embed * / comment
+ *
+ * @param $source string CSS data to remap
+ * @param $path string File path where the source was read from
*/
public static function remap( $source, $path ) {
- // Pre-process for URL rewriting
+ $pattern =
'/((?<embed>\s*\/\*\...@embed\s*\*\/)(?<rule>[^\;\}]*))?url\((?<file>[^)]*)\)(?<extra>[^;]*)[\;]?/';
$offset = 0;
- while ( preg_match(
-
'/((?<embed>\s*\/\*\...@embed\s*\*\/)(?<rule>[^\;\}]*))?url\((?<file>[^)]*)\)(?<extra>[^;]*)[\;]?/',
- $source, $match, PREG_OFFSET_CAPTURE, $offset
- ) ) {
- $url = $path . '/' . trim( $match['file'][0], "'\"" );
- $file = preg_replace( '/([^\?]*)(.*)/', '$1', $url );
- $embed = $match['embed'][0];
- $rule = $match['rule'][0];
- $extra = $match['extra'][0];
- if ( $match['embed'][1] > 0 && file_exists( $file ) &&
filesize( $file ) <= self::MAX_EMBED_SIZE ) {
- // If we ever get to PHP 5.3, we should use the
Fileinfo extension instead of mime_content_type
- $type = mime_content_type( $file );
- $data = rtrim( base64_encode(
file_get_contents( $file ) ), '=' );
- $replacement =
"{$rule}url(data:{$type};base64,{$data}){$extra};{$rule}url({$url}){$extra}!ie;";
- } else {
- $replacement =
"{$embed}{$rule}url({$url}){$extra};";
+ while ( preg_match( $pattern, $source, $match,
PREG_OFFSET_CAPTURE, $offset ) ) {
+ // Remove single or double quotes
+ $url = trim( $match['file'][0], "'\"" );
+ // Only proceed if the URL is to a local file
+ if ( !preg_match( '/^[a-zA-Z]*\:\/\//', $url ) ) {
+ // Shortcuts
+ $embed = $match['embed'][0];
+ $rule = $match['rule'][0];
+ $extra = $match['extra'][0];
+ // Strip query string from URL
+ $file = "{$path}/" . preg_replace(
'/([^\?]*)(.*)/', '$1', $url );
+ // Only proceed if we can access the file
+ if ( file_exists( $file ) ) {
+ // Add version parameter as a
time-stamp in ISO 8601 format, using Z for the timezone, meaning GMT
+ $url = "{$file}?" . gmdate(
'Y-m-d\TH:i:s\Z', round( filemtime( $file ), -2 ) );
+ // Detect when URLs were preceeded with
embed tags, and also verify file size is below the limit
+ if ( $match['embed'][1] > 0 &&
filesize( $file ) < self::EMBED_SIZE_LIMIT ) {
+ // If we ever get to PHP 5.3,
we should use the Fileinfo extension instead of mime_content_type
+ $type = mime_content_type(
$file );
+ // Strip off any trailing =
symbols (makes browsers freak out)
+ $data = rtrim( base64_encode(
file_get_contents( $file ) ), '=' );
+ // Build 2 CSS properties; one
which uses a base64 encoded data URI in place of the @embed
+ // comment to try and retain
line-number integrity , and the other with a remapped an versioned
+ // URL and an Internet Explorer
hack making it ignored in all browsers that support data URIs
+ $replacement =
"{$rule}url(data:{$type};base64,{$data}){$extra};{$rule}url({$url}){$extra}!ie;";
+ } else {
+ // Build a CSS property with a
remapped and versioned URL
+ $replacement =
"{$embed}{$rule}url({$url}){$extra};";
+ }
+ // Perform replacement on the source
+ $source = substr_replace( $source,
$replacement, $match[0][1], strlen( $match[0][0] ) );
+ // Move the offset to the end of the
replacement in the source
+ $offset = $match[0][1] + strlen(
$replacement );
+ continue;
+ }
}
- $source = substr_replace( $source, $replacement,
$match[0][1], strlen( $match[0][0] ) );
- $offset = $match[0][1] + strlen( $replacement );
+ // Move the offset to the end of the match, leaving it
alone
+ $offset = $match[0][1] + strlen( $match[0][0] );
}
return $source;
}
/*
- * As seen at http://www.lateralcode.com/css-minifier/
+ * Removes whitespace from CSS data
+ *
+ * @param $source string CSS data to minify
*/
public static function minify( $css ) {
- $css = preg_replace( '#\s+#', ' ', $css );
- $css = preg_replace( '#/\*.*?\*/#s', '', $css );
- $css = str_replace( '; ', ';', $css );
- $css = str_replace( ': ', ':', $css );
- $css = str_replace( ' {', '{', $css );
- $css = str_replace( '{ ', '{', $css );
- $css = str_replace( ', ', ',', $css );
- $css = str_replace( '} ', '}', $css );
- $css = str_replace( ';}', '}', $css );
- return trim( $css );
+ return trim(
+ str_replace(
+ array( '; ', ': ', ' {', '{ ', ', ', '} ', ';}'
),
+ array( ';', ':', '{', '{', ',', '}', '}' ),
+ preg_replace( array( '/\s+/', '/\/\*.*?\*\//s'
), array( ' ', '' ), $css )
+ )
+ );
}
}
\ No newline at end of file
_______________________________________________
MediaWiki-CVS mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-cvs