1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27:
28:
29: 30: 31: 32: 33: 34: 35: 36: 37:
38:
39: class csstidy_print
40: {
41: 42: 43: 44: 45:
46: var $input_css = '';
47:
48: 49: 50: 51: 52:
53: var $output_css = '';
54:
55: 56: 57: 58: 59:
60: var $output_css_plain = '';
61:
62: 63: 64: 65: 66: 67:
68: function csstidy_print(&$css)
69: {
70: $this->parser =& $css;
71: $this->template =& $css->template;
72: $this->tokens =& $css->tokens;
73: $this->charset =& $css->charset;
74: $this->import =& $css->import;
75: $this->namespace =& $css->namespace;
76: }
77:
78: 79: 80: 81: 82:
83: function _reset()
84: {
85: $this->output_css = '';
86: $this->output_css_plain = '';
87: }
88:
89: 90: 91: 92: 93: 94:
95: function plain()
96: {
97: $this->_print(true);
98: return $this->output_css_plain;
99: }
100:
101: 102: 103: 104: 105: 106:
107: function formatted()
108: {
109: $this->_print(false);
110: return $this->output_css;
111: }
112:
113: 114: 115: 116: 117: 118:
119: function _print($plain = false)
120: {
121: if ($this->output_css && $this->output_css_plain) {
122: return;
123: }
124:
125: $output = '';
126: if (!$this->parser->get_cfg('preserve_css')) {
127: $this->_convert_raw_css();
128: }
129:
130: $template =& $this->template;
131:
132: if ($plain) {
133: $template = array_map('strip_tags', $template);
134: }
135:
136: if ($this->parser->get_cfg('timestamp')) {
137: array_unshift($this->tokens, array(COMMENT, ' CSSTidy ' . $this->parser->version . ': ' . date('r') . ' '));
138: }
139:
140: if (!empty($this->charset)) {
141: $output .= $template[0].'@charset '.$template[5].$this->charset.$template[6];
142: }
143:
144: if (!empty($this->import)) {
145: for ($i = 0, $size = count($this->import); $i < $size; $i ++) {
146: $output .= $template[0].'@import '.$template[5].$this->import[$i].$template[6];
147: }
148: }
149:
150: if (!empty($this->namespace)) {
151: $output .= $template[0].'@namespace '.$template[5].$this->namespace.$template[6];
152: }
153:
154: $output .= $template[13];
155: $in_at_out = '';
156: $out =& $output;
157:
158: foreach ($this->tokens as $key => $token)
159: {
160: switch ($token[0])
161: {
162: case AT_START:
163: $out .= $template[0].$this->_htmlsp($token[1], $plain).$template[1];
164: $out =& $in_at_out;
165: break;
166:
167: case SEL_START:
168: if($this->parser->get_cfg('lowercase_s')) $token[1] = strtolower($token[1]);
169: $out .= ($token[1]{0} !== '@') ? $template[2].$this->_htmlsp($token[1], $plain) : $template[0].$this->_htmlsp($token[1], $plain);
170: $out .= $template[3];
171: break;
172:
173: case PROPERTY:
174: if($this->parser->get_cfg('case_properties') == 2) $token[1] = strtoupper($token[1]);
175: if($this->parser->get_cfg('case_properties') == 1) $token[1] = strtolower($token[1]);
176: $out .= $template[4] . $this->_htmlsp($token[1], $plain) . ':' . $template[5];
177: break;
178:
179: case VALUE:
180: $out .= $this->_htmlsp($token[1], $plain);
181: if($this->_seeknocomment($key, 1) == SEL_END && $this->parser->get_cfg('remove_last_;')) {
182: $out .= str_replace(';', '', $template[6]);
183: } else {
184: $out .= $template[6];
185: }
186: break;
187:
188: case SEL_END:
189: $out .= $template[7];
190: if($this->_seeknocomment($key, 1) != AT_END) $out .= $template[8];
191: break;
192:
193: case AT_END:
194: $out =& $output;
195: $out .= $template[10] . str_replace("\n", "\n" . $template[10], $in_at_out);
196: $in_at_out = '';
197: $out .= $template[9];
198: break;
199:
200: case COMMENT:
201: $out .= $template[11] . '/*' . $this->_htmlsp($token[1], $plain) . '*/' . $template[12];
202: break;
203: }
204: }
205:
206: $output = trim($output);
207:
208: if (!$plain) {
209: $this->output_css = $output;
210: $this->_print(true);
211: } else {
212: $this->output_css_plain = $output;
213: }
214: }
215:
216: 217: 218: 219: 220: 221: 222: 223:
224: function ($key, $move) {
225: $go = ($move > 0) ? 1 : -1;
226: for ($i = $key + 1; abs($key-$i)-1 < abs($move); $i += $go) {
227: if (!isset($this->tokens[$i])) {
228: return;
229: }
230: if ($this->tokens[$i][0] == COMMENT) {
231: $move += 1;
232: continue;
233: }
234: return $this->tokens[$i][0];
235: }
236: }
237:
238: 239: 240: 241: 242:
243: function _convert_raw_css()
244: {
245: $this->tokens = array();
246:
247: reset($this->parser->css);
248: while (list($medium, $val) = each($this->parser->css)) {
249: if ($this->parser->get_cfg('sort_selectors')) {
250: ksort($val);
251: }
252:
253: if ($medium != DEFAULT_AT) {
254: $this->parser->_add_token(AT_START, $medium, true);
255: }
256:
257: foreach ($val as $selector => $vali) {
258: if ($this->parser->get_cfg('sort_properties')) {
259: ksort($vali);
260: }
261:
262: $this->parser->_add_token(SEL_START, $selector, true);
263:
264: foreach ($vali as $property => $valj) {
265: foreach ($valj['p'] as $valk) {
266: $this->parser->_add_token(PROPERTY, $property, true);
267: $this->parser->_add_token(VALUE, $valk, true);
268: }
269: }
270:
271: $this->parser->_add_token(SEL_END, $selector, true);
272: }
273:
274: if ($medium != DEFAULT_AT) {
275: $this->parser->_add_token(AT_END, $medium, true);
276: }
277: }
278: }
279:
280: 281: 282: 283: 284: 285: 286: 287: 288:
289: function _htmlsp($string, $plain)
290: {
291: if (!$plain) {
292: return htmlspecialchars($string);
293: }
294: return $string;
295: }
296:
297: 298: 299: 300: 301: 302:
303: function get_ratio()
304: {
305: if (!$this->output_css_plain) {
306: $this->formatted();
307: }
308: return round((strlen($this->input_css) - strlen($this->output_css_plain)) / strlen($this->input_css), 3) * 100;
309: }
310:
311: 312: 313: 314: 315: 316:
317: function get_diff()
318: {
319: if (!$this->output_css_plain) {
320: $this->formatted();
321: }
322:
323: $diff = strlen($this->output_css_plain) - strlen($this->input_css);
324:
325: if ($diff > 0) {
326: return '+' . $diff;
327: } elseif ($diff == 0) {
328: return '+-' . $diff;
329: }
330:
331: return $diff;
332: }
333:
334: 335: 336: 337: 338: 339: 340:
341: function size($loc = 'output')
342: {
343: if ($loc == 'output' && !$this->output_css) {
344: $this->formatted();
345: }
346:
347: if ($loc == 'input') {
348: return (strlen($this->input_css) / 1000);
349: } else {
350: return (strlen($this->output_css_plain) / 1000);
351: }
352: }
353: }
354: