114 protected $configuration = array();
120 protected $parser = null;
126 protected $buffer =
"";
136 $this->configuration = $configuration;
137 $this->parser = $parser;
159 abstract public function parse($index, $char, $previousChar, $state);
182 protected $configuration = array();
188 protected $minifier = null;
198 $this->configuration = $configuration;
199 $this->minifier = $minifier;
236 protected $configuration = array();
242 protected $minifier = null;
252 $this->configuration = $configuration;
253 $this->minifier = $minifier;
261 abstract public function apply(array &$tokens);
283 protected $indent =
" ";
289 protected $padding = 0;
295 protected $tokens = array();
303 public function __construct(array $tokens, $indent = null, $padding = null)
305 $this->tokens = $tokens;
306 $this->indent = !is_null($indent) ? $indent : $this->indent;
307 $this->padding = !is_null($padding) ? $padding : $this->padding;
334 public $IsImportant =
false;
340 public $IsLast =
false;
346 public $Property =
"";
362 public function __construct($property, $value, $isImportant =
false, $isLast =
false)
364 $this->Property = $property;
365 $this->Value = $value;
366 $this->IsImportant = $isImportant;
367 $this->IsLast = $isLast;
376 return $this->Property .
":" . $this->Value . ($this->IsImportant ?
" !important" :
"") . ($this->IsLast ?
"" :
";");
439 for ($i = 0, $l = count($this->tokens); $i < $l; $i++)
441 $token = $this->tokens[$i];
442 $class = get_class($token);
443 $indent = str_repeat($this->indent, $level);
444 if ($class ===
"CssCommentToken")
446 $lines = array_map(
"trim", explode(
"\n", $token->Comment));
447 for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++)
449 $r[] = $indent . (substr($lines[$ii], 0, 1) ==
"*" ?
" " :
"") . $lines[$ii];
452 elseif ($class ===
"CssAtCharsetToken")
454 $r[] = $indent .
"@charset " . $token->Charset .
";";
456 elseif ($class ===
"CssAtFontFaceStartToken")
458 $r[] = $indent .
"@font-face";
459 $r[] = $this->indent . $indent .
"{";
462 elseif ($class ===
"CssAtImportToken")
464 $r[] = $indent .
"@import " . $token->Import .
" " . implode(
", ", $token->MediaTypes) .
";";
466 elseif ($class ===
"CssAtKeyframesStartToken")
468 $r[] = $indent .
"@keyframes \"" . $token->Name .
"\"";
469 $r[] = $this->indent . $indent .
"{";
472 elseif ($class ===
"CssAtMediaStartToken")
474 $r[] = $indent .
"@media " . implode(
", ", $token->MediaTypes);
475 $r[] = $this->indent . $indent .
"{";
478 elseif ($class ===
"CssAtPageStartToken")
480 $r[] = $indent .
"@page";
481 $r[] = $this->indent . $indent .
"{";
484 elseif ($class ===
"CssAtVariablesStartToken")
486 $r[] = $indent .
"@variables " . implode(
", ", $token->MediaTypes);
487 $r[] = $this->indent . $indent .
"{";
490 elseif ($class ===
"CssRulesetStartToken" || $class ===
"CssAtKeyframesRulesetStartToken")
492 $r[] = $indent . implode(
", ", $token->Selectors);
493 $r[] = $this->indent . $indent .
"{";
496 elseif ($class ==
"CssAtFontFaceDeclarationToken"
497 || $class ===
"CssAtKeyframesRulesetDeclarationToken"
498 || $class ===
"CssAtPageDeclarationToken"
499 || $class ==
"CssAtVariablesDeclarationToken"
500 || $class ===
"CssRulesetDeclarationToken"
503 $declaration = $indent . $token->Property .
": ";
506 $declaration = str_pad($declaration, $this->padding,
" ", STR_PAD_RIGHT);
508 $r[] = $declaration . $token->Value . ($token->IsImportant ?
" !important" :
"") .
";";
510 elseif ($class ===
"CssAtFontFaceEndToken"
511 || $class ===
"CssAtMediaEndToken"
512 || $class ===
"CssAtKeyframesEndToken"
513 || $class ===
"CssAtKeyframesRulesetEndToken"
514 || $class ===
"CssAtPageEndToken"
515 || $class ===
"CssAtVariablesEndToken"
516 || $class ===
"CssRulesetEndToken"
519 $r[] = $indent .
"}";
523 return implode(
"\n", $r);
561 private $reMatch =
"/var\((.+)\)/iSU";
567 private $variables = null;
575 return $this->variables;
585 if (stripos($token->Value,
"var") !==
false && preg_match_all($this->reMatch, $token->Value, $m))
587 $mediaTypes = $token->MediaTypes;
588 if (!in_array(
"all", $mediaTypes))
590 $mediaTypes[] =
"all";
592 for ($i = 0, $l = count($m[0]); $i < $l; $i++)
594 $variable = trim($m[1][$i]);
595 foreach ($mediaTypes as $mediaType)
597 if (isset($this->variables[$mediaType], $this->variables[$mediaType][$variable]))
600 $token->Value = str_replace($m[0][$i], $this->variables[$mediaType][$variable], $token->Value);
605 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": No value found for variable <code>" . $variable .
"</code> in media types <code>" . implode(
", ", $mediaTypes) .
"</code>", (
string) $token));
621 "CssAtFontFaceDeclarationToken",
622 "CssAtPageDeclarationToken",
623 "CssRulesetDeclarationToken"
634 $this->variables = $variables;
658 public function apply(array &$tokens)
660 $variables = array();
661 $defaultMediaTypes = array(
"all");
662 $mediaTypes = array();
664 for($i = 0, $l = count($tokens); $i < $l; $i++)
667 if (get_class($tokens[$i]) ===
"CssAtVariablesStartToken")
670 $mediaTypes = (count($tokens[$i]->MediaTypes) == 0 ? $defaultMediaTypes : $tokens[$i]->MediaTypes);
671 foreach ($mediaTypes as $mediaType)
673 if (!isset($variables[$mediaType]))
675 $variables[$mediaType] = array();
679 for($i = $i; $i < $l; $i++)
682 if (get_class($tokens[$i]) ===
"CssAtVariablesDeclarationToken")
684 foreach ($mediaTypes as $mediaType)
686 $variables[$mediaType][$tokens[$i]->Property] = $tokens[$i]->Value;
691 elseif (get_class($tokens[$i]) ===
"CssAtVariablesEndToken")
700 foreach($variables as $mediaType => $null)
702 foreach($variables[$mediaType] as $variable => $value)
705 if (stripos($value,
"var") !==
false && preg_match_all(
"/var\((.+)\)/iSU", $value, $m))
708 for ($i = 0, $l = count($m[0]); $i < $l; $i++)
710 $variables[$mediaType][$variable] = str_replace($m[0][$i], (isset($variables[$mediaType][$m[1][$i]]) ? $variables[$mediaType][$m[1][$i]] :
""), $variables[$mediaType][$variable]);
716 foreach ($remove as $i)
720 if (!($plugin = $this->minifier->getPlugin(
"CssVariablesMinifierPlugin")))
722 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": The plugin <code>CssVariablesMinifierPlugin</code> was not found but is required for <code>" . __CLASS__ .
"</code>"));
726 $plugin->setVariables($variables);
728 return count($remove);
753 return array(
"(",
")");
772 public function parse($index, $char, $previousChar, $state)
775 if ($char ===
"(" && strtolower(substr($this->parser->getSource(), $index - 3, 4)) ===
"url(" && $state !==
"T_URL")
777 $this->parser->pushState(
"T_URL");
778 $this->parser->setExclusive(__CLASS__);
781 elseif ($char ===
"\n" && $previousChar ===
"\\" && $state ===
"T_URL")
783 $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2));
786 elseif ($char ===
"\n" && $previousChar !==
"\\" && $state ===
"T_URL")
788 $line = $this->parser->getBuffer();
789 $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) .
")");
790 $this->parser->popState();
791 $this->parser->unsetExclusive();
795 elseif ($char ===
")" && $state ===
"T_URL")
797 $this->parser->popState();
798 $this->parser->unsetExclusive();
827 private $delimiterChar = null;
835 return array(
"\"",
"'",
"\n");
854 public function parse($index, $char, $previousChar, $state)
857 if (($char ===
"\"" || $char ===
"'") && $state !==
"T_STRING")
859 $this->delimiterChar = $char;
860 $this->parser->pushState(
"T_STRING");
861 $this->parser->setExclusive(__CLASS__);
864 elseif ($char ===
"\n" && $previousChar ===
"\\" && $state ===
"T_STRING")
866 $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2));
869 elseif ($char ===
"\n" && $previousChar !==
"\\" && $state ===
"T_STRING")
871 $line = $this->parser->getBuffer();
872 $this->parser->popState();
873 $this->parser->unsetExclusive();
874 $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . $this->delimiterChar);
876 $this->delimiterChar = null;
879 elseif ($char === $this->delimiterChar && $state ===
"T_STRING")
883 if ($previousChar ==
"\\")
885 $source = $this->parser->getSource();
888 while (substr($source, $i, 1) ===
"\\")
897 $this->parser->popState();
898 $this->parser->unsetExclusive();
899 $this->delimiterChar = null;
927 public function apply(array &$tokens)
930 for ($i = 0, $l = count($tokens); $i < $l; $i++)
933 if (get_class($tokens[$i]) !==
"CssRulesetStartToken") {
continue; }
936 for ($ii = $i + 1; $ii < $l; $ii++)
938 if (get_class($tokens[$ii]) !==
"CssRulesetEndToken") {
continue; }
942 if (!$endIndex) {
break; }
946 if ($endIndex - $startIndex <= 2) {
continue; }
948 for ($ii = $startIndex + 1; $ii < $endIndex; $ii++)
950 if (get_class($tokens[$ii]) !==
"CssRulesetDeclarationToken") {
continue(2); }
952 $declarations = array_slice($tokens, $startIndex + 1, $endIndex - $startIndex - 1);
954 $sortRequired = $lastPropertyName =
false;
955 foreach ($declarations as $declaration)
957 if ($lastPropertyName)
959 if (strcmp($lastPropertyName, $declaration->Property) > 0)
961 $sortRequired =
true;
965 $lastPropertyName = $declaration->Property;
967 if (!$sortRequired) {
continue; }
969 usort($declarations, array(__CLASS__,
"userDefinedSort1"));
971 for ($ii = 0, $ll = count($declarations) - 1; $ii <= $ll; $ii++)
975 $declarations[$ii]->IsLast =
true;
979 $declarations[$ii]->IsLast =
false;
983 array_splice($tokens, $startIndex + 1, $endIndex - $startIndex - 1, $declarations);
984 $r += $endIndex - $startIndex - 1;
995 return strcmp($a->Property, $b->Property);
1016 public $Selectors = array();
1025 $this->Selectors = $selectors;
1034 return implode(
",", $this->Selectors) .
"{";
1060 return array(
",",
"{",
"}",
":",
";");
1069 return array(
"T_DOCUMENT",
"T_AT_MEDIA",
"T_RULESET::SELECTORS",
"T_RULESET",
"T_RULESET_DECLARATION");
1076 private $selectors = array();
1085 public function parse($index, $char, $previousChar, $state)
1088 if ($char ===
"," && ($state ===
"T_DOCUMENT" || $state ===
"T_AT_MEDIA" || $state ===
"T_RULESET::SELECTORS"))
1090 if ($state !==
"T_RULESET::SELECTORS")
1092 $this->parser->pushState(
"T_RULESET::SELECTORS");
1094 $this->selectors[] = $this->parser->getAndClearBuffer(
",{");
1097 elseif ($char ===
"{" && ($state ===
"T_DOCUMENT" || $state ===
"T_AT_MEDIA" || $state ===
"T_RULESET::SELECTORS"))
1099 if ($this->parser->getBuffer() !==
"")
1101 $this->selectors[] = $this->parser->getAndClearBuffer(
",{");
1102 if ($state ==
"T_RULESET::SELECTORS")
1104 $this->parser->popState();
1106 $this->parser->pushState(
"T_RULESET");
1108 $this->selectors = array();
1112 elseif ($char ===
":" && $state ===
"T_RULESET")
1114 $this->parser->pushState(
"T_RULESET_DECLARATION");
1115 $this->buffer = $this->parser->getAndClearBuffer(
":;",
true);
1118 elseif ($char ===
":" && $state ===
"T_RULESET_DECLARATION")
1121 if ($this->buffer ===
"filter")
1125 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": Unterminated declaration", $this->buffer .
":" . $this->parser->getBuffer() .
"_"));
1128 elseif (($char ===
";" || $char ===
"}") && $state ===
"T_RULESET_DECLARATION")
1130 $value = $this->parser->getAndClearBuffer(
";}");
1131 if (strtolower(substr($value, -10, 10)) ===
"!important")
1133 $value = trim(substr($value, 0, -10));
1134 $isImportant =
true;
1138 $isImportant =
false;
1140 $this->parser->popState();
1141 $this->parser->appendToken(
new CssRulesetDeclarationToken($this->buffer, $value, $this->parser->getMediaTypes(), $isImportant));
1146 $this->parser->popState();
1151 elseif ($char ===
"}" && $state ===
"T_RULESET")
1153 $this->parser->popState();
1154 $this->parser->clearBuffer();
1157 $this->selectors = array();
1199 public $MediaTypes = array(
"all");
1210 public function __construct($property, $value, $mediaTypes = null, $isImportant =
false, $isLast =
false)
1213 $this->MediaTypes = $mediaTypes ? $mediaTypes : array(
"all");
1239 for ($i = 0, $l = count($tokens); $i < $l; $i++)
1241 $current = get_class($tokens[$i]);
1242 $next = isset($tokens[$i+1]) ? get_class($tokens[$i+1]) :
false;
1243 if (($current ===
"CssRulesetDeclarationToken" && $next ===
"CssRulesetEndToken") ||
1244 ($current ===
"CssAtFontFaceDeclarationToken" && $next ===
"CssAtFontFaceEndToken") ||
1245 ($current ===
"CssAtPageDeclarationToken" && $next ===
"CssAtPageEndToken"))
1247 $tokens[$i]->IsLast =
true;
1276 for ($i = 0, $l = count($tokens); $i < $l; $i++)
1278 $current = get_class($tokens[$i]);
1279 $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) :
false;
1280 if (($current ===
"CssRulesetStartToken" && $next ===
"CssRulesetEndToken") ||
1281 ($current ===
"CssAtKeyframesRulesetStartToken" && $next ===
"CssAtKeyframesRulesetEndToken" && !array_intersect(array(
"from",
"0%",
"to",
"100%"), array_map(
"strtolower", $tokens[$i]->Selectors)))
1285 $tokens[$i + 1] = null;
1316 for ($i = 0, $l = count($tokens); $i < $l; $i++)
1318 $current = get_class($tokens[$i]);
1319 $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) :
false;
1320 if (($current ===
"CssAtFontFaceStartToken" && $next ===
"CssAtFontFaceEndToken") ||
1321 ($current ===
"CssAtKeyframesStartToken" && $next ===
"CssAtKeyframesEndToken") ||
1322 ($current ===
"CssAtPageStartToken" && $next ===
"CssAtPageEndToken") ||
1323 ($current ===
"CssAtMediaStartToken" && $next ===
"CssAtMediaEndToken"))
1326 $tokens[$i + 1] = null;
1356 for ($i = 0, $l = count($tokens); $i < $l; $i++)
1358 if (get_class($tokens[$i]) ===
"CssCommentToken")
1385 private $buffer =
"";
1391 private $plugins = array();
1397 private $source =
"";
1403 private $state =
"T_DOCUMENT";
1409 private $stateExclusive =
false;
1415 private $stateMediaTypes =
false;
1421 private $states = array(
"T_DOCUMENT");
1427 private $tokens = array();
1439 $plugins = array_merge(array
1444 "Expression" =>
true,
1446 "AtCharset" =>
true,
1447 "AtFontFace" =>
true,
1449 "AtKeyframes" =>
true,
1452 "AtVariables" =>
true
1453 ), is_array($plugins) ? $plugins : array());
1455 foreach ($plugins as $name => $config)
1457 if ($config !==
false)
1459 $class =
"Css" . $name .
"ParserPlugin";
1460 $config = is_array($config) ? $config : array();
1461 if (class_exists($class))
1463 $this->plugins[] =
new $class($this, $config);
1467 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": The plugin <code>" . $name .
"</code> with the class name <code>" . $class .
"</code> was not found"));
1471 if (!is_null($source))
1473 $this->
parse($source);
1484 $this->tokens[] = $token;
1520 $r = trim($r,
" \t\n\r\0\x0B" . $trim);
1524 $r = strtolower($r);
1535 return $this->stateMediaTypes;
1544 return $this->source;
1553 return $this->state;
1563 static $index = null;
1564 if (is_null($index))
1567 for ($i = 0, $l = count($this->plugins); $i < $l; $i++)
1569 $index[get_class($this->plugins[$i])] = $i;
1572 return isset($index[$class]) ? $this->plugins[$index[$class]] :
false;
1581 return $this->tokens;
1591 return ($this->state == $state);
1603 $this->tokens = array();
1606 $globalTriggerChars =
"";
1607 $plugins = $this->plugins;
1608 $pluginCount = count($plugins);
1609 $pluginIndex = array();
1610 $pluginTriggerStates = array();
1611 $pluginTriggerChars = array();
1612 for ($i = 0, $l = count($plugins); $i < $l; $i++)
1614 $tPluginClassName = get_class($plugins[$i]);
1615 $pluginTriggerChars[$i] = implode(
"", $plugins[$i]->getTriggerChars());
1616 $tPluginTriggerStates = $plugins[$i]->getTriggerStates();
1617 $pluginTriggerStates[$i] = $tPluginTriggerStates ===
false ?
false :
"|" . implode(
"|", $tPluginTriggerStates) .
"|";
1618 $pluginIndex[$tPluginClassName] = $i;
1619 for ($ii = 0, $ll = strlen($pluginTriggerChars[$i]); $ii < $ll; $ii++)
1621 $c = substr($pluginTriggerChars[$i], $ii, 1);
1622 if (strpos($globalTriggerChars, $c) ===
false)
1624 $globalTriggerChars .= $c;
1629 $source = str_replace(
"\r\n",
"\n", $source);
1630 $source = str_replace(
"\r",
"\n", $source);
1631 $this->source = $source;
1633 $buffer = &$this->buffer;
1634 $exclusive = &$this->stateExclusive;
1635 $state = &$this->state;
1638 for ($i = 0, $l = strlen($source); $i < $l; $i++)
1643 if ($exclusive ===
false)
1645 if ($c ===
"\n" || $c ===
"\t")
1649 if ($c ===
" " && $p ===
" ")
1656 if (strpos($globalTriggerChars, $c) !==
false)
1661 $tPluginIndex = $pluginIndex[$exclusive];
1662 if (strpos($pluginTriggerChars[$tPluginIndex], $c) !==
false && ($pluginTriggerStates[$tPluginIndex] ===
false || strpos($pluginTriggerStates[$tPluginIndex], $state) !==
false))
1664 $r = $plugins[$tPluginIndex]->parse($i, $c, $p, $state);
1671 elseif ($r !==
false && $r != $i)
1681 $triggerState =
"|" . $state .
"|";
1682 for ($ii = 0, $ll = $pluginCount; $ii < $ll; $ii++)
1685 if (strpos($pluginTriggerChars[$ii], $c) !==
false && ($pluginTriggerStates[$ii] ===
false || strpos($pluginTriggerStates[$ii], $triggerState) !==
false))
1688 $r = $plugins[$ii]->parse($i, $c, $p, $state);
1695 elseif ($r !==
false && $r != $i)
1706 return $this->tokens;
1715 $r = array_pop($this->states);
1716 $this->state = $this->states[count($this->states) - 1];
1727 $r = array_push($this->states, $state);
1728 $this->state = $this->states[count($this->states) - 1];
1739 $this->buffer = $buffer;
1749 $this->stateExclusive = $exclusive;
1759 $this->stateMediaTypes = $mediaTypes;
1769 $r = array_pop($this->states);
1770 array_push($this->states, $state);
1771 $this->state = $this->states[count($this->states) - 1];
1781 $this->stateExclusive =
false;
1790 $this->stateMediaTypes =
false;
1815 for ($i = 0, $l = count($this->tokens); $i < $l; $i++)
1817 $token = $this->tokens[$i];
1818 $class = get_class($token);
1819 $indent = str_repeat($this->indent, $level);
1820 if ($class ===
"CssCommentToken")
1822 $lines = array_map(
"trim", explode(
"\n", $token->Comment));
1823 for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++)
1825 $r[] = $indent . (substr($lines[$ii], 0, 1) ==
"*" ?
" " :
"") . $lines[$ii];
1828 elseif ($class ===
"CssAtCharsetToken")
1830 $r[] = $indent .
"@charset " . $token->Charset .
";";
1832 elseif ($class ===
"CssAtFontFaceStartToken")
1834 $r[] = $indent .
"@font-face {";
1837 elseif ($class ===
"CssAtImportToken")
1839 $r[] = $indent .
"@import " . $token->Import .
" " . implode(
", ", $token->MediaTypes) .
";";
1841 elseif ($class ===
"CssAtKeyframesStartToken")
1843 $r[] = $indent .
"@keyframes \"" . $token->Name .
"\" {";
1846 elseif ($class ===
"CssAtMediaStartToken")
1848 $r[] = $indent .
"@media " . implode(
", ", $token->MediaTypes) .
" {";
1851 elseif ($class ===
"CssAtPageStartToken")
1853 $r[] = $indent .
"@page {";
1856 elseif ($class ===
"CssAtVariablesStartToken")
1858 $r[] = $indent .
"@variables " . implode(
", ", $token->MediaTypes) .
" {";
1861 elseif ($class ===
"CssRulesetStartToken" || $class ===
"CssAtKeyframesRulesetStartToken")
1863 $r[] = $indent . implode(
", ", $token->Selectors) .
" {";
1866 elseif ($class ==
"CssAtFontFaceDeclarationToken"
1867 || $class ===
"CssAtKeyframesRulesetDeclarationToken"
1868 || $class ===
"CssAtPageDeclarationToken"
1869 || $class ==
"CssAtVariablesDeclarationToken"
1870 || $class ===
"CssRulesetDeclarationToken"
1873 $declaration = $indent . $token->Property .
": ";
1876 $declaration = str_pad($declaration, $this->padding,
" ", STR_PAD_RIGHT);
1878 $r[] = $declaration . $token->Value . ($token->IsImportant ?
" !important" :
"") .
";";
1880 elseif ($class ===
"CssAtFontFaceEndToken"
1881 || $class ===
"CssAtMediaEndToken"
1882 || $class ===
"CssAtKeyframesEndToken"
1883 || $class ===
"CssAtKeyframesRulesetEndToken"
1884 || $class ===
"CssAtPageEndToken"
1885 || $class ===
"CssAtVariablesEndToken"
1886 || $class ===
"CssRulesetEndToken"
1890 $r[] = str_repeat($indent, $level) .
"}";
1893 return implode(
"\n", $r);
1937 private $filters = array();
1943 private $plugins = array();
1949 private $minified =
"";
1960 public function __construct($source = null, array $filters = null, array $plugins = null)
1962 $filters = array_merge(array
1964 "ImportImports" =>
false,
1965 "RemoveComments" =>
true,
1966 "RemoveEmptyRulesets" =>
true,
1967 "RemoveEmptyAtBlocks" =>
true,
1968 "ConvertLevel3Properties" =>
false,
1969 "ConvertLevel3AtKeyframes" =>
false,
1970 "Variables" =>
true,
1971 "RemoveLastDelarationSemiColon" =>
true
1972 ), is_array($filters) ? $filters : array());
1973 $plugins = array_merge(array
1975 "Variables" =>
true,
1976 "ConvertFontWeight" =>
false,
1977 "ConvertHslColors" =>
false,
1978 "ConvertRgbColors" =>
false,
1979 "ConvertNamedColors" =>
false,
1980 "CompressColorValues" =>
false,
1981 "CompressUnitValues" =>
false,
1982 "CompressExpressionValues" =>
false
1983 ), is_array($plugins) ? $plugins : array());
1985 foreach ($filters as $name => $config)
1987 if ($config !==
false)
1989 $class =
"Css" . $name .
"MinifierFilter";
1990 $config = is_array($config) ? $config : array();
1991 if (class_exists($class))
1993 $this->filters[] =
new $class($this, $config);
1997 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": The filter <code>" . $name .
"</code> with the class name <code>" . $class .
"</code> was not found"));
2002 foreach ($plugins as $name => $config)
2004 if ($config !==
false)
2006 $class =
"Css" . $name .
"MinifierPlugin";
2007 $config = is_array($config) ? $config : array();
2008 if (class_exists($class))
2010 $this->plugins[] =
new $class($this, $config);
2014 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": The plugin <code>" . $name .
"</code> with the class name <code>" . $class .
"</code> was not found"));
2019 if (!is_null($source))
2031 return $this->minified;
2041 static $index = null;
2042 if (is_null($index))
2045 for ($i = 0, $l = count($this->plugins); $i < $l; $i++)
2047 $index[get_class($this->plugins[$i])] = $i;
2050 return isset($index[$class]) ? $this->plugins[$index[$class]] :
false;
2063 $tokens = $parser->getTokens();
2064 $filters = $this->filters;
2065 $filterCount = count($this->filters);
2066 $plugins = $this->plugins;
2067 $pluginCount = count($plugins);
2068 $pluginIndex = array();
2069 $pluginTriggerTokens = array();
2070 $globalTriggerTokens = array();
2071 for ($i = 0, $l = count($plugins); $i < $l; $i++)
2073 $tPluginClassName = get_class($plugins[$i]);
2074 $pluginTriggerTokens[$i] = $plugins[$i]->getTriggerTokens();
2075 foreach ($pluginTriggerTokens[$i] as $v)
2077 if (!in_array($v, $globalTriggerTokens))
2079 $globalTriggerTokens[] = $v;
2082 $pluginTriggerTokens[$i] =
"|" . implode(
"|", $pluginTriggerTokens[$i]) .
"|";
2083 $pluginIndex[$tPluginClassName] = $i;
2085 $globalTriggerTokens =
"|" . implode(
"|", $globalTriggerTokens) .
"|";
2089 for($i = 0; $i < $filterCount; $i++)
2092 if ($filters[$i]->apply($tokens) > 0)
2095 $tokens = array_values(array_filter($tokens));
2098 $tokenCount = count($tokens);
2102 for($i = 0; $i < $tokenCount; $i++)
2104 $triggerToken =
"|" . get_class($tokens[$i]) .
"|";
2105 if (strpos($globalTriggerTokens, $triggerToken) !==
false)
2107 for($ii = 0; $ii < $pluginCount; $ii++)
2109 if (strpos($pluginTriggerTokens[$ii], $triggerToken) !==
false || $pluginTriggerTokens[$ii] ===
false)
2112 if ($plugins[$ii]->apply($tokens[$i]) ===
true)
2121 for($i = 0; $i < $tokenCount; $i++)
2123 $r .= (string) $tokens[$i];
2125 $this->minified = $r;
2169 private static $classIndex = array();
2175 private static $errors = array();
2181 private static $isVerbose =
false;
2190 if (isset(self::$classIndex[$class]))
2192 require(self::$classIndex[$class]);
2202 return self::$errors;
2211 return count(self::$errors) > 0;
2221 $paths = array(dirname(__FILE__));
2222 while (list($i, $path) = each($paths))
2224 $subDirectorys = glob($path .
"*", GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT);
2225 if (is_array($subDirectorys))
2227 foreach ($subDirectorys as $subDirectory)
2229 $paths[] = $subDirectory;
2232 $files = glob($path .
"*.php", 0);
2233 if (is_array($files))
2235 foreach ($files as $file)
2237 $class = substr(basename($file), 0, -4);
2238 self::$classIndex[$class] = $file;
2242 krsort(self::$classIndex);
2245 if (function_exists(
"spl_autoload_register") && !is_callable(
"__autoload"))
2247 spl_autoload_register(array(__CLASS__,
"autoload"));
2252 foreach (self::$classIndex as $class => $file)
2254 if (!class_exists($class))
2256 require_once($file);
2269 public static function minify($source, array $filters = null, array $plugins = null)
2271 self::$errors = array();
2272 $minifier =
new CssMinifier($source, $filters, $plugins);
2273 return $minifier->getMinified();
2282 public static function parse($source, array $plugins = null)
2284 self::$errors = array();
2285 $parser =
new CssParser($source, $plugins);
2286 return $parser->getTokens();
2296 self::$isVerbose = (boolean) $to;
2297 return self::$isVerbose;
2307 self::$errors[] = $error;
2308 if (self::$isVerbose)
2310 trigger_error((
string) $error, E_USER_WARNING);
2335 private $imported = array();
2344 if (!isset($this->configuration[
"BasePath"]) || !is_dir($this->configuration[
"BasePath"]))
2346 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": Base path <code>" . ($this->configuration[
"BasePath"] ? $this->configuration[
"BasePath"] :
"null").
"</code> is not a directory"));
2349 for ($i = 0, $l = count($tokens); $i < $l; $i++)
2351 if (get_class($tokens[$i]) ===
"CssAtImportToken")
2353 $import = $this->configuration[
"BasePath"] .
"/" . $tokens[$i]->Import;
2355 if (!is_file($import))
2357 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": Import file <code>" . $import.
"</code> was not found.", (
string) $tokens[$i]));
2360 elseif (in_array($import, $this->imported))
2362 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": Import file <code>" . $import.
"</code> was already imported.", (
string) $tokens[$i]));
2367 $this->imported[] = $import;
2368 $parser =
new CssParser(file_get_contents($import));
2369 $import = $parser->getTokens();
2371 if (count($tokens[$i]->MediaTypes) > 0 && !(count($tokens[$i]->MediaTypes) == 1 && $tokens[$i]->MediaTypes[0] ==
"all"))
2377 for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2379 if (get_class($import[$ii]) ===
"CssAtImportToken")
2382 if (count($import[$ii]->MediaTypes) == 0 || (count($import[$ii]->MediaTypes) == 1 && $import[$ii]->MediaTypes[0] ==
"all"))
2384 $import[$ii]->MediaTypes = $tokens[$i]->MediaTypes;
2387 elseif (count($import[$ii]->MediaTypes > 0))
2389 foreach ($import[$ii]->MediaTypes as $index => $mediaType)
2391 if (!in_array($mediaType, $tokens[$i]->MediaTypes))
2393 unset($import[$ii]->MediaTypes[$index]);
2396 $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes);
2398 if (count($import[$ii]->MediaTypes) == 0)
2400 $import[$ii] = null;
2408 for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2410 if (get_class($import[$ii]) ===
"CssAtMediaStartToken")
2412 foreach ($import[$ii]->MediaTypes as $index => $mediaType)
2414 if (!in_array($mediaType, $tokens[$i]->MediaTypes))
2416 unset($import[$ii]->MediaTypes[$index]);
2418 $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes);
2425 for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2427 if (get_class($import[$ii]) ===
"CssAtMediaStartToken")
2429 if (count($import[$ii]->MediaTypes) === 0)
2431 for ($iii = $ii; $iii < $ll; $iii++)
2433 if (get_class($import[$iii]) ===
"CssAtMediaEndToken")
2438 if (get_class($import[$iii]) ===
"CssAtMediaEndToken")
2440 array_splice($import, $ii, $iii - $ii + 1, array());
2441 $ll = count($import);
2450 for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2452 if (get_class($import[$ii]) ===
"CssAtMediaStartToken" && count(array_diff($tokens[$i]->MediaTypes, $import[$ii]->MediaTypes)) === 0)
2454 for ($iii = $ii; $iii < $ll; $iii++)
2456 if (get_class($import[$iii]) ==
"CssAtMediaEndToken")
2461 if (get_class($import[$iii]) ==
"CssAtMediaEndToken")
2463 unset($import[$ii]);
2464 unset($import[$iii]);
2465 $import = array_values($import);
2466 $ll = count($import);
2473 for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2475 $class = get_class($import[$ii]);
2476 if ($class ===
"CssAtImportToken" || $class ===
"CssAtCharsetToken")
2478 $blocks = array_merge($blocks, array_splice($import, $ii, 1, array()));
2479 $ll = count($import);
2485 for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2487 $class = get_class($import[$ii]);
2488 if ($class ===
"CssAtFontFaceStartToken" || $class ===
"CssAtMediaStartToken" || $class ===
"CssAtPageStartToken" || $class ===
"CssAtVariablesStartToken")
2490 for ($iii = $ii; $iii < $ll; $iii++)
2492 $class = get_class($import[$iii]);
2493 if ($class ===
"CssAtFontFaceEndToken" || $class ===
"CssAtMediaEndToken" || $class ===
"CssAtPageEndToken" || $class ===
"CssAtVariablesEndToken")
2498 $class = get_class($import[$iii]);
2499 if (isset($import[$iii]) && ($class ===
"CssAtFontFaceEndToken" || $class ===
"CssAtMediaEndToken" || $class ===
"CssAtPageEndToken" || $class ===
"CssAtVariablesEndToken"))
2501 $blocks = array_merge($blocks, array_splice($import, $ii, $iii - $ii + 1, array()));
2502 $ll = count($import);
2510 array_splice($tokens, $i, 1, $import);
2513 $l = count($tokens);
2540 private $leftBraces = 0;
2546 private $rightBraces = 0;
2554 return array(
"(",
")",
";",
"}");
2573 public function parse($index, $char, $previousChar, $state)
2576 if ($char ===
"(" && strtolower(substr($this->parser->getSource(), $index - 10, 11)) ===
"expression(" && $state !==
"T_EXPRESSION")
2578 $this->parser->pushState(
"T_EXPRESSION");
2579 $this->leftBraces++;
2582 elseif ($char ===
"(" && $state ===
"T_EXPRESSION")
2584 $this->leftBraces++;
2587 elseif ($char ===
")" && $state ===
"T_EXPRESSION")
2589 $this->rightBraces++;
2592 elseif (($char ===
";" || $char ===
"}") && $state ===
"T_EXPRESSION" && $this->leftBraces === $this->rightBraces)
2594 $this->leftBraces = $this->rightBraces = 0;
2595 $this->parser->popState();
2635 public $Message =
"";
2641 public $Source =
"";
2651 $this->File = $file;
2652 $this->Line = $line;
2653 $this->Message = $message;
2654 $this->Source = $source;
2663 return $this->Message . ($this->Source ?
": <br /><code>" . $this->Source .
"</code>":
"") .
"<br />in file " . $this->File .
" at line " . $this->Line;
2694 private $reMatch =
"/rgb\s*\(\s*([0-9%]+)\s*,\s*([0-9%]+)\s*,\s*([0-9%]+)\s*\)/iS";
2703 if (stripos($token->Value,
"rgb") !==
false && preg_match($this->reMatch, $token->Value, $m))
2705 for ($i = 1, $l = count($m); $i < $l; $i++)
2707 if (strpos(
"%", $m[$i]) !==
false)
2709 $m[$i] = substr($m[$i], 0, -1);
2710 $m[$i] = (int) (256 * ($m[$i] / 100));
2712 $m[$i] = str_pad(dechex($m[$i]), 2,
"0", STR_PAD_LEFT);
2714 $token->Value = str_replace($m[0],
"#" . $m[1] . $m[2] . $m[3], $token->Value);
2727 "CssAtFontFaceDeclarationToken",
2728 "CssAtPageDeclarationToken",
2729 "CssRulesetDeclarationToken"
2764 private $reMatch = null;
2770 private $reReplace =
"\"\${1}\" . \$this->transformation[strtolower(\"\${2}\")] . \"\${3}\"";
2776 private $transformation = array
2778 "aliceblue" =>
"#f0f8ff",
2779 "antiquewhite" =>
"#faebd7",
2781 "aquamarine" =>
"#7fffd4",
2782 "azure" =>
"#f0ffff",
2783 "beige" =>
"#f5f5dc",
2786 "blueviolet" =>
"#8a2be2",
2787 "brown" =>
"#a52a2a",
2788 "burlywood" =>
"#deb887",
2789 "cadetblue" =>
"#5f9ea0",
2790 "chartreuse" =>
"#7fff00",
2791 "chocolate" =>
"#d2691e",
2792 "coral" =>
"#ff7f50",
2793 "cornflowerblue" =>
"#6495ed",
2794 "cornsilk" =>
"#fff8dc",
2795 "crimson" =>
"#dc143c",
2796 "darkblue" =>
"#00008b",
2797 "darkcyan" =>
"#008b8b",
2798 "darkgoldenrod" =>
"#b8860b",
2799 "darkgray" =>
"#a9a9a9",
2800 "darkgreen" =>
"#006400",
2801 "darkkhaki" =>
"#bdb76b",
2802 "darkmagenta" =>
"#8b008b",
2803 "darkolivegreen" =>
"#556b2f",
2804 "darkorange" =>
"#ff8c00",
2805 "darkorchid" =>
"#9932cc",
2806 "darkred" =>
"#8b0000",
2807 "darksalmon" =>
"#e9967a",
2808 "darkseagreen" =>
"#8fbc8f",
2809 "darkslateblue" =>
"#483d8b",
2810 "darkslategray" =>
"#2f4f4f",
2811 "darkturquoise" =>
"#00ced1",
2812 "darkviolet" =>
"#9400d3",
2813 "deeppink" =>
"#ff1493",
2814 "deepskyblue" =>
"#00bfff",
2815 "dimgray" =>
"#696969",
2816 "dodgerblue" =>
"#1e90ff",
2817 "firebrick" =>
"#b22222",
2818 "floralwhite" =>
"#fffaf0",
2819 "forestgreen" =>
"#228b22",
2820 "fuchsia" =>
"#f0f",
2821 "gainsboro" =>
"#dcdcdc",
2822 "ghostwhite" =>
"#f8f8ff",
2823 "gold" =>
"#ffd700",
2824 "goldenrod" =>
"#daa520",
2825 "gray" =>
"#808080",
2826 "green" =>
"#008000",
2827 "greenyellow" =>
"#adff2f",
2828 "honeydew" =>
"#f0fff0",
2829 "hotpink" =>
"#ff69b4",
2830 "indianred" =>
"#cd5c5c",
2831 "indigo" =>
"#4b0082",
2832 "ivory" =>
"#fffff0",
2833 "khaki" =>
"#f0e68c",
2834 "lavender" =>
"#e6e6fa",
2835 "lavenderblush" =>
"#fff0f5",
2836 "lawngreen" =>
"#7cfc00",
2837 "lemonchiffon" =>
"#fffacd",
2838 "lightblue" =>
"#add8e6",
2839 "lightcoral" =>
"#f08080",
2840 "lightcyan" =>
"#e0ffff",
2841 "lightgoldenrodyellow" =>
"#fafad2",
2842 "lightgreen" =>
"#90ee90",
2843 "lightgrey" =>
"#d3d3d3",
2844 "lightpink" =>
"#ffb6c1",
2845 "lightsalmon" =>
"#ffa07a",
2846 "lightseagreen" =>
"#20b2aa",
2847 "lightskyblue" =>
"#87cefa",
2848 "lightslategray" =>
"#789",
2849 "lightsteelblue" =>
"#b0c4de",
2850 "lightyellow" =>
"#ffffe0",
2852 "limegreen" =>
"#32cd32",
2853 "linen" =>
"#faf0e6",
2854 "maroon" =>
"#800000",
2855 "mediumaquamarine" =>
"#66cdaa",
2856 "mediumblue" =>
"#0000cd",
2857 "mediumorchid" =>
"#ba55d3",
2858 "mediumpurple" =>
"#9370db",
2859 "mediumseagreen" =>
"#3cb371",
2860 "mediumslateblue" =>
"#7b68ee",
2861 "mediumspringgreen" =>
"#00fa9a",
2862 "mediumturquoise" =>
"#48d1cc",
2863 "mediumvioletred" =>
"#c71585",
2864 "midnightblue" =>
"#191970",
2865 "mintcream" =>
"#f5fffa",
2866 "mistyrose" =>
"#ffe4e1",
2867 "moccasin" =>
"#ffe4b5",
2868 "navajowhite" =>
"#ffdead",
2869 "navy" =>
"#000080",
2870 "oldlace" =>
"#fdf5e6",
2871 "olive" =>
"#808000",
2872 "olivedrab" =>
"#6b8e23",
2873 "orange" =>
"#ffa500",
2874 "orangered" =>
"#ff4500",
2875 "orchid" =>
"#da70d6",
2876 "palegoldenrod" =>
"#eee8aa",
2877 "palegreen" =>
"#98fb98",
2878 "paleturquoise" =>
"#afeeee",
2879 "palevioletred" =>
"#db7093",
2880 "papayawhip" =>
"#ffefd5",
2881 "peachpuff" =>
"#ffdab9",
2882 "peru" =>
"#cd853f",
2883 "pink" =>
"#ffc0cb",
2884 "plum" =>
"#dda0dd",
2885 "powderblue" =>
"#b0e0e6",
2886 "purple" =>
"#800080",
2888 "rosybrown" =>
"#bc8f8f",
2889 "royalblue" =>
"#4169e1",
2890 "saddlebrown" =>
"#8b4513",
2891 "salmon" =>
"#fa8072",
2892 "sandybrown" =>
"#f4a460",
2893 "seagreen" =>
"#2e8b57",
2894 "seashell" =>
"#fff5ee",
2895 "sienna" =>
"#a0522d",
2896 "silver" =>
"#c0c0c0",
2897 "skyblue" =>
"#87ceeb",
2898 "slateblue" =>
"#6a5acd",
2899 "slategray" =>
"#708090",
2900 "snow" =>
"#fffafa",
2901 "springgreen" =>
"#00ff7f",
2902 "steelblue" =>
"#4682b4",
2904 "teal" =>
"#008080",
2905 "thistle" =>
"#d8bfd8",
2906 "tomato" =>
"#ff6347",
2907 "turquoise" =>
"#40e0d0",
2908 "violet" =>
"#ee82ee",
2909 "wheat" =>
"#f5deb3",
2911 "whitesmoke" =>
"#f5f5f5",
2913 "yellowgreen" =>
"#9acd32"
2927 $this->reMatch =
"/(^|\s)+(" . implode(
"|", array_keys($this->transformation)) .
")(\s|$)+/eiS";
2938 $lcValue = strtolower($token->Value);
2940 if (isset($this->transformation[$lcValue]))
2942 $token->Value = $this->transformation[$lcValue];
2945 elseif (preg_match($this->reMatch, $token->Value))
2947 $token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value);
2960 "CssAtFontFaceDeclarationToken",
2961 "CssAtPageDeclarationToken",
2962 "CssRulesetDeclarationToken"
2986 private $transformations = array
2989 "animation" => array(null,
"-webkit-animation", null, null),
2990 "animation-delay" => array(null,
"-webkit-animation-delay", null, null),
2991 "animation-direction" => array(null,
"-webkit-animation-direction", null, null),
2992 "animation-duration" => array(null,
"-webkit-animation-duration", null, null),
2993 "animation-fill-mode" => array(null,
"-webkit-animation-fill-mode", null, null),
2994 "animation-iteration-count" => array(null,
"-webkit-animation-iteration-count", null, null),
2995 "animation-name" => array(null,
"-webkit-animation-name", null, null),
2996 "animation-play-state" => array(null,
"-webkit-animation-play-state", null, null),
2997 "animation-timing-function" => array(null,
"-webkit-animation-timing-function", null, null),
2998 "appearance" => array(
"-moz-appearance",
"-webkit-appearance", null, null),
2999 "backface-visibility" => array(null,
"-webkit-backface-visibility", null, null),
3000 "background-clip" => array(null,
"-webkit-background-clip", null, null),
3001 "background-composite" => array(null,
"-webkit-background-composite", null, null),
3002 "background-inline-policy" => array(
"-moz-background-inline-policy", null, null, null),
3003 "background-origin" => array(null,
"-webkit-background-origin", null, null),
3004 "background-position-x" => array(null, null, null,
"-ms-background-position-x"),
3005 "background-position-y" => array(null, null, null,
"-ms-background-position-y"),
3006 "background-size" => array(null,
"-webkit-background-size", null, null),
3007 "behavior" => array(null, null, null,
"-ms-behavior"),
3008 "binding" => array(
"-moz-binding", null, null, null),
3009 "border-after" => array(null,
"-webkit-border-after", null, null),
3010 "border-after-color" => array(null,
"-webkit-border-after-color", null, null),
3011 "border-after-style" => array(null,
"-webkit-border-after-style", null, null),
3012 "border-after-width" => array(null,
"-webkit-border-after-width", null, null),
3013 "border-before" => array(null,
"-webkit-border-before", null, null),
3014 "border-before-color" => array(null,
"-webkit-border-before-color", null, null),
3015 "border-before-style" => array(null,
"-webkit-border-before-style", null, null),
3016 "border-before-width" => array(null,
"-webkit-border-before-width", null, null),
3017 "border-border-bottom-colors" => array(
"-moz-border-bottom-colors", null, null, null),
3018 "border-bottom-left-radius" => array(
"-moz-border-radius-bottomleft",
"-webkit-border-bottom-left-radius", null, null),
3019 "border-bottom-right-radius" => array(
"-moz-border-radius-bottomright",
"-webkit-border-bottom-right-radius", null, null),
3020 "border-end" => array(
"-moz-border-end",
"-webkit-border-end", null, null),
3021 "border-end-color" => array(
"-moz-border-end-color",
"-webkit-border-end-color", null, null),
3022 "border-end-style" => array(
"-moz-border-end-style",
"-webkit-border-end-style", null, null),
3023 "border-end-width" => array(
"-moz-border-end-width",
"-webkit-border-end-width", null, null),
3024 "border-fit" => array(null,
"-webkit-border-fit", null, null),
3025 "border-horizontal-spacing" => array(null,
"-webkit-border-horizontal-spacing", null, null),
3026 "border-image" => array(
"-moz-border-image",
"-webkit-border-image", null, null),
3027 "border-left-colors" => array(
"-moz-border-left-colors", null, null, null),
3028 "border-radius" => array(
"-moz-border-radius",
"-webkit-border-radius", null, null),
3029 "border-border-right-colors" => array(
"-moz-border-right-colors", null, null, null),
3030 "border-start" => array(
"-moz-border-start",
"-webkit-border-start", null, null),
3031 "border-start-color" => array(
"-moz-border-start-color",
"-webkit-border-start-color", null, null),
3032 "border-start-style" => array(
"-moz-border-start-style",
"-webkit-border-start-style", null, null),
3033 "border-start-width" => array(
"-moz-border-start-width",
"-webkit-border-start-width", null, null),
3034 "border-top-colors" => array(
"-moz-border-top-colors", null, null, null),
3035 "border-top-left-radius" => array(
"-moz-border-radius-topleft",
"-webkit-border-top-left-radius", null, null),
3036 "border-top-right-radius" => array(
"-moz-border-radius-topright",
"-webkit-border-top-right-radius", null, null),
3037 "border-vertical-spacing" => array(null,
"-webkit-border-vertical-spacing", null, null),
3038 "box-align" => array(
"-moz-box-align",
"-webkit-box-align", null, null),
3039 "box-direction" => array(
"-moz-box-direction",
"-webkit-box-direction", null, null),
3040 "box-flex" => array(
"-moz-box-flex",
"-webkit-box-flex", null, null),
3041 "box-flex-group" => array(null,
"-webkit-box-flex-group", null, null),
3042 "box-flex-lines" => array(null,
"-webkit-box-flex-lines", null, null),
3043 "box-ordinal-group" => array(
"-moz-box-ordinal-group",
"-webkit-box-ordinal-group", null, null),
3044 "box-orient" => array(
"-moz-box-orient",
"-webkit-box-orient", null, null),
3045 "box-pack" => array(
"-moz-box-pack",
"-webkit-box-pack", null, null),
3046 "box-reflect" => array(null,
"-webkit-box-reflect", null, null),
3047 "box-shadow" => array(
"-moz-box-shadow",
"-webkit-box-shadow", null, null),
3048 "box-sizing" => array(
"-moz-box-sizing", null, null, null),
3049 "color-correction" => array(null,
"-webkit-color-correction", null, null),
3050 "column-break-after" => array(null,
"-webkit-column-break-after", null, null),
3051 "column-break-before" => array(null,
"-webkit-column-break-before", null, null),
3052 "column-break-inside" => array(null,
"-webkit-column-break-inside", null, null),
3053 "column-count" => array(
"-moz-column-count",
"-webkit-column-count", null, null),
3054 "column-gap" => array(
"-moz-column-gap",
"-webkit-column-gap", null, null),
3055 "column-rule" => array(
"-moz-column-rule",
"-webkit-column-rule", null, null),
3056 "column-rule-color" => array(
"-moz-column-rule-color",
"-webkit-column-rule-color", null, null),
3057 "column-rule-style" => array(
"-moz-column-rule-style",
"-webkit-column-rule-style", null, null),
3058 "column-rule-width" => array(
"-moz-column-rule-width",
"-webkit-column-rule-width", null, null),
3059 "column-span" => array(null,
"-webkit-column-span", null, null),
3060 "column-width" => array(
"-moz-column-width",
"-webkit-column-width", null, null),
3061 "columns" => array(null,
"-webkit-columns", null, null),
3062 "filter" => array(__CLASS__,
"filter"),
3063 "float-edge" => array(
"-moz-float-edge", null, null, null),
3064 "font-feature-settings" => array(
"-moz-font-feature-settings", null, null, null),
3065 "font-language-override" => array(
"-moz-font-language-override", null, null, null),
3066 "font-size-delta" => array(null,
"-webkit-font-size-delta", null, null),
3067 "font-smoothing" => array(null,
"-webkit-font-smoothing", null, null),
3068 "force-broken-image-icon" => array(
"-moz-force-broken-image-icon", null, null, null),
3069 "highlight" => array(null,
"-webkit-highlight", null, null),
3070 "hyphenate-character" => array(null,
"-webkit-hyphenate-character", null, null),
3071 "hyphenate-locale" => array(null,
"-webkit-hyphenate-locale", null, null),
3072 "hyphens" => array(null,
"-webkit-hyphens", null, null),
3073 "force-broken-image-icon" => array(
"-moz-image-region", null, null, null),
3074 "ime-mode" => array(null, null, null,
"-ms-ime-mode"),
3075 "interpolation-mode" => array(null, null, null,
"-ms-interpolation-mode"),
3076 "layout-flow" => array(null, null, null,
"-ms-layout-flow"),
3077 "layout-grid" => array(null, null, null,
"-ms-layout-grid"),
3078 "layout-grid-char" => array(null, null, null,
"-ms-layout-grid-char"),
3079 "layout-grid-line" => array(null, null, null,
"-ms-layout-grid-line"),
3080 "layout-grid-mode" => array(null, null, null,
"-ms-layout-grid-mode"),
3081 "layout-grid-type" => array(null, null, null,
"-ms-layout-grid-type"),
3082 "line-break" => array(null,
"-webkit-line-break", null,
"-ms-line-break"),
3083 "line-clamp" => array(null,
"-webkit-line-clamp", null, null),
3084 "line-grid-mode" => array(null, null, null,
"-ms-line-grid-mode"),
3085 "logical-height" => array(null,
"-webkit-logical-height", null, null),
3086 "logical-width" => array(null,
"-webkit-logical-width", null, null),
3087 "margin-after" => array(null,
"-webkit-margin-after", null, null),
3088 "margin-after-collapse" => array(null,
"-webkit-margin-after-collapse", null, null),
3089 "margin-before" => array(null,
"-webkit-margin-before", null, null),
3090 "margin-before-collapse" => array(null,
"-webkit-margin-before-collapse", null, null),
3091 "margin-bottom-collapse" => array(null,
"-webkit-margin-bottom-collapse", null, null),
3092 "margin-collapse" => array(null,
"-webkit-margin-collapse", null, null),
3093 "margin-end" => array(
"-moz-margin-end",
"-webkit-margin-end", null, null),
3094 "margin-start" => array(
"-moz-margin-start",
"-webkit-margin-start", null, null),
3095 "margin-top-collapse" => array(null,
"-webkit-margin-top-collapse", null, null),
3096 "marquee " => array(null,
"-webkit-marquee", null, null),
3097 "marquee-direction" => array(null,
"-webkit-marquee-direction", null, null),
3098 "marquee-increment" => array(null,
"-webkit-marquee-increment", null, null),
3099 "marquee-repetition" => array(null,
"-webkit-marquee-repetition", null, null),
3100 "marquee-speed" => array(null,
"-webkit-marquee-speed", null, null),
3101 "marquee-style" => array(null,
"-webkit-marquee-style", null, null),
3102 "mask" => array(null,
"-webkit-mask", null, null),
3103 "mask-attachment" => array(null,
"-webkit-mask-attachment", null, null),
3104 "mask-box-image" => array(null,
"-webkit-mask-box-image", null, null),
3105 "mask-clip" => array(null,
"-webkit-mask-clip", null, null),
3106 "mask-composite" => array(null,
"-webkit-mask-composite", null, null),
3107 "mask-image" => array(null,
"-webkit-mask-image", null, null),
3108 "mask-origin" => array(null,
"-webkit-mask-origin", null, null),
3109 "mask-position" => array(null,
"-webkit-mask-position", null, null),
3110 "mask-position-x" => array(null,
"-webkit-mask-position-x", null, null),
3111 "mask-position-y" => array(null,
"-webkit-mask-position-y", null, null),
3112 "mask-repeat" => array(null,
"-webkit-mask-repeat", null, null),
3113 "mask-repeat-x" => array(null,
"-webkit-mask-repeat-x", null, null),
3114 "mask-repeat-y" => array(null,
"-webkit-mask-repeat-y", null, null),
3115 "mask-size" => array(null,
"-webkit-mask-size", null, null),
3116 "match-nearest-mail-blockquote-color" => array(null,
"-webkit-match-nearest-mail-blockquote-color", null, null),
3117 "max-logical-height" => array(null,
"-webkit-max-logical-height", null, null),
3118 "max-logical-width" => array(null,
"-webkit-max-logical-width", null, null),
3119 "min-logical-height" => array(null,
"-webkit-min-logical-height", null, null),
3120 "min-logical-width" => array(null,
"-webkit-min-logical-width", null, null),
3121 "object-fit" => array(null, null,
"-o-object-fit", null),
3122 "object-position" => array(null, null,
"-o-object-position", null),
3123 "opacity" => array(__CLASS__,
"opacity"),
3124 "outline-radius" => array(
"-moz-outline-radius", null, null, null),
3125 "outline-bottom-left-radius" => array(
"-moz-outline-radius-bottomleft", null, null, null),
3126 "outline-bottom-right-radius" => array(
"-moz-outline-radius-bottomright", null, null, null),
3127 "outline-top-left-radius" => array(
"-moz-outline-radius-topleft", null, null, null),
3128 "outline-top-right-radius" => array(
"-moz-outline-radius-topright", null, null, null),
3129 "padding-after" => array(null,
"-webkit-padding-after", null, null),
3130 "padding-before" => array(null,
"-webkit-padding-before", null, null),
3131 "padding-end" => array(
"-moz-padding-end",
"-webkit-padding-end", null, null),
3132 "padding-start" => array(
"-moz-padding-start",
"-webkit-padding-start", null, null),
3133 "perspective" => array(null,
"-webkit-perspective", null, null),
3134 "perspective-origin" => array(null,
"-webkit-perspective-origin", null, null),
3135 "perspective-origin-x" => array(null,
"-webkit-perspective-origin-x", null, null),
3136 "perspective-origin-y" => array(null,
"-webkit-perspective-origin-y", null, null),
3137 "rtl-ordering" => array(null,
"-webkit-rtl-ordering", null, null),
3138 "scrollbar-3dlight-color" => array(null, null, null,
"-ms-scrollbar-3dlight-color"),
3139 "scrollbar-arrow-color" => array(null, null, null,
"-ms-scrollbar-arrow-color"),
3140 "scrollbar-base-color" => array(null, null, null,
"-ms-scrollbar-base-color"),
3141 "scrollbar-darkshadow-color" => array(null, null, null,
"-ms-scrollbar-darkshadow-color"),
3142 "scrollbar-face-color" => array(null, null, null,
"-ms-scrollbar-face-color"),
3143 "scrollbar-highlight-color" => array(null, null, null,
"-ms-scrollbar-highlight-color"),
3144 "scrollbar-shadow-color" => array(null, null, null,
"-ms-scrollbar-shadow-color"),
3145 "scrollbar-track-color" => array(null, null, null,
"-ms-scrollbar-track-color"),
3146 "stack-sizing" => array(
"-moz-stack-sizing", null, null, null),
3147 "svg-shadow" => array(null,
"-webkit-svg-shadow", null, null),
3148 "tab-size" => array(
"-moz-tab-size", null,
"-o-tab-size", null),
3149 "table-baseline" => array(null, null,
"-o-table-baseline", null),
3150 "text-align-last" => array(null, null, null,
"-ms-text-align-last"),
3151 "text-autospace" => array(null, null, null,
"-ms-text-autospace"),
3152 "text-combine" => array(null,
"-webkit-text-combine", null, null),
3153 "text-decorations-in-effect" => array(null,
"-webkit-text-decorations-in-effect", null, null),
3154 "text-emphasis" => array(null,
"-webkit-text-emphasis", null, null),
3155 "text-emphasis-color" => array(null,
"-webkit-text-emphasis-color", null, null),
3156 "text-emphasis-position" => array(null,
"-webkit-text-emphasis-position", null, null),
3157 "text-emphasis-style" => array(null,
"-webkit-text-emphasis-style", null, null),
3158 "text-fill-color" => array(null,
"-webkit-text-fill-color", null, null),
3159 "text-justify" => array(null, null, null,
"-ms-text-justify"),
3160 "text-kashida-space" => array(null, null, null,
"-ms-text-kashida-space"),
3161 "text-overflow" => array(null, null,
"-o-text-overflow",
"-ms-text-overflow"),
3162 "text-security" => array(null,
"-webkit-text-security", null, null),
3163 "text-size-adjust" => array(null,
"-webkit-text-size-adjust", null,
"-ms-text-size-adjust"),
3164 "text-stroke" => array(null,
"-webkit-text-stroke", null, null),
3165 "text-stroke-color" => array(null,
"-webkit-text-stroke-color", null, null),
3166 "text-stroke-width" => array(null,
"-webkit-text-stroke-width", null, null),
3167 "text-underline-position" => array(null, null, null,
"-ms-text-underline-position"),
3168 "transform" => array(
"-moz-transform",
"-webkit-transform",
"-o-transform", null),
3169 "transform-origin" => array(
"-moz-transform-origin",
"-webkit-transform-origin",
"-o-transform-origin", null),
3170 "transform-origin-x" => array(null,
"-webkit-transform-origin-x", null, null),
3171 "transform-origin-y" => array(null,
"-webkit-transform-origin-y", null, null),
3172 "transform-origin-z" => array(null,
"-webkit-transform-origin-z", null, null),
3173 "transform-style" => array(null,
"-webkit-transform-style", null, null),
3174 "transition" => array(
"-moz-transition",
"-webkit-transition",
"-o-transition", null),
3175 "transition-delay" => array(
"-moz-transition-delay",
"-webkit-transition-delay",
"-o-transition-delay", null),
3176 "transition-duration" => array(
"-moz-transition-duration",
"-webkit-transition-duration",
"-o-transition-duration", null),
3177 "transition-property" => array(
"-moz-transition-property",
"-webkit-transition-property",
"-o-transition-property", null),
3178 "transition-timing-function" => array(
"-moz-transition-timing-function",
"-webkit-transition-timing-function",
"-o-transition-timing-function", null),
3179 "user-drag" => array(null,
"-webkit-user-drag", null, null),
3180 "user-focus" => array(
"-moz-user-focus", null, null, null),
3181 "user-input" => array(
"-moz-user-input", null, null, null),
3182 "user-modify" => array(
"-moz-user-modify",
"-webkit-user-modify", null, null),
3183 "user-select" => array(
"-moz-user-select",
"-webkit-user-select", null, null),
3184 "white-space" => array(__CLASS__,
"whiteSpace"),
3185 "window-shadow" => array(
"-moz-window-shadow", null, null, null),
3186 "word-break" => array(null, null, null,
"-ms-word-break"),
3187 "word-wrap" => array(null, null, null,
"-ms-word-wrap"),
3188 "writing-mode" => array(null,
"-webkit-writing-mode", null,
"-ms-writing-mode"),
3189 "zoom" => array(null, null, null,
"-ms-zoom")
3200 $transformations = &$this->transformations;
3201 for ($i = 0, $l = count($tokens); $i < $l; $i++)
3203 if (get_class($tokens[$i]) ===
"CssRulesetDeclarationToken")
3205 $tProperty = $tokens[$i]->Property;
3206 if (isset($transformations[$tProperty]))
3209 if (is_callable($transformations[$tProperty]))
3211 $result = call_user_func_array($transformations[$tProperty], array($tokens[$i]));
3212 if (!is_array($result) && is_object($result))
3214 $result = array($result);
3219 $tValue = $tokens[$i]->Value;
3220 $tMediaTypes = $tokens[$i]->MediaTypes;
3221 foreach ($transformations[$tProperty] as $property)
3223 if ($property !== null)
3229 if (count($result) > 0)
3231 array_splice($tokens, $i + 1, 0, $result);
3232 $i += count($result);
3233 $l += count($result);
3247 private static function filter($token)
3261 private static function opacity($token)
3264 $ieValue = (int) ((
float) $token->Value * 100);
3281 private static function whiteSpace($token)
3283 if (strtolower($token->Value) ===
"pre-wrap")
3328 $transformations = array(
"-moz-keyframes",
"-webkit-keyframes");
3329 for ($i = 0, $l = count($tokens); $i < $l; $i++)
3331 if (get_class($tokens[$i]) ===
"CssAtKeyframesStartToken")
3333 for ($ii = $i; $ii < $l; $ii++)
3335 if (get_class($tokens[$ii]) ===
"CssAtKeyframesEndToken")
3340 if (get_class($tokens[$ii]) ===
"CssAtKeyframesEndToken")
3344 for ($iii = $i; $iii <= $ii; $iii++)
3346 $source[] = clone($tokens[$iii]);
3348 foreach ($transformations as $transformation)
3351 foreach ($source as $token)
3353 $t[] = clone($token);
3355 $t[0]->AtRuleName = $transformation;
3356 $add = array_merge($add, $t);
3358 if (isset($this->configuration[
"RemoveSource"]) && $this->configuration[
"RemoveSource"] ===
true)
3360 array_splice($tokens, $i, $ii - $i + 1, $add);
3364 array_splice($tokens, $ii + 1, 0, $add);
3366 $l = count($tokens);
3367 $i = $ii + count($add);
3403 private $reMatch =
"/^hsl\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*%\s*,\s*([0-9]+)\s*%\s*\)/iS";
3412 if (stripos($token->Value,
"hsl") !==
false && preg_match($this->reMatch, $token->Value, $m))
3414 $token->Value = str_replace($m[0], $this->hsl2hex($m[1], $m[2], $m[3]), $token->Value);
3427 "CssAtFontFaceDeclarationToken",
3428 "CssAtPageDeclarationToken",
3429 "CssRulesetDeclarationToken"
3442 private function hsl2hex($hue, $saturation, $lightness)
3445 $saturation = $saturation / 100;
3446 $lightness = $lightness / 100;
3447 if ($saturation == 0)
3449 $red = $lightness * 255;
3450 $green = $lightness * 255;
3451 $blue = $lightness * 255;
3455 if ($lightness < 0.5 )
3457 $v2 = $lightness * (1 + $saturation);
3461 $v2 = ($lightness + $saturation) - ($saturation * $lightness);
3463 $v1 = 2 * $lightness - $v2;
3464 $red = 255 * self::hue2rgb($v1, $v2, $hue + (1 / 3));
3465 $green = 255 * self::hue2rgb($v1, $v2, $hue);
3466 $blue = 255 * self::hue2rgb($v1, $v2, $hue - (1 / 3));
3468 return "#" . str_pad(dechex(round($red)), 2,
"0", STR_PAD_LEFT) . str_pad(dechex(round($green)), 2,
"0", STR_PAD_LEFT) . str_pad(dechex(round($blue)), 2,
"0", STR_PAD_LEFT);
3478 private function hue2rgb($v1, $v2, $hue)
3490 return ($v1 + ($v2 - $v1) * 6 * $hue);
3498 return ($v1 + ($v2 - $v1) * (( 2 / 3) - $hue) * 6);
3534 private $include = array
3544 private $reMatch = null;
3550 private $reReplace =
"\"\${1}\" . \$this->transformation[\"\${2}\"] . \"\${3}\"";
3556 private $transformation = array
3572 $this->reMatch =
"/(^|\s)+(" . implode(
"|", array_keys($this->transformation)).
")(\s|$)+/eiS";
3583 if (in_array($token->Property, $this->include) && preg_match($this->reMatch, $token->Value, $m))
3585 $token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value);
3598 "CssAtFontFaceDeclarationToken",
3599 "CssAtPageDeclarationToken",
3600 "CssRulesetDeclarationToken"
3640 "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)/iS" =>
"\${1}.\${2}\${4}",
3641 "/(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/iS" =>
"\${1}0",
3642 "/(^0\s0\s0\s0)|(^0\s0\s0$)|(^0\s0$)/iS" =>
"0"
3649 private $reMatch =
"/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)|(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)|(^0\s0\s0\s0$)|(^0\s0\s0$)|(^0\s0$)/iS";
3658 if (preg_match($this->reMatch, $token->Value))
3660 foreach ($this->re as $reMatch => $reReplace)
3662 $token->Value = preg_replace($reMatch, $reReplace, $token->Value);
3676 "CssAtFontFaceDeclarationToken",
3677 "CssAtPageDeclarationToken",
3678 "CssRulesetDeclarationToken"
3706 if (class_exists(
"JSMin") && stripos($token->Value,
"expression(") !==
false)
3708 $value = $token->Value;
3709 $value = substr($token->Value, stripos($token->Value,
"expression(") + 10);
3711 $token->Value =
"expression(" . $value .
")";
3724 "CssAtFontFaceDeclarationToken",
3725 "CssAtPageDeclarationToken",
3726 "CssRulesetDeclarationToken"
3759 private $reMatch =
"/\#([0-9a-f]{6})/iS";
3768 if (strpos($token->Value,
"#") !==
false && preg_match($this->reMatch, $token->Value, $m))
3770 $value = strtolower($m[1]);
3771 if ($value[0] == $value[1] && $value[2] == $value[3] && $value[4] == $value[5])
3773 $token->Value = str_replace($m[0],
"#" . $value[0] . $value[2] . $value[4], $token->Value);
3787 "CssAtFontFaceDeclarationToken",
3788 "CssAtPageDeclarationToken",
3789 "CssRulesetDeclarationToken"
3811 public $Comment =
"";
3829 return $this->Comment;
3854 return array(
"*",
"/");
3870 private $restoreBuffer =
"";
3879 public function parse($index, $char, $previousChar, $state)
3881 if ($char ===
"*" && $previousChar ===
"/" && $state !==
"T_COMMENT")
3883 $this->parser->pushState(
"T_COMMENT");
3884 $this->parser->setExclusive(__CLASS__);
3885 $this->restoreBuffer = substr($this->parser->getAndClearBuffer(), 0, -2);
3887 elseif ($char ===
"/" && $previousChar ===
"*" && $state ===
"T_COMMENT")
3889 $this->parser->popState();
3890 $this->parser->unsetExclusive();
3891 $this->parser->appendToken(
new CssCommentToken(
"/*" . $this->parser->getAndClearBuffer()));
3892 $this->parser->setBuffer($this->restoreBuffer);
3919 public $MediaTypes = array();
3928 $this->MediaTypes = $mediaTypes ? $mediaTypes : array(
"all");
3963 return array(
"@",
"{",
"}",
":",
";");
3972 return array(
"T_DOCUMENT",
"T_AT_VARIABLES::PREPARE",
"T_AT_VARIABLES",
"T_AT_VARIABLES_DECLARATION");
3982 public function parse($index, $char, $previousChar, $state)
3985 if ($char ===
"@" && $state ===
"T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) ===
"@variables")
3987 $this->parser->pushState(
"T_AT_VARIABLES::PREPARE");
3988 $this->parser->clearBuffer();
3992 elseif ($char ===
"{" && $state ===
"T_AT_VARIABLES::PREPARE")
3994 $this->parser->setState(
"T_AT_VARIABLES");
3995 $mediaTypes = array_filter(array_map(
"trim", explode(
",", $this->parser->getAndClearBuffer(
"{"))));
3999 if ($char ===
":" && $state ===
"T_AT_VARIABLES")
4001 $this->buffer = $this->parser->getAndClearBuffer(
":");
4002 $this->parser->pushState(
"T_AT_VARIABLES_DECLARATION");
4005 elseif ($char ===
":" && $state ===
"T_AT_VARIABLES_DECLARATION")
4008 if ($this->buffer ===
"filter")
4012 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": Unterminated @variables declaration", $this->buffer .
":" . $this->parser->getBuffer() .
"_"));
4015 elseif (($char ===
";" || $char ===
"}") && $state ===
"T_AT_VARIABLES_DECLARATION")
4017 $value = $this->parser->getAndClearBuffer(
";}");
4018 if (strtolower(substr($value, -10, 10)) ===
"!important")
4020 $value = trim(substr($value, 0, -10));
4021 $isImportant =
true;
4025 $isImportant =
false;
4027 $this->parser->popState();
4032 elseif ($char ===
"}" && $state ===
"T_AT_VARIABLES")
4034 $this->parser->popState();
4035 $this->parser->clearBuffer();
4109 public $Selector =
"";
4116 public function __construct($selector =
"")
4118 $this->Selector = $selector;
4127 return "@page" . ($this->Selector ?
" " . $this->Selector :
"") .
"{";
4153 return array(
"@",
"{",
"}",
":",
";");
4162 return array(
"T_DOCUMENT",
"T_AT_PAGE::SELECTOR",
"T_AT_PAGE",
"T_AT_PAGE_DECLARATION");
4172 public function parse($index, $char, $previousChar, $state)
4175 if ($char ===
"@" && $state ===
"T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 5)) ===
"@page")
4177 $this->parser->pushState(
"T_AT_PAGE::SELECTOR");
4178 $this->parser->clearBuffer();
4182 elseif ($char ===
"{" && $state ===
"T_AT_PAGE::SELECTOR")
4184 $selector = $this->parser->getAndClearBuffer(
"{");
4185 $this->parser->setState(
"T_AT_PAGE");
4186 $this->parser->clearBuffer();
4190 elseif ($char ===
":" && $state ===
"T_AT_PAGE")
4192 $this->parser->pushState(
"T_AT_PAGE_DECLARATION");
4193 $this->buffer = $this->parser->getAndClearBuffer(
":",
true);
4196 elseif ($char ===
":" && $state ===
"T_AT_PAGE_DECLARATION")
4199 if ($this->buffer ===
"filter")
4203 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": Unterminated @page declaration", $this->buffer .
":" . $this->parser->getBuffer() .
"_"));
4206 elseif (($char ===
";" || $char ===
"}") && $state ==
"T_AT_PAGE_DECLARATION")
4208 $value = $this->parser->getAndClearBuffer(
";}");
4209 if (strtolower(substr($value, -10, 10)) ==
"!important")
4211 $value = trim(substr($value, 0, -10));
4212 $isImportant =
true;
4216 $isImportant =
false;
4218 $this->parser->popState();
4223 $this->parser->popState();
4229 elseif ($char ===
"}" && $state ===
"T_AT_PAGE")
4231 $this->parser->popState();
4232 $this->parser->clearBuffer();
4293 $this->MediaTypes = $mediaTypes;
4302 return "@media " . implode(
",", $this->MediaTypes) .
"{";
4329 return array(
"@",
"{",
"}");
4338 return array(
"T_DOCUMENT",
"T_AT_MEDIA::PREPARE",
"T_AT_MEDIA");
4348 public function parse($index, $char, $previousChar, $state)
4350 if ($char ===
"@" && $state ===
"T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 6)) ===
"@media")
4352 $this->parser->pushState(
"T_AT_MEDIA::PREPARE");
4353 $this->parser->clearBuffer();
4356 elseif ($char ===
"{" && $state ===
"T_AT_MEDIA::PREPARE")
4358 $mediaTypes = array_filter(array_map(
"trim", explode(
",", $this->parser->getAndClearBuffer(
"{"))));
4359 $this->parser->setMediaTypes($mediaTypes);
4360 $this->parser->setState(
"T_AT_MEDIA");
4363 elseif ($char ===
"}" && $state ===
"T_AT_MEDIA")
4366 $this->parser->clearBuffer();
4367 $this->parser->unsetMediaTypes();
4368 $this->parser->popState();
4410 public $AtRuleName =
"keyframes";
4423 public function __construct($name, $atRuleName = null)
4425 $this->
Name = $name;
4426 if (!is_null($atRuleName))
4428 $this->AtRuleName = $atRuleName;
4438 return "@" . $this->AtRuleName .
" \"" . $this->
Name .
"\"{";
4459 public $Selectors = array();
4468 $this->Selectors = $selectors;
4477 return implode(
",", $this->Selectors) .
"{";
4526 private $atRuleName =
"";
4532 private $selectors = array();
4540 return array(
"@",
"{",
"}",
":",
",",
";");
4549 return array(
"T_DOCUMENT",
"T_AT_KEYFRAMES::NAME",
"T_AT_KEYFRAMES",
"T_AT_KEYFRAMES_RULESETS",
"T_AT_KEYFRAMES_RULESET",
"T_AT_KEYFRAMES_RULESET_DECLARATION");
4559 public function parse($index, $char, $previousChar, $state)
4562 if ($char ===
"@" && $state ===
"T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) ===
"@keyframes")
4564 $this->atRuleName =
"keyframes";
4565 $this->parser->pushState(
"T_AT_KEYFRAMES::NAME");
4566 $this->parser->clearBuffer();
4570 elseif ($char ===
"@" && $state ===
"T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 15)) ===
"@-moz-keyframes")
4572 $this->atRuleName =
"-moz-keyframes";
4573 $this->parser->pushState(
"T_AT_KEYFRAMES::NAME");
4574 $this->parser->clearBuffer();
4578 elseif ($char ===
"@" && $state ===
"T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 18)) ===
"@-webkit-keyframes")
4580 $this->atRuleName =
"-webkit-keyframes";
4581 $this->parser->pushState(
"T_AT_KEYFRAMES::NAME");
4582 $this->parser->clearBuffer();
4586 elseif ($char ===
"{" && $state ===
"T_AT_KEYFRAMES::NAME")
4588 $name = $this->parser->getAndClearBuffer(
"{\"'");
4589 $this->parser->setState(
"T_AT_KEYFRAMES_RULESETS");
4590 $this->parser->clearBuffer();
4594 if ($char ===
"," && $state ===
"T_AT_KEYFRAMES_RULESETS")
4596 $this->selectors[] = $this->parser->getAndClearBuffer(
",{");
4599 elseif ($char ===
"{" && $state ===
"T_AT_KEYFRAMES_RULESETS")
4601 if ($this->parser->getBuffer() !==
"")
4603 $this->selectors[] = $this->parser->getAndClearBuffer(
",{");
4604 $this->parser->pushState(
"T_AT_KEYFRAMES_RULESET");
4606 $this->selectors = array();
4610 elseif ($char ===
":" && $state ===
"T_AT_KEYFRAMES_RULESET")
4612 $this->parser->pushState(
"T_AT_KEYFRAMES_RULESET_DECLARATION");
4613 $this->buffer = $this->parser->getAndClearBuffer(
":;",
true);
4616 elseif ($char ===
":" && $state ===
"T_AT_KEYFRAMES_RULESET_DECLARATION")
4619 if ($this->buffer ===
"filter")
4623 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": Unterminated @keyframes ruleset declaration", $this->buffer .
":" . $this->parser->getBuffer() .
"_"));
4626 elseif (($char ===
";" || $char ===
"}") && $state ===
"T_AT_KEYFRAMES_RULESET_DECLARATION")
4628 $value = $this->parser->getAndClearBuffer(
";}");
4629 if (strtolower(substr($value, -10, 10)) ===
"!important")
4631 $value = trim(substr($value, 0, -10));
4632 $isImportant =
true;
4636 $isImportant =
false;
4638 $this->parser->popState();
4644 $this->parser->popState();
4649 elseif ($char ===
"}" && $state ===
"T_AT_KEYFRAMES_RULESET")
4651 $this->parser->clearBuffer();
4653 $this->parser->popState();
4657 elseif ($char ===
"}" && $state ===
"T_AT_KEYFRAMES_RULESETS")
4659 $this->parser->clearBuffer();
4660 $this->parser->popState();
4703 public $Import =
"";
4709 public $MediaTypes = array();
4719 $this->Import = $import;
4720 $this->MediaTypes = $mediaTypes ? $mediaTypes : array();
4729 return "@import \"" . $this->Import .
"\"" . (count($this->MediaTypes) > 0 ?
" " . implode(
",", $this->MediaTypes) :
"").
";";
4754 return array(
"@",
";",
",",
"\n");
4763 return array(
"T_DOCUMENT",
"T_AT_IMPORT");
4773 public function parse($index, $char, $previousChar, $state)
4775 if ($char ===
"@" && $state ===
"T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 7)) ===
"@import")
4777 $this->parser->pushState(
"T_AT_IMPORT");
4778 $this->parser->clearBuffer();
4781 elseif (($char ===
";" || $char ===
"\n") && $state ===
"T_AT_IMPORT")
4783 $this->buffer = $this->parser->getAndClearBuffer(
";");
4785 foreach (array(
")",
"\"",
"'") as $needle)
4787 if (($pos = strrpos($this->buffer, $needle)) !==
false)
4792 $import = substr($this->buffer, 0, $pos + 1);
4793 if (stripos($import,
"url(") === 0)
4795 $import = substr($import, 4, -1);
4797 $import = trim($import,
" \t\n\r\0\x0B'\"");
4798 $mediaTypes = array_filter(array_map(
"trim", explode(
",", trim(substr($this->buffer, $pos + 1),
" \t\n\r\0\x0B{"))));
4807 $this->parser->popState();
4836 return "@font-face{";
4862 return array(
"@",
"{",
"}",
":",
";");
4871 return array(
"T_DOCUMENT",
"T_AT_FONT_FACE::PREPARE",
"T_AT_FONT_FACE",
"T_AT_FONT_FACE_DECLARATION");
4881 public function parse($index, $char, $previousChar, $state)
4884 if ($char ===
"@" && $state ===
"T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) ===
"@font-face")
4886 $this->parser->pushState(
"T_AT_FONT_FACE::PREPARE");
4887 $this->parser->clearBuffer();
4891 elseif ($char ===
"{" && $state ===
"T_AT_FONT_FACE::PREPARE")
4893 $this->parser->setState(
"T_AT_FONT_FACE");
4894 $this->parser->clearBuffer();
4898 elseif ($char ===
":" && $state ===
"T_AT_FONT_FACE")
4900 $this->parser->pushState(
"T_AT_FONT_FACE_DECLARATION");
4901 $this->buffer = $this->parser->getAndClearBuffer(
":",
true);
4904 elseif ($char ===
":" && $state ===
"T_AT_FONT_FACE_DECLARATION")
4907 if ($this->buffer ===
"filter")
4911 CssMin::triggerError(
new CssError(__FILE__, __LINE__, __METHOD__ .
": Unterminated @font-face declaration", $this->buffer .
":" . $this->parser->getBuffer() .
"_"));
4914 elseif (($char ===
";" || $char ===
"}") && $state ===
"T_AT_FONT_FACE_DECLARATION")
4916 $value = $this->parser->getAndClearBuffer(
";}");
4917 if (strtolower(substr($value, -10, 10)) ===
"!important")
4919 $value = trim(substr($value, 0, -10));
4920 $isImportant =
true;
4924 $isImportant =
false;
4926 $this->parser->popState();
4933 $this->parser->popState();
4937 elseif ($char ===
"}" && $state ===
"T_AT_FONT_FACE")
4940 $this->parser->clearBuffer();
4941 $this->parser->popState();
4998 public $Charset =
"";
5007 $this->Charset = $charset;
5016 return "@charset " . $this->Charset .
";";
5041 return array(
"@",
";",
"\n");
5050 return array(
"T_DOCUMENT",
"T_AT_CHARSET");
5060 public function parse($index, $char, $previousChar, $state)
5062 if ($char ===
"@" && $state ===
"T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 8)) ===
"@charset")
5064 $this->parser->pushState(
"T_AT_CHARSET");
5065 $this->parser->clearBuffer();
5068 elseif (($char ===
";" || $char ===
"\n") && $state ===
"T_AT_CHARSET")
5070 $charset = $this->parser->getAndClearBuffer(
";");
5071 $this->parser->popState();