1*7d666900SdWiGhT<?php 2*7d666900SdWiGhT 3*7d666900SdWiGhT/** 4*7d666900SdWiGhT * CSSTidy - CSS Parser and Optimiser 5*7d666900SdWiGhT * 6*7d666900SdWiGhT * CSS Optimising Class 7*7d666900SdWiGhT * This class optimises CSS data generated by csstidy. 8*7d666900SdWiGhT * 9*7d666900SdWiGhT * Copyright 2005, 2006, 2007 Florian Schmitz 10*7d666900SdWiGhT * 11*7d666900SdWiGhT * This file is part of CSSTidy. 12*7d666900SdWiGhT * 13*7d666900SdWiGhT * CSSTidy is free software; you can redistribute it and/or modify 14*7d666900SdWiGhT * it under the terms of the GNU Lesser General Public License as published by 15*7d666900SdWiGhT * the Free Software Foundation; either version 2.1 of the License, or 16*7d666900SdWiGhT * (at your option) any later version. 17*7d666900SdWiGhT * 18*7d666900SdWiGhT * CSSTidy is distributed in the hope that it will be useful, 19*7d666900SdWiGhT * but WITHOUT ANY WARRANTY; without even the implied warranty of 20*7d666900SdWiGhT * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21*7d666900SdWiGhT * GNU Lesser General Public License for more details. 22*7d666900SdWiGhT * 23*7d666900SdWiGhT * You should have received a copy of the GNU Lesser General Public License 24*7d666900SdWiGhT * along with this program. If not, see <http://www.gnu.org/licenses/>. 25*7d666900SdWiGhT * 26*7d666900SdWiGhT * @license http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License 27*7d666900SdWiGhT * @package csstidy 28*7d666900SdWiGhT * @author Florian Schmitz (floele at gmail dot com) 2005-2007 29*7d666900SdWiGhT * @author Brett Zamir (brettz9 at yahoo dot com) 2007 30*7d666900SdWiGhT * @author Nikolay Matsievsky (speed at webo dot name) 2009-2010 31*7d666900SdWiGhT * @author Cedric Morin (cedric at yterium dot com) 2010-2012 32*7d666900SdWiGhT */ 33*7d666900SdWiGhT 34*7d666900SdWiGhT/** 35*7d666900SdWiGhT * CSS Optimising Class 36*7d666900SdWiGhT * 37*7d666900SdWiGhT * This class optimises CSS data generated by csstidy. 38*7d666900SdWiGhT * 39*7d666900SdWiGhT * @package csstidy 40*7d666900SdWiGhT * @author Florian Schmitz (floele at gmail dot com) 2005-2006 41*7d666900SdWiGhT * @version 1.0 42*7d666900SdWiGhT */ 43*7d666900SdWiGhTclass csstidy_optimise { 44*7d666900SdWiGhT 45*7d666900SdWiGhT /** 46*7d666900SdWiGhT * csstidy object 47*7d666900SdWiGhT * @var object 48*7d666900SdWiGhT */ 49*7d666900SdWiGhT public $parser; 50*7d666900SdWiGhT public $css; 51*7d666900SdWiGhT public $sub_value; 52*7d666900SdWiGhT public $at; 53*7d666900SdWiGhT public $selector; 54*7d666900SdWiGhT public $property; 55*7d666900SdWiGhT public $value; 56*7d666900SdWiGhT 57*7d666900SdWiGhT /** 58*7d666900SdWiGhT * Constructor 59*7d666900SdWiGhT * @param array $css contains the class csstidy 60*7d666900SdWiGhT * @access private 61*7d666900SdWiGhT * @version 1.0 62*7d666900SdWiGhT */ 63*7d666900SdWiGhT public function __construct($css) { 64*7d666900SdWiGhT $this->parser = $css; 65*7d666900SdWiGhT $this->css = & $css->css; 66*7d666900SdWiGhT $this->sub_value = & $css->sub_value; 67*7d666900SdWiGhT $this->at = & $css->at; 68*7d666900SdWiGhT $this->selector = & $css->selector; 69*7d666900SdWiGhT $this->property = & $css->property; 70*7d666900SdWiGhT $this->value = & $css->value; 71*7d666900SdWiGhT } 72*7d666900SdWiGhT 73*7d666900SdWiGhT /** 74*7d666900SdWiGhT * Optimises $css after parsing 75*7d666900SdWiGhT * @access public 76*7d666900SdWiGhT * @version 1.0 77*7d666900SdWiGhT */ 78*7d666900SdWiGhT public function postparse() { 79*7d666900SdWiGhT 80*7d666900SdWiGhT if ($this->parser->get_cfg('reverse_left_and_right') > 0) { 81*7d666900SdWiGhT 82*7d666900SdWiGhT foreach ($this->css as $medium => $selectors) { 83*7d666900SdWiGhT if (is_array($selectors)) { 84*7d666900SdWiGhT foreach ($selectors as $selector => $properties) { 85*7d666900SdWiGhT $this->css[$medium][$selector] = $this->reverse_left_and_right($this->css[$medium][$selector]); 86*7d666900SdWiGhT } 87*7d666900SdWiGhT } 88*7d666900SdWiGhT } 89*7d666900SdWiGhT 90*7d666900SdWiGhT } 91*7d666900SdWiGhT 92*7d666900SdWiGhT if ($this->parser->get_cfg('preserve_css')) { 93*7d666900SdWiGhT return; 94*7d666900SdWiGhT } 95*7d666900SdWiGhT 96*7d666900SdWiGhT if ((int)$this->parser->get_cfg('merge_selectors') === 2) { 97*7d666900SdWiGhT foreach ($this->css as $medium => $value) { 98*7d666900SdWiGhT if (is_array($value)) { 99*7d666900SdWiGhT $this->merge_selectors($this->css[$medium]); 100*7d666900SdWiGhT } 101*7d666900SdWiGhT } 102*7d666900SdWiGhT } 103*7d666900SdWiGhT 104*7d666900SdWiGhT if ($this->parser->get_cfg('discard_invalid_selectors')) { 105*7d666900SdWiGhT foreach ($this->css as $medium => $value) { 106*7d666900SdWiGhT if (is_array($value)) { 107*7d666900SdWiGhT $this->discard_invalid_selectors($this->css[$medium]); 108*7d666900SdWiGhT } 109*7d666900SdWiGhT } 110*7d666900SdWiGhT } 111*7d666900SdWiGhT 112*7d666900SdWiGhT if ($this->parser->get_cfg('optimise_shorthands') > 0) { 113*7d666900SdWiGhT foreach ($this->css as $medium => $value) { 114*7d666900SdWiGhT if (is_array($value)) { 115*7d666900SdWiGhT foreach ($value as $selector => $value1) { 116*7d666900SdWiGhT $this->css[$medium][$selector] = $this->merge_4value_shorthands($this->css[$medium][$selector]); 117*7d666900SdWiGhT $this->css[$medium][$selector] = $this->merge_4value_radius_shorthands($this->css[$medium][$selector]); 118*7d666900SdWiGhT 119*7d666900SdWiGhT if ($this->parser->get_cfg('optimise_shorthands') < 2) { 120*7d666900SdWiGhT continue; 121*7d666900SdWiGhT } 122*7d666900SdWiGhT 123*7d666900SdWiGhT $this->css[$medium][$selector] = $this->merge_font($this->css[$medium][$selector]); 124*7d666900SdWiGhT 125*7d666900SdWiGhT if ($this->parser->get_cfg('optimise_shorthands') < 3) { 126*7d666900SdWiGhT continue; 127*7d666900SdWiGhT } 128*7d666900SdWiGhT 129*7d666900SdWiGhT $this->css[$medium][$selector] = $this->merge_bg($this->css[$medium][$selector]); 130*7d666900SdWiGhT if (empty($this->css[$medium][$selector])) { 131*7d666900SdWiGhT unset($this->css[$medium][$selector]); 132*7d666900SdWiGhT } 133*7d666900SdWiGhT } 134*7d666900SdWiGhT } 135*7d666900SdWiGhT } 136*7d666900SdWiGhT } 137*7d666900SdWiGhT } 138*7d666900SdWiGhT 139*7d666900SdWiGhT /** 140*7d666900SdWiGhT * Optimises values 141*7d666900SdWiGhT * @access public 142*7d666900SdWiGhT * @version 1.0 143*7d666900SdWiGhT */ 144*7d666900SdWiGhT public function value() { 145*7d666900SdWiGhT $shorthands = & $this->parser->data['csstidy']['shorthands']; 146*7d666900SdWiGhT 147*7d666900SdWiGhT // optimise shorthand properties 148*7d666900SdWiGhT if (isset($shorthands[$this->property])) { 149*7d666900SdWiGhT $temp = $this->shorthand($this->value); // FIXME - move 150*7d666900SdWiGhT if ($temp != $this->value) { 151*7d666900SdWiGhT $this->parser->log('Optimised shorthand notation (' . $this->property . '): Changed "' . $this->value . '" to "' . $temp . '"', 'Information'); 152*7d666900SdWiGhT } 153*7d666900SdWiGhT $this->value = $temp; 154*7d666900SdWiGhT } 155*7d666900SdWiGhT 156*7d666900SdWiGhT // Remove whitespace at ! important 157*7d666900SdWiGhT if ($this->value != $this->compress_important($this->value)) { 158*7d666900SdWiGhT $this->parser->log('Optimised !important', 'Information'); 159*7d666900SdWiGhT } 160*7d666900SdWiGhT } 161*7d666900SdWiGhT 162*7d666900SdWiGhT /** 163*7d666900SdWiGhT * Optimises shorthands 164*7d666900SdWiGhT * @access public 165*7d666900SdWiGhT * @version 1.0 166*7d666900SdWiGhT */ 167*7d666900SdWiGhT public function shorthands() { 168*7d666900SdWiGhT $shorthands = & $this->parser->data['csstidy']['shorthands']; 169*7d666900SdWiGhT 170*7d666900SdWiGhT if (!$this->parser->get_cfg('optimise_shorthands') || $this->parser->get_cfg('preserve_css')) { 171*7d666900SdWiGhT return; 172*7d666900SdWiGhT } 173*7d666900SdWiGhT 174*7d666900SdWiGhT if ($this->property === 'font' && $this->parser->get_cfg('optimise_shorthands') > 1) { 175*7d666900SdWiGhT $this->css[$this->at][$this->selector]['font']=''; 176*7d666900SdWiGhT $this->parser->merge_css_blocks($this->at, $this->selector, $this->dissolve_short_font($this->value)); 177*7d666900SdWiGhT } 178*7d666900SdWiGhT if ($this->property === 'background' && $this->parser->get_cfg('optimise_shorthands') > 2) { 179*7d666900SdWiGhT $this->css[$this->at][$this->selector]['background']=''; 180*7d666900SdWiGhT $this->parser->merge_css_blocks($this->at, $this->selector, $this->dissolve_short_bg($this->value)); 181*7d666900SdWiGhT } 182*7d666900SdWiGhT if (isset($shorthands[$this->property])) { 183*7d666900SdWiGhT $this->parser->merge_css_blocks($this->at, $this->selector, $this->dissolve_4value_shorthands($this->property, $this->value)); 184*7d666900SdWiGhT if (is_array($shorthands[$this->property])) { 185*7d666900SdWiGhT $this->css[$this->at][$this->selector][$this->property] = ''; 186*7d666900SdWiGhT } 187*7d666900SdWiGhT } 188*7d666900SdWiGhT } 189*7d666900SdWiGhT 190*7d666900SdWiGhT /** 191*7d666900SdWiGhT * Optimises a sub-value 192*7d666900SdWiGhT * @access public 193*7d666900SdWiGhT * @version 1.0 194*7d666900SdWiGhT */ 195*7d666900SdWiGhT public function subvalue() { 196*7d666900SdWiGhT $replace_colors = & $this->parser->data['csstidy']['replace_colors']; 197*7d666900SdWiGhT 198*7d666900SdWiGhT $this->sub_value = trim($this->sub_value); 199*7d666900SdWiGhT if ($this->sub_value == '') { // caution : '0' 200*7d666900SdWiGhT return; 201*7d666900SdWiGhT } 202*7d666900SdWiGhT 203*7d666900SdWiGhT $important = ''; 204*7d666900SdWiGhT if ($this->parser->is_important($this->sub_value)) { 205*7d666900SdWiGhT $important = '!important'; 206*7d666900SdWiGhT } 207*7d666900SdWiGhT $this->sub_value = $this->parser->gvw_important($this->sub_value); 208*7d666900SdWiGhT 209*7d666900SdWiGhT // Compress font-weight 210*7d666900SdWiGhT if ($this->property === 'font-weight' && $this->parser->get_cfg('compress_font-weight')) { 211*7d666900SdWiGhT if ($this->sub_value === 'bold') { 212*7d666900SdWiGhT $this->sub_value = '700'; 213*7d666900SdWiGhT $this->parser->log('Optimised font-weight: Changed "bold" to "700"', 'Information'); 214*7d666900SdWiGhT } elseif ($this->sub_value === 'normal') { 215*7d666900SdWiGhT $this->sub_value = '400'; 216*7d666900SdWiGhT $this->parser->log('Optimised font-weight: Changed "normal" to "400"', 'Information'); 217*7d666900SdWiGhT } 218*7d666900SdWiGhT } 219*7d666900SdWiGhT 220*7d666900SdWiGhT $temp = $this->compress_numbers($this->sub_value); 221*7d666900SdWiGhT if (strcasecmp($temp, $this->sub_value) !== 0) { 222*7d666900SdWiGhT if (strlen($temp) > strlen($this->sub_value)) { 223*7d666900SdWiGhT $this->parser->log('Fixed invalid number: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Warning'); 224*7d666900SdWiGhT } else { 225*7d666900SdWiGhT $this->parser->log('Optimised number: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Information'); 226*7d666900SdWiGhT } 227*7d666900SdWiGhT $this->sub_value = $temp; 228*7d666900SdWiGhT } 229*7d666900SdWiGhT if ($this->parser->get_cfg('compress_colors')) { 230*7d666900SdWiGhT $temp = $this->cut_color($this->sub_value); 231*7d666900SdWiGhT if ($temp !== $this->sub_value) { 232*7d666900SdWiGhT if (isset($replace_colors[$this->sub_value])) { 233*7d666900SdWiGhT $this->parser->log('Fixed invalid color name: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Warning'); 234*7d666900SdWiGhT } else { 235*7d666900SdWiGhT $this->parser->log('Optimised color: Changed "' . $this->sub_value . '" to "' . $temp . '"', 'Information'); 236*7d666900SdWiGhT } 237*7d666900SdWiGhT $this->sub_value = $temp; 238*7d666900SdWiGhT } 239*7d666900SdWiGhT } 240*7d666900SdWiGhT $this->sub_value .= $important; 241*7d666900SdWiGhT } 242*7d666900SdWiGhT 243*7d666900SdWiGhT /** 244*7d666900SdWiGhT * Compresses shorthand values. Example: margin:1px 1px 1px 1px -> margin:1px 245*7d666900SdWiGhT * @param string $value 246*7d666900SdWiGhT * @access public 247*7d666900SdWiGhT * @return string 248*7d666900SdWiGhT * @version 1.0 249*7d666900SdWiGhT */ 250*7d666900SdWiGhT public function shorthand($value) { 251*7d666900SdWiGhT $important = ''; 252*7d666900SdWiGhT if ($this->parser->is_important($value)) { 253*7d666900SdWiGhT $values = $this->parser->gvw_important($value); 254*7d666900SdWiGhT $important = '!important'; 255*7d666900SdWiGhT } 256*7d666900SdWiGhT else 257*7d666900SdWiGhT $values = $value; 258*7d666900SdWiGhT 259*7d666900SdWiGhT $values = explode(' ', $values); 260*7d666900SdWiGhT switch (count($values)) { 261*7d666900SdWiGhT case 4: 262*7d666900SdWiGhT if ($values[0] == $values[1] && $values[0] == $values[2] && $values[0] == $values[3]) { 263*7d666900SdWiGhT return $values[0] . $important; 264*7d666900SdWiGhT } elseif ($values[1] == $values[3] && $values[0] == $values[2]) { 265*7d666900SdWiGhT return $values[0] . ' ' . $values[1] . $important; 266*7d666900SdWiGhT } elseif ($values[1] == $values[3]) { 267*7d666900SdWiGhT return $values[0] . ' ' . $values[1] . ' ' . $values[2] . $important; 268*7d666900SdWiGhT } 269*7d666900SdWiGhT break; 270*7d666900SdWiGhT 271*7d666900SdWiGhT case 3: 272*7d666900SdWiGhT if ($values[0] == $values[1] && $values[0] == $values[2]) { 273*7d666900SdWiGhT return $values[0] . $important; 274*7d666900SdWiGhT } elseif ($values[0] == $values[2]) { 275*7d666900SdWiGhT return $values[0] . ' ' . $values[1] . $important; 276*7d666900SdWiGhT } 277*7d666900SdWiGhT break; 278*7d666900SdWiGhT 279*7d666900SdWiGhT case 2: 280*7d666900SdWiGhT if ($values[0] == $values[1]) { 281*7d666900SdWiGhT return $values[0] . $important; 282*7d666900SdWiGhT } 283*7d666900SdWiGhT break; 284*7d666900SdWiGhT } 285*7d666900SdWiGhT 286*7d666900SdWiGhT return $value; 287*7d666900SdWiGhT } 288*7d666900SdWiGhT 289*7d666900SdWiGhT /** 290*7d666900SdWiGhT * Removes unnecessary whitespace in ! important 291*7d666900SdWiGhT * @param string $string 292*7d666900SdWiGhT * @return string 293*7d666900SdWiGhT * @access public 294*7d666900SdWiGhT * @version 1.1 295*7d666900SdWiGhT */ 296*7d666900SdWiGhT public function compress_important(&$string) { 297*7d666900SdWiGhT if ($this->parser->is_important($string)) { 298*7d666900SdWiGhT $important = $this->parser->get_cfg('space_before_important') ? ' !important' : '!important'; 299*7d666900SdWiGhT $string = $this->parser->gvw_important($string) . $important; 300*7d666900SdWiGhT } 301*7d666900SdWiGhT return $string; 302*7d666900SdWiGhT } 303*7d666900SdWiGhT 304*7d666900SdWiGhT /** 305*7d666900SdWiGhT * Color compression function. Converts all rgb() values to #-values and uses the short-form if possible. Also replaces 4 color names by #-values. 306*7d666900SdWiGhT * @param string $color 307*7d666900SdWiGhT * @return string 308*7d666900SdWiGhT * @version 1.1 309*7d666900SdWiGhT */ 310*7d666900SdWiGhT public function cut_color($color) { 311*7d666900SdWiGhT $replace_colors = & $this->parser->data['csstidy']['replace_colors']; 312*7d666900SdWiGhT 313*7d666900SdWiGhT // if it's a string, don't touch ! 314*7d666900SdWiGhT if (strncmp($color, "'", 1) == 0 || strncmp($color, '"', 1) == 0) 315*7d666900SdWiGhT return $color; 316*7d666900SdWiGhT 317*7d666900SdWiGhT /* expressions complexes de type gradient */ 318*7d666900SdWiGhT if (strpos($color, '(') !== false 319*7d666900SdWiGhT && (strncasecmp($color, 'rgb(' ,4) !== 0 and strncasecmp($color, 'rgba(' ,5) !== 0)) { 320*7d666900SdWiGhT // on ne touche pas aux couleurs dans les expression ms, c'est trop sensible 321*7d666900SdWiGhT if (stripos($color, 'progid:') !== false) 322*7d666900SdWiGhT return $color; 323*7d666900SdWiGhT preg_match_all(",rgba?\([^)]+\),i", $color, $matches, PREG_SET_ORDER); 324*7d666900SdWiGhT if (count($matches)) { 325*7d666900SdWiGhT foreach ($matches as $m) { 326*7d666900SdWiGhT $color = str_replace($m[0], $this->cut_color($m[0]), $color); 327*7d666900SdWiGhT } 328*7d666900SdWiGhT } 329*7d666900SdWiGhT preg_match_all(",#[0-9a-f]{6}(?=[^0-9a-f]),i", $color, $matches, PREG_SET_ORDER); 330*7d666900SdWiGhT if (count($matches)) { 331*7d666900SdWiGhT foreach ($matches as $m) { 332*7d666900SdWiGhT $color = str_replace($m[0],$this->cut_color($m[0]), $color); 333*7d666900SdWiGhT } 334*7d666900SdWiGhT } 335*7d666900SdWiGhT return $color; 336*7d666900SdWiGhT } 337*7d666900SdWiGhT 338*7d666900SdWiGhT // rgb(0,0,0) -> #000000 (or #000 in this case later) 339*7d666900SdWiGhT if ( 340*7d666900SdWiGhT // be sure to not corrupt a rgb with calc() value 341*7d666900SdWiGhT (strncasecmp($color, 'rgb(', 4)==0 and strpos($color, '(', 4) === false) 342*7d666900SdWiGhT or (strncasecmp($color, 'rgba(', 5)==0 and strpos($color, '(', 5) === false) 343*7d666900SdWiGhT ){ 344*7d666900SdWiGhT $color_tmp = explode('(', $color, 2); 345*7d666900SdWiGhT $color_tmp = rtrim(end($color_tmp), ')'); 346*7d666900SdWiGhT if (strpos($color_tmp, '/') !== false) { 347*7d666900SdWiGhT $color_tmp = explode('/', $color_tmp, 2); 348*7d666900SdWiGhT $color_parts = explode(' ', trim(reset($color_tmp)), 3); 349*7d666900SdWiGhT while (count($color_parts) < 3) { 350*7d666900SdWiGhT $color_parts[] = 0; 351*7d666900SdWiGhT } 352*7d666900SdWiGhT $color_parts[] = end($color_tmp); 353*7d666900SdWiGhT } 354*7d666900SdWiGhT else { 355*7d666900SdWiGhT $color_parts = explode(',', $color_tmp, 4); 356*7d666900SdWiGhT } 357*7d666900SdWiGhT for ($i = 0; $i < count($color_parts); $i++) { 358*7d666900SdWiGhT $color_parts[$i] = trim($color_parts[$i]); 359*7d666900SdWiGhT if (substr($color_parts[$i], -1) === '%') { 360*7d666900SdWiGhT $color_parts[$i] = round((255 * intval($color_parts[$i])) / 100); 361*7d666900SdWiGhT } elseif ($i>2) { 362*7d666900SdWiGhT // 4th argument is alpga layer between 0 and 1 (if not %) 363*7d666900SdWiGhT $color_parts[$i] = round((255 * floatval($color_parts[$i]))); 364*7d666900SdWiGhT } 365*7d666900SdWiGhT $color_parts[$i] = intval($color_parts[$i]); 366*7d666900SdWiGhT if ($color_parts[$i] > 255){ 367*7d666900SdWiGhT $color_parts[$i] = 255; 368*7d666900SdWiGhT } 369*7d666900SdWiGhT } 370*7d666900SdWiGhT $color = '#'; 371*7d666900SdWiGhT // 3 or 4 parts depending on alpha layer 372*7d666900SdWiGhT $nb = min(max(count($color_parts), 3),4); 373*7d666900SdWiGhT for ($i = 0; $i < $nb; $i++) { 374*7d666900SdWiGhT if (!isset($color_parts[$i])) { 375*7d666900SdWiGhT $color_parts[$i] = 0; 376*7d666900SdWiGhT } 377*7d666900SdWiGhT if ($color_parts[$i] < 16) { 378*7d666900SdWiGhT $color .= '0' . dechex($color_parts[$i]); 379*7d666900SdWiGhT } else { 380*7d666900SdWiGhT $color .= dechex($color_parts[$i]); 381*7d666900SdWiGhT } 382*7d666900SdWiGhT } 383*7d666900SdWiGhT } 384*7d666900SdWiGhT 385*7d666900SdWiGhT // Fix bad color names 386*7d666900SdWiGhT if (isset($replace_colors[strtolower($color)])) { 387*7d666900SdWiGhT $color = $replace_colors[strtolower($color)]; 388*7d666900SdWiGhT } 389*7d666900SdWiGhT 390*7d666900SdWiGhT // #aabbcc -> #abc 391*7d666900SdWiGhT if (strlen($color) == 7) { 392*7d666900SdWiGhT $color_temp = strtolower($color); 393*7d666900SdWiGhT if ($color_temp[0] === '#' && $color_temp[1] == $color_temp[2] && $color_temp[3] == $color_temp[4] && $color_temp[5] == $color_temp[6]) { 394*7d666900SdWiGhT $color = '#' . $color[1] . $color[3] . $color[5]; 395*7d666900SdWiGhT } 396*7d666900SdWiGhT } 397*7d666900SdWiGhT // #aabbccdd -> #abcd 398*7d666900SdWiGhT elseif (strlen($color) == 9) { 399*7d666900SdWiGhT $color_temp = strtolower($color); 400*7d666900SdWiGhT if ($color_temp[0] === '#' && $color_temp[1] == $color_temp[2] && $color_temp[3] == $color_temp[4] && $color_temp[5] == $color_temp[6] && $color_temp[7] == $color_temp[8]) { 401*7d666900SdWiGhT $color = '#' . $color[1] . $color[3] . $color[5] . $color[7]; 402*7d666900SdWiGhT } 403*7d666900SdWiGhT } 404*7d666900SdWiGhT 405*7d666900SdWiGhT switch (strtolower($color)) { 406*7d666900SdWiGhT /* color name -> hex code */ 407*7d666900SdWiGhT case 'black': return '#000'; 408*7d666900SdWiGhT case 'fuchsia': return '#f0f'; 409*7d666900SdWiGhT case 'white': return '#fff'; 410*7d666900SdWiGhT case 'yellow': return '#ff0'; 411*7d666900SdWiGhT 412*7d666900SdWiGhT /* hex code -> color name */ 413*7d666900SdWiGhT case '#800000': return 'maroon'; 414*7d666900SdWiGhT case '#ffa500': return 'orange'; 415*7d666900SdWiGhT case '#808000': return 'olive'; 416*7d666900SdWiGhT case '#800080': return 'purple'; 417*7d666900SdWiGhT case '#008000': return 'green'; 418*7d666900SdWiGhT case '#000080': return 'navy'; 419*7d666900SdWiGhT case '#008080': return 'teal'; 420*7d666900SdWiGhT case '#c0c0c0': return 'silver'; 421*7d666900SdWiGhT case '#808080': return 'gray'; 422*7d666900SdWiGhT case '#f00': return 'red'; 423*7d666900SdWiGhT } 424*7d666900SdWiGhT 425*7d666900SdWiGhT return $color; 426*7d666900SdWiGhT } 427*7d666900SdWiGhT 428*7d666900SdWiGhT /** 429*7d666900SdWiGhT * Compresses numbers (ie. 1.0 becomes 1 or 1.100 becomes 1.1 ) 430*7d666900SdWiGhT * @param string $subvalue 431*7d666900SdWiGhT * @return string 432*7d666900SdWiGhT * @version 1.2 433*7d666900SdWiGhT */ 434*7d666900SdWiGhT public function compress_numbers($subvalue) { 435*7d666900SdWiGhT $unit_values = & $this->parser->data['csstidy']['unit_values']; 436*7d666900SdWiGhT $color_values = & $this->parser->data['csstidy']['color_values']; 437*7d666900SdWiGhT 438*7d666900SdWiGhT // for font:1em/1em sans-serif...; 439*7d666900SdWiGhT if ($this->property === 'font') { 440*7d666900SdWiGhT $temp = explode('/', $subvalue); 441*7d666900SdWiGhT } else { 442*7d666900SdWiGhT $temp = array($subvalue); 443*7d666900SdWiGhT } 444*7d666900SdWiGhT 445*7d666900SdWiGhT for ($l = 0; $l < count($temp); $l++) { 446*7d666900SdWiGhT // if we are not dealing with a number at this point, do not optimise anything 447*7d666900SdWiGhT $number = $this->AnalyseCssNumber($temp[$l]); 448*7d666900SdWiGhT if ($number === false) { 449*7d666900SdWiGhT return $subvalue; 450*7d666900SdWiGhT } 451*7d666900SdWiGhT 452*7d666900SdWiGhT // Fix bad colors 453*7d666900SdWiGhT if (in_array($this->property, $color_values)) { 454*7d666900SdWiGhT $temp[$l] = '#' . $temp[$l]; 455*7d666900SdWiGhT continue; 456*7d666900SdWiGhT } 457*7d666900SdWiGhT 458*7d666900SdWiGhT if (abs($number[0]) > 0) { 459*7d666900SdWiGhT if ($number[1] == '' && in_array($this->property, $unit_values, true)) { 460*7d666900SdWiGhT $number[1] = 'px'; 461*7d666900SdWiGhT } 462*7d666900SdWiGhT } elseif ($number[1] != 's' && $number[1] != 'ms') { 463*7d666900SdWiGhT $number[1] = ''; 464*7d666900SdWiGhT } 465*7d666900SdWiGhT 466*7d666900SdWiGhT $temp[$l] = $number[0] . $number[1]; 467*7d666900SdWiGhT } 468*7d666900SdWiGhT 469*7d666900SdWiGhT return ((count($temp) > 1) ? $temp[0] . '/' . $temp[1] : $temp[0]); 470*7d666900SdWiGhT } 471*7d666900SdWiGhT 472*7d666900SdWiGhT /** 473*7d666900SdWiGhT * Checks if a given string is a CSS valid number. If it is, 474*7d666900SdWiGhT * an array containing the value and unit is returned 475*7d666900SdWiGhT * @param string $string 476*7d666900SdWiGhT * @return array ('unit' if unit is found or '' if no unit exists, number value) or false if no number 477*7d666900SdWiGhT */ 478*7d666900SdWiGhT public function AnalyseCssNumber($string) { 479*7d666900SdWiGhT // most simple checks first 480*7d666900SdWiGhT if (strlen($string) == 0 || ctype_alpha($string[0])) { 481*7d666900SdWiGhT return false; 482*7d666900SdWiGhT } 483*7d666900SdWiGhT 484*7d666900SdWiGhT $units = & $this->parser->data['csstidy']['units']; 485*7d666900SdWiGhT $return = array(0, ''); 486*7d666900SdWiGhT 487*7d666900SdWiGhT $return[0] = floatval($string); 488*7d666900SdWiGhT if (abs($return[0]) > 0 && abs($return[0]) < 1) { 489*7d666900SdWiGhT if ($return[0] < 0) { 490*7d666900SdWiGhT $return[0] = '-' . ltrim(substr($return[0], 1), '0'); 491*7d666900SdWiGhT } else { 492*7d666900SdWiGhT $return[0] = ltrim($return[0], '0'); 493*7d666900SdWiGhT } 494*7d666900SdWiGhT } 495*7d666900SdWiGhT 496*7d666900SdWiGhT // Look for unit and split from value if exists 497*7d666900SdWiGhT foreach ($units as $unit) { 498*7d666900SdWiGhT $expectUnitAt = strlen($string) - strlen($unit); 499*7d666900SdWiGhT if (!($unitInString = stristr($string, $unit))) { // mb_strpos() fails with "false" 500*7d666900SdWiGhT continue; 501*7d666900SdWiGhT } 502*7d666900SdWiGhT $actualPosition = strpos($string, $unitInString); 503*7d666900SdWiGhT if ($expectUnitAt === $actualPosition) { 504*7d666900SdWiGhT $return[1] = $unit; 505*7d666900SdWiGhT $string = substr($string, 0, - strlen($unit)); 506*7d666900SdWiGhT break; 507*7d666900SdWiGhT } 508*7d666900SdWiGhT } 509*7d666900SdWiGhT if (!is_numeric($string)) { 510*7d666900SdWiGhT return false; 511*7d666900SdWiGhT } 512*7d666900SdWiGhT return $return; 513*7d666900SdWiGhT } 514*7d666900SdWiGhT 515*7d666900SdWiGhT /** 516*7d666900SdWiGhT * Merges selectors with same properties. Example: a{color:red} b{color:red} -> a,b{color:red} 517*7d666900SdWiGhT * Very basic and has at least one bug. Hopefully there is a replacement soon. 518*7d666900SdWiGhT * @param array $array 519*7d666900SdWiGhT * @return array 520*7d666900SdWiGhT * @access public 521*7d666900SdWiGhT * @version 1.2 522*7d666900SdWiGhT */ 523*7d666900SdWiGhT public function merge_selectors(&$array) { 524*7d666900SdWiGhT $css = $array; 525*7d666900SdWiGhT foreach ($css as $key => $value) { 526*7d666900SdWiGhT if (!isset($css[$key])) { 527*7d666900SdWiGhT continue; 528*7d666900SdWiGhT } 529*7d666900SdWiGhT $newsel = ''; 530*7d666900SdWiGhT 531*7d666900SdWiGhT // Check if properties also exist in another selector 532*7d666900SdWiGhT $keys = array(); 533*7d666900SdWiGhT // PHP bug (?) without $css = $array; here 534*7d666900SdWiGhT foreach ($css as $selector => $vali) { 535*7d666900SdWiGhT if ($selector == $key) { 536*7d666900SdWiGhT continue; 537*7d666900SdWiGhT } 538*7d666900SdWiGhT 539*7d666900SdWiGhT if ($css[$key] === $vali) { 540*7d666900SdWiGhT $keys[] = $selector; 541*7d666900SdWiGhT } 542*7d666900SdWiGhT } 543*7d666900SdWiGhT 544*7d666900SdWiGhT if (!empty($keys)) { 545*7d666900SdWiGhT $newsel = $key; 546*7d666900SdWiGhT unset($css[$key]); 547*7d666900SdWiGhT foreach ($keys as $selector) { 548*7d666900SdWiGhT unset($css[$selector]); 549*7d666900SdWiGhT $newsel .= ',' . $selector; 550*7d666900SdWiGhT } 551*7d666900SdWiGhT $css[$newsel] = $value; 552*7d666900SdWiGhT } 553*7d666900SdWiGhT } 554*7d666900SdWiGhT $array = $css; 555*7d666900SdWiGhT } 556*7d666900SdWiGhT 557*7d666900SdWiGhT /** 558*7d666900SdWiGhT * Removes invalid selectors and their corresponding rule-sets as 559*7d666900SdWiGhT * defined by 4.1.7 in REC-CSS2. This is a very rudimentary check 560*7d666900SdWiGhT * and should be replaced by a full-blown parsing algorithm or 561*7d666900SdWiGhT * regular expression 562*7d666900SdWiGhT * @version 1.4 563*7d666900SdWiGhT */ 564*7d666900SdWiGhT public function discard_invalid_selectors(&$array) { 565*7d666900SdWiGhT $invalid = array('+' => true, '~' => true, ',' => true, '>' => true); 566*7d666900SdWiGhT foreach ($array as $selector => $decls) { 567*7d666900SdWiGhT $ok = true; 568*7d666900SdWiGhT $selectors = array_map('trim', explode(',', $selector)); 569*7d666900SdWiGhT foreach ($selectors as $s) { 570*7d666900SdWiGhT $simple_selectors = preg_split('/\s*[+>~\s]\s*/', $s); 571*7d666900SdWiGhT foreach ($simple_selectors as $ss) { 572*7d666900SdWiGhT if ($ss === '') 573*7d666900SdWiGhT $ok = false; 574*7d666900SdWiGhT // could also check $ss for internal structure, 575*7d666900SdWiGhT // but that probably would be too slow 576*7d666900SdWiGhT } 577*7d666900SdWiGhT } 578*7d666900SdWiGhT if (!$ok) 579*7d666900SdWiGhT unset($array[$selector]); 580*7d666900SdWiGhT } 581*7d666900SdWiGhT } 582*7d666900SdWiGhT 583*7d666900SdWiGhT /** 584*7d666900SdWiGhT * Dissolves properties like padding:10px 10px 10px to padding-top:10px;padding-bottom:10px;... 585*7d666900SdWiGhT * @param string $property 586*7d666900SdWiGhT * @param string $value 587*7d666900SdWiGhT * @param array|null $shorthands 588*7d666900SdWiGhT * @return array 589*7d666900SdWiGhT * @version 1.0 590*7d666900SdWiGhT * @see merge_4value_shorthands() 591*7d666900SdWiGhT */ 592*7d666900SdWiGhT public function dissolve_4value_shorthands($property, $value, $shorthands = null) { 593*7d666900SdWiGhT if (is_null($shorthands)) { 594*7d666900SdWiGhT $shorthands = & $this->parser->data['csstidy']['shorthands']; 595*7d666900SdWiGhT } 596*7d666900SdWiGhT if (!is_array($shorthands[$property])) { 597*7d666900SdWiGhT $return[$property] = $value; 598*7d666900SdWiGhT return $return; 599*7d666900SdWiGhT } 600*7d666900SdWiGhT 601*7d666900SdWiGhT $important = ''; 602*7d666900SdWiGhT if ($this->parser->is_important($value)) { 603*7d666900SdWiGhT $value = $this->parser->gvw_important($value); 604*7d666900SdWiGhT $important = '!important'; 605*7d666900SdWiGhT } 606*7d666900SdWiGhT $values = explode(' ', $value); 607*7d666900SdWiGhT 608*7d666900SdWiGhT 609*7d666900SdWiGhT $return = array(); 610*7d666900SdWiGhT if (count($values) == 4) { 611*7d666900SdWiGhT for ($i = 0; $i < 4; $i++) { 612*7d666900SdWiGhT $return[$shorthands[$property][$i]] = $values[$i] . $important; 613*7d666900SdWiGhT } 614*7d666900SdWiGhT } elseif (count($values) == 3) { 615*7d666900SdWiGhT $return[$shorthands[$property][0]] = $values[0] . $important; 616*7d666900SdWiGhT $return[$shorthands[$property][1]] = $values[1] . $important; 617*7d666900SdWiGhT $return[$shorthands[$property][3]] = $values[1] . $important; 618*7d666900SdWiGhT $return[$shorthands[$property][2]] = $values[2] . $important; 619*7d666900SdWiGhT } elseif (count($values) == 2) { 620*7d666900SdWiGhT for ($i = 0; $i < 4; $i++) { 621*7d666900SdWiGhT $return[$shorthands[$property][$i]] = (($i % 2 != 0)) ? $values[1] . $important : $values[0] . $important; 622*7d666900SdWiGhT } 623*7d666900SdWiGhT } else { 624*7d666900SdWiGhT for ($i = 0; $i < 4; $i++) { 625*7d666900SdWiGhT $return[$shorthands[$property][$i]] = $values[0] . $important; 626*7d666900SdWiGhT } 627*7d666900SdWiGhT } 628*7d666900SdWiGhT 629*7d666900SdWiGhT return $return; 630*7d666900SdWiGhT } 631*7d666900SdWiGhT 632*7d666900SdWiGhT /** 633*7d666900SdWiGhT * Dissolves radius properties like 634*7d666900SdWiGhT * border-radius:10px 10px 10px / 1px 2px 635*7d666900SdWiGhT * to border-top-left:10px 1px;border-top-right:10px 2x;... 636*7d666900SdWiGhT * @param string $property 637*7d666900SdWiGhT * @param string $value 638*7d666900SdWiGhT * @return array 639*7d666900SdWiGhT * @version 1.0 640*7d666900SdWiGhT * @use dissolve_4value_shorthands() 641*7d666900SdWiGhT * @see merge_4value_radius_shorthands() 642*7d666900SdWiGhT */ 643*7d666900SdWiGhT public function dissolve_4value_radius_shorthands($property, $value) { 644*7d666900SdWiGhT $shorthands = & $this->parser->data['csstidy']['radius_shorthands']; 645*7d666900SdWiGhT if (!is_array($shorthands[$property])) { 646*7d666900SdWiGhT $return[$property] = $value; 647*7d666900SdWiGhT return $return; 648*7d666900SdWiGhT } 649*7d666900SdWiGhT 650*7d666900SdWiGhT if (strpos($value, '/') !== false) { 651*7d666900SdWiGhT $values = $this->explode_ws('/', $value); 652*7d666900SdWiGhT if (count($values) == 2) { 653*7d666900SdWiGhT $r[0] = $this->dissolve_4value_shorthands($property, trim($values[0]), $shorthands); 654*7d666900SdWiGhT $r[1] = $this->dissolve_4value_shorthands($property, trim($values[1]), $shorthands); 655*7d666900SdWiGhT $return = array(); 656*7d666900SdWiGhT foreach ($r[0] as $p=>$v) { 657*7d666900SdWiGhT $return[$p] = $v; 658*7d666900SdWiGhT if ($r[1][$p] !== $v) { 659*7d666900SdWiGhT $return[$p] .= ' ' . $r[1][$p]; 660*7d666900SdWiGhT } 661*7d666900SdWiGhT } 662*7d666900SdWiGhT return $return; 663*7d666900SdWiGhT } 664*7d666900SdWiGhT } 665*7d666900SdWiGhT 666*7d666900SdWiGhT $return = $this->dissolve_4value_shorthands($property, $value, $shorthands); 667*7d666900SdWiGhT return $return; 668*7d666900SdWiGhT } 669*7d666900SdWiGhT 670*7d666900SdWiGhT /** 671*7d666900SdWiGhT * Explodes a string as explode() does, however, not if $sep is escaped or within a string. 672*7d666900SdWiGhT * @param string $sep seperator 673*7d666900SdWiGhT * @param string $string 674*7d666900SdWiGhT * @param bool $explode_in_parenthesis 675*7d666900SdWiGhT * @return array 676*7d666900SdWiGhT * @version 1.0 677*7d666900SdWiGhT */ 678*7d666900SdWiGhT public function explode_ws($sep, $string, $explode_in_parenthesis = false) { 679*7d666900SdWiGhT $status = 'st'; 680*7d666900SdWiGhT $to = ''; 681*7d666900SdWiGhT 682*7d666900SdWiGhT $output = array( 683*7d666900SdWiGhT 0 => '', 684*7d666900SdWiGhT ); 685*7d666900SdWiGhT $num = 0; 686*7d666900SdWiGhT for ($i = 0, $len = strlen($string); $i < $len; $i++) { 687*7d666900SdWiGhT switch ($status) { 688*7d666900SdWiGhT case 'st': 689*7d666900SdWiGhT if ($string[$i] == $sep && !$this->parser->escaped($string, $i)) { 690*7d666900SdWiGhT ++$num; 691*7d666900SdWiGhT } elseif ($string[$i] === '"' || $string[$i] === '\'' || (!$explode_in_parenthesis && $string[$i] === '(') && !$this->parser->escaped($string, $i)) { 692*7d666900SdWiGhT $status = 'str'; 693*7d666900SdWiGhT $to = ($string[$i] === '(') ? ')' : $string[$i]; 694*7d666900SdWiGhT (isset($output[$num])) ? $output[$num] .= $string[$i] : $output[$num] = $string[$i]; 695*7d666900SdWiGhT } else { 696*7d666900SdWiGhT (isset($output[$num])) ? $output[$num] .= $string[$i] : $output[$num] = $string[$i]; 697*7d666900SdWiGhT } 698*7d666900SdWiGhT break; 699*7d666900SdWiGhT 700*7d666900SdWiGhT case 'str': 701*7d666900SdWiGhT if ($string[$i] == $to && !$this->parser->escaped($string, $i)) { 702*7d666900SdWiGhT $status = 'st'; 703*7d666900SdWiGhT } 704*7d666900SdWiGhT (isset($output[$num])) ? $output[$num] .= $string[$i] : $output[$num] = $string[$i]; 705*7d666900SdWiGhT break; 706*7d666900SdWiGhT } 707*7d666900SdWiGhT } 708*7d666900SdWiGhT 709*7d666900SdWiGhT return $output; 710*7d666900SdWiGhT } 711*7d666900SdWiGhT 712*7d666900SdWiGhT /** 713*7d666900SdWiGhT * Merges Shorthand properties again, the opposite of dissolve_4value_shorthands() 714*7d666900SdWiGhT * @param array $array 715*7d666900SdWiGhT * @param array|null $shorthands 716*7d666900SdWiGhT * @return array 717*7d666900SdWiGhT * @version 1.2 718*7d666900SdWiGhT * @see dissolve_4value_shorthands() 719*7d666900SdWiGhT */ 720*7d666900SdWiGhT public function merge_4value_shorthands($array, $shorthands = null) { 721*7d666900SdWiGhT $return = $array; 722*7d666900SdWiGhT if (is_null($shorthands)) { 723*7d666900SdWiGhT $shorthands = & $this->parser->data['csstidy']['shorthands']; 724*7d666900SdWiGhT } 725*7d666900SdWiGhT 726*7d666900SdWiGhT foreach ($shorthands as $key => $value) { 727*7d666900SdWiGhT if ($value !== 0 && isset($array[$value[0]]) && isset($array[$value[1]]) 728*7d666900SdWiGhT && isset($array[$value[2]]) && isset($array[$value[3]])) { 729*7d666900SdWiGhT $return[$key] = ''; 730*7d666900SdWiGhT 731*7d666900SdWiGhT $important = ''; 732*7d666900SdWiGhT for ($i = 0; $i < 4; $i++) { 733*7d666900SdWiGhT $val = $array[$value[$i]]; 734*7d666900SdWiGhT if ($this->parser->is_important($val)) { 735*7d666900SdWiGhT $important = '!important'; 736*7d666900SdWiGhT $return[$key] .= $this->parser->gvw_important($val) . ' '; 737*7d666900SdWiGhT } else { 738*7d666900SdWiGhT $return[$key] .= $val . ' '; 739*7d666900SdWiGhT } 740*7d666900SdWiGhT unset($return[$value[$i]]); 741*7d666900SdWiGhT } 742*7d666900SdWiGhT $return[$key] = $this->shorthand(trim($return[$key] . $important)); 743*7d666900SdWiGhT } 744*7d666900SdWiGhT } 745*7d666900SdWiGhT return $return; 746*7d666900SdWiGhT } 747*7d666900SdWiGhT 748*7d666900SdWiGhT /** 749*7d666900SdWiGhT * Merges Shorthand properties again, the opposite of dissolve_4value_shorthands() 750*7d666900SdWiGhT * @param array $array 751*7d666900SdWiGhT * @return array 752*7d666900SdWiGhT * @version 1.2 753*7d666900SdWiGhT * @use merge_4value_shorthands() 754*7d666900SdWiGhT * @see dissolve_4value_radius_shorthands() 755*7d666900SdWiGhT */ 756*7d666900SdWiGhT public function merge_4value_radius_shorthands($array) { 757*7d666900SdWiGhT $return = $array; 758*7d666900SdWiGhT $shorthands = & $this->parser->data['csstidy']['radius_shorthands']; 759*7d666900SdWiGhT 760*7d666900SdWiGhT foreach ($shorthands as $key => $value) { 761*7d666900SdWiGhT if (isset($array[$value[0]]) && isset($array[$value[1]]) 762*7d666900SdWiGhT && isset($array[$value[2]]) && isset($array[$value[3]]) && $value !== 0) { 763*7d666900SdWiGhT $return[$key] = ''; 764*7d666900SdWiGhT $a = array(); 765*7d666900SdWiGhT for ($i = 0; $i < 4; $i++) { 766*7d666900SdWiGhT $v = $this->explode_ws(' ', trim($array[$value[$i]])); 767*7d666900SdWiGhT $a[0][$value[$i]] = reset($v); 768*7d666900SdWiGhT $a[1][$value[$i]] = end($v); 769*7d666900SdWiGhT } 770*7d666900SdWiGhT $r = array(); 771*7d666900SdWiGhT $r[0] = $this->merge_4value_shorthands($a[0], $shorthands); 772*7d666900SdWiGhT $r[1] = $this->merge_4value_shorthands($a[1], $shorthands); 773*7d666900SdWiGhT 774*7d666900SdWiGhT if (isset($r[0][$key]) and isset($r[1][$key])) { 775*7d666900SdWiGhT $return[$key] = $r[0][$key]; 776*7d666900SdWiGhT if ($r[1][$key] !== $r[0][$key]) { 777*7d666900SdWiGhT $return[$key] .= ' / ' . $r[1][$key]; 778*7d666900SdWiGhT } 779*7d666900SdWiGhT for ($i = 0; $i < 4; $i++) { 780*7d666900SdWiGhT unset($return[$value[$i]]); 781*7d666900SdWiGhT } 782*7d666900SdWiGhT } 783*7d666900SdWiGhT } 784*7d666900SdWiGhT } 785*7d666900SdWiGhT return $return; 786*7d666900SdWiGhT } 787*7d666900SdWiGhT /** 788*7d666900SdWiGhT * Dissolve background property 789*7d666900SdWiGhT * @param string $str_value 790*7d666900SdWiGhT * @return array 791*7d666900SdWiGhT * @version 1.0 792*7d666900SdWiGhT * @see merge_bg() 793*7d666900SdWiGhT * @todo full CSS 3 compliance 794*7d666900SdWiGhT */ 795*7d666900SdWiGhT public function dissolve_short_bg($str_value) { 796*7d666900SdWiGhT // don't try to explose background gradient ! 797*7d666900SdWiGhT if (stripos($str_value, 'gradient(')!== false) 798*7d666900SdWiGhT return array('background'=>$str_value); 799*7d666900SdWiGhT 800*7d666900SdWiGhT $background_prop_default = & $this->parser->data['csstidy']['background_prop_default']; 801*7d666900SdWiGhT $repeat = array('repeat', 'repeat-x', 'repeat-y', 'no-repeat', 'space'); 802*7d666900SdWiGhT $attachment = array('scroll', 'fixed', 'local'); 803*7d666900SdWiGhT $clip = array('border', 'padding'); 804*7d666900SdWiGhT $origin = array('border', 'padding', 'content'); 805*7d666900SdWiGhT $pos = array('top', 'center', 'bottom', 'left', 'right'); 806*7d666900SdWiGhT $important = ''; 807*7d666900SdWiGhT $return = array('background-image' => null, 'background-size' => null, 'background-repeat' => null, 'background-position' => null, 'background-attachment' => null, 'background-clip' => null, 'background-origin' => null, 'background-color' => null); 808*7d666900SdWiGhT 809*7d666900SdWiGhT if ($this->parser->is_important($str_value)) { 810*7d666900SdWiGhT $important = ' !important'; 811*7d666900SdWiGhT $str_value = $this->parser->gvw_important($str_value); 812*7d666900SdWiGhT } 813*7d666900SdWiGhT 814*7d666900SdWiGhT $str_value = $this->explode_ws(',', $str_value); 815*7d666900SdWiGhT for ($i = 0; $i < count($str_value); $i++) { 816*7d666900SdWiGhT $have['clip'] = false; 817*7d666900SdWiGhT $have['pos'] = false; 818*7d666900SdWiGhT $have['color'] = false; 819*7d666900SdWiGhT $have['bg'] = false; 820*7d666900SdWiGhT 821*7d666900SdWiGhT if (is_array($str_value[$i])) { 822*7d666900SdWiGhT $str_value[$i] = $str_value[$i][0]; 823*7d666900SdWiGhT } 824*7d666900SdWiGhT $str_value[$i] = $this->explode_ws(' ', trim($str_value[$i])); 825*7d666900SdWiGhT 826*7d666900SdWiGhT for ($j = 0; $j < count($str_value[$i]); $j++) { 827*7d666900SdWiGhT if ($have['bg'] === false && (substr($str_value[$i][$j], 0, 4) === 'url(' || $str_value[$i][$j] === 'none')) { 828*7d666900SdWiGhT $return['background-image'] .= $str_value[$i][$j] . ','; 829*7d666900SdWiGhT $have['bg'] = true; 830*7d666900SdWiGhT } elseif (in_array($str_value[$i][$j], $repeat, true)) { 831*7d666900SdWiGhT $return['background-repeat'] .= $str_value[$i][$j] . ','; 832*7d666900SdWiGhT } elseif (in_array($str_value[$i][$j], $attachment, true)) { 833*7d666900SdWiGhT $return['background-attachment'] .= $str_value[$i][$j] . ','; 834*7d666900SdWiGhT } elseif (in_array($str_value[$i][$j], $clip, true) && !$have['clip']) { 835*7d666900SdWiGhT $return['background-clip'] .= $str_value[$i][$j] . ','; 836*7d666900SdWiGhT $have['clip'] = true; 837*7d666900SdWiGhT } elseif (in_array($str_value[$i][$j], $origin, true)) { 838*7d666900SdWiGhT $return['background-origin'] .= $str_value[$i][$j] . ','; 839*7d666900SdWiGhT } elseif ($str_value[$i][$j][0] === '(') { 840*7d666900SdWiGhT $return['background-size'] .= substr($str_value[$i][$j], 1, -1) . ','; 841*7d666900SdWiGhT } elseif (in_array($str_value[$i][$j], $pos, true) || is_numeric($str_value[$i][$j][0]) || $str_value[$i][$j][0] === null || $str_value[$i][$j][0] === '-' || $str_value[$i][$j][0] === '.') { 842*7d666900SdWiGhT $return['background-position'] .= $str_value[$i][$j]; 843*7d666900SdWiGhT if (!$have['pos']) 844*7d666900SdWiGhT $return['background-position'] .= ' '; else 845*7d666900SdWiGhT $return['background-position'].= ','; 846*7d666900SdWiGhT $have['pos'] = true; 847*7d666900SdWiGhT } elseif (!$have['color']) { 848*7d666900SdWiGhT $return['background-color'] .= $str_value[$i][$j] . ','; 849*7d666900SdWiGhT $have['color'] = true; 850*7d666900SdWiGhT } 851*7d666900SdWiGhT } 852*7d666900SdWiGhT } 853*7d666900SdWiGhT 854*7d666900SdWiGhT foreach ($background_prop_default as $bg_prop => $default_value) { 855*7d666900SdWiGhT if ($return[$bg_prop] !== null) { 856*7d666900SdWiGhT $return[$bg_prop] = substr($return[$bg_prop], 0, -1) . $important; 857*7d666900SdWiGhT } 858*7d666900SdWiGhT else 859*7d666900SdWiGhT $return[$bg_prop] = $default_value . $important; 860*7d666900SdWiGhT } 861*7d666900SdWiGhT return $return; 862*7d666900SdWiGhT } 863*7d666900SdWiGhT 864*7d666900SdWiGhT /** 865*7d666900SdWiGhT * Merges all background properties 866*7d666900SdWiGhT * @param array $input_css 867*7d666900SdWiGhT * @return array 868*7d666900SdWiGhT * @version 1.0 869*7d666900SdWiGhT * @see dissolve_short_bg() 870*7d666900SdWiGhT * @todo full CSS 3 compliance 871*7d666900SdWiGhT */ 872*7d666900SdWiGhT public function merge_bg($input_css) { 873*7d666900SdWiGhT $background_prop_default = & $this->parser->data['csstidy']['background_prop_default']; 874*7d666900SdWiGhT // Max number of background images. CSS3 not yet fully implemented 875*7d666900SdWiGhT $number_of_values = @max(count($this->explode_ws(',', $input_css['background-image'])), count($this->explode_ws(',', $input_css['background-color'])), 1); 876*7d666900SdWiGhT // Array with background images to check if BG image exists 877*7d666900SdWiGhT $bg_img_array = @$this->explode_ws(',', $this->parser->gvw_important($input_css['background-image'])); 878*7d666900SdWiGhT $new_bg_value = ''; 879*7d666900SdWiGhT $important = ''; 880*7d666900SdWiGhT 881*7d666900SdWiGhT // if background properties is here and not empty, don't try anything 882*7d666900SdWiGhT if (isset($input_css['background']) && $input_css['background']) 883*7d666900SdWiGhT return $input_css; 884*7d666900SdWiGhT 885*7d666900SdWiGhT for ($i = 0; $i < $number_of_values; $i++) { 886*7d666900SdWiGhT foreach ($background_prop_default as $bg_property => $default_value) { 887*7d666900SdWiGhT // Skip if property does not exist 888*7d666900SdWiGhT if (!isset($input_css[$bg_property])) { 889*7d666900SdWiGhT continue; 890*7d666900SdWiGhT } 891*7d666900SdWiGhT 892*7d666900SdWiGhT $cur_value = $input_css[$bg_property]; 893*7d666900SdWiGhT // skip all optimisation if gradient() somewhere 894*7d666900SdWiGhT if (stripos($cur_value, 'gradient(') !== false) 895*7d666900SdWiGhT return $input_css; 896*7d666900SdWiGhT 897*7d666900SdWiGhT // Skip some properties if there is no background image 898*7d666900SdWiGhT if ((!isset($bg_img_array[$i]) || $bg_img_array[$i] === 'none') 899*7d666900SdWiGhT && ($bg_property === 'background-size' || $bg_property === 'background-position' 900*7d666900SdWiGhT || $bg_property === 'background-attachment' || $bg_property === 'background-repeat')) { 901*7d666900SdWiGhT continue; 902*7d666900SdWiGhT } 903*7d666900SdWiGhT 904*7d666900SdWiGhT // Remove !important 905*7d666900SdWiGhT if ($this->parser->is_important($cur_value)) { 906*7d666900SdWiGhT $important = ' !important'; 907*7d666900SdWiGhT $cur_value = $this->parser->gvw_important($cur_value); 908*7d666900SdWiGhT } 909*7d666900SdWiGhT 910*7d666900SdWiGhT // Do not add default values 911*7d666900SdWiGhT if ($cur_value === $default_value) { 912*7d666900SdWiGhT continue; 913*7d666900SdWiGhT } 914*7d666900SdWiGhT 915*7d666900SdWiGhT $temp = $this->explode_ws(',', $cur_value); 916*7d666900SdWiGhT 917*7d666900SdWiGhT if (isset($temp[$i])) { 918*7d666900SdWiGhT if ($bg_property === 'background-size') { 919*7d666900SdWiGhT $new_bg_value .= '(' . $temp[$i] . ') '; 920*7d666900SdWiGhT } else { 921*7d666900SdWiGhT $new_bg_value .= $temp[$i] . ' '; 922*7d666900SdWiGhT } 923*7d666900SdWiGhT } 924*7d666900SdWiGhT } 925*7d666900SdWiGhT 926*7d666900SdWiGhT $new_bg_value = trim($new_bg_value); 927*7d666900SdWiGhT if ($i != $number_of_values - 1) 928*7d666900SdWiGhT $new_bg_value .= ','; 929*7d666900SdWiGhT } 930*7d666900SdWiGhT 931*7d666900SdWiGhT // Delete all background-properties 932*7d666900SdWiGhT foreach ($background_prop_default as $bg_property => $default_value) { 933*7d666900SdWiGhT unset($input_css[$bg_property]); 934*7d666900SdWiGhT } 935*7d666900SdWiGhT 936*7d666900SdWiGhT // Add new background property 937*7d666900SdWiGhT if ($new_bg_value !== '') 938*7d666900SdWiGhT $input_css['background'] = $new_bg_value . $important; 939*7d666900SdWiGhT elseif(isset ($input_css['background'])) 940*7d666900SdWiGhT $input_css['background'] = 'none'; 941*7d666900SdWiGhT 942*7d666900SdWiGhT return $input_css; 943*7d666900SdWiGhT } 944*7d666900SdWiGhT 945*7d666900SdWiGhT /** 946*7d666900SdWiGhT * Dissolve font property 947*7d666900SdWiGhT * @param string $str_value 948*7d666900SdWiGhT * @return array 949*7d666900SdWiGhT * @version 1.3 950*7d666900SdWiGhT * @see merge_font() 951*7d666900SdWiGhT */ 952*7d666900SdWiGhT public function dissolve_short_font($str_value) { 953*7d666900SdWiGhT $font_prop_default = & $this->parser->data['csstidy']['font_prop_default']; 954*7d666900SdWiGhT $font_weight = array('normal', 'bold', 'bolder', 'lighter', 100, 200, 300, 400, 500, 600, 700, 800, 900); 955*7d666900SdWiGhT $font_variant = array('normal', 'small-caps'); 956*7d666900SdWiGhT $font_style = array('normal', 'italic', 'oblique'); 957*7d666900SdWiGhT $important = ''; 958*7d666900SdWiGhT $return = array('font-style' => null, 'font-variant' => null, 'font-weight' => null, 'font-size' => null, 'line-height' => null, 'font-family' => null); 959*7d666900SdWiGhT 960*7d666900SdWiGhT if ($this->parser->is_important($str_value)) { 961*7d666900SdWiGhT $important = '!important'; 962*7d666900SdWiGhT $str_value = $this->parser->gvw_important($str_value); 963*7d666900SdWiGhT } 964*7d666900SdWiGhT 965*7d666900SdWiGhT $have['style'] = false; 966*7d666900SdWiGhT $have['variant'] = false; 967*7d666900SdWiGhT $have['weight'] = false; 968*7d666900SdWiGhT $have['size'] = false; 969*7d666900SdWiGhT // Detects if font-family consists of several words w/o quotes 970*7d666900SdWiGhT $multiwords = false; 971*7d666900SdWiGhT 972*7d666900SdWiGhT // Workaround with multiple font-family 973*7d666900SdWiGhT $str_value = $this->explode_ws(',', trim($str_value)); 974*7d666900SdWiGhT 975*7d666900SdWiGhT $str_value[0] = $this->explode_ws(' ', trim($str_value[0])); 976*7d666900SdWiGhT 977*7d666900SdWiGhT for ($j = 0; $j < count($str_value[0]); $j++) { 978*7d666900SdWiGhT if ($have['weight'] === false && in_array($str_value[0][$j], $font_weight)) { 979*7d666900SdWiGhT $return['font-weight'] = $str_value[0][$j]; 980*7d666900SdWiGhT $have['weight'] = true; 981*7d666900SdWiGhT } elseif ($have['variant'] === false && in_array($str_value[0][$j], $font_variant)) { 982*7d666900SdWiGhT $return['font-variant'] = $str_value[0][$j]; 983*7d666900SdWiGhT $have['variant'] = true; 984*7d666900SdWiGhT } elseif ($have['style'] === false && in_array($str_value[0][$j], $font_style)) { 985*7d666900SdWiGhT $return['font-style'] = $str_value[0][$j]; 986*7d666900SdWiGhT $have['style'] = true; 987*7d666900SdWiGhT } elseif ($have['size'] === false && (is_numeric($str_value[0][$j][0]) || $str_value[0][$j][0] === null || $str_value[0][$j][0] === '.')) { 988*7d666900SdWiGhT $size = $this->explode_ws('/', trim($str_value[0][$j])); 989*7d666900SdWiGhT $return['font-size'] = $size[0]; 990*7d666900SdWiGhT if (isset($size[1])) { 991*7d666900SdWiGhT $return['line-height'] = $size[1]; 992*7d666900SdWiGhT } else { 993*7d666900SdWiGhT $return['line-height'] = ''; // don't add 'normal' ! 994*7d666900SdWiGhT } 995*7d666900SdWiGhT $have['size'] = true; 996*7d666900SdWiGhT } else { 997*7d666900SdWiGhT if (isset($return['font-family'])) { 998*7d666900SdWiGhT $return['font-family'] .= ' ' . $str_value[0][$j]; 999*7d666900SdWiGhT $multiwords = true; 1000*7d666900SdWiGhT } else { 1001*7d666900SdWiGhT $return['font-family'] = $str_value[0][$j]; 1002*7d666900SdWiGhT } 1003*7d666900SdWiGhT } 1004*7d666900SdWiGhT } 1005*7d666900SdWiGhT // add quotes if we have several qords in font-family 1006*7d666900SdWiGhT if ($multiwords !== false) { 1007*7d666900SdWiGhT $return['font-family'] = '"' . $return['font-family'] . '"'; 1008*7d666900SdWiGhT } 1009*7d666900SdWiGhT $i = 1; 1010*7d666900SdWiGhT while (isset($str_value[$i])) { 1011*7d666900SdWiGhT $return['font-family'] .= ',' . trim($str_value[$i]); 1012*7d666900SdWiGhT $i++; 1013*7d666900SdWiGhT } 1014*7d666900SdWiGhT 1015*7d666900SdWiGhT // Fix for 100 and more font-size 1016*7d666900SdWiGhT if ($have['size'] === false && isset($return['font-weight']) && 1017*7d666900SdWiGhT is_numeric($return['font-weight'][0])) { 1018*7d666900SdWiGhT $return['font-size'] = $return['font-weight']; 1019*7d666900SdWiGhT unset($return['font-weight']); 1020*7d666900SdWiGhT } 1021*7d666900SdWiGhT 1022*7d666900SdWiGhT foreach ($font_prop_default as $font_prop => $default_value) { 1023*7d666900SdWiGhT if ($return[$font_prop] !== null) { 1024*7d666900SdWiGhT $return[$font_prop] = $return[$font_prop] . $important; 1025*7d666900SdWiGhT } 1026*7d666900SdWiGhT else 1027*7d666900SdWiGhT $return[$font_prop] = $default_value . $important; 1028*7d666900SdWiGhT } 1029*7d666900SdWiGhT return $return; 1030*7d666900SdWiGhT } 1031*7d666900SdWiGhT 1032*7d666900SdWiGhT /** 1033*7d666900SdWiGhT * Merges all fonts properties 1034*7d666900SdWiGhT * @param array $input_css 1035*7d666900SdWiGhT * @return array 1036*7d666900SdWiGhT * @version 1.3 1037*7d666900SdWiGhT * @see dissolve_short_font() 1038*7d666900SdWiGhT */ 1039*7d666900SdWiGhT public function merge_font($input_css) { 1040*7d666900SdWiGhT $font_prop_default = & $this->parser->data['csstidy']['font_prop_default']; 1041*7d666900SdWiGhT $new_font_value = ''; 1042*7d666900SdWiGhT $important = ''; 1043*7d666900SdWiGhT // Skip if not font-family and font-size set 1044*7d666900SdWiGhT if (isset($input_css['font-family']) && isset($input_css['font-size']) && $input_css['font-family'] != 'inherit') { 1045*7d666900SdWiGhT // fix several words in font-family - add quotes 1046*7d666900SdWiGhT if (isset($input_css['font-family'])) { 1047*7d666900SdWiGhT $families = explode(',', $input_css['font-family']); 1048*7d666900SdWiGhT $result_families = array(); 1049*7d666900SdWiGhT foreach ($families as $family) { 1050*7d666900SdWiGhT $family = trim($family); 1051*7d666900SdWiGhT $len = strlen($family); 1052*7d666900SdWiGhT if (strpos($family, ' ') && 1053*7d666900SdWiGhT !(($family[0] === '"' && $family[$len - 1] === '"') || 1054*7d666900SdWiGhT ($family[0] === "'" && $family[$len - 1] === "'"))) { 1055*7d666900SdWiGhT $family = '"' . $family . '"'; 1056*7d666900SdWiGhT } 1057*7d666900SdWiGhT $result_families[] = $family; 1058*7d666900SdWiGhT } 1059*7d666900SdWiGhT $input_css['font-family'] = implode(',', $result_families); 1060*7d666900SdWiGhT } 1061*7d666900SdWiGhT foreach ($font_prop_default as $font_property => $default_value) { 1062*7d666900SdWiGhT 1063*7d666900SdWiGhT // Skip if property does not exist 1064*7d666900SdWiGhT if (!isset($input_css[$font_property])) { 1065*7d666900SdWiGhT continue; 1066*7d666900SdWiGhT } 1067*7d666900SdWiGhT 1068*7d666900SdWiGhT $cur_value = $input_css[$font_property]; 1069*7d666900SdWiGhT 1070*7d666900SdWiGhT // Skip if default value is used 1071*7d666900SdWiGhT if ($cur_value === $default_value) { 1072*7d666900SdWiGhT continue; 1073*7d666900SdWiGhT } 1074*7d666900SdWiGhT 1075*7d666900SdWiGhT // Remove !important 1076*7d666900SdWiGhT if ($this->parser->is_important($cur_value)) { 1077*7d666900SdWiGhT $important = '!important'; 1078*7d666900SdWiGhT $cur_value = $this->parser->gvw_important($cur_value); 1079*7d666900SdWiGhT } 1080*7d666900SdWiGhT 1081*7d666900SdWiGhT $new_font_value .= $cur_value; 1082*7d666900SdWiGhT // Add delimiter 1083*7d666900SdWiGhT $new_font_value .= ( $font_property === 'font-size' && 1084*7d666900SdWiGhT isset($input_css['line-height'])) ? '/' : ' '; 1085*7d666900SdWiGhT } 1086*7d666900SdWiGhT 1087*7d666900SdWiGhT $new_font_value = trim($new_font_value); 1088*7d666900SdWiGhT 1089*7d666900SdWiGhT // Delete all font-properties 1090*7d666900SdWiGhT foreach ($font_prop_default as $font_property => $default_value) { 1091*7d666900SdWiGhT if ($font_property !== 'font' || !$new_font_value) 1092*7d666900SdWiGhT unset($input_css[$font_property]); 1093*7d666900SdWiGhT } 1094*7d666900SdWiGhT 1095*7d666900SdWiGhT // Add new font property 1096*7d666900SdWiGhT if ($new_font_value !== '') { 1097*7d666900SdWiGhT $input_css['font'] = $new_font_value . $important; 1098*7d666900SdWiGhT } 1099*7d666900SdWiGhT } 1100*7d666900SdWiGhT 1101*7d666900SdWiGhT return $input_css; 1102*7d666900SdWiGhT } 1103*7d666900SdWiGhT 1104*7d666900SdWiGhT /** 1105*7d666900SdWiGhT * Reverse left vs right in a list of properties/values 1106*7d666900SdWiGhT * @param array $array 1107*7d666900SdWiGhT * @return array 1108*7d666900SdWiGhT */ 1109*7d666900SdWiGhT public function reverse_left_and_right($array) { 1110*7d666900SdWiGhT $return = array(); 1111*7d666900SdWiGhT 1112*7d666900SdWiGhT // change left <-> right in properties name and values 1113*7d666900SdWiGhT foreach ($array as $propertie => $value) { 1114*7d666900SdWiGhT 1115*7d666900SdWiGhT if (method_exists($this, $m = 'reverse_left_and_right_' . str_replace('-','_',trim($propertie)))) { 1116*7d666900SdWiGhT $value = $this->$m($value); 1117*7d666900SdWiGhT } 1118*7d666900SdWiGhT 1119*7d666900SdWiGhT // simple replacement for properties 1120*7d666900SdWiGhT $propertie = str_ireplace(array('left', 'right' ,"\x1"), array("\x1", 'left', 'right') , $propertie); 1121*7d666900SdWiGhT // be careful for values, not modifying protected or quoted valued 1122*7d666900SdWiGhT foreach (array('left' => "\x1", 'right' => 'left', "\x1" => 'right') as $v => $r) { 1123*7d666900SdWiGhT if (strpos($value, $v) !== false) { 1124*7d666900SdWiGhT // attraper les left et right separes du reste (pas au milieu d'un mot) 1125*7d666900SdWiGhT if (in_array($v, array('left', 'right') )) { 1126*7d666900SdWiGhT $value = preg_replace(",\\b$v\\b,", "\x0" , $value); 1127*7d666900SdWiGhT } 1128*7d666900SdWiGhT else { 1129*7d666900SdWiGhT $value = str_replace($v, "\x0" , $value); 1130*7d666900SdWiGhT } 1131*7d666900SdWiGhT $value = $this->explode_ws("\x0", $value . ' ', true); 1132*7d666900SdWiGhT $value = rtrim(implode($r, $value)); 1133*7d666900SdWiGhT $value = str_replace("\x0" , $v, $value); 1134*7d666900SdWiGhT } 1135*7d666900SdWiGhT } 1136*7d666900SdWiGhT $return[$propertie] = $value; 1137*7d666900SdWiGhT } 1138*7d666900SdWiGhT 1139*7d666900SdWiGhT return $return; 1140*7d666900SdWiGhT } 1141*7d666900SdWiGhT 1142*7d666900SdWiGhT /** 1143*7d666900SdWiGhT * Reversing 4 values shorthands properties 1144*7d666900SdWiGhT * @param string $value 1145*7d666900SdWiGhT * @return string 1146*7d666900SdWiGhT */ 1147*7d666900SdWiGhT public function reverse_left_and_right_4value_shorthands($property, $value) { 1148*7d666900SdWiGhT $shorthands = & $this->parser->data['csstidy']['shorthands']; 1149*7d666900SdWiGhT if (isset($shorthands[$property])) { 1150*7d666900SdWiGhT $property_right = $shorthands[$property][1]; 1151*7d666900SdWiGhT $property_left = $shorthands[$property][3]; 1152*7d666900SdWiGhT $v = $this->dissolve_4value_shorthands($property, $value); 1153*7d666900SdWiGhT if ($v[$property_left] !== $v[$property_right]) { 1154*7d666900SdWiGhT $r = $v[$property_right]; 1155*7d666900SdWiGhT $v[$property_right] = $v[$property_left]; 1156*7d666900SdWiGhT $v[$property_left] = $r; 1157*7d666900SdWiGhT $v = $this->merge_4value_shorthands($v); 1158*7d666900SdWiGhT if (isset($v[$property])) { 1159*7d666900SdWiGhT return $v[$property]; 1160*7d666900SdWiGhT } 1161*7d666900SdWiGhT } 1162*7d666900SdWiGhT } 1163*7d666900SdWiGhT return $value; 1164*7d666900SdWiGhT } 1165*7d666900SdWiGhT 1166*7d666900SdWiGhT /** 1167*7d666900SdWiGhT * Reversing 4 values radius shorthands properties 1168*7d666900SdWiGhT * @param string $value 1169*7d666900SdWiGhT * @return string 1170*7d666900SdWiGhT */ 1171*7d666900SdWiGhT public function reverse_left_and_right_4value_radius_shorthands($property, $value) { 1172*7d666900SdWiGhT $shorthands = & $this->parser->data['csstidy']['radius_shorthands']; 1173*7d666900SdWiGhT if (isset($shorthands[$property])) { 1174*7d666900SdWiGhT $v = $this->dissolve_4value_radius_shorthands($property, $value); 1175*7d666900SdWiGhT if ($v[$shorthands[$property][0]] !== $v[$shorthands[$property][1]] 1176*7d666900SdWiGhT or $v[$shorthands[$property][2]] !== $v[$shorthands[$property][3]]) { 1177*7d666900SdWiGhT $r = array( 1178*7d666900SdWiGhT $shorthands[$property][0] => $v[$shorthands[$property][1]], 1179*7d666900SdWiGhT $shorthands[$property][1] => $v[$shorthands[$property][0]], 1180*7d666900SdWiGhT $shorthands[$property][2] => $v[$shorthands[$property][3]], 1181*7d666900SdWiGhT $shorthands[$property][3] => $v[$shorthands[$property][2]], 1182*7d666900SdWiGhT ); 1183*7d666900SdWiGhT $v = $this->merge_4value_radius_shorthands($r); 1184*7d666900SdWiGhT if (isset($v[$property])) { 1185*7d666900SdWiGhT return $v[$property]; 1186*7d666900SdWiGhT } 1187*7d666900SdWiGhT } 1188*7d666900SdWiGhT } 1189*7d666900SdWiGhT return $value; 1190*7d666900SdWiGhT } 1191*7d666900SdWiGhT 1192*7d666900SdWiGhT /** 1193*7d666900SdWiGhT * Reversing margin shorthands 1194*7d666900SdWiGhT * @param string $value 1195*7d666900SdWiGhT * @return string 1196*7d666900SdWiGhT */ 1197*7d666900SdWiGhT public function reverse_left_and_right_margin($value) { 1198*7d666900SdWiGhT return $this->reverse_left_and_right_4value_shorthands('margin', $value); 1199*7d666900SdWiGhT } 1200*7d666900SdWiGhT 1201*7d666900SdWiGhT /** 1202*7d666900SdWiGhT * Reversing padding shorthands 1203*7d666900SdWiGhT * @param string $value 1204*7d666900SdWiGhT * @return string 1205*7d666900SdWiGhT */ 1206*7d666900SdWiGhT public function reverse_left_and_right_padding($value) { 1207*7d666900SdWiGhT return $this->reverse_left_and_right_4value_shorthands('padding', $value); 1208*7d666900SdWiGhT } 1209*7d666900SdWiGhT 1210*7d666900SdWiGhT /** 1211*7d666900SdWiGhT * Reversing border-color shorthands 1212*7d666900SdWiGhT * @param string $value 1213*7d666900SdWiGhT * @return string 1214*7d666900SdWiGhT */ 1215*7d666900SdWiGhT public function reverse_left_and_right_border_color($value) { 1216*7d666900SdWiGhT return $this->reverse_left_and_right_4value_shorthands('border-color', $value); 1217*7d666900SdWiGhT } 1218*7d666900SdWiGhT 1219*7d666900SdWiGhT /** 1220*7d666900SdWiGhT * Reversing border-style shorthands 1221*7d666900SdWiGhT * @param string $value 1222*7d666900SdWiGhT * @return string 1223*7d666900SdWiGhT */ 1224*7d666900SdWiGhT public function reverse_left_and_right_border_style($value) { 1225*7d666900SdWiGhT return $this->reverse_left_and_right_4value_shorthands('border-style', $value); 1226*7d666900SdWiGhT } 1227*7d666900SdWiGhT 1228*7d666900SdWiGhT /** 1229*7d666900SdWiGhT * Reversing border-width shorthands 1230*7d666900SdWiGhT * @param string $value 1231*7d666900SdWiGhT * @return string 1232*7d666900SdWiGhT */ 1233*7d666900SdWiGhT public function reverse_left_and_right_border_width($value) { 1234*7d666900SdWiGhT return $this->reverse_left_and_right_4value_shorthands('border-width', $value); 1235*7d666900SdWiGhT } 1236*7d666900SdWiGhT 1237*7d666900SdWiGhT /** 1238*7d666900SdWiGhT * Reversing border-radius shorthands 1239*7d666900SdWiGhT * @param string $value 1240*7d666900SdWiGhT * @return string 1241*7d666900SdWiGhT */ 1242*7d666900SdWiGhT public function reverse_left_and_right_border_radius($value) { 1243*7d666900SdWiGhT return $this->reverse_left_and_right_4value_radius_shorthands('border-radius', $value); 1244*7d666900SdWiGhT } 1245*7d666900SdWiGhT 1246*7d666900SdWiGhT /** 1247*7d666900SdWiGhT * Reversing border-radius shorthands 1248*7d666900SdWiGhT * @param string $value 1249*7d666900SdWiGhT * @return string 1250*7d666900SdWiGhT */ 1251*7d666900SdWiGhT public function reverse_left_and_right__moz_border_radius($value) { 1252*7d666900SdWiGhT return $this->reverse_left_and_right_4value_radius_shorthands('border-radius', $value); 1253*7d666900SdWiGhT } 1254*7d666900SdWiGhT 1255*7d666900SdWiGhT /** 1256*7d666900SdWiGhT * Reversing border-radius shorthands 1257*7d666900SdWiGhT * @param string $value 1258*7d666900SdWiGhT * @return string 1259*7d666900SdWiGhT */ 1260*7d666900SdWiGhT public function reverse_left_and_right__webkit_border_radius($value) { 1261*7d666900SdWiGhT return $this->reverse_left_and_right_4value_radius_shorthands('border-radius', $value); 1262*7d666900SdWiGhT } 1263*7d666900SdWiGhT 1264*7d666900SdWiGhT 1265*7d666900SdWiGhT /** 1266*7d666900SdWiGhT * Reversing background shorthands 1267*7d666900SdWiGhT * @param string $value 1268*7d666900SdWiGhT * @return string 1269*7d666900SdWiGhT */ 1270*7d666900SdWiGhT public function reverse_left_and_right_background($value) { 1271*7d666900SdWiGhT $values = $this->dissolve_short_bg($value); 1272*7d666900SdWiGhT if (isset($values['background-position']) and $values['background-position']) { 1273*7d666900SdWiGhT $v = $this->reverse_left_and_right_background_position($values['background-position']); 1274*7d666900SdWiGhT if ($v !== $values['background-position']) { 1275*7d666900SdWiGhT if ($value == $values['background-position']) { 1276*7d666900SdWiGhT return $v; 1277*7d666900SdWiGhT } 1278*7d666900SdWiGhT else { 1279*7d666900SdWiGhT $values['background-position'] = $v; 1280*7d666900SdWiGhT $x = $this->merge_bg($values); 1281*7d666900SdWiGhT if (isset($x['background'])) { 1282*7d666900SdWiGhT return $x['background']; 1283*7d666900SdWiGhT } 1284*7d666900SdWiGhT } 1285*7d666900SdWiGhT } 1286*7d666900SdWiGhT } 1287*7d666900SdWiGhT return $value; 1288*7d666900SdWiGhT } 1289*7d666900SdWiGhT 1290*7d666900SdWiGhT /** 1291*7d666900SdWiGhT * Reversing background position shorthands 1292*7d666900SdWiGhT * @param string $value 1293*7d666900SdWiGhT * @return string 1294*7d666900SdWiGhT */ 1295*7d666900SdWiGhT public function reverse_left_and_right_background_position_x($value) { 1296*7d666900SdWiGhT return $this->reverse_left_and_right_background_position($value); 1297*7d666900SdWiGhT } 1298*7d666900SdWiGhT 1299*7d666900SdWiGhT /** 1300*7d666900SdWiGhT * Reversing background position shorthands 1301*7d666900SdWiGhT * @param string $value 1302*7d666900SdWiGhT * @return string 1303*7d666900SdWiGhT */ 1304*7d666900SdWiGhT public function reverse_left_and_right_background_position($value) { 1305*7d666900SdWiGhT // multiple background case 1306*7d666900SdWiGhT if (strpos($value, ',') !== false) { 1307*7d666900SdWiGhT $values = $this->explode_ws(',', $value); 1308*7d666900SdWiGhT if (count($values) > 1) { 1309*7d666900SdWiGhT foreach ($values as $k=>$v) { 1310*7d666900SdWiGhT $values[$k] = $this->reverse_left_and_right_background_position($v); 1311*7d666900SdWiGhT } 1312*7d666900SdWiGhT return implode(',', $values); 1313*7d666900SdWiGhT } 1314*7d666900SdWiGhT } 1315*7d666900SdWiGhT 1316*7d666900SdWiGhT // if no explicit left or right value 1317*7d666900SdWiGhT if (stripos($value, 'left') === false and stripos($value, 'right') === false) { 1318*7d666900SdWiGhT $values = $this->explode_ws(' ', trim($value)); 1319*7d666900SdWiGhT $values = array_map('trim', $values); 1320*7d666900SdWiGhT $values = array_filter($values, function ($v) { return strlen($v);}); 1321*7d666900SdWiGhT $values = array_values($values); 1322*7d666900SdWiGhT if (count($values) == 1) { 1323*7d666900SdWiGhT if (in_array($value, array('center', 'top', 'bottom', 'inherit', 'initial', 'unset'))) { 1324*7d666900SdWiGhT return $value; 1325*7d666900SdWiGhT } 1326*7d666900SdWiGhT return "left $value"; 1327*7d666900SdWiGhT } 1328*7d666900SdWiGhT if ($values[1] == 'top' or $values[1] == 'bottom') { 1329*7d666900SdWiGhT if ($values[0] === 'center') { 1330*7d666900SdWiGhT return $value; 1331*7d666900SdWiGhT } 1332*7d666900SdWiGhT return 'left ' . implode(' ', $values); 1333*7d666900SdWiGhT } 1334*7d666900SdWiGhT else { 1335*7d666900SdWiGhT $last = array_pop($values); 1336*7d666900SdWiGhT if ($last === 'center') { 1337*7d666900SdWiGhT return $value; 1338*7d666900SdWiGhT } 1339*7d666900SdWiGhT return implode(' ', $values) . ' left ' . $last; 1340*7d666900SdWiGhT } 1341*7d666900SdWiGhT } 1342*7d666900SdWiGhT 1343*7d666900SdWiGhT return $value; 1344*7d666900SdWiGhT } 1345*7d666900SdWiGhT 1346*7d666900SdWiGhT}