CssParser::parse()   F
last analyzed

Complexity

Conditions 26
Paths 189

Size

Total Lines 108
Code Lines 55

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 26
eloc 55
nc 189
nop 1
dl 0
loc 108
rs 3.425
c 1
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
namespace PHPWee;
3
/**
4
 * CssMin - A (simple) css minifier with benefits
5
 * 
6
 * --
7
 * Copyright (c) 2011 Joe Scylla <[email protected]>
8
 *
9
 * Permission is hereby granted, free of charge, to any person obtaining a copy
10
 * of this software and associated documentation files (the "Software"), to deal
11
 * in the Software without restriction, including without limitation the rights
12
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
 * copies of the Software, and to permit persons to whom the Software is
14
 * furnished to do so, subject to the following conditions:
15
 * 
16
 * The above copyright notice and this permission notice shall be included in
17
 * all copies or substantial portions of the Software.
18
 * 
19
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
 * THE SOFTWARE.
26
 * --
27
 * 
28
 * @package		CssMin
29
 * @link		http://code.google.com/p/cssmin/
30
 * @author		Joe Scylla <[email protected]>
31
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
32
 * @license		http://opensource.org/licenses/mit-license.php MIT License
33
 * @version		3.0.1
34
 */
35
/**
36
 * Abstract definition of a CSS token class.
37
 * 
38
 * Every token has to extend this class.
39
 *
40
 * @package		CssMin/Tokens
41
 * @link		http://code.google.com/p/cssmin/
42
 * @author		Joe Scylla <[email protected]>
43
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
44
 * @license		http://opensource.org/licenses/mit-license.php MIT License
45
 * @version		3.0.1
46
 */
47
abstract class aCssToken
48
	{
49
	/**
50
	 * Returns the token as string.
51
	 * 
52
	 * @return string
53
	 */
54
	abstract public function __toString();
55
	}
56
57
/**
58
 * Abstract definition of a for a ruleset start token.
59
 *
60
 * @package		CssMin/Tokens
61
 * @link		http://code.google.com/p/cssmin/
62
 * @author		Joe Scylla <[email protected]>
63
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
64
 * @license		http://opensource.org/licenses/mit-license.php MIT License
65
 * @version		3.0.1
66
 */
67
abstract class aCssRulesetStartToken extends aCssToken
68
	{
69
	
70
	}
71
72
/**
73
 * Abstract definition of a for ruleset end token.
74
 *
75
 * @package		CssMin/Tokens
76
 * @link		http://code.google.com/p/cssmin/
77
 * @author		Joe Scylla <[email protected]>
78
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
79
 * @license		http://opensource.org/licenses/mit-license.php MIT License
80
 * @version		3.0.1
81
 */
82
abstract class aCssRulesetEndToken extends aCssToken
83
	{
84
	/**
85
	 * Implements {@link aCssToken::__toString()}.
86
	 * 
87
	 * @return string
88
	 */
89
	public function __toString()
90
		{
91
		return "}";
92
		}
93
	}
94
95
/**
96
 * Abstract definition of a parser plugin.
97
 * 
98
 * Every parser plugin have to extend this class. A parser plugin contains the logic to parse one or aspects of a 
99
 * stylesheet.
100
 * 
101
 * @package		CssMin/Parser/Plugins
102
 * @link		http://code.google.com/p/cssmin/
103
 * @author		Joe Scylla <[email protected]>
104
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
105
 * @license		http://opensource.org/licenses/mit-license.php MIT License
106
 * @version		3.0.1
107
 */
108
abstract class aCssParserPlugin
109
	{
110
	/**
111
	 * Plugin configuration.
112
	 * 
113
	 * @var array
114
	 */
115
	protected $configuration = array();
116
	/**
117
	 * The CssParser of the plugin.
118
	 * 
119
	 * @var CssParser
120
	 */
121
	protected $parser = null;
122
	/**
123
	 * Plugin buffer.
124
	 * 
125
	 * @var string
126
	 */
127
	protected $buffer = "";
128
	/**
129
	 * Constructor.
130
	 * 
131
	 * @param CssParser $parser The CssParser object of this plugin.
132
	 * @param array $configuration Plugin configuration [optional]
133
	 * @return void
134
	 */
135
	public function __construct(CssParser $parser, array $configuration = null)
136
		{
137
		$this->configuration	= $configuration;
138
		$this->parser			= $parser;
139
		}
140
	/**
141
	 * Returns the array of chars triggering the parser plugin.
142
	 * 
143
	 * @return array
144
	 */
145
	abstract public function getTriggerChars();
146
	/**
147
	 * Returns the array of states triggering the parser plugin or FALSE if every state will trigger the parser plugin.
148
	 * 
149
	 * @return array
150
	 */
151
	abstract public function getTriggerStates();
152
	/**
153
	 * Parser routine of the plugin.
154
	 * 
155
	 * @param integer $index Current index
156
	 * @param string $char Current char
157
	 * @param string $previousChar Previous char
158
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
159
	 */
160
	abstract public function parse($index, $char, $previousChar, $state);
161
	}
162
163
/**
164
 * Abstract definition of a minifier plugin class. 
165
 * 
166
 * Minifier plugin process the parsed tokens one by one to apply changes to the token. Every minifier plugin has to 
167
 * extend this class.
168
 *
169
 * @package		CssMin/Minifier/Plugins
170
 * @link		http://code.google.com/p/cssmin/
171
 * @author		Joe Scylla <[email protected]>
172
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
173
 * @license		http://opensource.org/licenses/mit-license.php MIT License
174
 * @version		3.0.1
175
 */
176
abstract class aCssMinifierPlugin
177
	{
178
	/**
179
	 * Plugin configuration.
180
	 * 
181
	 * @var array
182
	 */
183
	protected $configuration = array();
184
	/**
185
	 * The CssMinifier of the plugin.
186
	 * 
187
	 * @var CssMinifier
188
	 */
189
	protected $minifier = null;
190
	/**
191
	 * Constructor.
192
	 * 
193
	 * @param CssMinifier $minifier The CssMinifier object of this plugin.
194
	 * @param array $configuration Plugin configuration [optional]
195
	 * @return void
196
	 */
197
	public function __construct(CssMinifier $minifier, array $configuration = array())
198
		{
199
		$this->configuration	= $configuration;
200
		$this->minifier			= $minifier;
201
		}
202
	/**
203
	 * Apply the plugin to the token.
204
	 * 
205
	 * @param aCssToken $token Token to process
206
	 * @return boolean Return TRUE to break the processing of this token; FALSE to continue
207
	 */
208
	abstract public function apply(aCssToken &$token);
209
	/**
210
	 * --
211
	 * 
212
	 * @return array
213
	 */
214
	abstract public function getTriggerTokens();
215
	}
216
217
/**
218
 * Abstract definition of a minifier filter class. 
219
 * 
220
 * Minifier filters allows a pre-processing of the parsed token to add, edit or delete tokens. Every minifier filter
221
 * has to extend this class.
222
 * 
223
 * @package		CssMin/Minifier/Filters
224
 * @link		http://code.google.com/p/cssmin/
225
 * @author		Joe Scylla <[email protected]>
226
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
227
 * @license		http://opensource.org/licenses/mit-license.php MIT License
228
 * @version		3.0.1
229
 */
230
abstract class aCssMinifierFilter
231
	{
232
	/**
233
	 * Filter configuration.
234
	 * 
235
	 * @var array
236
	 */
237
	protected $configuration = array();
238
	/**
239
	 * The CssMinifier of the filter.
240
	 * 
241
	 * @var CssMinifier
242
	 */
243
	protected $minifier = null;
244
	/**
245
	 * Constructor.
246
	 * 
247
	 * @param CssMinifier $minifier The CssMinifier object of this plugin.
248
	 * @param array $configuration Filter configuration [optional]
249
	 * @return void
250
	 */
251
	public function __construct(CssMinifier $minifier, array $configuration = array())
252
		{
253
		$this->configuration	= $configuration;
254
		$this->minifier			= $minifier;
255
		}
256
	/**
257
	 * Filter the tokens.
258
	 * 
259
	 * @param array $tokens Array of objects of type aCssToken
260
	 * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
261
	 */
262
	abstract public function apply(array &$tokens);
263
	}
264
265
/**
266
 * Abstract formatter definition.
267
 * 
268
 * Every formatter have to extend this class.
269
 * 
270
 * @package		CssMin/Formatter
271
 * @link		http://code.google.com/p/cssmin/
272
 * @author		Joe Scylla <[email protected]>
273
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
274
 * @license		http://opensource.org/licenses/mit-license.php MIT License
275
 * @version		3.0.1
276
 */
277
abstract class aCssFormatter
278
	{
279
	/**
280
	 * Indent string.
281
	 * 
282
	 * @var string
283
	 */
284
	protected $indent = "    ";
285
	/**
286
	 * Declaration padding.
287
	 * 
288
	 * @var integer
289
	 */
290
	protected $padding = 0;
291
	/**
292
	 * Tokens.
293
	 * 
294
	 * @var array
295
	 */
296
	protected $tokens = array();
297
	/**
298
	 * Constructor.
299
	 * 
300
	 * @param array $tokens Array of CssToken
301
	 * @param string $indent Indent string [optional]
302
	 * @param integer $padding Declaration value padding [optional]
303
	 */
304
	public function __construct(array $tokens, $indent = null, $padding = null)
305
		{
306
		$this->tokens	= $tokens;
307
		$this->indent	= !is_null($indent) ? $indent : $this->indent;
308
		$this->padding	= !is_null($padding) ? $padding : $this->padding;
309
		}
310
	/**
311
	 * Returns the array of aCssToken as formatted string.
312
	 * 
313
	 * @return string
314
	 */
315
	abstract public function __toString();
316
	}
317
318
/**
319
 * Abstract definition of a ruleset declaration token.
320
 *
321
 * @package		CssMin/Tokens
322
 * @link		http://code.google.com/p/cssmin/
323
 * @author		Joe Scylla <[email protected]>
324
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
325
 * @license		http://opensource.org/licenses/mit-license.php MIT License
326
 * @version		3.0.1
327
 */
328
abstract class aCssDeclarationToken extends aCssToken
329
	{
330
	/**
331
	 * Is the declaration flagged as important?
332
	 * 
333
	 * @var boolean
334
	 */
335
	public $IsImportant = false;
336
	/**
337
	 * Is the declaration flagged as last one of the ruleset?
338
	 * 
339
	 * @var boolean
340
	 */
341
	public $IsLast = false;
342
	/**
343
	 * Property name of the declaration.
344
	 * 
345
	 * @var string
346
	 */
347
	public $Property = "";
348
	/**
349
	 * Value of the declaration.
350
	 * 
351
	 * @var string
352
	 */
353
	public $Value = "";
354
	/**
355
	 * Set the properties of the @font-face declaration. 
356
	 * 
357
	 * @param string $property Property of the declaration
358
	 * @param string $value Value of the declaration
359
	 * @param boolean $isImportant Is the !important flag is set?
360
	 * @param boolean $IsLast Is the declaration the last one of the block?
361
	 * @return void
362
	 */
363
	public function __construct($property, $value, $isImportant = false, $isLast = false)
364
		{
365
		$this->Property		= $property;
366
		$this->Value		= $value;
367
		$this->IsImportant	= $isImportant;
368
		$this->IsLast		= $isLast;
369
		}
370
	/**
371
	 * Implements {@link aCssToken::__toString()}.
372
	 * 
373
	 * @return string
374
	 */
375
	public function __toString()
376
		{
377
		return $this->Property . ":" . $this->Value . ($this->IsImportant ? " !important" : "") . ($this->IsLast ? "" : ";");
378
		}
379
	}
380
381
/**
382
 * Abstract definition of a for at-rule block start token.
383
 *
384
 * @package		CssMin/Tokens
385
 * @link		http://code.google.com/p/cssmin/
386
 * @author		Joe Scylla <[email protected]>
387
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
388
 * @license		http://opensource.org/licenses/mit-license.php MIT License
389
 * @version		3.0.1
390
 */
391
abstract class aCssAtBlockStartToken extends aCssToken
392
	{
393
	
394
	}
395
396
/**
397
 * Abstract definition of a for at-rule block end token.
398
 *
399
 * @package		CssMin/Tokens
400
 * @link		http://code.google.com/p/cssmin/
401
 * @author		Joe Scylla <[email protected]>
402
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
403
 * @license		http://opensource.org/licenses/mit-license.php MIT License
404
 * @version		3.0.1
405
 */
406
abstract class aCssAtBlockEndToken extends aCssToken
407
	{
408
	/**
409
	 * Implements {@link aCssToken::__toString()}.
410
	 * 
411
	 * @return string
412
	 */
413
	public function __toString()
414
		{
415
		return "}";
416
		}
417
	}
418
419
/**
420
 * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/etzLs Whitesmiths indent style}.
421
 * 
422
 * @package		CssMin/Formatter
423
 * @link		http://code.google.com/p/cssmin/
424
 * @author		Joe Scylla <[email protected]>
425
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
426
 * @license		http://opensource.org/licenses/mit-license.php MIT License
427
 * @version		3.0.1
428
 */
429
class CssWhitesmithsFormatter extends aCssFormatter
430
	{
431
	/**
432
	 * Implements {@link aCssFormatter::__toString()}.
433
	 * 
434
	 * @return string
435
	 */
436
	public function __toString()
437
		{
438
		$r				= array();
439
		$level			= 0;
440
		for ($i = 0, $l = count($this->tokens); $i < $l; $i++)
441
			{
442
			$token		= $this->tokens[$i];
443
			$class		= get_class($token);
444
			$indent 	= str_repeat($this->indent, $level);
445
			if ($class === "CssCommentToken")
446
				{
447
				$lines = array_map("trim", explode("\n", $token->Comment));
448
				for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++)
449
					{
450
					$r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii];
451
					}
452
				}
453
			elseif ($class === "CssAtCharsetToken")
454
				{
455
				$r[] = $indent . "@charset " . $token->Charset . ";";
456
				}
457
			elseif ($class === "CssAtFontFaceStartToken")
458
				{
459
				$r[] = $indent . "@font-face";
460
				$r[] = $this->indent . $indent . "{";
461
				$level++;
462
				}
463
			elseif ($class === "CssAtImportToken")
464
				{
465
				$r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";";
466
				}
467
			elseif ($class === "CssAtKeyframesStartToken")
468
				{
469
				$r[] = $indent . "@keyframes \"" . $token->Name . "\"";
470
				$r[] = $this->indent . $indent . "{";
471
				$level++;
472
				}
473
			elseif ($class === "CssAtMediaStartToken")
474
				{
475
				$r[] = $indent . "@media " . implode(", ", $token->MediaTypes);
476
				$r[] = $this->indent . $indent . "{";
477
				$level++;
478
				}
479
			elseif ($class === "CssAtPageStartToken")
480
				{
481
				$r[] = $indent . "@page";
482
				$r[] = $this->indent . $indent . "{";
483
				$level++;
484
				}
485
			elseif ($class === "CssAtVariablesStartToken")
486
				{
487
				$r[] = $indent . "@variables " . implode(", ", $token->MediaTypes);
488
				$r[] = $this->indent . $indent . "{";
489
				$level++;
490
				}
491
			elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken")
492
				{
493
				$r[] = $indent . implode(", ", $token->Selectors);
494
				$r[] = $this->indent . $indent . "{";
495
				$level++;
496
				}
497
			elseif ($class == "CssAtFontFaceDeclarationToken"
498
				|| $class === "CssAtKeyframesRulesetDeclarationToken"
499
				|| $class === "CssAtPageDeclarationToken"
500
				|| $class == "CssAtVariablesDeclarationToken"
501
				|| $class === "CssRulesetDeclarationToken"
502
				)
503
				{
504
				$declaration = $indent . $token->Property . ": ";
505
				if ($this->padding)
506
					{
507
					$declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT);
508
					}
509
				$r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";";
510
				}
511
			elseif ($class === "CssAtFontFaceEndToken"
512
				|| $class === "CssAtMediaEndToken"
513
				|| $class === "CssAtKeyframesEndToken"
514
				|| $class === "CssAtKeyframesRulesetEndToken"
515
				|| $class === "CssAtPageEndToken"
516
				|| $class === "CssAtVariablesEndToken"
517
				|| $class === "CssRulesetEndToken"
518
				)
519
				{
520
				$r[] = $indent . "}";
521
				$level--;
522
				}
523
			}
524
		return implode("\n", $r);
525
		}
526
	}
527
528
/**
529
 * This {@link aCssMinifierPlugin} will process var-statement and sets the declaration value to the variable value. 
530
 * 
531
 * This plugin only apply the variable values. The variable values itself will get parsed by the
532
 * {@link CssVariablesMinifierFilter}.
533
 * 
534
 * Example:
535
 * <code>
536
 * @variables
537
 * 		{
538
 * 		defaultColor: black;
539
 * 		}
540
 * color: var(defaultColor);
541
 * </code>
542
 * 
543
 * Will get converted to:
544
 * <code>
545
 * color:black;
546
 * </code>
547
 *
548
 * @package		CssMin/Minifier/Plugins
549
 * @link		http://code.google.com/p/cssmin/
550
 * @author		Joe Scylla <[email protected]>
551
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
552
 * @license		http://opensource.org/licenses/mit-license.php MIT License
553
 * @version		3.0.1
554
 */
555
class CssVariablesMinifierPlugin extends aCssMinifierPlugin
556
	{
557
	/**
558
	 * Regular expression matching a value.
559
	 * 
560
	 * @var string
561
	 */
562
	private $reMatch = "/var\((.+)\)/iSU";
563
	/**
564
	 * Parsed variables.
565
	 * 
566
	 * @var array
567
	 */
568
	private $variables = null;
569
	/**
570
	 * Returns the variables.
571
	 * 
572
	 * @return array
573
	 */
574
	public function getVariables()
575
		{
576
		return $this->variables;
577
		}
578
	/**
579
	 * Implements {@link aCssMinifierPlugin::minify()}.
580
	 * 
581
	 * @param aCssToken $token Token to process
582
	 * @return boolean Return TRUE to break the processing of this token; FALSE to continue
583
	 */
584
	public function apply(aCssToken &$token)
585
		{
586
		if (stripos($token->Value, "var") !== false && preg_match_all($this->reMatch, $token->Value, $m))
587
			{
588
			$mediaTypes	= $token->MediaTypes;
589
			if (!in_array("all", $mediaTypes))
590
				{
591
				$mediaTypes[] = "all";
592
				}
593
			for ($i = 0, $l = count($m[0]); $i < $l; $i++)
594
				{
595
				$variable	= trim($m[1][$i]);
596
				foreach ($mediaTypes as $mediaType)
597
					{
598
					if (isset($this->variables[$mediaType], $this->variables[$mediaType][$variable]))
599
						{
600
						// Variable value found => set the declaration value to the variable value and return
601
						$token->Value = str_replace($m[0][$i], $this->variables[$mediaType][$variable], $token->Value);
602
						continue 2;
603
						}
604
					}
605
				// If no value was found trigger an error and replace the token with a CssNullToken
606
				CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": No value found for variable <code>" . $variable . "</code> in media types <code>" . implode(", ", $mediaTypes) . "</code>", (string) $token));
607
				$token = new CssNullToken();
608
				return true;
609
				}
610
			}
611
		return false;
612
		}
613
	/**
614
	 * Implements {@link aMinifierPlugin::getTriggerTokens()}
615
	 * 
616
	 * @return array
617
	 */
618
	public function getTriggerTokens()
619
		{
620
		return array
621
			(
622
			"CssAtFontFaceDeclarationToken",
623
			"CssAtPageDeclarationToken",
624
			"CssRulesetDeclarationToken"
625
			);
626
		}
627
	/**
628
	 * Sets the variables.
629
	 * 
630
	 * @param array $variables Variables to set
631
	 * @return void
632
	 */
633
	public function setVariables(array $variables)
634
		{
635
		$this->variables = $variables;
636
		}
637
	}
638
639
/**
640
 * This {@link aCssMinifierFilter minifier filter} will parse the variable declarations out of @variables at-rule 
641
 * blocks. The variables will get store in the {@link CssVariablesMinifierPlugin} that will apply the variables to 
642
 * declaration.
643
 * 
644
 * @package		CssMin/Minifier/Filters
645
 * @link		http://code.google.com/p/cssmin/
646
 * @author		Joe Scylla <[email protected]>
647
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
648
 * @license		http://opensource.org/licenses/mit-license.php MIT License
649
 * @version		3.0.1
650
 */
651
class CssVariablesMinifierFilter extends aCssMinifierFilter
652
	{
653
	/**
654
	 * Implements {@link aCssMinifierFilter::filter()}.
655
	 * 
656
	 * @param array $tokens Array of objects of type aCssToken
657
	 * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
658
	 */
659
	public function apply(array &$tokens)
660
		{
661
		$variables			= array();
662
		$defaultMediaTypes	= array("all");
663
		$mediaTypes			= array();
0 ignored issues
show
Unused Code introduced by
The assignment to $mediaTypes is dead and can be removed.
Loading history...
664
		$remove				= array();
665
		for($i = 0, $l = count($tokens); $i < $l; $i++)
666
			{
667
			// @variables at-rule block found
668
			if (get_class($tokens[$i]) === "CssAtVariablesStartToken")
669
				{
670
				$remove[] = $i;
671
				$mediaTypes = (count($tokens[$i]->MediaTypes) == 0 ? $defaultMediaTypes : $tokens[$i]->MediaTypes);
672
				foreach ($mediaTypes as $mediaType)
673
					{
674
					if (!isset($variables[$mediaType]))
675
						{
676
						$variables[$mediaType] = array();
677
						}
678
					}
679
				// Read the variable declaration tokens
680
				for($i = $i; $i < $l; $i++)
681
					{
682
					// Found a variable declaration => read the variable values
683
					if (get_class($tokens[$i]) === "CssAtVariablesDeclarationToken")
684
						{
685
						foreach ($mediaTypes as $mediaType)
686
							{
687
							$variables[$mediaType][$tokens[$i]->Property] = $tokens[$i]->Value;
688
							}
689
						$remove[] = $i;
690
						}
691
					// Found the variables end token => break;
692
					elseif (get_class($tokens[$i]) === "CssAtVariablesEndToken")
693
						{
694
						$remove[] = $i;
695
						break;
696
						}
697
					}
698
				}
699
			}
700
		// Variables in @variables at-rule blocks
701
		foreach($variables as $mediaType => $null)
702
			{
703
			foreach($variables[$mediaType] as $variable => $value)
704
				{
705
				// If a var() statement in a variable value found...
706
				if (stripos($value, "var") !== false && preg_match_all("/var\((.+)\)/iSU", $value, $m))
707
					{
708
					// ... then replace the var() statement with the variable values.
709
					for ($i = 0, $l = count($m[0]); $i < $l; $i++)
710
						{
711
						$variables[$mediaType][$variable] = str_replace($m[0][$i], (isset($variables[$mediaType][$m[1][$i]]) ? $variables[$mediaType][$m[1][$i]] : ""), $variables[$mediaType][$variable]);
712
						}
713
					}
714
				}
715
			}
716
		// Remove the complete @variables at-rule block
717
		foreach ($remove as $i)
718
			{
719
			$tokens[$i] = null;
720
			}
721
		if (!($plugin = $this->minifier->getPlugin("CssVariablesMinifierPlugin")))
722
			{
723
			CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin <code>CssVariablesMinifierPlugin</code> was not found but is required for <code>" . __CLASS__ . "</code>"));
724
			}
725
		else
726
			{
727
			$plugin->setVariables($variables);
0 ignored issues
show
Bug introduced by
The method setVariables() does not exist on PHPWee\aCssMinifierPlugin. It seems like you code against a sub-type of PHPWee\aCssMinifierPlugin such as PHPWee\CssVariablesMinifierPlugin. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

727
			$plugin->/** @scrutinizer ignore-call */ 
728
            setVariables($variables);
Loading history...
728
			}
729
		return count($remove);
730
		}
731
	}
