1<?php 2/** 3 * CSSTidy - CSS Parser and Optimiser 4 * 5 * CSS Printing class 6 * This class prints CSS data generated by csstidy. 7 * 8 * This file is part of CSSTidy. 9 * 10 * CSSTidy is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * CSSTidy is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with CSSTidy; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 * 24 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 25 * @package csstidy 26 * @author Florian Schmitz (floele at gmail dot com) 2005-2006 27 */ 28 29/** 30 * CSS Printing class 31 * 32 * This class prints CSS data generated by csstidy. 33 * 34 * @package csstidy 35 * @author Florian Schmitz (floele at gmail dot com) 2005-2006 36 * @version 1.0 37 */ 38 39class csstidy_print 40{ 41 /** 42 * Saves the input CSS string 43 * @var string 44 * @access private 45 */ 46 var $input_css = ''; 47 48 /** 49 * Saves the formatted CSS string 50 * @var string 51 * @access public 52 */ 53 var $output_css = ''; 54 55 /** 56 * Saves the formatted CSS string (plain text) 57 * @var string 58 * @access public 59 */ 60 var $output_css_plain = ''; 61 62 /** 63 * Constructor 64 * @param array $css contains the class csstidy 65 * @access private 66 * @version 1.0 67 */ 68 function csstidy_print(&$css) 69 { 70 $this->parser =& $css; 71 $this->css =& $css->css; 72 $this->template =& $css->template; 73 $this->tokens =& $css->tokens; 74 $this->charset =& $css->charset; 75 $this->import =& $css->import; 76 $this->namespace =& $css->namespace; 77 } 78 79 /** 80 * Resets output_css and output_css_plain (new css code) 81 * @access private 82 * @version 1.0 83 */ 84 function _reset() 85 { 86 $this->output_css = ''; 87 $this->output_css_plain = ''; 88 } 89 90 /** 91 * Returns the CSS code as plain text 92 * @return string 93 * @access public 94 * @version 1.0 95 */ 96 function plain() 97 { 98 $this->_print(true); 99 return $this->output_css_plain; 100 } 101 102 /** 103 * Returns the formatted CSS code 104 * @return string 105 * @access public 106 * @version 1.0 107 */ 108 function formatted() 109 { 110 $this->_print(false); 111 return $this->output_css; 112 } 113 114 /** 115 * Returns the formatted CSS Code and saves it into $this->output_css and $this->output_css_plain 116 * @param bool $plain plain text or not 117 * @access private 118 * @version 2.0 119 */ 120 function _print($plain = false) 121 { 122 if ($this->output_css && $this->output_css_plain) { 123 return; 124 } 125 126 $output = ''; 127 if (!$this->parser->get_cfg('preserve_css')) { 128 $this->_convert_raw_css(); 129 } 130 131 $template =& $this->template; 132 133 if ($plain) { 134 $template = array_map('strip_tags', $template); 135 } 136 137 if ($this->parser->get_cfg('timestamp')) { 138 array_unshift($this->tokens, array(COMMENT, ' CSSTidy ' . $this->parser->version . ': ' . date('r') . ' ')); 139 } 140 141 if (!empty($this->charset)) { 142 $output .= $template[0].'@charset '.$template[5].$this->charset.$template[6]; 143 } 144 145 if (!empty($this->import)) { 146 for ($i = 0, $size = count($this->import); $i < $size; $i ++) { 147 $output .= $template[0].'@import '.$template[5].$this->import[$i].$template[6]; 148 } 149 } 150 151 if (!empty($this->namespace)) { 152 $output .= $template[0].'@namespace '.$template[5].$this->namespace.$template[6]; 153 } 154 155 $output .= $template[13]; 156 $in_at_out = ''; 157 $out =& $output; 158 159 foreach ($this->tokens as $key => $token) 160 { 161 switch ($token[0]) 162 { 163 case AT_START: 164 $out .= $template[0].$this->_htmlsp($token[1], $plain).$template[1]; 165 $out =& $in_at_out; 166 break; 167 168 case SEL_START: 169 if($this->parser->get_cfg('lowercase_s')) $token[1] = strtolower($token[1]); 170 $out .= ($token[1]{0} !== '@') ? $template[2].$this->_htmlsp($token[1], $plain) : $template[0].$this->_htmlsp($token[1], $plain); 171 $out .= $template[3]; 172 break; 173 174 case PROPERTY: 175 if($this->parser->get_cfg('case_properties') == 2) $token[1] = strtoupper($token[1]); 176 if($this->parser->get_cfg('case_properties') == 1) $token[1] = strtolower($token[1]); 177 $out .= $template[4] . $this->_htmlsp($token[1], $plain) . ':' . $template[5]; 178 break; 179 180 case VALUE: 181 $out .= $this->_htmlsp($token[1], $plain); 182 if($this->_seeknocomment($key, 1) == SEL_END && $this->parser->get_cfg('remove_last_;')) { 183 $out .= str_replace(';', '', $template[6]); 184 } else { 185 $out .= $template[6]; 186 } 187 break; 188 189 case SEL_END: 190 $out .= $template[7]; 191 if($this->_seeknocomment($key, 1) != AT_END) $out .= $template[8]; 192 break; 193 194 case AT_END: 195 $out =& $output; 196 $out .= $template[10] . str_replace("\n", "\n" . $template[10], $in_at_out); 197 $in_at_out = ''; 198 $out .= $template[9]; 199 break; 200 201 case COMMENT: 202 $out .= $template[11] . '/*' . $this->_htmlsp($token[1], $plain) . '*/' . $template[12]; 203 break; 204 } 205 } 206 207 $output = trim($output); 208 209 if (!$plain) { 210 $this->output_css = $output; 211 $this->_print(true); 212 } else { 213 $this->output_css_plain = $output; 214 } 215 } 216 217 /** 218 * Gets the next token type which is $move away from $key, excluding comments 219 * @param integer $key current position 220 * @param integer $move move this far 221 * @return mixed a token type 222 * @access private 223 * @version 1.0 224 */ 225 function _seeknocomment($key, $move) { 226 $go = ($move > 0) ? 1 : -1; 227 for ($i = $key + 1; abs($key-$i)-1 < abs($move); $i += $go) { 228 if (!isset($this->tokens[$i])) { 229 return; 230 } 231 if ($this->tokens[$i][0] == COMMENT) { 232 $move += 1; 233 continue; 234 } 235 return $this->tokens[$i][0]; 236 } 237 } 238 239 /** 240 * Converts $this->css array to a raw array ($this->tokens) 241 * @access private 242 * @version 1.0 243 */ 244 function _convert_raw_css() 245 { 246 $this->tokens = array(); 247 ksort($this->css); 248 249 foreach ($this->css as $medium => $val) 250 { 251 if ($this->parser->get_cfg('sort_selectors')) ksort($val); 252 if ($medium != DEFAULT_AT) { 253 $this->parser->_add_token(AT_START, $medium, true); 254 } 255 256 foreach ($val as $selector => $vali) 257 { 258 if ($this->parser->get_cfg('sort_properties')) ksort($vali); 259 $this->parser->_add_token(SEL_START, $selector, true); 260 261 foreach ($vali as $property => $valj) 262 { 263 $this->parser->_add_token(PROPERTY, $property, true); 264 $this->parser->_add_token(VALUE, $valj, true); 265 } 266 267 $this->parser->_add_token(SEL_END, $selector, true); 268 } 269 270 if ($medium != DEFAULT_AT) { 271 $this->parser->_add_token(AT_END, $medium, true); 272 } 273 } 274 } 275 276 /** 277 * Same as htmlspecialchars, only that chars are not replaced if $plain !== true. This makes print_code() cleaner. 278 * @param string $string 279 * @param bool $plain 280 * @return string 281 * @see csstidy_print::_print() 282 * @access private 283 * @version 1.0 284 */ 285 function _htmlsp($string, $plain) 286 { 287 if (!$plain) { 288 return htmlspecialchars($string); 289 } 290 return $string; 291 } 292 293 /** 294 * Get compression ratio 295 * @access public 296 * @return float 297 * @version 1.2 298 */ 299 function get_ratio() 300 { 301 if (!$this->output_css_plain) { 302 $this->formatted(); 303 } 304 return round((strlen($this->input_css) - strlen($this->output_css_plain)) / strlen($this->input_css), 3) * 100; 305 } 306 307 /** 308 * Get difference between the old and new code in bytes and prints the code if necessary. 309 * @access public 310 * @return string 311 * @version 1.1 312 */ 313 function get_diff() 314 { 315 if (!$this->output_css_plain) { 316 $this->formatted(); 317 } 318 319 $diff = strlen($this->output_css_plain) - strlen($this->input_css); 320 321 if ($diff > 0) { 322 return '+' . $diff; 323 } elseif ($diff == 0) { 324 return '+-' . $diff; 325 } 326 327 return $diff; 328 } 329 330 /** 331 * Get the size of either input or output CSS in KB 332 * @param string $loc default is "output" 333 * @access public 334 * @return integer 335 * @version 1.0 336 */ 337 function size($loc = 'output') 338 { 339 if ($loc == 'output' && !$this->output_css) { 340 $this->formatted(); 341 } 342 343 if ($loc == 'input') { 344 return (strlen($this->input_css) / 1000); 345 } else { 346 return (strlen($this->output_css_plain) / 1000); 347 } 348 } 349} 350?>