forked from extern/egroupware
171 lines
6.2 KiB
PHP
171 lines
6.2 KiB
PHP
|
<?php
|
||
|
/**
|
||
|
* Class Minify_YUI_CssCompressor
|
||
|
* @package Minify
|
||
|
*
|
||
|
* YUI Compressor
|
||
|
* Author: Julien Lecomte - http://www.julienlecomte.net/
|
||
|
* Author: Isaac Schlueter - http://foohack.com/
|
||
|
* Author: Stoyan Stefanov - http://phpied.com/
|
||
|
* Author: Steve Clay - http://www.mrclay.org/ (PHP port)
|
||
|
* Copyright (c) 2009 Yahoo! Inc. All rights reserved.
|
||
|
* The copyrights embodied in the content of this file are licensed
|
||
|
* by Yahoo! Inc. under the BSD (revised) open source license.
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* Compress CSS (incomplete DO NOT USE)
|
||
|
*
|
||
|
* @see https://github.com/yui/yuicompressor/blob/master/src/com/yahoo/platform/yui/compressor/CssCompressor.java
|
||
|
*
|
||
|
* @package Minify
|
||
|
*/
|
||
|
class Minify_YUI_CssCompressor {
|
||
|
|
||
|
/**
|
||
|
* Minify a CSS string
|
||
|
*
|
||
|
* @param string $css
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public function compress($css, $linebreakpos = 0)
|
||
|
{
|
||
|
$css = str_replace("\r\n", "\n", $css);
|
||
|
|
||
|
/**
|
||
|
* @todo comment removal
|
||
|
* @todo re-port from newer Java version
|
||
|
*/
|
||
|
|
||
|
// Normalize all whitespace strings to single spaces. Easier to work with that way.
|
||
|
$css = preg_replace('@\s+@', ' ', $css);
|
||
|
|
||
|
// Make a pseudo class for the Box Model Hack
|
||
|
$css = preg_replace("@\"\\\\\"}\\\\\"\"@", "___PSEUDOCLASSBMH___", $css);
|
||
|
|
||
|
// Remove the spaces before the things that should not have spaces before them.
|
||
|
// But, be careful not to turn "p :link {...}" into "p:link{...}"
|
||
|
// Swap out any pseudo-class colons with the token, and then swap back.
|
||
|
$css = preg_replace_callback("@(^|\\})(([^\\{:])+:)+([^\\{]*\\{)@", array($this, '_removeSpacesCB'), $css);
|
||
|
|
||
|
$css = preg_replace("@\\s+([!{};:>+\\(\\)\\],])@", "$1", $css);
|
||
|
$css = str_replace("___PSEUDOCLASSCOLON___", ":", $css);
|
||
|
|
||
|
// Remove the spaces after the things that should not have spaces after them.
|
||
|
$css = preg_replace("@([!{}:;>+\\(\\[,])\\s+@", "$1", $css);
|
||
|
|
||
|
// Add the semicolon where it's missing.
|
||
|
$css = preg_replace("@([^;\\}])}@", "$1;}", $css);
|
||
|
|
||
|
// Replace 0(px,em,%) with 0.
|
||
|
$css = preg_replace("@([\\s:])(0)(px|em|%|in|cm|mm|pc|pt|ex)@", "$1$2", $css);
|
||
|
|
||
|
// Replace 0 0 0 0; with 0.
|
||
|
$css = str_replace(":0 0 0 0;", ":0;", $css);
|
||
|
$css = str_replace(":0 0 0;", ":0;", $css);
|
||
|
$css = str_replace(":0 0;", ":0;", $css);
|
||
|
|
||
|
// Replace background-position:0; with background-position:0 0;
|
||
|
$css = str_replace("background-position:0;", "background-position:0 0;", $css);
|
||
|
|
||
|
// Replace 0.6 to .6, but only when preceded by : or a white-space
|
||
|
$css = preg_replace("@(:|\\s)0+\\.(\\d+)@", "$1.$2", $css);
|
||
|
|
||
|
// Shorten colors from rgb(51,102,153) to #336699
|
||
|
// This makes it more likely that it'll get further compressed in the next step.
|
||
|
$css = preg_replace_callback("@rgb\\s*\\(\\s*([0-9,\\s]+)\\s*\\)@", array($this, '_shortenRgbCB'), $css);
|
||
|
|
||
|
// Shorten colors from #AABBCC to #ABC. Note that we want to make sure
|
||
|
// the color is not preceded by either ", " or =. Indeed, the property
|
||
|
// filter: chroma(color="#FFFFFF");
|
||
|
// would become
|
||
|
// filter: chroma(color="#FFF");
|
||
|
// which makes the filter break in IE.
|
||
|
$css = preg_replace_callback("@([^\"'=\\s])(\\s*)#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])@", array($this, '_shortenHexCB'), $css);
|
||
|
|
||
|
// Remove empty rules.
|
||
|
$css = preg_replace("@[^\\}]+\\{;\\}@", "", $css);
|
||
|
|
||
|
$linebreakpos = isset($this->_options['linebreakpos'])
|
||
|
? $this->_options['linebreakpos']
|
||
|
: 0;
|
||
|
|
||
|
if ($linebreakpos > 0) {
|
||
|
// Some source control tools don't like it when files containing lines longer
|
||
|
// than, say 8000 characters, are checked in. The linebreak option is used in
|
||
|
// that case to split long lines after a specific column.
|
||
|
$i = 0;
|
||
|
$linestartpos = 0;
|
||
|
$sb = $css;
|
||
|
|
||
|
// make sure strlen returns byte count
|
||
|
$mbIntEnc = null;
|
||
|
if (function_exists('mb_strlen') && ((int)ini_get('mbstring.func_overload') & 2)) {
|
||
|
$mbIntEnc = mb_internal_encoding();
|
||
|
mb_internal_encoding('8bit');
|
||
|
}
|
||
|
$sbLength = strlen($css);
|
||
|
while ($i < $sbLength) {
|
||
|
$c = $sb[$i++];
|
||
|
if ($c === '}' && $i - $linestartpos > $linebreakpos) {
|
||
|
$sb = substr_replace($sb, "\n", $i, 0);
|
||
|
$sbLength++;
|
||
|
$linestartpos = $i;
|
||
|
}
|
||
|
}
|
||
|
$css = $sb;
|
||
|
|
||
|
// undo potential mb_encoding change
|
||
|
if ($mbIntEnc !== null) {
|
||
|
mb_internal_encoding($mbIntEnc);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Replace the pseudo class for the Box Model Hack
|
||
|
$css = str_replace("___PSEUDOCLASSBMH___", "\"\\\\\"}\\\\\"\"", $css);
|
||
|
|
||
|
// Replace multiple semi-colons in a row by a single one
|
||
|
// See SF bug #1980989
|
||
|
$css = preg_replace("@;;+@", ";", $css);
|
||
|
|
||
|
// prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
|
||
|
$css = preg_replace('/:first-l(etter|ine)\\{/', ':first-l$1 {', $css);
|
||
|
|
||
|
// Trim the final string (for any leading or trailing white spaces)
|
||
|
$css = trim($css);
|
||
|
|
||
|
return $css;
|
||
|
}
|
||
|
|
||
|
protected function _removeSpacesCB($m)
|
||
|
{
|
||
|
return str_replace(':', '___PSEUDOCLASSCOLON___', $m[0]);
|
||
|
}
|
||
|
|
||
|
protected function _shortenRgbCB($m)
|
||
|
{
|
||
|
$rgbcolors = explode(',', $m[1]);
|
||
|
$hexcolor = '#';
|
||
|
for ($i = 0; $i < count($rgbcolors); $i++) {
|
||
|
$val = round($rgbcolors[$i]);
|
||
|
if ($val < 16) {
|
||
|
$hexcolor .= '0';
|
||
|
}
|
||
|
$hexcolor .= dechex($val);
|
||
|
}
|
||
|
return $hexcolor;
|
||
|
}
|
||
|
|
||
|
protected function _shortenHexCB($m)
|
||
|
{
|
||
|
// Test for AABBCC pattern
|
||
|
if ((strtolower($m[3])===strtolower($m[4])) &&
|
||
|
(strtolower($m[5])===strtolower($m[6])) &&
|
||
|
(strtolower($m[7])===strtolower($m[8]))) {
|
||
|
return $m[1] . $m[2] . "#" . $m[3] . $m[5] . $m[7];
|
||
|
} else {
|
||
|
return $m[0];
|
||
|
}
|
||
|
}
|
||
|
}
|