732
733
/**
734
 * {@link aCssParserPlugin Parser plugin} for preserve parsing url() values.
735
 * 
736
 * This plugin return no {@link aCssToken CssToken} but ensures that url() values will get parsed properly.
737
 * 
738
 * @package		CssMin/Parser/Plugins
739
 * @link		http://code.google.com/p/cssmin/
740
 * @author		Joe Scylla <[email protected]>
741
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
742
 * @license		http://opensource.org/licenses/mit-license.php MIT License
743
 * @version		3.0.1
744
 */
745
class CssUrlParserPlugin extends aCssParserPlugin
746
	{
747
	/**
748
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
749
	 * 
750
	 * @return array
751
	 */
752
	public function getTriggerChars()
753
		{
754
		return array("(", ")");
755
		}
756
	/**
757
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
758
	 * 
759
	 * @return array
760
	 */
761
	public function getTriggerStates()
762
		{
763
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
764
		}
765
	/**
766
	 * Implements {@link aCssParserPlugin::parse()}.
767
	 * 
768
	 * @param integer $index Current index
769
	 * @param string $char Current char
770
	 * @param string $previousChar Previous char
771
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
772
	 */
773
	public function parse($index, $char, $previousChar, $state)
774
		{
775
		// Start of string
776
		if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 3, 4)) === "url(" && $state !== "T_URL")
777
			{
778
			$this->parser->pushState("T_URL");
0 ignored issues
show
Bug introduced by
'T_URL' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

778
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_URL");
Loading history...
779
			$this->parser->setExclusive(__CLASS__);
780
			}
781
		// Escaped LF in url => remove escape backslash and LF
782
		elseif ($char === "\n" && $previousChar === "\\" && $state === "T_URL")
783
			{
784
			$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2));
785
			}
786
		// Parse error: Unescaped LF in string literal
787
		elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_URL")
788
			{
789
			$line = $this->parser->getBuffer();
790
			$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . ")"); // Replace the LF with the url string delimiter
791
			$this->parser->popState();
792
			$this->parser->unsetExclusive();
793
			CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_"));
794
			}
795
		// End of string
796
		elseif ($char === ")" && $state === "T_URL")
797
			{
798
			$this->parser->popState();
799
			$this->parser->unsetExclusive();
800
			}
801
		else
802
			{
803
			return false;
804
			}
805
		return true;
806
		}
807
	}
808
809
/**
810
 * {@link aCssParserPlugin Parser plugin} for preserve parsing string values.
811
 * 
812
 * This plugin return no {@link aCssToken CssToken} but ensures that string values will get parsed properly.
813
 * 
814
 * @package		CssMin/Parser/Plugins
815
 * @link		http://code.google.com/p/cssmin/
816
 * @author		Joe Scylla <[email protected]>
817
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
818
 * @license		http://opensource.org/licenses/mit-license.php MIT License
819
 * @version		3.0.1
820
 */
821
class CssStringParserPlugin extends aCssParserPlugin
822
	{
823
	/**
824
	 * Current string delimiter char.
825
	 * 
826
	 * @var string
827
	 */
828
	private $delimiterChar = null;
829
	/**
830
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
831
	 * 
832
	 * @return array
833
	 */
834
	public function getTriggerChars()
835
		{
836
		return array("\"", "'", "\n");
837
		}
838
	/**
839
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
840
	 * 
841
	 * @return array
842
	 */
843
	public function getTriggerStates()
844
		{
845
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
846
		}
847
	/**
848
	 * Implements {@link aCssParserPlugin::parse()}.
849
	 * 
850
	 * @param integer $index Current index
851
	 * @param string $char Current char
852
	 * @param string $previousChar Previous char
853
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
854
	 */
855
	public function parse($index, $char, $previousChar, $state)
856
		{
857
		// Start of string
858
		if (($char === "\"" || $char === "'") && $state !== "T_STRING")
859
			{
860
			$this->delimiterChar = $char;
861
			$this->parser->pushState("T_STRING");
0 ignored issues
show
Bug introduced by
'T_STRING' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

861
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_STRING");
Loading history...
862
			$this->parser->setExclusive(__CLASS__);
863
			}
864
		// Escaped LF in string => remove escape backslash and LF
865
		elseif ($char === "\n" && $previousChar === "\\" && $state === "T_STRING")
866
			{
867
			$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2));
868
			}
869
		// Parse error: Unescaped LF in string literal
870
		elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_STRING")
871
			{
872
			$line = $this->parser->getBuffer();
873
			$this->parser->popState();
874
			$this->parser->unsetExclusive();
875
			$this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . $this->delimiterChar); // Replace the LF with the current string char
876
			CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_"));
877
			$this->delimiterChar = null;
878
			}
879
		// End of string
880
		elseif ($char === $this->delimiterChar && $state === "T_STRING")
881
			{
882
			// If the Previous char is a escape char count the amount of the previous escape chars. If the amount of 
883
			// escape chars is uneven do not end the string
884
			if ($previousChar == "\\")
885
				{
886
				$source	= $this->parser->getSource();
887
				$c		= 1;
888
				$i		= $index - 2;
889
				while (substr($source, $i, 1) === "\\")
890
					{
891
					$c++; $i--;
892
					}
893
				if ($c % 2)
894
					{
895
					return false;
896
					}
897
				}
898
			$this->parser->popState();
899
			$this->parser->unsetExclusive();
900
			$this->delimiterChar = null;
901
			}
902
		else
903
			{
904
			return false;
905
			}
906
		return true;
907
		}
908
	}
909
910
/**
911
 * This {@link aCssMinifierFilter minifier filter} sorts the ruleset declarations of a ruleset by name.
912
 * 
913
 * @package		CssMin/Minifier/Filters
914
 * @link		http://code.google.com/p/cssmin/
915
 * @author		Rowan Beentje <http://assanka.net>
916
 * @copyright	Rowan Beentje <http://assanka.net>
917
 * @license		http://opensource.org/licenses/mit-license.php MIT License
918
 * @version		3.0.1
919
 */
920
class CssSortRulesetPropertiesMinifierFilter extends aCssMinifierFilter
921
	{
922
	/**
923
	 * Implements {@link aCssMinifierFilter::filter()}.
924
	 * 
925
	 * @param array $tokens Array of objects of type aCssToken
926
	 * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array
927
	 */
928
	public function apply(array &$tokens)
929
		{
930
		$r = 0;
931
		for ($i = 0, $l = count($tokens); $i < $l; $i++)
932
			{
933
			// Only look for ruleset start rules
934
			if (get_class($tokens[$i]) !== "CssRulesetStartToken") { continue; }
935
			// Look for the corresponding ruleset end
936
			$endIndex = false;
937
			for ($ii = $i + 1; $ii < $l; $ii++)
938
				{
939
				if (get_class($tokens[$ii]) !== "CssRulesetEndToken") { continue; }
940
				$endIndex = $ii;
941
				break;
942
				}
943
			if (!$endIndex) { break; }
0 ignored issues
show
Bug Best Practice introduced by
The expression $endIndex of type false|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
944
			$startIndex = $i;
945
			$i = $endIndex;
946
			// Skip if there's only one token in this ruleset
947
			if ($endIndex - $startIndex <= 2) { continue; }
948
			// Ensure that everything between the start and end is a declaration token, for safety
949
			for ($ii = $startIndex + 1; $ii < $endIndex; $ii++)
950
				{
951
				if (get_class($tokens[$ii]) !== "CssRulesetDeclarationToken") { continue(2); }
952
				}
953
			$declarations = array_slice($tokens, $startIndex + 1, $endIndex - $startIndex - 1);
954
			// Check whether a sort is required
955
			$sortRequired = $lastPropertyName = false;
956
			foreach ($declarations as $declaration)	
957
				{
958
				if ($lastPropertyName)
959
					{
960
					if (strcmp($lastPropertyName, $declaration->Property) > 0)
961
						{
962
						$sortRequired = true;
963
						break;
964
						}
965
					}
966
				$lastPropertyName = $declaration->Property;
967
				}
968
			if (!$sortRequired) { continue; }
969
			// Arrange the declarations alphabetically by name
970
			usort($declarations, array(__CLASS__, "userDefinedSort1"));
971
			// Update "IsLast" property
972
			for ($ii = 0, $ll = count($declarations) - 1; $ii <= $ll; $ii++)
973
				{
974
				if ($ii == $ll)
975
					{
976
					$declarations[$ii]->IsLast = true;
977
					}
978
				else
979
					{
980
					$declarations[$ii]->IsLast = false;
981
					}
982
				}
983
			// Splice back into the array.
984
			array_splice($tokens, $startIndex + 1, $endIndex - $startIndex - 1, $declarations);
985
			$r += $endIndex - $startIndex - 1;
986
			}
987
		return $r;
988
		}
989
	/**
990
	 * User defined sort function.
991
	 * 
992
	 * @return integer
993
	 */
994
	public static function userDefinedSort1($a, $b)
995
		{
996
		return strcmp($a->Property, $b->Property);
997
		}
998
	}
999
1000
/**
1001
 * This {@link aCssToken CSS token} represents the start of a ruleset.
1002
 * 
1003
 * @package		CssMin/Tokens
1004
 * @link		http://code.google.com/p/cssmin/
1005
 * @author		Joe Scylla <[email protected]>
1006
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1007
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1008
 * @version		3.0.1
1009
 */
1010
class CssRulesetStartToken extends aCssRulesetStartToken
1011
	{
1012
	/**
1013
	 * Array of selectors.
1014
	 * 
1015
	 * @var array
1016
	 */
1017
	public $Selectors = array();
1018
	/**
1019
	 * Set the properties of a ruleset token.
1020
	 * 
1021
	 * @param array $selectors Selectors of the ruleset 
1022
	 * @return void
1023
	 */
1024
	public function __construct(array $selectors = array())
1025
		{
1026
		$this->Selectors = $selectors;
1027
		}
1028
	/**
1029
	 * Implements {@link aCssToken::__toString()}.
1030
	 * 
1031
	 * @return string
1032
	 */
1033
	public function __toString()
1034
		{
1035
		return implode(",", $this->Selectors) . "{";
1036
		}
1037
	}
1038
1039
/**
1040
 * {@link aCssParserPlugin Parser plugin} for parsing ruleset block with including declarations.
1041
 * 
1042
 * Found rulesets will add a {@link CssRulesetStartToken} and {@link CssRulesetEndToken} to the 
1043
 * parser; including declarations as {@link CssRulesetDeclarationToken}.
1044
 *
1045
 * @package		CssMin/Parser/Plugins
1046
 * @link		http://code.google.com/p/cssmin/
1047
 * @author		Joe Scylla <[email protected]>
1048
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1049
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1050
 * @version		3.0.1
1051
 */
