View source
<?php
class CSSCompression_Combine_BorderRadius {
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:(.*?)((?<!\\\\);|\$)/",
),
);
public function __construct(CSSCompression_Control $control, CSSCompression_Combine $combine) {
$this->Control = $control;
$this->Combine = $combine;
}
public function combine($val) {
foreach ($this->borderRadius as $regex) {
$val = $this
->fix($val, $regex);
}
return $val;
}
private function fix($val, $regex) {
$val = $this
->base($val, $regex);
$replace = $regex['mod'];
if (($storage = $this
->storage($val, $regex)) === false) {
return $val;
}
foreach ($storage as $dir => &$config) {
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'];
}
}
}
}
}
$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 $val;
}
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) {
if ($this->Combine
->checkUncombinables($config['parts'])) {
$pos = $match[0][1] + strlen($match[0][0]) - 1;
continue 2;
}
else {
if ($config['parts'] === '') {
continue;
}
}
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;
}
}
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;
}
private function storage($val, $regex) {
$storage = array(
'horizontal' => array(
'replace' => '',
),
'vertical' => array(
'replace' => '',
'keep' => false,
),
);
$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';
}
}
if (count($storage['horizontal']) != 5 || $this->Combine
->checkUncombinables($storage['horizontal']) || $this->Combine
->checkUncombinables($storage['vertical'])) {
return false;
}
return $storage;
}
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);
}
}
}