class CSSCompression_Combine_BorderRadius in Advanced CSS/JS Aggregation 7
Same name and namespace in other branches
- 6 advagg_css_compress/css-compressor-3.x/src/lib/Combine/BorderRadius.inc \CSSCompression_Combine_BorderRadius
CSS Compressor [VERSION] [DATE] Corey Hart @ http://www.codenothing.com
Hierarchy
Expanded class hierarchy of CSSCompression_Combine_BorderRadius
File
- advagg_css_compress/
css-compressor-3.x/ src/ lib/ Combine/ BorderRadius.inc, line 8
View source
class CSSCompression_Combine_BorderRadius {
/**
* Combine Patterns
*
* @class Control: Compression Controller
* @class Combine: Combine Controller
* @param (regex) rspace: Checks for space without an escape '\' character before it
* @param (regex) rslash: Checks for unescaped slash character
* @param (array) borderRadius: Various border radii components
*/
private $Control;
private $Combine;
private $rspace = "/(?<!\\\\)\\s/";
private $rslash = "/(?<!\\\\)\\//";
private $borderRadius = array(
'css3' => array(
'mod' => '',
'base' => "/(^|(?<!\\\\);)border-radius:(.*?)((?<!\\\\);|\$)/",
'full' => "/(^|(?<!\\\\);)border-(top|bottom)-(left|right)-radius:(.*?)((?<!\\\\);|\$)/",
),
'moz' => array(
'mod' => '-moz-',
'base' => "/(^|(?<!\\\\);)-moz-border-radius:(.*?)((?<!\\\\);|\$)/",
'full' => "/(^|(?<!\\\\);)-moz-border-radius-(top|bottom)(left|right):(.*?)((?<!\\\\);|\$)/",
),
'webkit' => array(
'mod' => '-webkit-',
'base' => "/(^|(?<!\\\\);)-webkit-border-radius:(.*?)((?<!\\\\);|\$)/",
'full' => "/(^|(?<!\\\\);)-webkit-border-(top|bottom)-(left|right)-radius:(.*?)((?<!\\\\);|\$)/",
),
);
/**
* Stash a reference to the controller & combiner
*
* @param (class) control: CSSCompression Controller
* @param (class) combine: CSSCompression Combiner
*/
public function __construct(CSSCompression_Control $control, CSSCompression_Combine $combine) {
$this->Control = $control;
$this->Combine = $combine;
}
/**
* Main handler to combine border-radii into a single rule
*
* @param (string) val: Rule Set
*/
public function combine($val) {
foreach ($this->borderRadius as $regex) {
$val = $this
->fix($val, $regex);
}
return $val;
}
/**
* Does the actual combining
*
* @param (string) val: Rule Set
*/
private function fix($val, $regex) {
$val = $this
->base($val, $regex);
$replace = $regex['mod'];
// Storage builder
if (($storage = $this
->storage($val, $regex)) === false) {
return $val;
}
// Setup horizontal/vertical radii
foreach ($storage as $dir => &$config) {
// Verticals are optional
if ($dir == 'vertical' && !$config['keep']) {
break;
}
else {
if ($config['top-left'] == $config['top-right'] && $config['top-right'] == $config['bottom-right'] && $config['bottom-right'] == $config['bottom-left']) {
$config['replace'] .= $config['top-left'];
}
else {
if ($config['top-left'] == $config['bottom-right'] && $config['top-right'] == $config['bottom-left']) {
$config['replace'] .= $config['top-left'] . ' ' . $config['top-right'];
}
else {
if ($config['top-right'] == $config['bottom-left']) {
$config['replace'] .= $config['top-left'] . ' ' . $config['top-right'] . ' ' . $config['bottom-right'];
}
else {
$config['replace'] .= $config['top-left'] . ' ' . $config['top-right'] . ' ' . $config['bottom-right'] . ' ' . $config['bottom-left'];
}
}
}
}
}
// Now rebuild the string replacing all instances of margin/padding if shorthand exists
$pos = 0;
$replace = $regex['mod'] . "border-radius:" . $storage['horizontal']['replace'] . $storage['vertical']['replace'] . ';';
while (preg_match($regex['full'], $val, $match, PREG_OFFSET_CAPTURE, $pos)) {
$colon = strlen($match[1][0]);
$val = substr_replace($val, $replace, $match[0][1] + $colon, strlen($match[0][0]) - $colon);
$pos = $match[0][1] + strlen($replace) - $colon - 1;
$replace = '';
}
// Return converted val
return $val;
}
/**
* Expands short handed border radius props for combination
*
* @param (string) val: Rule Set
*/
private function base($val, $regex) {
$pos = 0;
while (preg_match($regex['base'], $val, $match, PREG_OFFSET_CAPTURE, $pos)) {
$replace = '';
$colon = strlen($match[1][0]);
$parts = preg_split($this->rslash, trim($match[2][0]), 2);
$positions = array(
'top-left' => 0,
'top-right' => 0,
'bottom-right' => 0,
'bottom-left' => 0,
);
$base = array(
'horizontal' => array(
'parts' => preg_split($this->rspace, trim($parts[0])),
'pos' => $positions,
),
'vertical' => array(
'parts' => isset($parts[1]) ? preg_split($this->rspace, trim($parts[1])) : '',
'pos' => $positions,
),
);
foreach ($base as &$config) {
// Skip uncombinables
if ($this->Combine
->checkUncombinables($config['parts'])) {
$pos = $match[0][1] + strlen($match[0][0]) - 1;
continue 2;
}
else {
if ($config['parts'] === '') {
continue;
}
}
// Each position needs a value
switch (count($config['parts'])) {
case 1:
$config['pos']['top-left'] = $config['pos']['top-right'] = $config['parts'][0];
$config['pos']['bottom-left'] = $config['pos']['bottom-right'] = $config['parts'][0];
break;
case 2:
$config['pos']['top-left'] = $config['pos']['bottom-right'] = $config['parts'][0];
$config['pos']['bottom-left'] = $config['pos']['top-right'] = $config['parts'][1];
break;
case 3:
$config['pos']['top-left'] = $config['parts'][0];
$config['pos']['bottom-left'] = $config['pos']['top-right'] = $config['parts'][1];
$config['pos']['bottom-right'] = $config['parts'][2];
break;
case 4:
$config['pos']['top-left'] = $config['parts'][0];
$config['pos']['top-right'] = $config['parts'][1];
$config['pos']['bottom-right'] = $config['parts'][2];
$config['pos']['bottom-left'] = $config['parts'][3];
break;
default:
continue 2;
}
}
// Build the replacement
foreach ($positions as $p => $v) {
if ($regex['mod'] == '-moz-') {
$replace .= "-moz-border-radius-" . preg_replace("/-/", '', $p) . ":" . $base['horizontal']['pos'][$p] . ($base['vertical']['parts'] === '' ? '' : ' ' . $base['vertical']['pos'][$p]) . ';';
}
else {
$replace .= $regex['mod'] . "border-{$p}-radius:" . $base['horizontal']['pos'][$p] . ($base['vertical']['parts'] === '' ? '' : ' ' . $base['vertical']['pos'][$p]) . ';';
}
}
$pos += strlen($replace);
$val = substr_replace($val, $replace, $match[0][1] + $colon, strlen($match[0][0]) - $colon);
}
return $val;
}
/**
* Builds the storage object for border radius props
*
* @param (string) val: Rule Set
* @param (array) regex: Current border radius type checking props
*/
private function storage($val, $regex) {
$storage = array(
'horizontal' => array(
'replace' => '',
),
'vertical' => array(
'replace' => '',
'keep' => false,
),
);
// Find all possible occurences of this border-radius type and mark their directional value
$pos = 0;
while (preg_match($regex['full'], $val, $match, PREG_OFFSET_CAPTURE, $pos)) {
$pos = $match[0][1] + strlen($match[0][0]) - 1;
$parts = preg_split($this->rspace, $match[4][0], 2);
$storage['horizontal'][$match[2][0] . '-' . $match[3][0]] = trim($parts[0]);
if (isset($parts[1])) {
$storage['vertical'][$match[2][0] . '-' . $match[3][0]] = trim($parts[1]);
$storage['vertical']['keep'] = true;
$storage['vertical']['replace'] = '/';
}
else {
$storage['vertical'][$match[2][0] . '-' . $match[3][0]] = '0';
}
}
// Only combine if all 4 definitions are found (5 including replace)
if (count($storage['horizontal']) != 5 || $this->Combine
->checkUncombinables($storage['horizontal']) || $this->Combine
->checkUncombinables($storage['vertical'])) {
return false;
}
return $storage;
}
/**
* Access to private methods for testing
*
* @param (string) method: Method to be called
* @param (array) args: Array of paramters to be passed in
*/
public function access($method, $args) {
if (method_exists($this, $method)) {
return call_user_func_array(array(
$this,
$method,
), $args);
}
else {
throw new CSSCompression_Exception("Unknown method in BorderRadius Class - " . $method);
}
}
}