1052
class CssRulesetParserPlugin extends aCssParserPlugin
1053
	{
1054
	/**
1055
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
1056
	 * 
1057
	 * @return array
1058
	 */
1059
	public function getTriggerChars()
1060
		{
1061
		return array(",", "{", "}", ":", ";");
1062
		}
1063
	/**
1064
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
1065
	 * 
1066
	 * @return array
1067
	 */
1068
	public function getTriggerStates()
1069
		{
1070
		return array("T_DOCUMENT", "T_AT_MEDIA", "T_RULESET::SELECTORS", "T_RULESET", "T_RULESET_DECLARATION");
1071
		}
1072
	/**
1073
	 * Selectors.
1074
	 * 
1075
	 * @var array
1076
	 */
1077
	private $selectors = array();
1078
	/**
1079
	 * Implements {@link aCssParserPlugin::parse()}.
1080
	 * 
1081
	 * @param integer $index Current index
1082
	 * @param string $char Current char
1083
	 * @param string $previousChar Previous char
1084
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
1085
	 */
1086
	public function parse($index, $char, $previousChar, $state)
1087
		{
1088
		// Start of Ruleset and selectors
1089
		if ($char === "," && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS"))
1090
			{
1091
			if ($state !== "T_RULESET::SELECTORS")
1092
				{
1093
				$this->parser->pushState("T_RULESET::SELECTORS");
0 ignored issues
show
Bug introduced by
'T_RULESET::SELECTORS' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1093
				$this->parser->pushState(/** @scrutinizer ignore-type */ "T_RULESET::SELECTORS");
Loading history...
1094
				}
1095
			$this->selectors[] = $this->parser->getAndClearBuffer(",{");
1096
			}
1097
		// End of selectors and start of declarations
1098
		elseif ($char === "{" && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS"))
1099
			{
1100
			if ($this->parser->getBuffer() !== "")
1101
				{
1102
				$this->selectors[] = $this->parser->getAndClearBuffer(",{");
1103
				if ($state == "T_RULESET::SELECTORS")
1104
					{
1105
					$this->parser->popState();
1106
					}
1107
				$this->parser->pushState("T_RULESET");
1108
				$this->parser->appendToken(new CssRulesetStartToken($this->selectors));
1109
				$this->selectors = array();
1110
				}
1111
			}
1112
		// Start of declaration
1113
		elseif ($char === ":" && $state === "T_RULESET")
1114
			{
1115
			$this->parser->pushState("T_RULESET_DECLARATION");
1116
			$this->buffer = $this->parser->getAndClearBuffer(":;", true);
1117
			}
1118
		// Unterminated ruleset declaration
1119
		elseif ($char === ":" && $state === "T_RULESET_DECLARATION")
1120
			{
1121
			// Ignore Internet Explorer filter declarations
1122
			if ($this->buffer === "filter")
1123
				{
1124
				return false;
1125
				}
1126
			CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_"));
1127
			}
1128
		// End of declaration
1129
		elseif (($char === ";" || $char === "}") && $state === "T_RULESET_DECLARATION")
1130
			{
1131
			$value = $this->parser->getAndClearBuffer(";}");
1132
			if (strtolower(substr($value, -10, 10)) === "!important")
1133
				{
1134
				$value = trim(substr($value, 0, -10));
1135
				$isImportant = true;
1136
				}
1137
			else
1138
				{
1139
				$isImportant = false;
1140
				}
1141
			$this->parser->popState();
1142
			$this->parser->appendToken(new CssRulesetDeclarationToken($this->buffer, $value, $this->parser->getMediaTypes(), $isImportant));
1143
			// Declaration ends with a right curly brace; so we have to end the ruleset
1144
			if ($char === "}")
1145
				{
1146
				$this->parser->appendToken(new CssRulesetEndToken());
1147
				$this->parser->popState();
1148
				}
1149
			$this->buffer = "";
1150
			}
1151
		// End of ruleset
1152
		elseif ($char === "}" && $state === "T_RULESET")
1153
			{
1154
			$this->parser->popState();
1155
			$this->parser->clearBuffer();
1156
			$this->parser->appendToken(new CssRulesetEndToken());
1157
			$this->buffer = "";
1158
			$this->selectors = array();
1159
			}
1160
		else
1161
			{
1162
			return false;
1163
			}
1164
		return true;
1165
		}
1166
	}
1167
1168
/**
1169
 *  This {@link aCssToken CSS token} represents the end of a ruleset.
1170
 *
1171
 * @package		CssMin/Tokens
1172
 * @link		http://code.google.com/p/cssmin/
1173
 * @author		Joe Scylla <[email protected]>
1174
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1175
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1176
 * @version		3.0.1
1177
 */
1178
class CssRulesetEndToken extends aCssRulesetEndToken
1179
	{
1180
	
1181
	}
1182
1183
/**
1184
 * This {@link aCssToken CSS token} represents a ruleset declaration.
1185
 *
1186
 * @package		CssMin/Tokens
1187
 * @link		http://code.google.com/p/cssmin/
1188
 * @author		Joe Scylla <[email protected]>
1189
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1190
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1191
 * @version		3.0.1
1192
 */
1193
class CssRulesetDeclarationToken extends aCssDeclarationToken
1194
	{
1195
	/**
1196
	 * Media types of the declaration.
1197
	 * 
1198
	 * @var array
1199
	 */
1200
	public $MediaTypes = array("all");
1201
	/**
1202
	 * Set the properties of a ddocument- or at-rule @media level declaration. 
1203
	 * 
1204
	 * @param string $property Property of the declaration
1205
	 * @param string $value Value of the declaration
1206
	 * @param mixed $mediaTypes Media types of the declaration
1207
	 * @param boolean $isImportant Is the !important flag is set
1208
	 * @param boolean $isLast Is the declaration the last one of the ruleset
1209
	 * @return void
1210
	 */
1211
	public function __construct($property, $value, $mediaTypes = null, $isImportant = false, $isLast = false)
1212
		{
1213
		parent::__construct($property, $value, $isImportant, $isLast);
1214
		$this->MediaTypes	= $mediaTypes ? $mediaTypes : array("all");
1215
		}
1216
	}
1217
1218
/**
1219
 * This {@link aCssMinifierFilter minifier filter} sets the IsLast property of any last declaration in a ruleset, 
1220
 * @font-face at-rule or @page at-rule block. If the property IsLast is TRUE the decrations will get stringified 
1221
 * without tailing semicolon.
1222
 * 
1223
 * @package		CssMin/Minifier/Filters
1224
 * @link		http://code.google.com/p/cssmin/
1225
 * @author		Joe Scylla <[email protected]>
1226
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1227
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1228
 * @version		3.0.1
1229
 */
1230
class CssRemoveLastDelarationSemiColonMinifierFilter extends aCssMinifierFilter
1231
	{
1232
	/**
1233
	 * Implements {@link aCssMinifierFilter::filter()}.
1234
	 * 
1235
	 * @param array $tokens Array of objects of type aCssToken
1236
	 * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
1237
	 */
1238
	public function apply(array &$tokens)
1239
		{
1240
		for ($i = 0, $l = count($tokens); $i < $l; $i++)
1241
			{
1242
			$current	= get_class($tokens[$i]);
1243
			$next		= isset($tokens[$i+1]) ? get_class($tokens[$i+1]) : false;
1244
			if (($current === "CssRulesetDeclarationToken" && $next === "CssRulesetEndToken") ||
1245
				($current === "CssAtFontFaceDeclarationToken" && $next === "CssAtFontFaceEndToken") || 
1246
				($current === "CssAtPageDeclarationToken" && $next === "CssAtPageEndToken"))
1247
				{
1248
				$tokens[$i]->IsLast = true;
1249
				}
1250
			}
1251
		return 0;
1252
		}
1253
	}
1254
1255
/**
1256
 * This {@link aCssMinifierFilter minifier filter} will remove any empty rulesets (including @keyframes at-rule block 
1257
 * rulesets).
1258
 *
1259
 * @package		CssMin/Minifier/Filters
1260
 * @link		http://code.google.com/p/cssmin/
1261
 * @author		Joe Scylla <[email protected]>
1262
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1263
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1264
 * @version		3.0.1
1265
 */
1266
class CssRemoveEmptyRulesetsMinifierFilter extends aCssMinifierFilter
1267
	{
1268
	/**
1269
	 * Implements {@link aCssMinifierFilter::filter()}.
1270
	 * 
1271
	 * @param array $tokens Array of objects of type aCssToken
1272
	 * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
1273
	 */
1274
	public function apply(array &$tokens)
1275
		{
1276
		$r = 0;
1277
		for ($i = 0, $l = count($tokens); $i < $l; $i++)
1278
			{
1279
			$current	= get_class($tokens[$i]);
1280
			$next		= isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false;
1281
			if (($current === "CssRulesetStartToken" && $next === "CssRulesetEndToken") ||
1282
				($current === "CssAtKeyframesRulesetStartToken" && $next === "CssAtKeyframesRulesetEndToken" && !array_intersect(array("from", "0%", "to", "100%"), array_map("strtolower", $tokens[$i]->Selectors)))
1283
				)
1284
				{
1285
				$tokens[$i]		= null;
1286
				$tokens[$i + 1]	= null;
1287
				$i++;
1288
				$r = $r + 2;
1289
				}
1290
			}
1291
		return $r;
1292
		}
1293
	}
1294
1295
/**
1296
 * This {@link aCssMinifierFilter minifier filter} will remove any empty @font-face, @keyframes, @media and @page 
1297
 * at-rule blocks.
1298
 * 
1299
 * @package		CssMin/Minifier/Filters
1300
 * @link		http://code.google.com/p/cssmin/
1301
 * @author		Joe Scylla <[email protected]>
1302
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1303
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1304
 * @version		3.0.1
1305
 */
1306
class CssRemoveEmptyAtBlocksMinifierFilter extends aCssMinifierFilter
1307
	{
1308
	/**
1309
	 * Implements {@link aCssMinifierFilter::filter()}.
1310
	 * 
1311
	 * @param array $tokens Array of objects of type aCssToken
1312
	 * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
1313
	 */
1314
	public function apply(array &$tokens)
1315
		{
1316
		$r = 0;
1317
		for ($i = 0, $l = count($tokens); $i < $l; $i++)
1318
			{
1319
			$current	= get_class($tokens[$i]);
1320
			$next		= isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false;
1321
			if (($current === "CssAtFontFaceStartToken" && $next === "CssAtFontFaceEndToken") ||
1322
				($current === "CssAtKeyframesStartToken" && $next === "CssAtKeyframesEndToken") ||
1323
				($current === "CssAtPageStartToken" && $next === "CssAtPageEndToken") ||
1324
				($current === "CssAtMediaStartToken" && $next === "CssAtMediaEndToken"))
1325
				{
1326
				$tokens[$i]		= null;
1327
				$tokens[$i + 1]	= null;
1328
				$i++;
1329
				$r = $r + 2;
1330
				}
1331
			}
1332
		return $r;
1333
		}
1334
	}
1335
1336
/**
1337
 * This {@link aCssMinifierFilter minifier filter} will remove any comments from the array of parsed tokens.
1338
 * 
1339
 * @package		CssMin/Minifier/Filters
1340
 * @link		http://code.google.com/p/cssmin/
1341
 * @author		Joe Scylla <[email protected]>
1342
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1343
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1344
 * @version		3.0.1
1345
 */
1346
class CssRemoveCommentsMinifierFilter extends aCssMinifierFilter
1347
	{
1348
	/**
1349
	 * Implements {@link aCssMinifierFilter::filter()}.
1350
	 * 
1351
	 * @param array $tokens Array of objects of type aCssToken
1352
	 * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
1353
	 */
1354
	public function apply(array &$tokens)
1355
		{
1356
		$r = 0;
1357
		for ($i = 0, $l = count($tokens); $i < $l; $i++)
1358
			{
1359
			if (get_class($tokens[$i]) === "CssCommentToken")
1360
				{
1361
				$tokens[$i] = null;
1362
				$r++;
1363
				}
1364
			}
1365
		return $r;
1366
		}
1367
	}
1368
1369
/**
1370
 * CSS Parser.
1371
 * 
1372
 * @package		CssMin/Parser
1373
 * @link		http://code.google.com/p/cssmin/
1374
 * @author		Joe Scylla <[email protected]>
1375
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1376
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1377
 * @version		3.0.1
1378
 */
1379
class CssParser
1380
	{
1381
	/**
1382
	 * Parse buffer.
1383
	 * 
1384
	 * @var string
1385
	 */
1386
	private $buffer = "";
1387
	/**
1388
	 * {@link aCssParserPlugin Plugins}.
1389
	 * 
1390
	 * @var array
1391
	 */
1392
	private $plugins = array();
1393
	/**
1394
	 * Source to parse.
1395
	 * 
1396
	 * @var string
1397
	 */
1398
	private $source = "";
1399
	/**
1400
	 * Current state.
1401
	 * 
1402
	 * @var integer
1403
	 */
1404
	private $state = "T_DOCUMENT";
1405
	/**
1406
	 * Exclusive state.
1407
	 * 
1408
	 * @var string
1409
	 */
1410
	private $stateExclusive = false;
1411
	/**
1412
	 * Media types state.
1413
	 * 
1414
	 * @var mixed
1415
	 */
1416
	private $stateMediaTypes = false;
1417
	/**
1418
	 * State stack.
1419
	 * 
1420
	 * @var array
1421
	 */
1422
	private $states = array("T_DOCUMENT");
1423
	/**
1424
	 * Parsed tokens.
1425
	 * 
1426
	 * @var array
1427
	 */
1428
	private $tokens = array();
1429
	/**
1430
	 * Constructer.
1431
	 * 
1432
	 *  Create instances of the used {@link aCssParserPlugin plugins}.
1433
	 * 
1434
	 * @param string $source CSS source [optional]
1435
	 * @param array $plugins Plugin configuration [optional]
1436
	 * @return void
1437
	 */
1438
	public function __construct($source = null, array $plugins = null)
1439
		{
1440
		$plugins = array_merge(array
1441
			(
1442
			"Comment"		=> true,
1443
			"String"		=> true,
1444
			"Url"			=> true,
1445
			"Expression"	=> true,
1446
			"Ruleset"		=> true,
1447
			"AtCharset"		=> true,
1448
			"AtFontFace"	=> true,
1449
			"AtImport"		=> true,
1450
			"AtKeyframes"	=> true,
1451
			"AtMedia"		=> true,
1452
			"AtPage"		=> true,
1453
			"AtVariables"	=> true
1454
			), is_array($plugins) ? $plugins : array());
1455
		// Create plugin instances
1456
		foreach ($plugins as $name => $config)
1457
			{
1458
			if ($config !== false)
1459
				{
1460
				$class	= "Css" . $name . "ParserPlugin";
1461
				$config = is_array($config) ? $config : array();
1462
				if (class_exists($class))
1463
					{
1464
					$this->plugins[] = new $class($this, $config);
1465
					}
1466
				else
1467
					{
1468
					CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin <code>" . $name . "</code> with the class name <code>" . $class . "</code> was not found"));
1469
					}
1470
				}
1471
			}
1472
		if (!is_null($source))
1473
			{
1474
			$this->parse($source);
1475
			}
1476
		}
1477
	/**
1478
	 * Append a token to the array of tokens.
1479
	 * 
1480
	 * @param aCssToken $token Token to append
1481
	 * @return void
1482
	 */
1483
	public function appendToken(aCssToken $token)
1484
		{
1485
		$this->tokens[] = $token;
1486
		}
1487
	/**
1488
	 * Clears the current buffer.
1489
	 * 
1490
	 * @return void
1491
	 */
1492
	public function clearBuffer()
1493
		{
1494
		$this->buffer = "";
1495
		}
1496
	/**
1497
	 * Returns and clear the current buffer.
1498
	 * 
1499
	 * @param string $trim Chars to use to trim the returned buffer
1500
	 * @param boolean $tolower if TRUE the returned buffer will get converted to lower case
1501
	 * @return string
1502
	 */
1503
	public function getAndClearBuffer($trim = "", $tolower = false)
1504
		{
1505
		$r = $this->getBuffer($trim, $tolower);
1506
		$this->buffer = "";
1507
		return $r;
1508
		}
1509
	/**
1510
	 * Returns the current buffer.
1511
	 * 
1512
	 * @param string $trim Chars to use to trim the returned buffer
1513
	 * @param boolean $tolower if TRUE the returned buffer will get converted to lower case
1514
	 * @return string
1515
	 */
1516
	public function getBuffer($trim = "", $tolower = false)
1517
		{
1518
		$r = $this->buffer;
1519
		if ($trim)
1520
			{
1521
			$r = trim($r, " \t\n\r\0\x0B" . $trim);
1522
			}
1523
		if ($tolower)
1524
			{
1525
			$r = strtolower($r);
1526
			}
1527
		return $r;
1528
		}
1529
	/**
1530
	 * Returns the current media types state.
1531
	 * 
1532
	 * @return array
1533
	 */	
1534
	public function getMediaTypes()
1535
		{
1536
		return $this->stateMediaTypes;
1537
		}
1538
	/**
1539
	 * Returns the CSS source.
1540
	 * 
1541
	 * @return string
1542
	 */
1543
	public function getSource()
1544
		{
1545
		return $this->source;
1546
		}
1547
	/**
1548
	 * Returns the current state.
1549
	 * 
1550
	 * @return integer The current state
1551
	 */
1552
	public function getState()
1553
		{
1554
		return $this->state;
1555
		}
1556
	/**
1557
	 * Returns a plugin by class name.
1558
	 * 
1559
	 * @param string $name Class name of the plugin 
1560
	 * @return aCssParserPlugin
1561
	 */
1562
	public function getPlugin($class)
1563
		{
1564
		static $index = null;
1565
		if (is_null($index))
1566
			{
1567
			$index = array();
1568
			for ($i = 0, $l = count($this->plugins); $i < $l; $i++)
1569
				{
1570
				$index[get_class($this->plugins[$i])] = $i;
1571
				}
1572
			}
1573
		return isset($index[$class]) ? $this->plugins[$index[$class]] : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $this...$index[$class]] : false could also return false which is incompatible with the documented return type PHPWee\aCssParserPlugin. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
1574
		}
1575
	/**
1576
	 * Returns the parsed tokens.
1577
	 * 
1578
	 * @return array
1579
	 */
1580
	public function getTokens()
1581
		{
1582
		return $this->tokens;
1583
		}
1584
	/**
1585
	 * Returns if the current state equals the passed state.
1586
	 * 
1587
	 * @param integer $state State to compare with the current state
1588
	 * @return boolean TRUE is the state equals to the passed state; FALSE if not
1589
	 */
1590
	public function isState($state)
1591
		{
1592
		return ($this->state == $state);
1593
		}
1594
	/**
1595
	 * Parse the CSS source and return a array with parsed tokens.
1596
	 * 
1597
	 * @param string $source CSS source
1598
	 * @return array Array with tokens
1599
	 */
1600
	public function parse($source)
1601
		{
1602
		// Reset
1603
		$this->source = "";
1604
		$this->tokens = array();
1605
		// Create a global and plugin lookup table for trigger chars; set array of plugins as local variable and create 
1606
		// several helper variables for plugin handling
1607
		$globalTriggerChars		= "";
1608
		$plugins				= $this->plugins;
1609
		$pluginCount			= count($plugins);
1610
		$pluginIndex			= array();
1611
		$pluginTriggerStates	= array();
1612
		$pluginTriggerChars		= array();
1613
		for ($i = 0, $l = count($plugins); $i < $l; $i++)
1614
			{
1615
			$tPluginClassName				= get_class($plugins[$i]);
1616
			$pluginTriggerChars[$i]			= implode("", $plugins[$i]->getTriggerChars());
1617
			$tPluginTriggerStates			= $plugins[$i]->getTriggerStates();
1618
			$pluginTriggerStates[$i]		= $tPluginTriggerStates === false ? false : "|" . implode("|", $tPluginTriggerStates) . "|";
1619
			$pluginIndex[$tPluginClassName]	= $i;
1620
			for ($ii = 0, $ll = strlen($pluginTriggerChars[$i]); $ii < $ll; $ii++)
1621
				{
1622
				$c = substr($pluginTriggerChars[$i], $ii, 1);
1623
				if (strpos($globalTriggerChars, $c) === false)
1624
					{
1625
					$globalTriggerChars .= $c;
1626
					}
1627
				}
1628
			}
1629
		// Normalise line endings
1630
		$source			= str_replace("\r\n", "\n", $source);	// Windows to Unix line endings
1631
		$source			= str_replace("\r", "\n", $source);		// Mac to Unix line endings
1632
		$this->source	= $source;
1633
		// Variables
1634
		$buffer			= &$this->buffer;
1635
		$exclusive		= &$this->stateExclusive;
1636
		$state			= &$this->state;
1637
		$c = $p 		= null;
0 ignored issues
show
Unused Code introduced by
The assignment to $c is dead and can be removed.
Loading history...
1638
		// --
1639
		for ($i = 0, $l = strlen($source); $i < $l; $i++)
1640
			{
1641
			// Set the current Char
1642
			$c = $source[$i]; // Is faster than: $c = substr($source, $i, 1);
1643
			// Normalize and filter double whitespace characters
1644
			if ($exclusive === false)
1645
				{
1646
				if ($c === "\n" || $c === "\t")
1647
					{
1648
					$c = " ";
1649
					}
1650
				if ($c === " " && $p === " ")
1651
					{
1652
					continue;
1653
					}
1654
				}
1655
			$buffer .= $c;
1656
			// Extended processing only if the current char is a global trigger char
1657
			if (strpos($globalTriggerChars, $c) !== false)
1658
				{
1659
				// Exclusive state is set; process with the exclusive plugin 
1660
				if ($exclusive)
1661
					{
1662
					$tPluginIndex = $pluginIndex[$exclusive];
1663
					if (strpos($pluginTriggerChars[$tPluginIndex], $c) !== false && ($pluginTriggerStates[$tPluginIndex] === false || strpos($pluginTriggerStates[$tPluginIndex], $state) !== false))
1664
						{
1665
						$r = $plugins[$tPluginIndex]->parse($i, $c, $p, $state);
1666
						// Return value is TRUE => continue with next char
1667
						if ($r === true)
1668
							{
1669
							continue;
1670
							}
1671
						// Return value is numeric => set new index and continue with next char
1672
						elseif ($r !== false && $r != $i)
1673
							{
1674
							$i = $r;
1675
							continue;
1676
							}
1677
						}
1678
					}
1679
				// Else iterate through the plugins
1680
				else
1681
					{
1682
					$triggerState = "|" . $state . "|";
1683
					for ($ii = 0, $ll = $pluginCount; $ii < $ll; $ii++)
1684
						{
1685
						// Only process if the current char is one of the plugin trigger chars
1686
						if (strpos($pluginTriggerChars[$ii], $c) !== false && ($pluginTriggerStates[$ii] === false || strpos($pluginTriggerStates[$ii], $triggerState) !== false))
1687
							{
1688
							// Process with the plugin
1689
							$r = $plugins[$ii]->parse($i, $c, $p, $state);
1690
							// Return value is TRUE => break the plugin loop and and continue with next char
1691
							if ($r === true)
1692
								{
1693
								break;
1694
								}
1695
							// Return value is numeric => set new index, break the plugin loop and and continue with next char
1696
							elseif ($r !== false && $r != $i)
1697
								{
1698
								$i = $r;
1699
								break;
1700
								}
1701
							}
1702
						}
1703
					}
1704
				}
1705
			$p = $c; // Set the parent char
1706
			}
1707
		return $this->tokens;
1708
		}
1709
	/**
1710
	 * Remove the last state of the state stack and return the removed stack value.
1711
	 * 
1712
	 * @return integer Removed state value
1713
	 */
1714
	public function popState()
1715
		{
1716
		$r = array_pop($this->states);
1717
		$this->state = $this->states[count($this->states) - 1];
1718
		return $r;
1719
		}
1720
	/**
1721
	 * Adds a new state onto the state stack.
1722
	 * 
1723
	 * @param integer $state State to add onto the state stack.
1724
	 * @return integer The index of the added state in the state stacks
1725
	 */
1726
	public function pushState($state)
1727
		{
1728
		$r = array_push($this->states, $state);
1729
		$this->state = $this->states[count($this->states) - 1];
1730
		return $r;
1731
		}
1732
	/**
1733
	 * Sets/restores the buffer.
1734
	 * 
1735
	 * @param string $buffer Buffer to set
1736
	 * @return void
1737
	 */	
1738
	public function setBuffer($buffer)
1739
		{
1740
		$this->buffer = $buffer;
1741
		}
1742
	/**
1743
	 * Set the exclusive state.
1744
	 * 
1745
	 * @param string $exclusive Exclusive state
1746
	 * @return void
1747
	 */	
1748
	public function setExclusive($exclusive)
1749
		{
1750
		$this->stateExclusive = $exclusive; 
1751
		}
1752
	/**
1753
	 * Set the media types state.
1754
	 * 
1755
	 * @param array $mediaTypes Media types state
1756
	 * @return void
1757
	 */	
1758
	public function setMediaTypes(array $mediaTypes)
1759
		{
1760
		$this->stateMediaTypes = $mediaTypes; 
1761
		}
1762
	/**
1763
	 * Sets the current state in the state stack; equals to {@link CssParser::popState()} + {@link CssParser::pushState()}.
1764
	 * 
1765
	 * @param integer $state State to set
1766
	 * @return integer
1767
	 */
1768
	public function setState($state)
1769
		{
1770
		$r = array_pop($this->states);
1771
		array_push($this->states, $state);
1772
		$this->state = $this->states[count($this->states) - 1];
1773
		return $r;
1774
		}
1775
	/**
1776
	 * Removes the exclusive state.
1777
	 * 
1778
	 * @return void
1779
	 */
1780
	public function unsetExclusive()
1781
		{
1782
		$this->stateExclusive = false;
0 ignored issues
show
Documentation Bug introduced by
The property $stateExclusive was declared of type string, but false is of type false. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
1783
		}
1784
	/**
1785
	 * Removes the media types state.
1786
	 * 
1787
	 * @return void
1788
	 */
1789
	public function unsetMediaTypes()
1790
		{
1791
		$this->stateMediaTypes = false;
1792
		}
1793
	}
1794
1795
/**
1796
 * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/j4XdU OTBS indent style} (The One True Brace Style).
1797
 * 
1798
 * @package		CssMin/Formatter
1799
 * @link		http://code.google.com/p/cssmin/
1800
 * @author		Joe Scylla <[email protected]>
1801
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1802
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1803
 * @version		3.0.1
1804
 */
1805
class CssOtbsFormatter extends aCssFormatter
1806
	{
1807
	/**
1808
	 * Implements {@link aCssFormatter::__toString()}.
1809
	 * 
1810
	 * @return string
1811
	 */
1812
	public function __toString()
1813
		{
1814
		$r				= array();
1815
		$level			= 0;
1816
		for ($i = 0, $l = count($this->tokens); $i < $l; $i++)
1817
			{
1818
			$token		= $this->tokens[$i];
1819
			$class		= get_class($token);
1820
			$indent 	= str_repeat($this->indent, $level);
1821
			if ($class === "CssCommentToken")
1822
				{
1823
				$lines = array_map("trim", explode("\n", $token->Comment));
1824
				for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++)
1825
					{
1826
					$r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii];
1827
					}
1828
				}
1829
			elseif ($class === "CssAtCharsetToken")
1830
				{
1831
				$r[] = $indent . "@charset " . $token->Charset . ";";
1832
				}
1833
			elseif ($class === "CssAtFontFaceStartToken")
1834
				{
1835
				$r[] = $indent . "@font-face {";
1836
				$level++;
1837
				}
1838
			elseif ($class === "CssAtImportToken")
1839
				{
1840
				$r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";";
1841
				}
1842
			elseif ($class === "CssAtKeyframesStartToken")
1843
				{
1844
				$r[] = $indent . "@keyframes \"" . $token->Name . "\" {";
1845
				$level++;
1846
				}
1847
			elseif ($class === "CssAtMediaStartToken")
1848
				{
1849
				$r[] = $indent . "@media " . implode(", ", $token->MediaTypes) . " {";
1850
				$level++;
1851
				}
1852
			elseif ($class === "CssAtPageStartToken")
1853
				{
1854
				$r[] = $indent . "@page {";
1855
				$level++;
1856
				}
1857
			elseif ($class === "CssAtVariablesStartToken")
1858
				{
1859
				$r[] = $indent . "@variables " . implode(", ", $token->MediaTypes) . " {";
1860
				$level++;
1861
				}
1862
			elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken")
1863
				{
1864
				$r[] = $indent . implode(", ", $token->Selectors) . " {";
1865
				$level++;
1866
				}
1867
			elseif ($class == "CssAtFontFaceDeclarationToken"
1868
				|| $class === "CssAtKeyframesRulesetDeclarationToken"
1869
				|| $class === "CssAtPageDeclarationToken"
1870
				|| $class == "CssAtVariablesDeclarationToken"
1871
				|| $class === "CssRulesetDeclarationToken"
1872
				)
1873
				{
1874
				$declaration = $indent . $token->Property . ": ";
1875
				if ($this->padding)
1876
					{
1877
					$declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT);
1878
					}
1879
				$r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";";
1880
				}
1881
			elseif ($class === "CssAtFontFaceEndToken"
1882
				|| $class === "CssAtMediaEndToken"
1883
				|| $class === "CssAtKeyframesEndToken"
1884
				|| $class === "CssAtKeyframesRulesetEndToken"
1885
				|| $class === "CssAtPageEndToken"
1886
				|| $class === "CssAtVariablesEndToken"
1887
				|| $class === "CssRulesetEndToken"
1888
				)
1889
				{
1890
				$level--;
1891
				$r[] = str_repeat($indent, $level) . "}";
1892
				}
1893
			}
1894
		return implode("\n", $r);
1895
		}
1896
	}
1897
1898
/**
1899
 * This {@link aCssToken CSS token} is a utility token that extends {@link aNullToken} and returns only a empty string.
1900
 *
1901
 * @package		CssMin/Tokens
1902
 * @link		http://code.google.com/p/cssmin/
1903
 * @author		Joe Scylla <[email protected]>
1904
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1905
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1906
 * @version		3.0.1
1907
 */
1908
class CssNullToken extends aCssToken
1909
	{
1910
	/**
1911
	 * Implements {@link aCssToken::__toString()}.
1912
	 * 
1913
	 * @return string
1914
	 */
1915
	public function __toString()
1916
		{
1917
		return "";
1918
		}
1919
	}
1920
1921
/**
1922
 * CSS Minifier.
1923
 * 
1924
 * @package		CssMin/Minifier
1925
 * @link		http://code.google.com/p/cssmin/
1926
 * @author		Joe Scylla <[email protected]>
1927
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
1928
 * @license		http://opensource.org/licenses/mit-license.php MIT License
1929
 * @version		3.0.1
1930
 */
1931
class CssMinifier
1932
	{
1933
	/**
1934
	 * {@link aCssMinifierFilter Filters}.
1935
	 *  
1936
	 * @var array
1937
	 */
1938
	private $filters = array();
1939
	/**
1940
	 * {@link aCssMinifierPlugin Plugins}.
1941
	 * 
1942
	 * @var array
1943
	 */
1944
	private $plugins = array();
1945
	/**
1946
	 * Minified source.
1947
	 * 
1948
	 * @var string
1949
	 */
1950
	private $minified = "";
1951
	/**
1952
	 * Constructer.
1953
	 * 
1954
	 * Creates instances of {@link aCssMinifierFilter filters} and {@link aCssMinifierPlugin plugins}.
1955
	 * 
1956
	 * @param string $source CSS source [optional]
1957
	 * @param array $filters Filter configuration [optional]
1958
	 * @param array $plugins Plugin configuration [optional]
1959
	 * @return void
1960
	 */
1961
	public function __construct($source = null, array $filters = null, array $plugins = null)
1962
		{
1963
		$filters = array_merge(array
1964
			(
1965
			"ImportImports"					=> false,
1966
			"RemoveComments"				=> true, 
1967
			"RemoveEmptyRulesets"			=> true,
1968
			"RemoveEmptyAtBlocks"			=> true,
1969
			"ConvertLevel3Properties"		=> false,
1970
			"ConvertLevel3AtKeyframes"		=> false,
1971
			"Variables"						=> true,
1972
			"RemoveLastDelarationSemiColon"	=> true
1973
			), is_array($filters) ? $filters : array());
1974
		$plugins = array_merge(array
1975
			(
1976
			"Variables"						=> true,
1977
			"ConvertFontWeight"				=> false,
1978
			"ConvertHslColors"				=> false,
1979
			"ConvertRgbColors"				=> false,
1980
			"ConvertNamedColors"			=> false,
1981
			"CompressColorValues"			=> false,
1982
			"CompressUnitValues"			=> false,
1983
			"CompressExpressionValues"		=> false
1984
			), is_array($plugins) ? $plugins : array());
1985
		// Filters
1986
		foreach ($filters as $name => $config)
1987
			{
1988
			if ($config !== false)
1989
				{
1990
				$class	= "Css" . $name . "MinifierFilter";
1991
				$config = is_array($config) ? $config : array();
1992
				if (class_exists($class))
1993
					{
1994
					$this->filters[] = new $class($this, $config);
1995
					}
1996
				else
1997
					{
1998
					CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The filter <code>" . $name . "</code> with the class name <code>" . $class . "</code> was not found"));
1999
					}
2000
				}
2001
			}
2002
		// Plugins
2003
		foreach ($plugins as $name => $config)
2004
			{
2005
			if ($config !== false)
2006
				{
2007
				$class	= "Css" . $name . "MinifierPlugin";
2008
				$config = is_array($config) ? $config : array();
2009
				if (class_exists($class))
2010
					{
2011
					$this->plugins[] = new $class($this, $config);
2012
					}
2013
				else
2014
					{
2015
					CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin <code>" . $name . "</code> with the class name <code>" . $class . "</code> was not found"));
2016
					}
2017
				}
2018
			}
2019
		// --
2020
		if (!is_null($source))
2021
			{
2022
			$this->minify($source);
2023
			}
2024
		}
2025
	/**
2026
	 * Returns the minified Source.
2027
	 * 
2028
	 * @return string
2029
	 */
2030
	public function getMinified()
2031
		{
2032
		return $this->minified;
2033
		}
2034
	/**
2035
	 * Returns a plugin by class name.
2036
	 * 
2037
	 * @param string $name Class name of the plugin
2038
	 * @return aCssMinifierPlugin
2039
	 */
2040
	public function getPlugin($class)
2041
		{
2042
		static $index = null;
2043
		if (is_null($index))
2044
			{
2045
			$index = array();
2046
			for ($i = 0, $l = count($this->plugins); $i < $l; $i++)
2047
				{
2048
				$index[get_class($this->plugins[$i])] = $i;
2049
				}
2050
			}
2051
		return isset($index[$class]) ? $this->plugins[$index[$class]] : false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return IssetNode ? $this...$index[$class]] : false could also return false which is incompatible with the documented return type PHPWee\aCssMinifierPlugin. Did you maybe forget to handle an error condition?

If the returned type also contains false, it is an indicator that maybe an error condition leading to the specific return statement remains unhandled.

Loading history...
2052
		}
2053
	/**
2054
	 * Minifies the CSS source.
2055
	 * 
2056
	 * @param string $source CSS source
2057
	 * @return string
2058
	 */
2059
	public function minify($source)
2060
		{
2061
		// Variables
2062
		$r						= "";
2063
		$parser					= new CssParser($source);
2064
		$tokens					= $parser->getTokens();
2065
		$filters 				= $this->filters;
2066
		$filterCount			= count($this->filters);
2067
		$plugins				= $this->plugins;
2068
		$pluginCount			= count($plugins);
2069
		$pluginIndex			= array();
2070
		$pluginTriggerTokens	= array();
2071
		$globalTriggerTokens	= array();
2072
		for ($i = 0, $l = count($plugins); $i < $l; $i++)
2073
			{
2074
			$tPluginClassName				= get_class($plugins[$i]);
2075
			$pluginTriggerTokens[$i]		= $plugins[$i]->getTriggerTokens();
2076
			foreach ($pluginTriggerTokens[$i] as $v)
2077
				{
2078
				if (!in_array($v, $globalTriggerTokens))
2079
					{
2080
					$globalTriggerTokens[] = $v;
2081
					}
2082
				}
2083
			$pluginTriggerTokens[$i] = "|" . implode("|", $pluginTriggerTokens[$i]) . "|";
2084
			$pluginIndex[$tPluginClassName]	= $i;
2085
			}
2086
		$globalTriggerTokens = "|" . implode("|", $globalTriggerTokens) . "|";
2087
		/*
2088
		 * Apply filters
2089
		 */
2090
		for($i = 0; $i < $filterCount; $i++)
2091
			{
2092
			// Apply the filter; if the return value is larger than 0...
2093
			if ($filters[$i]->apply($tokens) > 0)
2094
				{
2095
				// ...then filter null values and rebuild the token array
2096
				$tokens = array_values(array_filter($tokens));
2097
				}
2098
			}
2099
		$tokenCount = count($tokens);
2100
		/*
2101
		 * Apply plugins
2102
		 */
2103
		for($i = 0; $i < $tokenCount; $i++)
2104
			{
2105
			$triggerToken = "|" . get_class($tokens[$i]) . "|";
2106
			if (strpos($globalTriggerTokens, $triggerToken) !== false)
2107
				{
2108
				for($ii = 0; $ii < $pluginCount; $ii++)
2109
					{
2110
					if (strpos($pluginTriggerTokens[$ii], $triggerToken) !== false || $pluginTriggerTokens[$ii] === false)
2111
						{
2112
						// Apply the plugin; if the return value is TRUE continue to the next token
2113
						if ($plugins[$ii]->apply($tokens[$i]) === true)
2114
							{
2115
							continue 2;
2116
							}
2117
						}
2118
					}
2119
				}
2120
			}
2121
		// Stringify the tokens
2122
		for($i = 0; $i < $tokenCount; $i++)
2123
			{
2124
			$r .= (string) $tokens[$i];
2125
			}
2126
		$this->minified = $r;
2127
		return $r;
2128
		}
2129
	}
2130
2131
/**
2132
 * CssMin - A (simple) css minifier with benefits
2133
 * 
2134
 * --
2135
 * Copyright (c) 2011 Joe Scylla <[email protected]>
2136
 *
2137
 * Permission is hereby granted, free of charge, to any person obtaining a copy
2138
 * of this software and associated documentation files (the "Software"), to deal
2139
 * in the Software without restriction, including without limitation the rights
2140
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
2141
 * copies of the Software, and to permit persons to whom the Software is
2142
 * furnished to do so, subject to the following conditions:
2143
 * 
2144
 * The above copyright notice and this permission notice shall be included in
2145
 * all copies or substantial portions of the Software.
2146
 * 
2147
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2148
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2149
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2150
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2151
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2152
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2153
 * THE SOFTWARE.
2154
 * --
2155
 * 
2156
 * @package		CssMin
2157
 * @link		http://code.google.com/p/cssmin/
2158
 * @author		Joe Scylla <[email protected]>
2159
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
2160
 * @license		http://opensource.org/licenses/mit-license.php MIT License
2161
 * @version		3.0.1
2162
 */
2163
class CssMin
2164
	{
2165
	/**
2166
	 * Index of classes
2167
	 * 
2168
	 * @var array
2169
	 */
2170
	private static $classIndex = array();
2171
	/**
2172
	 * Parse/minify errors
2173
	 * 
2174
	 * @var array
2175
	 */
2176
	private static $errors = array();
2177
	/**
2178
	 * Verbose output.
2179
	 * 
2180
	 * @var boolean
2181
	 */
2182
	private static $isVerbose = false;
2183
	/**
2184
	 * {@link http://goo.gl/JrW54 Autoload} function of CssMin.
2185
	 * 
2186
	 * @param string $class Name of the class
2187
	 * @return void
2188
	 */
2189
	public static function autoload($class)
2190
		{
2191
		if (isset(self::$classIndex[$class]))
2192
			{
2193
			require(self::$classIndex[$class]);
2194
			}
2195
		}
2196
	/**
2197
	 * Return errors
2198
	 * 
2199
	 * @return array of {CssError}.
2200
	 */
2201
	public static function getErrors()
2202
		{
2203
		return self::$errors;
2204
		}
2205
	/**
2206
	 * Returns if there were errors.
2207
	 * 
2208
	 * @return boolean
2209
	 */
2210
	public static function hasErrors()
2211
		{
2212
		return count(self::$errors) > 0;
2213
		}
2214
	/**
2215
	 * Initialises CssMin.
2216
	 * 
2217
	 * @return void
2218
	 */
2219
	public static function initialise()
2220
		{
2221
		// Create the class index for autoloading or including
2222
		$paths = array(dirname(__FILE__));
2223
		while (list($i, $path) = each($paths))
2224
			{
2225
			$subDirectorys = glob($path . "*", GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT);
2226
			if (is_array($subDirectorys))
2227
				{
2228
				foreach ($subDirectorys as $subDirectory)
2229
					{
2230
					$paths[] = $subDirectory;
2231
					}
2232
				}
2233
			$files = glob($path . "*.php", 0);
2234
			if (is_array($files))
2235
				{
2236
				foreach ($files as $file)
2237
					{
2238
					$class = substr(basename($file), 0, -4);
2239
					self::$classIndex[$class] = $file;
2240
					}
2241
				}
2242
			}
2243
		krsort(self::$classIndex);
2244
		// Only use autoloading if spl_autoload_register() is available and no __autoload() is defined (because 
2245
		// __autoload() breaks if spl_autoload_register() is used. 
2246
		if (function_exists("spl_autoload_register") && !is_callable("__autoload"))
2247
			{
2248
			spl_autoload_register(array(__CLASS__, "autoload"));
2249
			}
2250
		// Otherwise include all class files
2251
		else
2252
			{
2253
			foreach (self::$classIndex as $class => $file)
2254
				{
2255
				if (!class_exists($class))
2256
					{
2257
					require_once($file);
2258
					}
2259
				}
2260
			}
2261
		}
2262
	/**
2263
	 * Minifies CSS source.
2264
	 * 
2265
	 * @param string $source CSS source
2266
	 * @param array $filters Filter configuration [optional]
2267
	 * @param array $plugins Plugin configuration [optional]
2268
	 * @return string Minified CSS
2269
	 */
2270
	public static function minify($source, array $filters = null, array $plugins = null)
2271
		{
2272
		self::$errors = array();
2273
		$minifier = new CssMinifier($source, $filters, $plugins);
2274
		return $minifier->getMinified();
2275
		}
2276
	/**
2277
	 * Parse the CSS source.
2278
	 * 
2279
	 * @param string $source CSS source
2280
	 * @param array $plugins Plugin configuration [optional]
2281
	 * @return array Array of aCssToken
2282
	 */
2283
	public static function parse($source, array $plugins = null)
2284
		{
2285
		self::$errors = array();
2286
		$parser = new CssParser($source, $plugins);
2287
		return $parser->getTokens();
2288
		}
2289
	/**
2290
	 * --
2291
	 * 
2292
	 * @param boolean $to
2293
	 * @return boolean
2294
	 */
2295
	public static function setVerbose($to)
2296
		{
2297
		self::$isVerbose = (boolean) $to;
2298
		return self::$isVerbose;
2299
		}
2300
	/**
2301
	 * --
2302
	 * 
2303
	 * @param CssError $error
2304
	 * @return void
2305
	 */
2306
	public static function triggerError(CssError $error)
2307
		{
2308
		self::$errors[] = $error;
2309
		if (self::$isVerbose)
2310
			{
2311
			trigger_error((string) $error, E_USER_WARNING);
2312
			}
2313
		}
2314
	}
2315
// Initialises CssMin
2316
CssMin::initialise();
2317
2318
/**
2319
 * This {@link aCssMinifierFilter minifier filter} import external css files defined with the @import at-rule into the 
2320
 * current stylesheet. 
2321
 * 
2322
 * @package		CssMin/Minifier/Filters
2323
 * @link		http://code.google.com/p/cssmin/
2324
 * @author		Joe Scylla <[email protected]>
2325
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
2326
 * @license		http://opensource.org/licenses/mit-license.php MIT License
2327
 * @version		3.0.1
2328
 */
2329
class CssImportImportsMinifierFilter extends aCssMinifierFilter
2330
	{
2331
	/**
2332
	 * Array with already imported external stylesheets.
2333
	 * 
2334
	 * @var array
2335
	 */
2336
	private $imported = array();
2337
	/**
2338
	 * Implements {@link aCssMinifierFilter::filter()}.
2339
	 * 
2340
	 * @param array $tokens Array of objects of type aCssToken
2341
	 * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
2342
	 */
2343
	public function apply(array &$tokens)
2344
		{
2345
		if (!isset($this->configuration["BasePath"]) || !is_dir($this->configuration["BasePath"]))
2346
			{
2347
			CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Base path <code>" . ($this->configuration["BasePath"] ? $this->configuration["BasePath"] : "null"). "</code> is not a directory"));
2348
			return 0;
2349
			}
2350
		for ($i = 0, $l = count($tokens); $i < $l; $i++)
2351
			{
2352
			if (get_class($tokens[$i]) === "CssAtImportToken")
2353
				{
2354
				$import = $this->configuration["BasePath"] . "/" . $tokens[$i]->Import;
2355
				// Import file was not found/is not a file
2356
				if (!is_file($import))
2357
					{
2358
					CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Import file <code>" . $import. "</code> was not found.", (string) $tokens[$i]));
2359
					}
2360
				// Import file already imported; remove this @import at-rule to prevent recursions
2361
				elseif (in_array($import, $this->imported))
2362
					{
2363
					CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Import file <code>" . $import. "</code> was already imported.", (string) $tokens[$i]));
2364
					$tokens[$i] = null;
2365
					}
2366
				else
2367
					{
2368
					$this->imported[] = $import;
2369
					$parser = new CssParser(file_get_contents($import));
2370
					$import = $parser->getTokens();
2371
					// The @import at-rule has media types defined requiring special handling
2372
					if (count($tokens[$i]->MediaTypes) > 0 && !(count($tokens[$i]->MediaTypes) == 1 && $tokens[$i]->MediaTypes[0] == "all"))
2373
						{
2374
						$blocks = array();
2375
						/*
2376
						 * Filter or set media types of @import at-rule or remove the @import at-rule if no media type is matching the parent @import at-rule
2377
						 */
2378
						for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2379
							{
2380
							if (get_class($import[$ii]) === "CssAtImportToken")
2381
								{
2382
								// @import at-rule defines no media type or only the "all" media type; set the media types to the one defined in the parent @import at-rule
2383
								if (count($import[$ii]->MediaTypes) == 0 || (count($import[$ii]->MediaTypes) == 1 && $import[$ii]->MediaTypes[0] == "all"))
2384
									{
2385
									$import[$ii]->MediaTypes = $tokens[$i]->MediaTypes;
2386
									}
2387
								// @import at-rule defineds one or more media types; filter out media types not matching with the  parent @import at-rule
2388
								elseif (count($import[$ii]->MediaTypes > 0))
0 ignored issues
show
Bug introduced by
$import[$ii]->MediaTypes > 0 of type boolean is incompatible with the type Countable|array expected by parameter $value of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2388
								elseif (count(/** @scrutinizer ignore-type */ $import[$ii]->MediaTypes > 0))
Loading history...
2389
									{
2390
									foreach ($import[$ii]->MediaTypes as $index => $mediaType)
2391
										{
2392
										if (!in_array($mediaType, $tokens[$i]->MediaTypes))
2393
											{
2394
											unset($import[$ii]->MediaTypes[$index]);
2395
											}
2396
										}
2397
									$import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes);
2398
									// If there are no media types left in the @import at-rule remove the @import at-rule
2399
									if (count($import[$ii]->MediaTypes) == 0)
2400
										{
2401
										$import[$ii] = null;
2402
										}
2403
									}
2404
								}
2405
							}
2406
						/*
2407
						 * Remove media types of @media at-rule block not defined in the @import at-rule
2408
						 */
2409
						for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2410
							{
2411
							if (get_class($import[$ii]) === "CssAtMediaStartToken")
2412
								{
2413
								foreach ($import[$ii]->MediaTypes as $index => $mediaType)
2414
									{
2415
									if (!in_array($mediaType, $tokens[$i]->MediaTypes))
2416
										{
2417
										unset($import[$ii]->MediaTypes[$index]);
2418
										}
2419
									$import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes);
2420
									}
2421
								}
2422
							}
2423
						/*
2424
						 * If no media types left of the @media at-rule block remove the complete block
2425
						 */
2426
						for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2427
							{
2428
							if (get_class($import[$ii]) === "CssAtMediaStartToken")
2429
								{
2430
								if (count($import[$ii]->MediaTypes) === 0)
2431
									{
2432
									for ($iii = $ii; $iii < $ll; $iii++)
2433
										{
2434
										if (get_class($import[$iii]) === "CssAtMediaEndToken")
2435
											{
2436
											break;
2437
											}
2438
										}
2439
									if (get_class($import[$iii]) === "CssAtMediaEndToken")
2440
										{
2441
										array_splice($import, $ii, $iii - $ii + 1, array());
2442
										$ll = count($import);
2443
										}
2444
									}
2445
								}
2446
							}
2447
						/*
2448
						 * If the media types of the @media at-rule equals the media types defined in the @import 
2449
						 * at-rule remove the CssAtMediaStartToken and CssAtMediaEndToken token
2450
						 */ 
2451
						for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2452
							{
2453
							if (get_class($import[$ii]) === "CssAtMediaStartToken" && count(array_diff($tokens[$i]->MediaTypes, $import[$ii]->MediaTypes)) === 0)
2454
								{
2455
								for ($iii = $ii; $iii < $ll; $iii++)
2456
									{
2457
									if (get_class($import[$iii]) == "CssAtMediaEndToken")
2458
										{
2459
										break;
2460
										}
2461
									}
2462
								if (get_class($import[$iii]) == "CssAtMediaEndToken")
2463
									{
2464
									unset($import[$ii]);
2465
									unset($import[$iii]);
2466
									$import = array_values($import);
2467
									$ll = count($import);
2468
									}
2469
								}
2470
							}
2471
						/**
2472
						 * Extract CssAtImportToken and CssAtCharsetToken tokens
2473
						 */
2474
						for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2475
							{
2476
							$class = get_class($import[$ii]);
2477
							if ($class === "CssAtImportToken" || $class === "CssAtCharsetToken")
2478
								{
2479
								$blocks = array_merge($blocks, array_splice($import, $ii, 1, array()));
2480
								$ll = count($import);
2481
								}
2482
							}
2483
						/*
2484
						 * Extract the @font-face, @media and @page at-rule block
2485
						 */
2486
						for($ii = 0, $ll = count($import); $ii < $ll; $ii++)
2487
							{
2488
							$class = get_class($import[$ii]);
2489
							if ($class === "CssAtFontFaceStartToken" || $class === "CssAtMediaStartToken" || $class === "CssAtPageStartToken" || $class === "CssAtVariablesStartToken")
2490
								{
2491
								for ($iii = $ii; $iii < $ll; $iii++)
2492
									{
2493
									$class = get_class($import[$iii]);
2494
									if ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken")
2495
										{
2496
										break;
2497
										}
2498
									}
2499
								$class = get_class($import[$iii]);
2500
								if (isset($import[$iii]) && ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken"))
2501
									{
2502
									$blocks = array_merge($blocks, array_splice($import, $ii, $iii - $ii + 1, array()));
2503
									$ll = count($import);
2504
									}
2505
								}
2506
							}
2507
						// Create the import array with extracted tokens and the rulesets wrapped into a @media at-rule block
2508
						$import = array_merge($blocks, array(new CssAtMediaStartToken($tokens[$i]->MediaTypes)), $import, array(new CssAtMediaEndToken()));
2509
						}
2510
					// Insert the imported tokens
2511
					array_splice($tokens, $i, 1, $import);
2512
					// Modify parameters of the for-loop
2513
					$i--;
2514
					$l = count($tokens);
2515
					}
2516
				}
2517
			}
2518
		}
2519
	}
2520
2521
/**
2522
 * {@link aCssParserPlugin Parser plugin} for preserve parsing expression() declaration values.
2523
 * 
2524
 * This plugin return no {@link aCssToken CssToken} but ensures that expression() declaration values will get parsed 
2525
 * properly.
2526
 * 
2527
 * @package		CssMin/Parser/Plugins
2528
 * @link		http://code.google.com/p/cssmin/
2529
 * @author		Joe Scylla <[email protected]>
2530
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
2531
 * @license		http://opensource.org/licenses/mit-license.php MIT License
2532
 * @version		3.0.1
2533
 */
2534
class CssExpressionParserPlugin extends aCssParserPlugin
2535
	{
2536
	/**
2537
	 * Count of left braces.
2538
	 * 
2539
	 * @var integer
2540
	 */
2541
	private $leftBraces = 0;
2542
	/**
2543
	 * Count of right braces.
2544
	 * 
2545
	 * @var integer
2546
	 */
2547
	private $rightBraces = 0;
2548
	/**
2549
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
2550
	 * 
2551
	 * @return array
2552
	 */
2553
	public function getTriggerChars()
2554
		{
2555
		return array("(", ")", ";", "}");
2556
		}
2557
	/**
2558
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
2559
	 * 
2560
	 * @return array
2561
	 */
2562
	public function getTriggerStates()
2563
		{
2564
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
2565
		}
2566
	/**
2567
	 * Implements {@link aCssParserPlugin::parse()}.
2568
	 * 
2569
	 * @param integer $index Current index
2570
	 * @param string $char Current char
2571
	 * @param string $previousChar Previous char
2572
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
2573
	 */
2574
	public function parse($index, $char, $previousChar, $state)
2575
		{
2576
		// Start of expression
2577
		if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 10, 11)) === "expression(" && $state !== "T_EXPRESSION")
2578
			{
2579
			$this->parser->pushState("T_EXPRESSION");
0 ignored issues
show
Bug introduced by
'T_EXPRESSION' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2579
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_EXPRESSION");
Loading history...
2580
			$this->leftBraces++;
2581
			}
2582
		// Count left braces
2583
		elseif ($char === "(" && $state === "T_EXPRESSION")
2584
			{
2585
			$this->leftBraces++;
2586
			}
2587
		// Count right braces
2588
		elseif ($char === ")" && $state === "T_EXPRESSION")
2589
			{
2590
			$this->rightBraces++;
2591
			}
2592
		// Possible end of expression; if left and right braces are equal the expressen ends
2593
		elseif (($char === ";" || $char === "}") && $state === "T_EXPRESSION" && $this->leftBraces === $this->rightBraces)
2594
			{
2595
			$this->leftBraces = $this->rightBraces = 0;
2596
			$this->parser->popState();
2597
			return $index - 1;
2598
			}
2599
		else
2600
			{
2601
			return false;
2602
			}
2603
		return true;
2604
		}
2605
	}
2606
2607
/**
2608
 * CSS Error.
2609
 * 
2610
 * @package		CssMin
2611
 * @link		http://code.google.com/p/cssmin/
2612
 * @author		Joe Scylla <[email protected]>
2613
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
2614
 * @license		http://opensource.org/licenses/mit-license.php MIT License
2615
 * @version		3.0.1
2616
 */
2617
class CssError
2618
	{
2619
	/**
2620
	 * File.
2621
	 * 
2622
	 * @var string
2623
	 */
2624
	public $File = "";
2625
	/**
2626
	 * Line.
2627
	 * 
2628
	 * @var integer
2629
	 */
2630
	public $Line = 0;
2631
	/**
2632
	 * Error message.
2633
	 * 
2634
	 * @var string
2635
	 */
2636
	public $Message = "";
2637
	/**
2638
	 * Source.
2639
	 * 
2640
	 * @var string
2641
	 */
2642
	public $Source = "";
2643
	/**
2644
	 * Constructor triggering the error.
2645
	 * 
2646
	 * @param string $message Error message
2647
	 * @param string $source Corresponding line [optional]
2648
	 * @return void
2649
	 */
2650
	public function __construct($file, $line, $message, $source = "")
2651
		{
2652
		$this->File		= $file;
2653
		$this->Line		= $line;
2654
		$this->Message	= $message;
2655
		$this->Source	= $source;
2656
		}
2657
	/**
2658
	 * Returns the error as formatted string.
2659
	 * 
2660
	 * @return string
2661
	 */	
2662
	public function __toString()
2663
		{
2664
		return $this->Message . ($this->Source ? ": <br /><code>" . $this->Source . "</code>": "") . "<br />in file " . $this->File . " at line " . $this->Line;
2665
		}
2666
	}
2667
2668
/**
2669
 * This {@link aCssMinifierPlugin} will convert a color value in rgb notation to hexadecimal notation.
2670
 * 
2671
 * Example:
2672
 * <code>
2673
 * color: rgb(200,60%,5);
2674
 * </code>
2675
 * 
2676
 * Will get converted to:
2677
 * <code>
2678
 * color:#c89905;
2679
 * </code>
2680
 *
2681
 * @package		CssMin/Minifier/Plugins
2682
 * @link		http://code.google.com/p/cssmin/
2683
 * @author		Joe Scylla <[email protected]>
2684
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
2685
 * @license		http://opensource.org/licenses/mit-license.php MIT License
2686
 * @version		3.0.1
2687
 */
2688
class CssConvertRgbColorsMinifierPlugin extends aCssMinifierPlugin
2689
	{
2690
	/**
2691
	 * Regular expression matching the value.
2692
	 * 
2693
	 * @var string
2694
	 */
2695
	private $reMatch = "/rgb\s*\(\s*([0-9%]+)\s*,\s*([0-9%]+)\s*,\s*([0-9%]+)\s*\)/iS";
2696
	/**
2697
	 * Implements {@link aCssMinifierPlugin::minify()}.
2698
	 * 
2699
	 * @param aCssToken $token Token to process
2700
	 * @return boolean Return TRUE to break the processing of this token; FALSE to continue
2701
	 */
2702
	public function apply(aCssToken &$token)
2703
		{
2704
		if (stripos($token->Value, "rgb") !== false && preg_match($this->reMatch, $token->Value, $m))
2705
			{
2706
			for ($i = 1, $l = count($m); $i < $l; $i++)
2707
				{
2708
				if (strpos("%", $m[$i]) !== false)
2709
					{
2710
					$m[$i] = substr($m[$i], 0, -1);
2711
					$m[$i] = (int) (256 * ($m[$i] / 100));
2712
					}
2713
				$m[$i] = str_pad(dechex($m[$i]),  2, "0", STR_PAD_LEFT);
2714
				}
2715
			$token->Value = str_replace($m[0], "#" . $m[1] . $m[2] . $m[3], $token->Value);
2716
			}
2717
		return false;
2718
		}
2719
	/**
2720
	 * Implements {@link aMinifierPlugin::getTriggerTokens()}
2721
	 * 
2722
	 * @return array
2723
	 */
2724
	public function getTriggerTokens()
2725
		{
2726
		return array
2727
			(
2728
			"CssAtFontFaceDeclarationToken",
2729
			"CssAtPageDeclarationToken",
2730
			"CssRulesetDeclarationToken"
2731
			);
2732
		}
2733
	}
2734
2735
/**
2736
 * This {@link aCssMinifierPlugin} will convert named color values to hexadecimal notation.
2737
 * 
2738
 * Example:
2739
 * <code>
2740
 * color: black;
2741
 * border: 1px solid indigo;
2742
 * </code>
2743
 * 
2744
 * Will get converted to:
2745
 * <code>
2746
 * color:#000;
2747
 * border:1px solid #4b0082;
2748
 * </code>
2749
 * 
2750
 * @package		CssMin/Minifier/Plugins
2751
 * @link		http://code.google.com/p/cssmin/
2752
 * @author		Joe Scylla <[email protected]>
2753
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
2754
 * @license		http://opensource.org/licenses/mit-license.php MIT License
2755
 * @version		3.0.1
2756
 */
2757
class CssConvertNamedColorsMinifierPlugin extends aCssMinifierPlugin
2758
	{
2759
	
2760
	/**
2761
	 * Regular expression matching the value.
2762
	 * 
2763
	 * @var string
2764
	 */
2765
	private $reMatch = null;
2766
	/**
2767
	 * Regular expression replacing the value.
2768
	 * 
2769
	 * @var string
2770
	 */
2771
	private $reReplace = "\"\${1}\" . \$this->transformation[strtolower(\"\${2}\")] . \"\${3}\"";
2772
	/**
2773
	 * Transformation table used by the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression}.
2774
	 * 
2775
	 * @var array
2776
	 */
2777
	private $transformation = array
2778
		( 
2779
		"aliceblue"						=> "#f0f8ff",
2780
		"antiquewhite"					=> "#faebd7",
2781
		"aqua"							=> "#0ff",
2782
		"aquamarine"					=> "#7fffd4",
2783
		"azure"							=> "#f0ffff",
2784
		"beige"							=> "#f5f5dc",
2785
		"black"							=> "#000",
2786
		"blue"							=> "#00f",
2787
		"blueviolet"					=> "#8a2be2",
2788
		"brown"							=> "#a52a2a",
2789
		"burlywood"						=> "#deb887",
2790
		"cadetblue"						=> "#5f9ea0",
2791
		"chartreuse"					=> "#7fff00",
2792
		"chocolate"						=> "#d2691e",
2793
		"coral"							=> "#ff7f50",
2794
		"cornflowerblue"				=> "#6495ed",
2795
		"cornsilk"						=> "#fff8dc",
2796
		"crimson"						=> "#dc143c",
2797
		"darkblue"						=> "#00008b",
2798
		"darkcyan"						=> "#008b8b",
2799
		"darkgoldenrod"					=> "#b8860b",
2800
		"darkgray"						=> "#a9a9a9",
2801
		"darkgreen"						=> "#006400",
2802
		"darkkhaki"						=> "#bdb76b",
2803
		"darkmagenta"					=> "#8b008b",
2804
		"darkolivegreen"				=> "#556b2f",
2805
		"darkorange"					=> "#ff8c00",
2806
		"darkorchid"					=> "#9932cc",
2807
		"darkred"						=> "#8b0000",
2808
		"darksalmon"					=> "#e9967a",
2809
		"darkseagreen"					=> "#8fbc8f",
2810
		"darkslateblue"					=> "#483d8b",
2811
		"darkslategray"					=> "#2f4f4f",
2812
		"darkturquoise"					=> "#00ced1",
2813
		"darkviolet"					=> "#9400d3",
2814
		"deeppink"						=> "#ff1493",
2815
		"deepskyblue"					=> "#00bfff",
2816
		"dimgray"						=> "#696969",
2817
		"dodgerblue"					=> "#1e90ff",
2818
		"firebrick"						=> "#b22222",
2819
		"floralwhite"					=> "#fffaf0",
2820
		"forestgreen"					=> "#228b22",
2821
		"fuchsia"						=> "#f0f",
2822
		"gainsboro"						=> "#dcdcdc",
2823
		"ghostwhite"					=> "#f8f8ff",
2824
		"gold"							=> "#ffd700",
2825
		"goldenrod"						=> "#daa520",
2826
		"gray"							=> "#808080",
2827
		"green"							=> "#008000",
2828
		"greenyellow"					=> "#adff2f",
2829
		"honeydew"						=> "#f0fff0",
2830
		"hotpink"						=> "#ff69b4",
2831
		"indianred"						=> "#cd5c5c",
2832
		"indigo"						=> "#4b0082",
2833
		"ivory"							=> "#fffff0",
2834
		"khaki"							=> "#f0e68c",
2835
		"lavender"						=> "#e6e6fa",
2836
		"lavenderblush"					=> "#fff0f5",
2837
		"lawngreen"						=> "#7cfc00",
2838
		"lemonchiffon"					=> "#fffacd",
2839
		"lightblue"						=> "#add8e6",
2840
		"lightcoral"					=> "#f08080",
2841
		"lightcyan"						=> "#e0ffff",
2842
		"lightgoldenrodyellow"			=> "#fafad2",
2843
		"lightgreen"					=> "#90ee90",
2844
		"lightgrey"						=> "#d3d3d3",
2845
		"lightpink"						=> "#ffb6c1",
2846
		"lightsalmon"					=> "#ffa07a",
2847
		"lightseagreen"					=> "#20b2aa",
2848
		"lightskyblue"					=> "#87cefa",
2849
		"lightslategray"				=> "#789",
2850
		"lightsteelblue"				=> "#b0c4de",
2851
		"lightyellow"					=> "#ffffe0",
2852
		"lime"							=> "#0f0",
2853
		"limegreen"						=> "#32cd32",
2854
		"linen"							=> "#faf0e6",
2855
		"maroon"						=> "#800000",
2856
		"mediumaquamarine"				=> "#66cdaa",
2857
		"mediumblue"					=> "#0000cd",
2858
		"mediumorchid"					=> "#ba55d3",
2859
		"mediumpurple"					=> "#9370db",
2860
		"mediumseagreen"				=> "#3cb371",
2861
		"mediumslateblue"				=> "#7b68ee",
2862
		"mediumspringgreen"				=> "#00fa9a",
2863
		"mediumturquoise"				=> "#48d1cc",
2864
		"mediumvioletred"				=> "#c71585",
2865
		"midnightblue"					=> "#191970",
2866
		"mintcream"						=> "#f5fffa",
2867
		"mistyrose"						=> "#ffe4e1",
2868
		"moccasin"						=> "#ffe4b5",
2869
		"navajowhite"					=> "#ffdead",
2870
		"navy"							=> "#000080",
2871
		"oldlace"						=> "#fdf5e6",
2872
		"olive"							=> "#808000",
2873
		"olivedrab"						=> "#6b8e23",
2874
		"orange"						=> "#ffa500",
2875
		"orangered"						=> "#ff4500",
2876
		"orchid"						=> "#da70d6",
2877
		"palegoldenrod"					=> "#eee8aa",
2878
		"palegreen"						=> "#98fb98",
2879
		"paleturquoise"					=> "#afeeee",
2880
		"palevioletred"					=> "#db7093",
2881
		"papayawhip"					=> "#ffefd5",
2882
		"peachpuff"						=> "#ffdab9",
2883
		"peru"							=> "#cd853f",
2884
		"pink"							=> "#ffc0cb",
2885
		"plum"							=> "#dda0dd",
2886
		"powderblue"					=> "#b0e0e6",
2887
		"purple"						=> "#800080",
2888
		"red"							=> "#f00",
2889
		"rosybrown"						=> "#bc8f8f",
2890
		"royalblue"						=> "#4169e1",
2891
		"saddlebrown"					=> "#8b4513",
2892
		"salmon"						=> "#fa8072",
2893
		"sandybrown"					=> "#f4a460",
2894
		"seagreen"						=> "#2e8b57",
2895
		"seashell"						=> "#fff5ee",
2896
		"sienna"						=> "#a0522d",
2897
		"silver"						=> "#c0c0c0",
2898
		"skyblue"						=> "#87ceeb",
2899
		"slateblue"						=> "#6a5acd",
2900
		"slategray"						=> "#708090",
2901
		"snow"							=> "#fffafa",
2902
		"springgreen"					=> "#00ff7f",
2903
		"steelblue"						=> "#4682b4",
2904
		"tan"							=> "#d2b48c",
2905
		"teal"							=> "#008080",
2906
		"thistle"						=> "#d8bfd8",
2907
		"tomato"						=> "#ff6347",
2908
		"turquoise"						=> "#40e0d0",
2909
		"violet"						=> "#ee82ee",
2910
		"wheat"							=> "#f5deb3",
2911
		"white"							=> "#fff",
2912
		"whitesmoke"					=> "#f5f5f5",
2913
		"yellow"						=> "#ff0",
2914
		"yellowgreen"					=> "#9acd32"
2915
		);
2916
	/**
2917
	 * Overwrites {@link aCssMinifierPlugin::__construct()}.
2918
	 * 
2919
	 * The constructor will create the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression}
2920
	 * based on the {@link CssConvertNamedColorsMinifierPlugin::$transformation transformation table}.
2921
	 * 
2922
	 * @param CssMinifier $minifier The CssMinifier object of this plugin.
2923
	 * @param array $configuration Plugin configuration [optional]
2924
	 * @return void
2925
	 */
2926
	public function __construct(CssMinifier $minifier, array $configuration = array())
2927
		{
2928
		$this->reMatch = "/(^|\s)+(" . implode("|", array_keys($this->transformation)) . ")(\s|$)+/eiS";
2929
		parent::__construct($minifier, $configuration);
2930
		}
2931
	/**
2932
	 * Implements {@link aCssMinifierPlugin::minify()}.
2933
	 * 
2934
	 * @param aCssToken $token Token to process
2935
	 * @return boolean Return TRUE to break the processing of this token; FALSE to continue
2936
	 */
2937
	public function apply(aCssToken &$token)
2938
		{
2939
		$lcValue = strtolower($token->Value);
2940
		// Declaration value equals a value in the transformation table => simple replace
2941
		if (isset($this->transformation[$lcValue]))
2942
			{
2943
			$token->Value = $this->transformation[$lcValue];
2944
			}
2945
		// Declaration value contains a value in the transformation table => regular expression replace
2946
		elseif (preg_match($this->reMatch, $token->Value))
2947
			{
2948
			$token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value);
2949
			}
2950
		return false;
2951
		}
2952
	/**
2953
	 * Implements {@link aMinifierPlugin::getTriggerTokens()}
2954
	 * 
2955
	 * @return array
2956
	 */
2957
	public function getTriggerTokens()
2958
		{
2959
		return array
2960
			(
2961
			"CssAtFontFaceDeclarationToken",
2962
			"CssAtPageDeclarationToken",
2963
			"CssRulesetDeclarationToken"
2964
			);
2965
		}
2966
	}
2967
2968
/**
2969
 * This {@link aCssMinifierFilter minifier filter} triggers on CSS Level 3 properties and will add declaration tokens
2970
 * with browser-specific properties.
2971
 * 
2972
 * @package		CssMin/Minifier/Filters
2973
 * @link		http://code.google.com/p/cssmin/
2974
 * @author		Joe Scylla <[email protected]>
2975
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
2976
 * @license		http://opensource.org/licenses/mit-license.php MIT License
2977
 * @version		3.0.1
2978
 */
2979
class CssConvertLevel3PropertiesMinifierFilter extends aCssMinifierFilter
2980
	{
2981
	/**
2982
	 * Css property transformations table. Used to convert CSS3 and proprietary properties to the browser-specific 
2983
	 * counterparts.
2984
	 * 
2985
	 * @var array
2986
	 */
2987
	private $transformations = array
2988
		(
2989
		// Property						Array(Mozilla, Webkit, Opera, Internet Explorer); NULL values are placeholders and will get ignored
2990
		"animation"						=> array(null, "-webkit-animation", null, null),
2991
		"animation-delay"				=> array(null, "-webkit-animation-delay", null, null),
2992
		"animation-direction" 			=> array(null, "-webkit-animation-direction", null, null),
2993
		"animation-duration"			=> array(null, "-webkit-animation-duration", null, null),
2994
		"animation-fill-mode"			=> array(null, "-webkit-animation-fill-mode", null, null),
2995
		"animation-iteration-count"		=> array(null, "-webkit-animation-iteration-count", null, null),
2996
		"animation-name"				=> array(null, "-webkit-animation-name", null, null),
2997
		"animation-play-state"			=> array(null, "-webkit-animation-play-state", null, null),
2998
		"animation-timing-function"		=> array(null, "-webkit-animation-timing-function", null, null),
2999
		"appearance"					=> array("-moz-appearance", "-webkit-appearance", null, null),
3000
		"backface-visibility"			=> array(null, "-webkit-backface-visibility", null, null),
3001
		"background-clip"				=> array(null, "-webkit-background-clip", null, null),
3002
		"background-composite"			=> array(null, "-webkit-background-composite", null, null),
3003
		"background-inline-policy"		=> array("-moz-background-inline-policy", null, null, null),
3004
		"background-origin"				=> array(null, "-webkit-background-origin", null, null),
3005
		"background-position-x"			=> array(null, null, null, "-ms-background-position-x"),
3006
		"background-position-y"			=> array(null, null, null, "-ms-background-position-y"),
3007
		"background-size"				=> array(null, "-webkit-background-size", null, null),
3008
		"behavior"						=> array(null, null, null, "-ms-behavior"),
3009
		"binding"						=> array("-moz-binding", null, null, null),
3010
		"border-after"					=> array(null, "-webkit-border-after", null, null),
3011
		"border-after-color"			=> array(null, "-webkit-border-after-color", null, null),
3012
		"border-after-style"			=> array(null, "-webkit-border-after-style", null, null),
3013
		"border-after-width"			=> array(null, "-webkit-border-after-width", null, null),
3014
		"border-before"					=> array(null, "-webkit-border-before", null, null),
3015
		"border-before-color"			=> array(null, "-webkit-border-before-color", null, null),
3016
		"border-before-style"			=> array(null, "-webkit-border-before-style", null, null),
3017
		"border-before-width"			=> array(null, "-webkit-border-before-width", null, null),
3018
		"border-border-bottom-colors"	=> array("-moz-border-bottom-colors", null, null, null),
3019
		"border-bottom-left-radius"		=> array("-moz-border-radius-bottomleft", "-webkit-border-bottom-left-radius", null, null),
3020
		"border-bottom-right-radius"	=> array("-moz-border-radius-bottomright", "-webkit-border-bottom-right-radius", null, null),
3021
		"border-end"					=> array("-moz-border-end", "-webkit-border-end", null, null),
3022
		"border-end-color"				=> array("-moz-border-end-color", "-webkit-border-end-color", null, null),
3023
		"border-end-style"				=> array("-moz-border-end-style", "-webkit-border-end-style", null, null),
3024
		"border-end-width"				=> array("-moz-border-end-width", "-webkit-border-end-width", null, null),
3025
		"border-fit"					=> array(null, "-webkit-border-fit", null, null),
3026
		"border-horizontal-spacing"		=> array(null, "-webkit-border-horizontal-spacing", null, null),
3027
		"border-image"					=> array("-moz-border-image", "-webkit-border-image", null, null),
3028
		"border-left-colors"			=> array("-moz-border-left-colors", null, null, null),
3029
		"border-radius"					=> array("-moz-border-radius", "-webkit-border-radius", null, null),
3030
		"border-border-right-colors"	=> array("-moz-border-right-colors", null, null, null),
3031
		"border-start"					=> array("-moz-border-start", "-webkit-border-start", null, null),
3032
		"border-start-color"			=> array("-moz-border-start-color", "-webkit-border-start-color", null, null),
3033
		"border-start-style"			=> array("-moz-border-start-style", "-webkit-border-start-style", null, null),
3034
		"border-start-width"			=> array("-moz-border-start-width", "-webkit-border-start-width", null, null),
3035
		"border-top-colors"				=> array("-moz-border-top-colors", null, null, null),
3036
		"border-top-left-radius"		=> array("-moz-border-radius-topleft", "-webkit-border-top-left-radius", null, null),
3037
		"border-top-right-radius"		=> array("-moz-border-radius-topright", "-webkit-border-top-right-radius", null, null),
3038
		"border-vertical-spacing"		=> array(null, "-webkit-border-vertical-spacing", null, null),
3039
		"box-align"						=> array("-moz-box-align", "-webkit-box-align", null, null),
3040
		"box-direction"					=> array("-moz-box-direction", "-webkit-box-direction", null, null),
3041
		"box-flex"						=> array("-moz-box-flex", "-webkit-box-flex", null, null),
3042
		"box-flex-group"				=> array(null, "-webkit-box-flex-group", null, null),
3043
		"box-flex-lines"				=> array(null, "-webkit-box-flex-lines", null, null),
3044
		"box-ordinal-group"				=> array("-moz-box-ordinal-group", "-webkit-box-ordinal-group", null, null),
3045
		"box-orient"					=> array("-moz-box-orient", "-webkit-box-orient", null, null),
3046
		"box-pack"						=> array("-moz-box-pack", "-webkit-box-pack", null, null),
3047
		"box-reflect"					=> array(null, "-webkit-box-reflect", null, null),
3048
		"box-shadow"					=> array("-moz-box-shadow", "-webkit-box-shadow", null, null),
3049
		"box-sizing"					=> array("-moz-box-sizing", null, null, null),
3050
		"color-correction"				=> array(null, "-webkit-color-correction", null, null),
3051
		"column-break-after"			=> array(null, "-webkit-column-break-after", null, null),
3052
		"column-break-before"			=> array(null, "-webkit-column-break-before", null, null),
3053
		"column-break-inside"			=> array(null, "-webkit-column-break-inside", null, null),
3054
		"column-count"					=> array("-moz-column-count", "-webkit-column-count", null, null),
3055
		"column-gap"					=> array("-moz-column-gap", "-webkit-column-gap", null, null),
3056
		"column-rule"					=> array("-moz-column-rule", "-webkit-column-rule", null, null),
3057
		"column-rule-color"				=> array("-moz-column-rule-color", "-webkit-column-rule-color", null, null),
3058
		"column-rule-style"				=> array("-moz-column-rule-style", "-webkit-column-rule-style", null, null),
3059
		"column-rule-width"				=> array("-moz-column-rule-width", "-webkit-column-rule-width", null, null),
3060
		"column-span"					=> array(null, "-webkit-column-span", null, null),
3061
		"column-width"					=> array("-moz-column-width", "-webkit-column-width", null, null),
3062
		"columns"						=> array(null, "-webkit-columns", null, null),
3063
		"filter"						=> array(__CLASS__, "filter"),
3064
		"float-edge"					=> array("-moz-float-edge", null, null, null),
3065
		"font-feature-settings"			=> array("-moz-font-feature-settings", null, null, null),
3066
		"font-language-override"		=> array("-moz-font-language-override", null, null, null),
3067
		"font-size-delta"				=> array(null, "-webkit-font-size-delta", null, null),
3068
		"font-smoothing"				=> array(null, "-webkit-font-smoothing", null, null),
3069
		"force-broken-image-icon"		=> array("-moz-force-broken-image-icon", null, null, null),
3070
		"highlight"						=> array(null, "-webkit-highlight", null, null),
3071
		"hyphenate-character"			=> array(null, "-webkit-hyphenate-character", null, null),
3072
		"hyphenate-locale"				=> array(null, "-webkit-hyphenate-locale", null, null),
3073
		"hyphens"						=> array(null, "-webkit-hyphens", null, null),
3074
		"force-broken-image-icon"		=> array("-moz-image-region", null, null, null),
3075
		"ime-mode"						=> array(null, null, null, "-ms-ime-mode"),
3076
		"interpolation-mode"			=> array(null, null, null, "-ms-interpolation-mode"),
3077
		"layout-flow"					=> array(null, null, null, "-ms-layout-flow"),
3078
		"layout-grid"					=> array(null, null, null, "-ms-layout-grid"),
3079
		"layout-grid-char"				=> array(null, null, null, "-ms-layout-grid-char"),
3080
		"layout-grid-line"				=> array(null, null, null, "-ms-layout-grid-line"),
3081
		"layout-grid-mode"				=> array(null, null, null, "-ms-layout-grid-mode"),
3082
		"layout-grid-type"				=> array(null, null, null, "-ms-layout-grid-type"),
3083
		"line-break"					=> array(null, "-webkit-line-break", null, "-ms-line-break"),
3084
		"line-clamp"					=> array(null, "-webkit-line-clamp", null, null),
3085
		"line-grid-mode"				=> array(null, null, null, "-ms-line-grid-mode"),
3086
		"logical-height"				=> array(null, "-webkit-logical-height", null, null),
3087
		"logical-width"					=> array(null, "-webkit-logical-width", null, null),
3088
		"margin-after"					=> array(null, "-webkit-margin-after", null, null),
3089
		"margin-after-collapse"			=> array(null, "-webkit-margin-after-collapse", null, null),
3090
		"margin-before"					=> array(null, "-webkit-margin-before", null, null),
3091
		"margin-before-collapse"		=> array(null, "-webkit-margin-before-collapse", null, null),
3092
		"margin-bottom-collapse"		=> array(null, "-webkit-margin-bottom-collapse", null, null),
3093
		"margin-collapse"				=> array(null, "-webkit-margin-collapse", null, null),
3094
		"margin-end"					=> array("-moz-margin-end", "-webkit-margin-end", null, null),
3095
		"margin-start"					=> array("-moz-margin-start", "-webkit-margin-start", null, null),
3096
		"margin-top-collapse"			=> array(null, "-webkit-margin-top-collapse", null, null),
3097
		"marquee "						=> array(null, "-webkit-marquee", null, null),
3098
		"marquee-direction"				=> array(null, "-webkit-marquee-direction", null, null),
3099
		"marquee-increment"				=> array(null, "-webkit-marquee-increment", null, null),
3100
		"marquee-repetition"			=> array(null, "-webkit-marquee-repetition", null, null),
3101
		"marquee-speed"					=> array(null, "-webkit-marquee-speed", null, null),
3102
		"marquee-style"					=> array(null, "-webkit-marquee-style", null, null),
3103
		"mask"							=> array(null, "-webkit-mask", null, null),
3104
		"mask-attachment"				=> array(null, "-webkit-mask-attachment", null, null),
3105
		"mask-box-image"				=> array(null, "-webkit-mask-box-image", null, null),
3106
		"mask-clip"						=> array(null, "-webkit-mask-clip", null, null),
3107
		"mask-composite"				=> array(null, "-webkit-mask-composite", null, null),
3108
		"mask-image"					=> array(null, "-webkit-mask-image", null, null),
3109
		"mask-origin"					=> array(null, "-webkit-mask-origin", null, null),
3110
		"mask-position"					=> array(null, "-webkit-mask-position", null, null),
3111
		"mask-position-x"				=> array(null, "-webkit-mask-position-x", null, null),
3112
		"mask-position-y"				=> array(null, "-webkit-mask-position-y", null, null),
3113
		"mask-repeat"					=> array(null, "-webkit-mask-repeat", null, null),
3114
		"mask-repeat-x"					=> array(null, "-webkit-mask-repeat-x", null, null),
3115
		"mask-repeat-y"					=> array(null, "-webkit-mask-repeat-y", null, null),
3116
		"mask-size"						=> array(null, "-webkit-mask-size", null, null),
3117
		"match-nearest-mail-blockquote-color" => array(null, "-webkit-match-nearest-mail-blockquote-color", null, null),
3118
		"max-logical-height"			=> array(null, "-webkit-max-logical-height", null, null),
3119
		"max-logical-width"				=> array(null, "-webkit-max-logical-width", null, null),
3120
		"min-logical-height"			=> array(null, "-webkit-min-logical-height", null, null),
3121
		"min-logical-width"				=> array(null, "-webkit-min-logical-width", null, null),
3122
		"object-fit"					=> array(null, null, "-o-object-fit", null),
3123
		"object-position"				=> array(null, null, "-o-object-position", null),
3124
		"opacity"						=> array(__CLASS__, "opacity"),
3125
		"outline-radius"				=> array("-moz-outline-radius", null, null, null),
3126
		"outline-bottom-left-radius"	=> array("-moz-outline-radius-bottomleft", null, null, null),
3127
		"outline-bottom-right-radius"	=> array("-moz-outline-radius-bottomright", null, null, null),
3128
		"outline-top-left-radius"		=> array("-moz-outline-radius-topleft", null, null, null),
3129
		"outline-top-right-radius"		=> array("-moz-outline-radius-topright", null, null, null),
3130
		"padding-after"					=> array(null, "-webkit-padding-after", null, null),
3131
		"padding-before"				=> array(null, "-webkit-padding-before", null, null),
3132
		"padding-end"					=> array("-moz-padding-end", "-webkit-padding-end", null, null),
3133
		"padding-start"					=> array("-moz-padding-start", "-webkit-padding-start", null, null),
3134
		"perspective"					=> array(null, "-webkit-perspective", null, null),
3135
		"perspective-origin"			=> array(null, "-webkit-perspective-origin", null, null),
3136
		"perspective-origin-x"			=> array(null, "-webkit-perspective-origin-x", null, null),
3137
		"perspective-origin-y"			=> array(null, "-webkit-perspective-origin-y", null, null),
3138
		"rtl-ordering"					=> array(null, "-webkit-rtl-ordering", null, null),
3139
		"scrollbar-3dlight-color"		=> array(null, null, null, "-ms-scrollbar-3dlight-color"),
3140
		"scrollbar-arrow-color"			=> array(null, null, null, "-ms-scrollbar-arrow-color"),
3141
		"scrollbar-base-color"			=> array(null, null, null, "-ms-scrollbar-base-color"),
3142
		"scrollbar-darkshadow-color"	=> array(null, null, null, "-ms-scrollbar-darkshadow-color"),
3143
		"scrollbar-face-color"			=> array(null, null, null, "-ms-scrollbar-face-color"),
3144
		"scrollbar-highlight-color"		=> array(null, null, null, "-ms-scrollbar-highlight-color"),
3145
		"scrollbar-shadow-color"		=> array(null, null, null, "-ms-scrollbar-shadow-color"),
3146
		"scrollbar-track-color"			=> array(null, null, null, "-ms-scrollbar-track-color"),
3147
		"stack-sizing"					=> array("-moz-stack-sizing", null, null, null),
3148
		"svg-shadow"					=> array(null, "-webkit-svg-shadow", null, null),
3149
		"tab-size"						=> array("-moz-tab-size", null, "-o-tab-size", null),
3150
		"table-baseline"				=> array(null, null, "-o-table-baseline", null),
3151
		"text-align-last"				=> array(null, null, null, "-ms-text-align-last"),
3152
		"text-autospace"				=> array(null, null, null, "-ms-text-autospace"),
3153
		"text-combine"					=> array(null, "-webkit-text-combine", null, null),
3154
		"text-decorations-in-effect"	=> array(null, "-webkit-text-decorations-in-effect", null, null),
3155
		"text-emphasis"					=> array(null, "-webkit-text-emphasis", null, null),
3156
		"text-emphasis-color"			=> array(null, "-webkit-text-emphasis-color", null, null),
3157
		"text-emphasis-position"		=> array(null, "-webkit-text-emphasis-position", null, null),
3158
		"text-emphasis-style"			=> array(null, "-webkit-text-emphasis-style", null, null),
3159
		"text-fill-color"				=> array(null, "-webkit-text-fill-color", null, null),
3160
		"text-justify"					=> array(null, null, null, "-ms-text-justify"),
3161
		"text-kashida-space"			=> array(null, null, null, "-ms-text-kashida-space"),
3162
		"text-overflow"					=> array(null, null, "-o-text-overflow", "-ms-text-overflow"),
3163
		"text-security"					=> array(null, "-webkit-text-security", null, null),
3164
		"text-size-adjust"				=> array(null, "-webkit-text-size-adjust", null, "-ms-text-size-adjust"),
3165
		"text-stroke"					=> array(null, "-webkit-text-stroke", null, null),
3166
		"text-stroke-color"				=> array(null, "-webkit-text-stroke-color", null, null),
3167
		"text-stroke-width"				=> array(null, "-webkit-text-stroke-width", null, null),
3168
		"text-underline-position"		=> array(null, null, null, "-ms-text-underline-position"),
3169
		"transform"						=> array("-moz-transform", "-webkit-transform", "-o-transform", null),
3170
		"transform-origin"				=> array("-moz-transform-origin", "-webkit-transform-origin", "-o-transform-origin", null),
3171
		"transform-origin-x"			=> array(null, "-webkit-transform-origin-x", null, null),
3172
		"transform-origin-y"			=> array(null, "-webkit-transform-origin-y", null, null),
3173
		"transform-origin-z"			=> array(null, "-webkit-transform-origin-z", null, null),
3174
		"transform-style"				=> array(null, "-webkit-transform-style", null, null),
3175
		"transition"					=> array("-moz-transition", "-webkit-transition", "-o-transition", null),
3176
		"transition-delay"				=> array("-moz-transition-delay", "-webkit-transition-delay", "-o-transition-delay", null),
3177
		"transition-duration"			=> array("-moz-transition-duration", "-webkit-transition-duration", "-o-transition-duration", null),
3178
		"transition-property"			=> array("-moz-transition-property", "-webkit-transition-property", "-o-transition-property", null),
3179
		"transition-timing-function"	=> array("-moz-transition-timing-function", "-webkit-transition-timing-function", "-o-transition-timing-function", null),
3180
		"user-drag"						=> array(null, "-webkit-user-drag", null, null),
3181
		"user-focus"					=> array("-moz-user-focus", null, null, null),
3182
		"user-input"					=> array("-moz-user-input", null, null, null),
3183
		"user-modify"					=> array("-moz-user-modify", "-webkit-user-modify", null, null),
3184
		"user-select"					=> array("-moz-user-select", "-webkit-user-select", null, null),
3185
		"white-space"					=> array(__CLASS__, "whiteSpace"),
3186
		"window-shadow"					=> array("-moz-window-shadow", null, null, null),
3187
		"word-break"					=> array(null, null, null, "-ms-word-break"),
3188
		"word-wrap"						=> array(null, null, null, "-ms-word-wrap"),
3189
		"writing-mode"					=> array(null, "-webkit-writing-mode", null, "-ms-writing-mode"),
3190
		"zoom"							=> array(null, null, null, "-ms-zoom")
3191
		);
3192
	/**
3193
	 * Implements {@link aCssMinifierFilter::filter()}.
3194
	 * 
3195
	 * @param array $tokens Array of objects of type aCssToken
3196
	 * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array
3197
	 */
3198
	public function apply(array &$tokens)
3199
		{
3200
		$r = 0;
3201
		$transformations = &$this->transformations;
3202
		for ($i = 0, $l = count($tokens); $i < $l; $i++)
3203
			{
3204
			if (get_class($tokens[$i]) === "CssRulesetDeclarationToken")
3205
				{
3206
				$tProperty = $tokens[$i]->Property;
3207
				if (isset($transformations[$tProperty]))
3208
					{
3209
					$result = array();
3210
					if (is_callable($transformations[$tProperty]))
3211
						{
3212
						$result = call_user_func_array($transformations[$tProperty], array($tokens[$i]));
3213
						if (!is_array($result) && is_object($result))
3214
							{
3215
							$result = array($result);
3216
							}
3217
						}
3218
					else
3219
						{
3220
						$tValue			= $tokens[$i]->Value;
3221
						$tMediaTypes	= $tokens[$i]->MediaTypes;
3222
						foreach ($transformations[$tProperty] as $property)
3223
							{
3224
							if ($property !== null)
3225
								{
3226
								$result[] = new CssRulesetDeclarationToken($property, $tValue, $tMediaTypes);
3227
								}
3228
							}
3229
						}
3230
					if (count($result) > 0)
3231
						{
3232
						array_splice($tokens, $i + 1, 0, $result);
3233
						$i += count($result);
3234
						$l += count($result);
3235
						}
3236
					}
3237
				}
3238
			}
3239
		return $r;
3240
		}
3241
	/**
3242
	 * Transforms the Internet Explorer specific declaration property "filter" to Internet Explorer 8+ compatible 
3243
	 * declaratiopn property "-ms-filter". 
3244
	 * 
3245
	 * @param aCssToken $token
3246
	 * @return array
3247
	 */
3248
	private static function filter($token)
3249
		{
3250
		$r = array
3251
			(
3252
			new CssRulesetDeclarationToken("-ms-filter", "\"" . $token->Value . "\"", $token->MediaTypes),
3253
			);
3254
		return $r;
3255
		}
3256
	/**
3257
	 * Transforms "opacity: {value}" into browser specific counterparts.
3258
	 * 
3259
	 * @param aCssToken $token
3260
	 * @return array
3261
	 */
3262
	private static function opacity($token)
3263
		{
3264
		// Calculate the value for Internet Explorer filter statement
3265
		$ieValue = (int) ((float) $token->Value * 100);
3266
		$r = array
3267
			(
3268
			// Internet Explorer >= 8
3269
			new CssRulesetDeclarationToken("-ms-filter", "\"alpha(opacity=" . $ieValue . ")\"", $token->MediaTypes),
3270
			// Internet Explorer >= 4 <= 7
3271
			new CssRulesetDeclarationToken("filter", "alpha(opacity=" . $ieValue . ")", $token->MediaTypes),
3272
			new CssRulesetDeclarationToken("zoom", "1", $token->MediaTypes)
3273
			);
3274
		return $r;
3275
		}
3276
	/**
3277
	 * Transforms "white-space: pre-wrap" into browser specific counterparts.
3278
	 * 
3279
	 * @param aCssToken $token
3280
	 * @return array
3281
	 */
3282
	private static function whiteSpace($token)
3283
		{
3284
		if (strtolower($token->Value) === "pre-wrap")
3285
			{
3286
			$r = array
3287
				(
3288
				// Firefox < 3
3289
				new CssRulesetDeclarationToken("white-space", "-moz-pre-wrap", $token->MediaTypes),
3290
				// Webkit
3291
				new CssRulesetDeclarationToken("white-space", "-webkit-pre-wrap", $token->MediaTypes),
3292
				// Opera >= 4 <= 6
3293
				new CssRulesetDeclarationToken("white-space", "-pre-wrap", $token->MediaTypes),
3294
				// Opera >= 7
3295
				new CssRulesetDeclarationToken("white-space", "-o-pre-wrap", $token->MediaTypes),
3296
				// Internet Explorer >= 5.5
3297
				new CssRulesetDeclarationToken("word-wrap", "break-word", $token->MediaTypes)
3298
				);
3299
			return $r;
3300
			}
3301
		else
3302
			{
3303
			return array();
3304
			}
3305
		}
3306
	}
3307
3308
/**
3309
 * This {@link aCssMinifierFilter minifier filter} will convert @keyframes at-rule block to browser specific counterparts.
3310
 * 
3311
 * @package		CssMin/Minifier/Filters
3312
 * @link		http://code.google.com/p/cssmin/
3313
 * @author		Joe Scylla <[email protected]>
3314
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3315
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3316
 * @version		3.0.1
3317
 */
3318
class CssConvertLevel3AtKeyframesMinifierFilter extends aCssMinifierFilter
3319
	{
3320
	/**
3321
	 * Implements {@link aCssMinifierFilter::filter()}.
3322
	 * 
3323
	 * @param array $tokens Array of objects of type aCssToken
3324
	 * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array
3325
	 */
3326
	public function apply(array &$tokens)
3327
		{
3328
		$r = 0;
3329
		$transformations = array("-moz-keyframes", "-webkit-keyframes");
3330
		for ($i = 0, $l = count($tokens); $i < $l; $i++)
3331
			{
3332
			if (get_class($tokens[$i]) === "CssAtKeyframesStartToken")
3333
				{
3334
				for ($ii = $i; $ii < $l; $ii++)
3335
					{
3336
					if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken")
3337
						{
3338
						break;
3339
						}
3340
					}
3341
				if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken")
3342
					{
3343
					$add	= array();
3344
					$source	= array();
3345
					for ($iii = $i; $iii <= $ii; $iii++)
3346
						{
3347
						$source[] = clone($tokens[$iii]);
3348
						}
3349
					foreach ($transformations as $transformation)
3350
						{
3351
						$t = array();
3352
						foreach ($source as $token)
3353
							{
3354
							$t[] = clone($token);
3355
							}
3356
						$t[0]->AtRuleName = $transformation;
3357
						$add = array_merge($add, $t);
3358
						}
3359
					if (isset($this->configuration["RemoveSource"]) && $this->configuration["RemoveSource"] === true)
3360
						{
3361
						array_splice($tokens, $i, $ii - $i + 1, $add);
3362
						}
3363
					else
3364
						{
3365
						array_splice($tokens, $ii + 1, 0, $add);
3366
						}
3367
					$l = count($tokens);
3368
					$i = $ii + count($add);
3369
					$r += count($add);
3370
					}
3371
				}
3372
			}
3373
		return $r;
3374
		}
3375
	}
3376
3377
/**
3378
 * This {@link aCssMinifierPlugin} will convert a color value in hsl notation to hexadecimal notation.
3379
 * 
3380
 * Example:
3381
 * <code>
3382
 * color: hsl(232,36%,48%);
3383
 * </code>
3384
 * 
3385
 * Will get converted to:
3386
 * <code>
3387
 * color:#4e5aa7;
3388
 * </code>
3389
 * 
3390
 * @package		CssMin/Minifier/Plugins
3391
 * @link		http://code.google.com/p/cssmin/
3392
 * @author		Joe Scylla <[email protected]>
3393
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3394
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3395
 * @version		3.0.1
3396
 */
3397
class CssConvertHslColorsMinifierPlugin extends aCssMinifierPlugin
3398
	{
3399
	/**
3400
	 * Regular expression matching the value.
3401
	 * 
3402
	 * @var string
3403
	 */
3404
	private $reMatch = "/^hsl\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*%\s*,\s*([0-9]+)\s*%\s*\)/iS";
3405
	/**
3406
	 * Implements {@link aCssMinifierPlugin::minify()}.
3407
	 * 
3408
	 * @param aCssToken $token Token to process
3409
	 * @return boolean Return TRUE to break the processing of this token; FALSE to continue
3410
	 */
3411
	public function apply(aCssToken &$token)
3412
		{
3413
		if (stripos($token->Value, "hsl") !== false && preg_match($this->reMatch, $token->Value, $m))
3414
			{
3415
			$token->Value = str_replace($m[0], $this->hsl2hex($m[1], $m[2], $m[3]), $token->Value);
3416
			}
3417
		return false;
3418
		}
3419
	/**
3420
	 * Implements {@link aMinifierPlugin::getTriggerTokens()}
3421
	 * 
3422
	 * @return array
3423
	 */
3424
	public function getTriggerTokens()
3425
		{
3426
		return array
3427
			(
3428
			"CssAtFontFaceDeclarationToken",
3429
			"CssAtPageDeclarationToken",
3430
			"CssRulesetDeclarationToken"
3431
			);
3432
		}
3433
	/**
3434
	 * Convert a HSL value to hexadecimal notation.
3435
	 * 
3436
	 * Based on: {@link http://www.easyrgb.com/index.php?X=MATH&H=19#text19}.
3437
	 * 
3438
	 * @param integer $hue Hue
3439
	 * @param integer $saturation Saturation
3440
	 * @param integer $lightness Lightnesss
3441
	 * @return string
3442
	 */
3443
	private function hsl2hex($hue, $saturation, $lightness)
3444
		{
3445
		$hue		= $hue / 360;
3446
		$saturation	= $saturation / 100;
3447
		$lightness	= $lightness / 100;
3448
		if ($saturation == 0)
3449
			{
3450
			$red	= $lightness * 255;
3451
			$green	= $lightness * 255;
3452
			$blue	= $lightness * 255;
3453
			}
3454
		else
3455
			{
3456
			if ($lightness < 0.5 )
3457
				{
3458
				$v2 = $lightness * (1 + $saturation);
3459
				}
3460
			else
3461
				{
3462
				$v2 = ($lightness + $saturation) - ($saturation * $lightness);
3463
				}
3464
			$v1		= 2 * $lightness - $v2;
3465
			$red	= 255 * self::hue2rgb($v1, $v2, $hue + (1 / 3));
0 ignored issues
show
Bug Best Practice introduced by
The method PHPWee\CssConvertHslColo...nifierPlugin::hue2rgb() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

3465
			$red	= 255 * self::/** @scrutinizer ignore-call */ hue2rgb($v1, $v2, $hue + (1 / 3));
Loading history...
3466
			$green	= 255 * self::hue2rgb($v1, $v2, $hue);
3467
			$blue	= 255 * self::hue2rgb($v1, $v2, $hue - (1 / 3));
3468
			}
3469
		return "#" . str_pad(dechex(round($red)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($green)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($blue)), 2, "0", STR_PAD_LEFT);
0 ignored issues
show
Bug introduced by
round($red) of type double is incompatible with the type integer expected by parameter $num of dechex(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3469
		return "#" . str_pad(dechex(/** @scrutinizer ignore-type */ round($red)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($green)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($blue)), 2, "0", STR_PAD_LEFT);
Loading history...
3470
		}
3471
	/**
3472
	 * Apply hue to a rgb color value.
3473
	 * 
3474
	 * @param integer $v1 Value 1
3475
	 * @param integer $v2 Value 2
3476
	 * @param integer $hue Hue
3477
	 * @return integer
3478
	 */
3479
	private function hue2rgb($v1, $v2, $hue)
3480
		{
3481
		if ($hue < 0)
3482
			{
3483
			$hue += 1;
3484
			}
3485
		if ($hue > 1)
3486
			{
3487
			$hue -= 1;
3488
			}
3489
		if ((6 * $hue) < 1)
3490
			{
3491
			return ($v1 + ($v2 - $v1) * 6 * $hue);
3492
			}
3493
		if ((2 * $hue) < 1)
3494
			{
3495
			return ($v2);
3496
			}
3497
		if ((3 * $hue) < 2)
3498
			{
3499
			return ($v1 + ($v2 - $v1) * (( 2 / 3) - $hue) * 6);
3500
			}
3501
		return $v1;
3502
		}
3503
	}
3504
3505
/**
3506
 * This {@link aCssMinifierPlugin} will convert the font-weight values normal and bold to their numeric notation.
3507
 * 
3508
 * Example:
3509
 * <code>
3510
 * font-weight: normal;
3511
 * font: bold 11px monospace;
3512
 * </code>
3513
 * 
3514
 * Will get converted to:
3515
 * <code>
3516
 * font-weight:400;
3517
 * font:700 11px monospace;
3518
 * </code>
3519
 *
3520
 * @package		CssMin/Minifier/Pluginsn
3521
 * @link		http://code.google.com/p/cssmin/
3522
 * @author		Joe Scylla <[email protected]>
3523
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3524
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3525
 * @version		3.0.1
3526
 */
3527
class CssConvertFontWeightMinifierPlugin extends aCssMinifierPlugin
3528
	{
3529
	/**
3530
	 * Array of included declaration properties this plugin will process; others declaration properties will get
3531
	 * ignored. 
3532
	 * 
3533
	 * @var array
3534
	 */
3535
	private $include = array
3536
		(
3537
		"font",
3538
		"font-weight"
3539
		);
3540
	/**
3541
	 * Regular expression matching the value.
3542
	 * 
3543
	 * @var string
3544
	 */
3545
	private $reMatch = null;
3546
	/**
3547
	 * Regular expression replace the value.
3548
	 * 
3549
	 * @var string
3550
	 */
3551
	private $reReplace = "\"\${1}\" . \$this->transformation[\"\${2}\"] . \"\${3}\"";
3552
	/**
3553
	 * Transformation table used by the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression}.
3554
	 * 
3555
	 * @var array
3556
	 */
3557
	private $transformation = array
3558
		(
3559
		"normal"	=> "400",
3560
 		"bold"		=> "700"
3561
		);
3562
	/**
3563
	 * Overwrites {@link aCssMinifierPlugin::__construct()}.
3564
	 * 
3565
	 * The constructor will create the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression}
3566
	 * based on the {@link CssConvertFontWeightMinifierPlugin::$transformation transformation table}.
3567
	 * 
3568
	 * @param CssMinifier $minifier The CssMinifier object of this plugin.
3569
	 * @return void
3570
	 */
3571
	public function __construct(CssMinifier $minifier)
3572
		{
3573
		$this->reMatch = "/(^|\s)+(" . implode("|", array_keys($this->transformation)). ")(\s|$)+/eiS";
3574
		parent::__construct($minifier);
3575
		}
3576
	/**
3577
	 * Implements {@link aCssMinifierPlugin::minify()}.
3578
	 * 
3579
	 * @param aCssToken $token Token to process
3580
	 * @return boolean Return TRUE to break the processing of this token; FALSE to continue
3581
	 */
3582
	public function apply(aCssToken &$token)
3583
		{
3584
		if (in_array($token->Property, $this->include) && preg_match($this->reMatch, $token->Value, $m))
3585
			{
3586
			$token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value);
3587
			}
3588
		return false;
3589
		}
3590
	/**
3591
	 * Implements {@link aMinifierPlugin::getTriggerTokens()}
3592
	 * 
3593
	 * @return array
3594
	 */
3595
	public function getTriggerTokens()
3596
		{
3597
		return array
3598
			(
3599
			"CssAtFontFaceDeclarationToken",
3600
			"CssAtPageDeclarationToken",
3601
			"CssRulesetDeclarationToken"
3602
			);
3603
		}
3604
	}
3605
3606
/**
3607
 * This {@link aCssMinifierPlugin} will compress several unit values to their short notations. Examples:
3608
 * 
3609
 * <code>
3610
 * padding: 0.5em;
3611
 * border: 0px;
3612
 * margin: 0 0 0 0;
3613
 * </code>
3614
 * 
3615
 * Will get compressed to:
3616
 * 
3617
 * <code>
3618
 * padding:.5px;
3619
 * border:0;
3620
 * margin:0;
3621
 * </code>
3622
 * 
3623
 * --
3624
 *
3625
 * @package		CssMin/Minifier/Plugins
3626
 * @link		http://code.google.com/p/cssmin/
3627
 * @author		Joe Scylla <[email protected]>
3628
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3629
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3630
 * @version		3.0.1
3631
 */
3632
class CssCompressUnitValuesMinifierPlugin extends aCssMinifierPlugin
3633
	{
3634
	/**
3635
	 * Regular expression used for matching and replacing unit values.
3636
	 * 
3637
	 * @var array
3638
	 */
3639
	private $re = array
3640
		(
3641
		"/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}.\${2}\${4}",
3642
		"/(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}0",
3643
		"/(^0\s0\s0\s0)|(^0\s0\s0$)|(^0\s0$)/iS" => "0"
3644
		);
3645
	/**
3646
	 * Regular expression matching the value.
3647
	 * 
3648
	 * @var string
3649
	 */
3650
	private $reMatch = "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)|(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)|(^0\s0\s0\s0$)|(^0\s0\s0$)|(^0\s0$)/iS";
3651
	/**
3652
	 * Implements {@link aCssMinifierPlugin::minify()}.
3653
	 * 
3654
	 * @param aCssToken $token Token to process
3655
	 * @return boolean Return TRUE to break the processing of this token; FALSE to continue
3656
	 */
3657
	public function apply(aCssToken &$token)
3658
		{
3659
		if (preg_match($this->reMatch, $token->Value))
3660
			{
3661
			foreach ($this->re as $reMatch => $reReplace)
3662
				{
3663
				$token->Value = preg_replace($reMatch, $reReplace, $token->Value);
3664
				}
3665
			}
3666
		return false;
3667
		}
3668
	/**
3669
	 * Implements {@link aMinifierPlugin::getTriggerTokens()}
3670
	 * 
3671
	 * @return array
3672
	 */
3673
	public function getTriggerTokens()
3674
		{
3675
		return array
3676
			(
3677
			"CssAtFontFaceDeclarationToken",
3678
			"CssAtPageDeclarationToken",
3679
			"CssRulesetDeclarationToken"
3680
			);
3681
		}
3682
	}
3683
3684
/**
3685
 * This {@link aCssMinifierPlugin} compress the content of expresssion() declaration values.
3686
 * 
3687
 * For compression of expressions {@link https://github.com/rgrove/jsmin-php/ JSMin} will get used. JSMin have to be 
3688
 * already included or loadable via {@link http://goo.gl/JrW54 PHP autoloading}. 
3689
 * 
3690
 * @package		CssMin/Minifier/Plugins
3691
 * @link		http://code.google.com/p/cssmin/
3692
 * @author		Joe Scylla <[email protected]>
3693
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3694
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3695
 * @version		3.0.1
3696
 */
3697
class CssCompressExpressionValuesMinifierPlugin extends aCssMinifierPlugin
3698
	{
3699
	/**
3700
	 * Implements {@link aCssMinifierPlugin::minify()}.
3701
	 * 
3702
	 * @param aCssToken $token Token to process
3703
	 * @return boolean Return TRUE to break the processing of this token; FALSE to continue
3704
	 */
3705
	public function apply(aCssToken &$token)
3706
		{
3707
		if (class_exists("JSMin") && stripos($token->Value, "expression(") !== false)
3708
			{
3709
			$value	= $token->Value;
0 ignored issues
show
Unused Code introduced by
The assignment to $value is dead and can be removed.
Loading history...
3710
			$value	= substr($token->Value, stripos($token->Value, "expression(") + 10);
3711
			$value	= trim(JSMin::minify($value));
3712
			$token->Value = "expression(" . $value . ")";
3713
			}
3714
		return false;
3715
		}
3716
	/**
3717
	 * Implements {@link aMinifierPlugin::getTriggerTokens()}
3718
	 * 
3719
	 * @return array
3720
	 */
3721
	public function getTriggerTokens()
3722
		{
3723
		return array
3724
			(
3725
			"CssAtFontFaceDeclarationToken",
3726
			"CssAtPageDeclarationToken",
3727
			"CssRulesetDeclarationToken"
3728
			);
3729
		}
3730
	}
3731
3732
/**
3733
 * This {@link aCssMinifierPlugin} will convert hexadecimal color value with 6 chars to their 3 char hexadecimal 
3734
 * notation (if possible). 
3735
 * 
3736
 * Example:
3737
 * <code>
3738
 * color: #aabbcc;
3739
 * </code>
3740
 * 
3741
 * Will get converted to:
3742
 * <code>
3743
 * color:#abc;
3744
 * </code>
3745
 * 
3746
 * @package		CssMin/Minifier/Plugins
3747
 * @link		http://code.google.com/p/cssmin/
3748
 * @author		Joe Scylla <[email protected]>
3749
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3750
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3751
 * @version		3.0.1
3752
 */
3753
class CssCompressColorValuesMinifierPlugin extends aCssMinifierPlugin
3754
	{
3755
	/**
3756
	 * Regular expression matching 6 char hexadecimal color values.
3757
	 * 
3758
	 * @var string
3759
	 */
3760
	private $reMatch = "/\#([0-9a-f]{6})/iS";
3761
	/**
3762
	 * Implements {@link aCssMinifierPlugin::minify()}.
3763
	 * 
3764
	 * @param aCssToken $token Token to process
3765
	 * @return boolean Return TRUE to break the processing of this token; FALSE to continue
3766
	 */
3767
	public function apply(aCssToken &$token)
3768
		{
3769
		if (strpos($token->Value, "#") !== false && preg_match($this->reMatch, $token->Value, $m))
3770
			{
3771
			$value = strtolower($m[1]);
3772
			if ($value[0] == $value[1] && $value[2] == $value[3] && $value[4] == $value[5])
3773
				{
3774
				$token->Value = str_replace($m[0], "#" . $value[0] . $value[2] . $value[4], $token->Value);
3775
				}
3776
			}
3777
		return false;
3778
		}
3779
	/**
3780
	 * Implements {@link aMinifierPlugin::getTriggerTokens()}
3781
	 * 
3782
	 * @return array
3783
	 */
3784
	public function getTriggerTokens()
3785
		{
3786
		return array
3787
			(
3788
			"CssAtFontFaceDeclarationToken",
3789
			"CssAtPageDeclarationToken",
3790
			"CssRulesetDeclarationToken"
3791
			);
3792
		}
3793
	}
3794
3795
/**
3796
 * This {@link aCssToken CSS token} represents a CSS comment.
3797
 * 
3798
 * @package		CssMin/Tokens
3799
 * @link		http://code.google.com/p/cssmin/
3800
 * @author		Joe Scylla <[email protected]>
3801
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3802
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3803
 * @version		3.0.1
3804
 */
3805
class CssCommentToken extends aCssToken
3806
	{
3807
	/**
3808
	 * Comment as Text.
3809
	 * 
3810
	 * @var string
3811
	 */
3812
	public $Comment = "";
3813
	/**
3814
	 * Set the properties of a comment token.
3815
	 * 
3816
	 * @param string $comment Comment including comment delimiters 
3817
	 * @return void
3818
	 */
3819
	public function __construct($comment)
3820
		{
3821
		$this->Comment = $comment;
3822
		}
3823
	/**
3824
	 * Implements {@link aCssToken::__toString()}.
3825
	 * 
3826
	 * @return string
3827
	 */
3828
	public function __toString()
3829
		{
3830
		return $this->Comment;
3831
		}
3832
	}
3833
3834
/**
3835
 * {@link aCssParserPlugin Parser plugin} for parsing comments.
3836
 * 
3837
 * Adds a {@link CssCommentToken} to the parser if a comment was found.
3838
 * 
3839
 * @package		CssMin/Parser/Plugins
3840
 * @link		http://code.google.com/p/cssmin/
3841
 * @author		Joe Scylla <[email protected]>
3842
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3843
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3844
 * @version		3.0.1
3845
 */
3846
class CssCommentParserPlugin extends aCssParserPlugin
3847
	{
3848
	/**
3849
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
3850
	 * 
3851
	 * @return array
3852
	 */
3853
	public function getTriggerChars()
3854
		{
3855
		return array("*", "/");
3856
		}
3857
	/**
3858
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
3859
	 * 
3860
	 * @return array
3861
	 */
3862
	public function getTriggerStates()
3863
		{
3864
		return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type array.
Loading history...
3865
		}
3866
	/**
3867
	 * Stored buffer for restore.
3868
	 * 
3869
	 * @var string
3870
	 */
3871
	private $restoreBuffer = "";
3872
	/**
3873
	 * Implements {@link aCssParserPlugin::parse()}.
3874
	 * 
3875
	 * @param integer $index Current index
3876
	 * @param string $char Current char
3877
	 * @param string $previousChar Previous char
3878
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
3879
	 */
3880
	public function parse($index, $char, $previousChar, $state)
3881
		{
3882
		if ($char === "*" && $previousChar === "/" && $state !== "T_COMMENT")
3883
			{
3884
			$this->parser->pushState("T_COMMENT");
0 ignored issues
show
Bug introduced by
'T_COMMENT' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3884
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_COMMENT");
Loading history...
3885
			$this->parser->setExclusive(__CLASS__);
3886
			$this->restoreBuffer = substr($this->parser->getAndClearBuffer(), 0, -2);
3887
			}
3888
		elseif ($char === "/" && $previousChar === "*" && $state === "T_COMMENT")
3889
			{
3890
			$this->parser->popState();
3891
			$this->parser->unsetExclusive();
3892
			$this->parser->appendToken(new CssCommentToken("/*" . $this->parser->getAndClearBuffer()));
3893
			$this->parser->setBuffer($this->restoreBuffer);
3894
			}
3895
		else
3896
			{
3897
			return false;
3898
			}
3899
		return true;
3900
		}
3901
	}
3902
3903
/**
3904
 * This {@link aCssToken CSS token} represents the start of a @variables at-rule block.
3905
 *
3906
 * @package		CssMin/Tokens
3907
 * @link		http://code.google.com/p/cssmin/
3908
 * @author		Joe Scylla <[email protected]>
3909
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3910
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3911
 * @version		3.0.1
3912
 */
3913
class CssAtVariablesStartToken extends aCssAtBlockStartToken
3914
	{
3915
	/**
3916
	 * Media types of the @variables at-rule block.
3917
	 * 
3918
	 * @var array
3919
	 */
3920
	public $MediaTypes = array();
3921
	/**
3922
	 * Set the properties of a @variables at-rule token.
3923
	 * 
3924
	 * @param array $mediaTypes Media types
3925
	 * @return void
3926
	 */
3927
	public function __construct($mediaTypes = null)
3928
		{
3929
		$this->MediaTypes = $mediaTypes ? $mediaTypes : array("all");
3930
		}
3931
	/**
3932
	 * Implements {@link aCssToken::__toString()}.
3933
	 * 
3934
	 * @return string
3935
	 */
3936
	public function __toString()
3937
		{
3938
		return "";
3939
		}
3940
	}
3941
3942
/**
3943
 * {@link aCssParserPlugin Parser plugin} for parsing @variables at-rule block with including declarations.
3944
 * 
3945
 * Found @variables at-rule blocks will add a {@link CssAtVariablesStartToken} and {@link CssAtVariablesEndToken} to the 
3946
 * parser; including declarations as {@link CssAtVariablesDeclarationToken}.
3947
 * 
3948
 * @package		CssMin/Parser/Plugins
3949
 * @link		http://code.google.com/p/cssmin/
3950
 * @author		Joe Scylla <[email protected]>
3951
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
3952
 * @license		http://opensource.org/licenses/mit-license.php MIT License
3953
 * @version		3.0.1
3954
 */
3955
class CssAtVariablesParserPlugin extends aCssParserPlugin
3956
	{
3957
	/**
3958
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
3959
	 * 
3960
	 * @return array
3961
	 */
3962
	public function getTriggerChars()
3963
		{
3964
		return array("@", "{", "}", ":", ";");
3965
		}
3966
	/**
3967
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
3968
	 * 
3969
	 * @return array
3970
	 */
3971
	public function getTriggerStates()
3972
		{
3973
		return array("T_DOCUMENT", "T_AT_VARIABLES::PREPARE", "T_AT_VARIABLES", "T_AT_VARIABLES_DECLARATION");
3974
		}
3975
	/**
3976
	 * Implements {@link aCssParserPlugin::parse()}.
3977
	 * 
3978
	 * @param integer $index Current index
3979
	 * @param string $char Current char
3980
	 * @param string $previousChar Previous char
3981
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
3982
	 */
3983
	public function parse($index, $char, $previousChar, $state)
3984
		{
3985
		// Start of @variables at-rule block
3986
		if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@variables")
3987
			{
3988
			$this->parser->pushState("T_AT_VARIABLES::PREPARE");
0 ignored issues
show
Bug introduced by
'T_AT_VARIABLES::PREPARE' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3988
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_AT_VARIABLES::PREPARE");
Loading history...
3989
			$this->parser->clearBuffer();
3990
			return $index + 10;
3991
			}
3992
		// Start of @variables declarations
3993
		elseif ($char === "{" && $state === "T_AT_VARIABLES::PREPARE")
3994
			{
3995
			$this->parser->setState("T_AT_VARIABLES");
0 ignored issues
show
Bug introduced by
'T_AT_VARIABLES' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::setState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

3995
			$this->parser->setState(/** @scrutinizer ignore-type */ "T_AT_VARIABLES");
Loading history...
3996
			$mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{"))));
3997
			$this->parser->appendToken(new CssAtVariablesStartToken($mediaTypes));
3998
			}
3999
		// Start of @variables declaration
4000
		if ($char === ":" && $state === "T_AT_VARIABLES")
4001
			{
4002
			$this->buffer = $this->parser->getAndClearBuffer(":");
4003
			$this->parser->pushState("T_AT_VARIABLES_DECLARATION");
4004
			}
4005
		// Unterminated @variables declaration
4006
		elseif ($char === ":" && $state === "T_AT_VARIABLES_DECLARATION")
4007
			{
4008
			// Ignore Internet Explorer filter declarations
4009
			if ($this->buffer === "filter")
4010
				{
4011
				return false;
4012
				}
4013
			CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @variables declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_"));
4014
			}
4015
		// End of @variables declaration
4016
		elseif (($char === ";" || $char === "}") && $state === "T_AT_VARIABLES_DECLARATION")
4017
			{
4018
			$value = $this->parser->getAndClearBuffer(";}");
4019
			if (strtolower(substr($value, -10, 10)) === "!important")
4020
				{
4021
				$value = trim(substr($value, 0, -10));
4022
				$isImportant = true;
4023
				}
4024
			else
4025
				{
4026
				$isImportant = false;
4027
				}
4028
			$this->parser->popState();
4029
			$this->parser->appendToken(new CssAtVariablesDeclarationToken($this->buffer, $value, $isImportant));
4030
			$this->buffer = "";
4031
			}
4032
		// End of @variables at-rule block
4033
		elseif ($char === "}" && $state === "T_AT_VARIABLES")
4034
			{
4035
			$this->parser->popState();
4036
			$this->parser->clearBuffer();
4037
			$this->parser->appendToken(new CssAtVariablesEndToken());
4038
			}
4039
		else
4040
			{
4041
			return false;
4042
			}
4043
		return true;
4044
		}
4045
	}
4046
4047
/**
4048
 * This {@link aCssToken CSS token} represents the end of a @variables at-rule block.
4049
 *
4050
 * @package		CssMin/Tokens
4051
 * @link		http://code.google.com/p/cssmin/
4052
 * @author		Joe Scylla <[email protected]>
4053
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4054
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4055
 * @version		3.0.1
4056
 */
4057
class CssAtVariablesEndToken extends aCssAtBlockEndToken
4058
	{
4059
	/**
4060
	 * Implements {@link aCssToken::__toString()}.
4061
	 * 
4062
	 * @return string
4063
	 */
4064
	public function __toString()
4065
		{
4066
		return "";
4067
		}
4068
	}
4069
4070
/**
4071
 * This {@link aCssToken CSS token} represents a declaration of a @variables at-rule block.
4072
 * 
4073
 * @package		CssMin/Tokens
4074
 * @link		http://code.google.com/p/cssmin/
4075
 * @author		Joe Scylla <[email protected]>
4076
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4077
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4078
 * @version		3.0.1
4079
 */
4080
class CssAtVariablesDeclarationToken extends aCssDeclarationToken
4081
	{
4082
	/**
4083
	 * Implements {@link aCssToken::__toString()}.
4084
	 * 
4085
	 * @return string
4086
	 */
4087
	public function __toString()
4088
		{
4089
		return "";
4090
		}
4091
	}
4092
4093
/**
4094
* This {@link aCssToken CSS token} represents the start of a @page at-rule block.
4095
 *
4096
 * @package		CssMin/Tokens
4097
 * @link		http://code.google.com/p/cssmin/
4098
 * @author		Joe Scylla <[email protected]>
4099
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4100
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4101
 * @version		3.0.1
4102
 */
4103
class CssAtPageStartToken extends aCssAtBlockStartToken
4104
	{
4105
	/**
4106
	 * Selector.
4107
	 * 
4108
	 * @var string
4109
	 */
4110
	public $Selector = "";
4111
	/**
4112
	 * Sets the properties of the @page at-rule.
4113
	 * 
4114
	 * @param string $selector Selector
4115
	 * @return void
4116
	 */
4117
	public function __construct($selector = "")
4118
		{
4119
		$this->Selector = $selector;
4120
		}
4121
	/**
4122
	 * Implements {@link aCssToken::__toString()}.
4123
	 * 
4124
	 * @return string
4125
	 */
4126
	public function __toString()
4127
		{
4128
		return "@page" . ($this->Selector ? " " . $this->Selector : "") . "{";
4129
		}
4130
	}
4131
4132
/**
4133
 * {@link aCssParserPlugin Parser plugin} for parsing @page at-rule block with including declarations.
4134
 * 
4135
 * Found @page at-rule blocks will add a {@link CssAtPageStartToken} and {@link CssAtPageEndToken} to the 
4136
 * parser; including declarations as {@link CssAtPageDeclarationToken}.
4137
 * 
4138
 * @package		CssMin/Parser/Plugins
4139
 * @link		http://code.google.com/p/cssmin/
4140
 * @author		Joe Scylla <[email protected]>
4141
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4142
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4143
 * @version		3.0.1
4144
 */
4145
class CssAtPageParserPlugin extends aCssParserPlugin
4146
	{
4147
	/**
4148
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
4149
	 * 
4150
	 * @return array
4151
	 */
4152
	public function getTriggerChars()
4153
		{
4154
		return array("@", "{", "}", ":", ";");
4155
		}
4156
	/**
4157
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
4158
	 * 
4159
	 * @return array
4160
	 */
4161
	public function getTriggerStates()
4162
		{
4163
		return array("T_DOCUMENT", "T_AT_PAGE::SELECTOR", "T_AT_PAGE", "T_AT_PAGE_DECLARATION");
4164
		}
4165
	/**
4166
	 * Implements {@link aCssParserPlugin::parse()}.
4167
	 * 
4168
	 * @param integer $index Current index
4169
	 * @param string $char Current char
4170
	 * @param string $previousChar Previous char
4171
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
4172
	 */
4173
	public function parse($index, $char, $previousChar, $state)
4174
		{
4175
		// Start of @page at-rule block
4176
		if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 5)) === "@page")
4177
			{
4178
			$this->parser->pushState("T_AT_PAGE::SELECTOR");
0 ignored issues
show
Bug introduced by
'T_AT_PAGE::SELECTOR' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4178
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_AT_PAGE::SELECTOR");
Loading history...
4179
			$this->parser->clearBuffer();
4180
			return $index + 5;
4181
			}
4182
		// Start of @page declarations
4183
		elseif ($char === "{" && $state === "T_AT_PAGE::SELECTOR")
4184
			{
4185
			$selector = $this->parser->getAndClearBuffer("{");
4186
			$this->parser->setState("T_AT_PAGE");
0 ignored issues
show
Bug introduced by
'T_AT_PAGE' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::setState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4186
			$this->parser->setState(/** @scrutinizer ignore-type */ "T_AT_PAGE");
Loading history...
4187
			$this->parser->clearBuffer();
4188
			$this->parser->appendToken(new CssAtPageStartToken($selector));
4189
			}
4190
		// Start of @page declaration
4191
		elseif ($char === ":" && $state === "T_AT_PAGE")
4192
			{
4193
			$this->parser->pushState("T_AT_PAGE_DECLARATION");
4194
			$this->buffer = $this->parser->getAndClearBuffer(":", true);
4195
			}
4196
		// Unterminated @font-face declaration
4197
		elseif ($char === ":" && $state === "T_AT_PAGE_DECLARATION")
4198
			{
4199
			// Ignore Internet Explorer filter declarations
4200
			if ($this->buffer === "filter")
4201
				{
4202
				return false;
4203
				}
4204
			CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @page declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_"));
4205
			}
4206
		// End of @page declaration
4207
		elseif (($char === ";" || $char === "}") && $state == "T_AT_PAGE_DECLARATION")
4208
			{
4209
			$value = $this->parser->getAndClearBuffer(";}");
4210
			if (strtolower(substr($value, -10, 10)) == "!important")
4211
				{
4212
				$value = trim(substr($value, 0, -10));
4213
				$isImportant = true;
4214
				}
4215
			else
4216
				{
4217
				$isImportant = false;
4218
				}
4219
			$this->parser->popState();
4220
			$this->parser->appendToken(new CssAtPageDeclarationToken($this->buffer, $value, $isImportant));
4221
			// --
4222
			if ($char === "}")
4223
				{
4224
				$this->parser->popState();
4225
				$this->parser->appendToken(new CssAtPageEndToken());
4226
				}
4227
			$this->buffer = "";
4228
			}
4229
		// End of @page at-rule block
4230
		elseif ($char === "}" && $state === "T_AT_PAGE")
4231
			{
4232
			$this->parser->popState();
4233
			$this->parser->clearBuffer();
4234
			$this->parser->appendToken(new CssAtPageEndToken());
4235
			}
4236
		else
4237
			{
4238
			return false;
4239
			}
4240
		return true;
4241
		}
4242
	}
4243
4244
/**
4245
 * This {@link aCssToken CSS token} represents the end of a @page at-rule block.
4246
 *
4247
 * @package		CssMin/Tokens
4248
 * @link		http://code.google.com/p/cssmin/
4249
 * @author		Joe Scylla <[email protected]>
4250
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4251
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4252
 * @version		3.0.1
4253
 */
4254
class CssAtPageEndToken extends aCssAtBlockEndToken
4255
	{
4256
	
4257
	}
4258
4259
/**
4260
 * This {@link aCssToken CSS token} represents a declaration of a @page at-rule block.
4261
 * 
4262
 * @package		CssMin/Tokens
4263
 * @link		http://code.google.com/p/cssmin/
4264
 * @author		Joe Scylla <[email protected]>
4265
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4266
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4267
 * @version		3.0.1
4268
 */
4269
class CssAtPageDeclarationToken extends aCssDeclarationToken
4270
	{
4271
	
4272
	}
4273
4274
/**
4275
 * This {@link aCssToken CSS token} represents the start of a @media at-rule block.
4276
 *
4277
 * @package		CssMin/Tokens
4278
 * @link		http://code.google.com/p/cssmin/
4279
 * @author		Joe Scylla <[email protected]>
4280
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4281
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4282
 * @version		3.0.1
4283
 */
4284
class CssAtMediaStartToken extends aCssAtBlockStartToken
4285
	{
4286
	/**
4287
	 * Sets the properties of the @media at-rule.
4288
	 * 
4289
	 * @param array $mediaTypes Media types
4290
	 * @return void
4291
	 */
4292
	public function __construct(array $mediaTypes = array())
4293
		{
4294
		$this->MediaTypes = $mediaTypes;
0 ignored issues
show
Bug Best Practice introduced by
The property MediaTypes does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
4295
		}
4296
	/**
4297
	 * Implements {@link aCssToken::__toString()}.
4298
	 * 
4299
	 * @return string
4300
	 */
4301
	public function __toString()
4302
		{
4303
		return "@media " . implode(",", $this->MediaTypes) . "{";
4304
		}
4305
	}
4306
4307
/**
4308
 * {@link aCssParserPlugin Parser plugin} for parsing @media at-rule block.
4309
 * 
4310
 * Found @media at-rule blocks will add a {@link CssAtMediaStartToken} and {@link CssAtMediaEndToken} to the parser. 
4311
 * This plugin will also set the the current media types using {@link CssParser::setMediaTypes()} and
4312
 * {@link CssParser::unsetMediaTypes()}.
4313
 *
4314
 * @package		CssMin/Parser/Plugins
4315
 * @link		http://code.google.com/p/cssmin/
4316
 * @author		Joe Scylla <[email protected]>
4317
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4318
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4319
 * @version		3.0.1
4320
 */
4321
class CssAtMediaParserPlugin extends aCssParserPlugin
4322
	{
4323
	/**
4324
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
4325
	 * 
4326
	 * @return array
4327
	 */
4328
	public function getTriggerChars()
4329
		{
4330
		return array("@", "{", "}");
4331
		}
4332
	/**
4333
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
4334
	 * 
4335
	 * @return array
4336
	 */
4337
	public function getTriggerStates()
4338
		{
4339
		return array("T_DOCUMENT", "T_AT_MEDIA::PREPARE", "T_AT_MEDIA");
4340
		}
4341
	/**
4342
	 * Implements {@link aCssParserPlugin::parse()}.
4343
	 * 
4344
	 * @param integer $index Current index
4345
	 * @param string $char Current char
4346
	 * @param string $previousChar Previous char
4347
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
4348
	 */
4349
	public function parse($index, $char, $previousChar, $state)
4350
		{
4351
		if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 6)) === "@media")
4352
			{
4353
			$this->parser->pushState("T_AT_MEDIA::PREPARE");
0 ignored issues
show
Bug introduced by
'T_AT_MEDIA::PREPARE' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4353
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_AT_MEDIA::PREPARE");
Loading history...
4354
			$this->parser->clearBuffer();
4355
			return $index + 6;
4356
			}
4357
		elseif ($char === "{" && $state === "T_AT_MEDIA::PREPARE")
4358
			{
4359
			$mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{"))));
4360
			$this->parser->setMediaTypes($mediaTypes);
4361
			$this->parser->setState("T_AT_MEDIA");
0 ignored issues
show
Bug introduced by
'T_AT_MEDIA' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::setState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4361
			$this->parser->setState(/** @scrutinizer ignore-type */ "T_AT_MEDIA");
Loading history...
4362
			$this->parser->appendToken(new CssAtMediaStartToken($mediaTypes));
4363
			}
4364
		elseif ($char === "}" && $state === "T_AT_MEDIA")
4365
			{
4366
			$this->parser->appendToken(new CssAtMediaEndToken());
4367
			$this->parser->clearBuffer();
4368
			$this->parser->unsetMediaTypes();
4369
			$this->parser->popState();
4370
			}
4371
		else
4372
			{
4373
			return false;
4374
			}
4375
		return true;
4376
		}
4377
	}
4378
4379
/**
4380
 * This {@link aCssToken CSS token} represents the end of a @media at-rule block.
4381
 *
4382
 * @package		CssMin/Tokens
4383
 * @link		http://code.google.com/p/cssmin/
4384
 * @author		Joe Scylla <[email protected]>
4385
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4386
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4387
 * @version		3.0.1
4388
 */
4389
class CssAtMediaEndToken extends aCssAtBlockEndToken
4390
	{
4391
	
4392
	}
4393
4394
/**
4395
 * This {@link aCssToken CSS token} represents the start of a @keyframes at-rule block.
4396
 *
4397
 * @package		CssMin/Tokens
4398
 * @link		http://code.google.com/p/cssmin/
4399
 * @author		Joe Scylla <[email protected]>
4400
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4401
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4402
 * @version		3.0.1
4403
 */
4404
class CssAtKeyframesStartToken extends aCssAtBlockStartToken
4405
	{
4406
	/**
4407
	 * Name of the at-rule.
4408
	 * 
4409
	 * @var string
4410
	 */
4411
	public $AtRuleName = "keyframes";
4412
	/**
4413
	 * Name
4414
	 * 
4415
	 * @var string
4416
	 */
4417
	public $Name = "";
4418
	/**
4419
	 * Sets the properties of the @page at-rule.
4420
	 * 
4421
	 * @param string $selector Selector
4422
	 * @return void
4423
	 */
4424
	public function __construct($name, $atRuleName = null)
4425
		{
4426
		$this->Name = $name;
4427
		if (!is_null($atRuleName))
4428
			{
4429
			$this->AtRuleName = $atRuleName;
4430
			}
4431
		}
4432
	/**
4433
	 * Implements {@link aCssToken::__toString()}.
4434
	 * 
4435
	 * @return string
4436
	 */
4437
	public function __toString()
4438
		{
4439
		return "@" . $this->AtRuleName . " \"" . $this->Name . "\"{";
4440
		}
4441
	}
4442
4443
/**
4444
 * This {@link aCssToken CSS token} represents the start of a ruleset of a @keyframes at-rule block.
4445
 * 
4446
 * @package		CssMin/Tokens
4447
 * @link		http://code.google.com/p/cssmin/
4448
 * @author		Joe Scylla <[email protected]>
4449
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4450
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4451
 * @version		3.0.1
4452
 */
4453
class CssAtKeyframesRulesetStartToken extends aCssRulesetStartToken
4454
	{
4455
	/**
4456
	 * Array of selectors.
4457
	 * 
4458
	 * @var array
4459
	 */
4460
	public $Selectors = array();
4461
	/**
4462
	 * Set the properties of a ruleset token.
4463
	 * 
4464
	 * @param array $selectors Selectors of the ruleset 
4465
	 * @return void
4466
	 */
4467
	public function __construct(array $selectors = array())
4468
		{
4469
		$this->Selectors = $selectors;
4470
		}
4471
	/**
4472
	 * Implements {@link aCssToken::__toString()}.
4473
	 * 
4474
	 * @return string
4475
	 */
4476
	public function __toString()
4477
		{
4478
		return implode(",", $this->Selectors) . "{";
4479
		}
4480
	}
4481
4482
/**
4483
 * This {@link aCssToken CSS token} represents the end of a ruleset of a @keyframes at-rule block.
4484
 * 
4485
 * @package		CssMin/Tokens
4486
 * @link		http://code.google.com/p/cssmin/
4487
 * @author		Joe Scylla <[email protected]>
4488
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4489
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4490
 * @version		3.0.1
4491
 */
4492
class CssAtKeyframesRulesetEndToken extends aCssRulesetEndToken
4493
	{
4494
	
4495
	}
4496
4497
/**
4498
 * This {@link aCssToken CSS token} represents a ruleset declaration of a @keyframes at-rule block.
4499
 *
4500
 * @package		CssMin/Tokens
4501
 * @link		http://code.google.com/p/cssmin/
4502
 * @author		Joe Scylla <[email protected]>
4503
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4504
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4505
 * @version		3.0.1
4506
 */
4507
class CssAtKeyframesRulesetDeclarationToken extends aCssDeclarationToken
4508
	{
4509
	
4510
	}
4511
4512
/**
4513
 * {@link aCssParserPlugin Parser plugin} for parsing @keyframes at-rule blocks, rulesets and declarations.
4514
 * 
4515
 * @package		CssMin/Parser/Plugins
4516
 * @link		http://code.google.com/p/cssmin/
4517
 * @author		Joe Scylla <[email protected]>
4518
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4519
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4520
 * @version		3.0.1
4521
 */
4522
class CssAtKeyframesParserPlugin extends aCssParserPlugin
4523
	{
4524
	/**
4525
	 * @var string Keyword
4526
	 */
4527
	private $atRuleName = "";
4528
	/**
4529
	 * Selectors.
4530
	 * 
4531
	 * @var array
4532
	 */
4533
	private $selectors = array();
4534
	/**
4535
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
4536
	 * 
4537
	 * @return array
4538
	 */
4539
	public function getTriggerChars()
4540
		{
4541
		return array("@", "{", "}", ":", ",", ";");
4542
		}
4543
	/**
4544
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
4545
	 * 
4546
	 * @return array
4547
	 */
4548
	public function getTriggerStates()
4549
		{
4550
		return array("T_DOCUMENT", "T_AT_KEYFRAMES::NAME", "T_AT_KEYFRAMES", "T_AT_KEYFRAMES_RULESETS", "T_AT_KEYFRAMES_RULESET", "T_AT_KEYFRAMES_RULESET_DECLARATION");
4551
		}
4552
	/**
4553
	 * Implements {@link aCssParserPlugin::parse()}.
4554
	 * 
4555
	 * @param integer $index Current index
4556
	 * @param string $char Current char
4557
	 * @param string $previousChar Previous char
4558
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
4559
	 */
4560
	public function parse($index, $char, $previousChar, $state)
4561
		{
4562
		// Start of @keyframes at-rule block
4563
		if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@keyframes") 
4564
			{
4565
			$this->atRuleName = "keyframes";
4566
			$this->parser->pushState("T_AT_KEYFRAMES::NAME");
0 ignored issues
show
Bug introduced by
'T_AT_KEYFRAMES::NAME' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4566
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_AT_KEYFRAMES::NAME");
Loading history...
4567
			$this->parser->clearBuffer();
4568
			return $index + 10;
4569
			}
4570
		// Start of @keyframes at-rule block (@-moz-keyframes)
4571
		elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 15)) === "@-moz-keyframes")
4572
			{
4573
			$this->atRuleName = "-moz-keyframes";
4574
			$this->parser->pushState("T_AT_KEYFRAMES::NAME");
4575
			$this->parser->clearBuffer();
4576
			return $index + 15;
4577
			}
4578
		// Start of @keyframes at-rule block (@-webkit-keyframes)
4579
		elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 18)) === "@-webkit-keyframes")
4580
			{
4581
			$this->atRuleName = "-webkit-keyframes";
4582
			$this->parser->pushState("T_AT_KEYFRAMES::NAME");
4583
			$this->parser->clearBuffer();
4584
			return $index + 18;
4585
			}
4586
		// Start of @keyframes rulesets
4587
		elseif ($char === "{" && $state === "T_AT_KEYFRAMES::NAME")
4588
			{
4589
			$name = $this->parser->getAndClearBuffer("{\"'");
4590
			$this->parser->setState("T_AT_KEYFRAMES_RULESETS");
0 ignored issues
show
Bug introduced by
'T_AT_KEYFRAMES_RULESETS' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::setState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4590
			$this->parser->setState(/** @scrutinizer ignore-type */ "T_AT_KEYFRAMES_RULESETS");
Loading history...
4591
			$this->parser->clearBuffer();
4592
			$this->parser->appendToken(new CssAtKeyframesStartToken($name, $this->atRuleName));
4593
			}
4594
		// Start of @keyframe ruleset and selectors
4595
		if ($char === "," && $state === "T_AT_KEYFRAMES_RULESETS")
4596
			{
4597
			$this->selectors[] = $this->parser->getAndClearBuffer(",{");
4598
			}
4599
		// Start of a @keyframes ruleset
4600
		elseif ($char === "{" && $state === "T_AT_KEYFRAMES_RULESETS")
4601
			{
4602
			if ($this->parser->getBuffer() !== "")
4603
				{
4604
				$this->selectors[] = $this->parser->getAndClearBuffer(",{");
4605
				$this->parser->pushState("T_AT_KEYFRAMES_RULESET");
4606
				$this->parser->appendToken(new CssAtKeyframesRulesetStartToken($this->selectors));
4607
				$this->selectors = array();
4608
				}
4609
			}
4610
		// Start of @keyframes ruleset declaration
4611
		elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET")
4612
			{
4613
			$this->parser->pushState("T_AT_KEYFRAMES_RULESET_DECLARATION");
4614
			$this->buffer = $this->parser->getAndClearBuffer(":;", true);
4615
			}
4616
		// Unterminated @keyframes ruleset declaration
4617
		elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION")
4618
			{
4619
			// Ignore Internet Explorer filter declarations
4620
			if ($this->buffer === "filter")
4621
				{
4622
				return false;
4623
				}
4624
			CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @keyframes ruleset declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_"));
4625
			}
4626
		// End of declaration
4627
		elseif (($char === ";" || $char === "}") && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION")
4628
			{
4629
			$value = $this->parser->getAndClearBuffer(";}");
4630
			if (strtolower(substr($value, -10, 10)) === "!important")
4631
				{
4632
				$value = trim(substr($value, 0, -10));
4633
				$isImportant = true;
4634
				}
4635
			else
4636
				{
4637
				$isImportant = false;
4638
				}
4639
			$this->parser->popState();
4640
			$this->parser->appendToken(new CssAtKeyframesRulesetDeclarationToken($this->buffer, $value, $isImportant));
4641
			// Declaration ends with a right curly brace; so we have to end the ruleset
4642
			if ($char === "}")
4643
				{
4644
				$this->parser->appendToken(new CssAtKeyframesRulesetEndToken());
4645
				$this->parser->popState();
4646
				}
4647
			$this->buffer = "";
4648
			}
4649
		// End of @keyframes ruleset
4650
		elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESET")
4651
			{
4652
			$this->parser->clearBuffer();
4653
			
4654
			$this->parser->popState();
4655
			$this->parser->appendToken(new CssAtKeyframesRulesetEndToken());
4656
			}
4657
		// End of @keyframes rulesets
4658
		elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESETS")
4659
			{
4660
			$this->parser->clearBuffer();
4661
			$this->parser->popState();
4662
			$this->parser->appendToken(new CssAtKeyframesEndToken());
4663
			}
4664
		else
4665
			{
4666
			return false;
4667
			}
4668
		return true;
4669
		}
4670
	}
4671
4672
/**
4673
 * This {@link aCssToken CSS token} represents the end of a @keyframes at-rule block.
4674
 *
4675
 * @package		CssMin/Tokens
4676
 * @link		http://code.google.com/p/cssmin/
4677
 * @author		Joe Scylla <[email protected]>
4678
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4679
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4680
 * @version		3.0.1
4681
 */
4682
class CssAtKeyframesEndToken extends aCssAtBlockEndToken
4683
	{
4684
	
4685
	}
4686
4687
/**
4688
 * This {@link aCssToken CSS token} represents a @import at-rule.
4689
 * 
4690
 * @package		CssMin/Tokens
4691
 * @link		http://code.google.com/p/cssmin/
4692
 * @author		Joe Scylla <[email protected]>
4693
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4694
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4695
 * @version		3.0.1.b1 (2001-02-22)
4696
 */
4697
class CssAtImportToken extends aCssToken
4698
	{
4699
	/**
4700
	 * Import path of the @import at-rule.
4701
	 * 
4702
	 * @var string
4703
	 */
4704
	public $Import = "";
4705
	/**
4706
	 * Media types of the @import at-rule.
4707
	 * 
4708
	 * @var array
4709
	 */
4710
	public $MediaTypes = array();
4711
	/**
4712
	 * Set the properties of a @import at-rule token.
4713
	 * 
4714
	 * @param string $import Import path
4715
	 * @param array $mediaTypes Media types
4716
	 * @return void
4717
	 */
4718
	public function __construct($import, $mediaTypes)
4719
		{
4720
		$this->Import		= $import;
4721
		$this->MediaTypes	= $mediaTypes ? $mediaTypes : array();
4722
		}
4723
	/**
4724
	 * Implements {@link aCssToken::__toString()}.
4725
	 * 
4726
	 * @return string
4727
	 */
4728
	public function __toString()
4729
		{
4730
		return "@import \"" . $this->Import . "\"" . (count($this->MediaTypes) > 0 ? " "  . implode(",", $this->MediaTypes) : ""). ";";
4731
		}
4732
	}
4733
4734
/**
4735
 * {@link aCssParserPlugin Parser plugin} for parsing @import at-rule.
4736
 * 
4737
 * If a @import at-rule was found this plugin will add a {@link CssAtImportToken} to the parser.
4738
 * 
4739
 * @package		CssMin/Parser/Plugins
4740
 * @link		http://code.google.com/p/cssmin/
4741
 * @author		Joe Scylla <[email protected]>
4742
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4743
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4744
 * @version		3.0.1
4745
 */
4746
class CssAtImportParserPlugin extends aCssParserPlugin
4747
	{
4748
	/**
4749
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
4750
	 * 
4751
	 * @return array
4752
	 */
4753
	public function getTriggerChars()
4754
		{
4755
		return array("@", ";", ",", "\n");
4756
		}
4757
	/**
4758
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
4759
	 * 
4760
	 * @return array
4761
	 */
4762
	public function getTriggerStates()
4763
		{
4764
		return array("T_DOCUMENT", "T_AT_IMPORT");
4765
		}
4766
	/**
4767
	 * Implements {@link aCssParserPlugin::parse()}.
4768
	 * 
4769
	 * @param integer $index Current index
4770
	 * @param string $char Current char
4771
	 * @param string $previousChar Previous char
4772
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
4773
	 */
4774
	public function parse($index, $char, $previousChar, $state)
4775
		{
4776
		if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 7)) === "@import")
4777
			{
4778
			$this->parser->pushState("T_AT_IMPORT");
0 ignored issues
show
Bug introduced by
'T_AT_IMPORT' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4778
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_AT_IMPORT");
Loading history...
4779
			$this->parser->clearBuffer();
4780
			return $index + 7;
4781
			}
4782
		elseif (($char === ";" || $char === "\n") && $state === "T_AT_IMPORT")
4783
			{
4784
			$this->buffer = $this->parser->getAndClearBuffer(";");
4785
			$pos = false;
4786
			foreach (array(")", "\"", "'") as $needle)
4787
				{
4788
				if (($pos = strrpos($this->buffer, $needle)) !== false)
4789
					{
4790
					break;
4791
					}
4792
				}
4793
			$import = substr($this->buffer, 0, $pos + 1);
4794
			if (stripos($import, "url(") === 0)
4795
				{
4796
				$import = substr($import, 4, -1);
4797
				}
4798
			$import = trim($import, " \t\n\r\0\x0B'\"");
4799
			$mediaTypes = array_filter(array_map("trim", explode(",", trim(substr($this->buffer, $pos + 1), " \t\n\r\0\x0B{"))));
4800
			if ($pos)
0 ignored issues
show
Bug Best Practice introduced by
The expression $pos of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
4801
				{
4802
				$this->parser->appendToken(new CssAtImportToken($import, $mediaTypes));
4803
				}
4804
			else
4805
				{
4806
				CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Invalid @import at-rule syntax", $this->parser->buffer));
0 ignored issues
show
Bug introduced by
The property buffer is declared private in PHPWee\CssParser and cannot be accessed from this context.
Loading history...
4807
				}
4808
			$this->parser->popState();
4809
			}
4810
		else
4811
			{
4812
			return false;
4813
			}
4814
		return true;
4815
		}
4816
	}
4817
4818
/**
4819
 * This {@link aCssToken CSS token} represents the start of a @font-face at-rule block.
4820
 *
4821
 * @package		CssMin/Tokens
4822
 * @link		http://code.google.com/p/cssmin/
4823
 * @author		Joe Scylla <[email protected]>
4824
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4825
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4826
 * @version		3.0.1
4827
 */
4828
class CssAtFontFaceStartToken extends aCssAtBlockStartToken
4829
	{
4830
	/**
4831
	 * Implements {@link aCssToken::__toString()}.
4832
	 * 
4833
	 * @return string
4834
	 */
4835
	public function __toString()
4836
		{
4837
		return "@font-face{";
4838
		}
4839
	}
4840
4841
/**
4842
 * {@link aCssParserPlugin Parser plugin} for parsing @font-face at-rule block with including declarations.
4843
 * 
4844
 * Found @font-face at-rule blocks will add a {@link CssAtFontFaceStartToken} and {@link CssAtFontFaceEndToken} to the 
4845
 * parser; including declarations as {@link CssAtFontFaceDeclarationToken}.
4846
 * 
4847
 * @package		CssMin/Parser/Plugins
4848
 * @link		http://code.google.com/p/cssmin/
4849
 * @author		Joe Scylla <[email protected]>
4850
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4851
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4852
 * @version		3.0.1
4853
 */
4854
class CssAtFontFaceParserPlugin extends aCssParserPlugin
4855
	{
4856
	/**
4857
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
4858
	 * 
4859
	 * @return array
4860
	 */
4861
	public function getTriggerChars()
4862
		{
4863
		return array("@", "{", "}", ":", ";");
4864
		}
4865
	/**
4866
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
4867
	 * 
4868
	 * @return array
4869
	 */
4870
	public function getTriggerStates()
4871
		{
4872
		return array("T_DOCUMENT", "T_AT_FONT_FACE::PREPARE", "T_AT_FONT_FACE", "T_AT_FONT_FACE_DECLARATION");
4873
		}
4874
	/**
4875
	 * Implements {@link aCssParserPlugin::parse()}.
4876
	 * 
4877
	 * @param integer $index Current index
4878
	 * @param string $char Current char
4879
	 * @param string $previousChar Previous char
4880
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
4881
	 */
4882
	public function parse($index, $char, $previousChar, $state)
4883
		{
4884
		// Start of @font-face at-rule block
4885
		if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@font-face")
4886
			{
4887
			$this->parser->pushState("T_AT_FONT_FACE::PREPARE");
0 ignored issues
show
Bug introduced by
'T_AT_FONT_FACE::PREPARE' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4887
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_AT_FONT_FACE::PREPARE");
Loading history...
4888
			$this->parser->clearBuffer();
4889
			return $index + 10;
4890
			}
4891
		// Start of @font-face declarations
4892
		elseif ($char === "{" && $state === "T_AT_FONT_FACE::PREPARE")
4893
			{
4894
			$this->parser->setState("T_AT_FONT_FACE");
0 ignored issues
show
Bug introduced by
'T_AT_FONT_FACE' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::setState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

4894
			$this->parser->setState(/** @scrutinizer ignore-type */ "T_AT_FONT_FACE");
Loading history...
4895
			$this->parser->clearBuffer();
4896
			$this->parser->appendToken(new CssAtFontFaceStartToken());
4897
			}
4898
		// Start of @font-face declaration
4899
		elseif ($char === ":" && $state === "T_AT_FONT_FACE")
4900
			{
4901
			$this->parser->pushState("T_AT_FONT_FACE_DECLARATION");
4902
			$this->buffer = $this->parser->getAndClearBuffer(":", true);
4903
			}
4904
		// Unterminated @font-face declaration
4905
		elseif ($char === ":" && $state === "T_AT_FONT_FACE_DECLARATION")
4906
			{
4907
			// Ignore Internet Explorer filter declarations
4908
			if ($this->buffer === "filter")
4909
				{
4910
				return false;
4911
				}
4912
			CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @font-face declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_"));
4913
			}
4914
		// End of @font-face declaration
4915
		elseif (($char === ";" || $char === "}") && $state === "T_AT_FONT_FACE_DECLARATION")
4916
			{
4917
			$value = $this->parser->getAndClearBuffer(";}");
4918
			if (strtolower(substr($value, -10, 10)) === "!important")
4919
				{
4920
				$value = trim(substr($value, 0, -10));
4921
				$isImportant = true;
4922
				}
4923
			else
4924
				{
4925
				$isImportant = false;
4926
				}
4927
			$this->parser->popState();
4928
			$this->parser->appendToken(new CssAtFontFaceDeclarationToken($this->buffer, $value, $isImportant));
4929
			$this->buffer = "";
4930
			// --
4931
			if ($char === "}")
4932
				{
4933
				$this->parser->appendToken(new CssAtFontFaceEndToken());
4934
				$this->parser->popState();
4935
				}
4936
			}
4937
		// End of @font-face at-rule block
4938
		elseif ($char === "}" && $state === "T_AT_FONT_FACE")
4939
			{
4940
			$this->parser->appendToken(new CssAtFontFaceEndToken());
4941
			$this->parser->clearBuffer();
4942
			$this->parser->popState();
4943
			}
4944
		else
4945
			{
4946
			return false;
4947
			}
4948
		return true;
4949
		}
4950
	}
4951
4952
/**
4953
 * This {@link aCssToken CSS token} represents the end of a @font-face at-rule block.
4954
 *
4955
 * @package		CssMin/Tokens
4956
 * @link		http://code.google.com/p/cssmin/
4957
 * @author		Joe Scylla <[email protected]>
4958
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4959
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4960
 * @version		3.0.1
4961
 */
4962
class CssAtFontFaceEndToken extends aCssAtBlockEndToken
4963
	{
4964
	
4965
	}
4966
4967
/**
4968
 * This {@link aCssToken CSS token} represents a declaration of a @font-face at-rule block.
4969
 *
4970
 * @package		CssMin/Tokens
4971
 * @link		http://code.google.com/p/cssmin/
4972
 * @author		Joe Scylla <[email protected]>
4973
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4974
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4975
 * @version		3.0.1
4976
 */
4977
class CssAtFontFaceDeclarationToken extends aCssDeclarationToken
4978
	{
4979
	
4980
	}
4981
4982
/**
4983
 * This {@link aCssToken CSS token} represents a @charset at-rule.
4984
 * 
4985
 * @package		CssMin/Tokens
4986
 * @link		http://code.google.com/p/cssmin/
4987
 * @author		Joe Scylla <[email protected]>
4988
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
4989
 * @license		http://opensource.org/licenses/mit-license.php MIT License
4990
 * @version		3.0.1
4991
 */
4992
class CssAtCharsetToken extends aCssToken
4993
	{
4994
	/**
4995
	 * Charset of the @charset at-rule.
4996
	 * 
4997
	 * @var string
4998
	 */
4999
	public $Charset = "";
5000
	/**
5001
	 * Set the properties of @charset at-rule token. 
5002
	 * 
5003
	 * @param string $charset Charset of the @charset at-rule token
5004
	 * @return void
5005
	 */
5006
	public function __construct($charset)
5007
		{
5008
		$this->Charset = $charset;
5009
		}
5010
	/**
5011
	 * Implements {@link aCssToken::__toString()}.
5012
	 * 
5013
	 * @return string
5014
	 */
5015
	public function __toString()
5016
		{
5017
		return "@charset " . $this->Charset . ";";
5018
		}
5019
	}
5020
5021
/**
5022
 * {@link aCssParserPlugin Parser plugin} for parsing @charset at-rule.
5023
 * 
5024
 * If a @charset at-rule was found this plugin will add a {@link CssAtCharsetToken} to the parser.
5025
 *
5026
 * @package		CssMin/Parser/Plugins
5027
 * @link		http://code.google.com/p/cssmin/
5028
 * @author		Joe Scylla <[email protected]>
5029
 * @copyright	2008 - 2011 Joe Scylla <[email protected]>
5030
 * @license		http://opensource.org/licenses/mit-license.php MIT License
5031
 * @version		3.0.1
5032
 */
5033
class CssAtCharsetParserPlugin extends aCssParserPlugin
5034
	{
5035
	/**
5036
	 * Implements {@link aCssParserPlugin::getTriggerChars()}.
5037
	 * 
5038
	 * @return array
5039
	 */
5040
	public function getTriggerChars()
5041
		{
5042
		return array("@", ";", "\n");
5043
		}
5044
	/**
5045
	 * Implements {@link aCssParserPlugin::getTriggerStates()}.
5046
	 * 
5047
	 * @return array
5048
	 */
5049
	public function getTriggerStates()
5050
		{
5051
		return array("T_DOCUMENT", "T_AT_CHARSET");
5052
		}
5053
	/**
5054
	 * Implements {@link aCssParserPlugin::parse()}.
5055
	 * 
5056
	 * @param integer $index Current index
5057
	 * @param string $char Current char
5058
	 * @param string $previousChar Previous char
5059
	 * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing
5060
	 */
5061
	public function parse($index, $char, $previousChar, $state)
5062
		{
5063
		if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 8)) === "@charset")
5064
			{
5065
			$this->parser->pushState("T_AT_CHARSET");
0 ignored issues
show
Bug introduced by
'T_AT_CHARSET' of type string is incompatible with the type integer expected by parameter $state of PHPWee\CssParser::pushState(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

5065
			$this->parser->pushState(/** @scrutinizer ignore-type */ "T_AT_CHARSET");
Loading history...
5066
			$this->parser->clearBuffer();
5067
			return $index + 8;
5068
			}
5069
		elseif (($char === ";" || $char === "\n") && $state === "T_AT_CHARSET")
5070
			{
5071
			$charset = $this->parser->getAndClearBuffer(";");
5072
			$this->parser->popState();
5073
			$this->parser->appendToken(new CssAtCharsetToken($charset));
5074
			}
5075
		else
5076
			{
5077
			return false;
5078
			}
5079
		return true;
5080
		}
5081
	}
5082
5083
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...