MDL-65759 library: Update php-css-parser to 8.3.0
[moodle.git] / lib / php-css-parser / Value / Value.php
1 <?php
3 namespace Sabberworm\CSS\Value;
5 use Sabberworm\CSS\Parsing\ParserState;
6 use Sabberworm\CSS\Parsing\UnexpectedTokenException;
7 use Sabberworm\CSS\Renderable;
9 abstract class Value implements Renderable {
10         protected $iLineNo;
12         public function __construct($iLineNo = 0) {
13                 $this->iLineNo = $iLineNo;
14         }
16         public static function parseValue(ParserState $oParserState, $aListDelimiters = array()) {
17                 $aStack = array();
18                 $oParserState->consumeWhiteSpace();
19                 //Build a list of delimiters and parsed values
20                 while (!($oParserState->comes('}') || $oParserState->comes(';') || $oParserState->comes('!') || $oParserState->comes(')') || $oParserState->comes('\\'))) {
21                         if (count($aStack) > 0) {
22                                 $bFoundDelimiter = false;
23                                 foreach ($aListDelimiters as $sDelimiter) {
24                                         if ($oParserState->comes($sDelimiter)) {
25                                                 array_push($aStack, $oParserState->consume($sDelimiter));
26                                                 $oParserState->consumeWhiteSpace();
27                                                 $bFoundDelimiter = true;
28                                                 break;
29                                         }
30                                 }
31                                 if (!$bFoundDelimiter) {
32                                         //Whitespace was the list delimiter
33                                         array_push($aStack, ' ');
34                                 }
35                         }
36                         array_push($aStack, self::parsePrimitiveValue($oParserState));
37                         $oParserState->consumeWhiteSpace();
38                 }
39                 //Convert the list to list objects
40                 foreach ($aListDelimiters as $sDelimiter) {
41                         if (count($aStack) === 1) {
42                                 return $aStack[0];
43                         }
44                         $iStartPosition = null;
45                         while (($iStartPosition = array_search($sDelimiter, $aStack, true)) !== false) {
46                                 $iLength = 2; //Number of elements to be joined
47                                 for ($i = $iStartPosition + 2; $i < count($aStack); $i+=2, ++$iLength) {
48                                         if ($sDelimiter !== $aStack[$i]) {
49                                                 break;
50                                         }
51                                 }
52                                 $oList = new RuleValueList($sDelimiter, $oParserState->currentLine());
53                                 for ($i = $iStartPosition - 1; $i - $iStartPosition + 1 < $iLength * 2; $i+=2) {
54                                         $oList->addListComponent($aStack[$i]);
55                                 }
56                                 array_splice($aStack, $iStartPosition - 1, $iLength * 2 - 1, array($oList));
57                         }
58                 }
59                 if (!isset($aStack[0])) {
60                         throw new UnexpectedTokenException(" {$oParserState->peek()} ", $oParserState->peek(1, -1) . $oParserState->peek(2), 'literal', $oParserState->currentLine());
61                 }
62                 return $aStack[0];
63         }
65         public static function parseIdentifierOrFunction(ParserState $oParserState, $bIgnoreCase = false) {
66                 $sResult = $oParserState->parseIdentifier($bIgnoreCase);
68                 if ($oParserState->comes('(')) {
69                         $oParserState->consume('(');
70                         $aArguments = Value::parseValue($oParserState, array('=', ' ', ','));
71                         $sResult = new CSSFunction($sResult, $aArguments, ',', $oParserState->currentLine());
72                         $oParserState->consume(')');
73                 }
75                 return $sResult;
76         }
78         public static function parsePrimitiveValue(ParserState $oParserState) {
79                 $oValue = null;
80                 $oParserState->consumeWhiteSpace();
81                 if (is_numeric($oParserState->peek()) || ($oParserState->comes('-.') && is_numeric($oParserState->peek(1, 2))) || (($oParserState->comes('-') || $oParserState->comes('.')) && is_numeric($oParserState->peek(1, 1)))) {
82                         $oValue = Size::parse($oParserState);
83                 } else if ($oParserState->comes('#') || $oParserState->comes('rgb', true) || $oParserState->comes('hsl', true)) {
84                         $oValue = Color::parse($oParserState);
85                 } else if ($oParserState->comes('url', true)) {
86                         $oValue = URL::parse($oParserState);
87                 } else if ($oParserState->comes('calc', true) || $oParserState->comes('-webkit-calc', true) || $oParserState->comes('-moz-calc', true)) {
88                         $oValue = CalcFunction::parse($oParserState);
89                 } else if ($oParserState->comes("'") || $oParserState->comes('"')) {
90                         $oValue = CSSString::parse($oParserState);
91                 } else if ($oParserState->comes("progid:") && $oParserState->getSettings()->bLenientParsing) {
92                         $oValue = self::parseMicrosoftFilter($oParserState);
93                 } else if ($oParserState->comes("[")) {
94                         $oValue = LineName::parse($oParserState);
95                 } else if ($oParserState->comes("U+")) {
96                         $oValue = self::parseUnicodeRangeValue($oParserState);
97                 } else {
98                         $oValue = self::parseIdentifierOrFunction($oParserState);
99                 }
100                 $oParserState->consumeWhiteSpace();
101                 return $oValue;
102         }
104         private static function parseMicrosoftFilter(ParserState $oParserState) {
105                 $sFunction = $oParserState->consumeUntil('(', false, true);
106                 $aArguments = Value::parseValue($oParserState, array(',', '='));
107                 return new CSSFunction($sFunction, $aArguments, ',', $oParserState->currentLine());
108         }
110         private static function parseUnicodeRangeValue(ParserState $oParserState) {
111                 $iCodepointMaxLenth = 6; // Code points outside BMP can use up to six digits
112                 $sRange = "";
113                 $oParserState->consume("U+");
114                 do {
115                         if ($oParserState->comes('-')) $iCodepointMaxLenth = 13; // Max length is 2 six digit code points + the dash(-) between them
116                         $sRange .= $oParserState->consume(1);
117                 } while (strlen($sRange) < $iCodepointMaxLenth && preg_match("/[A-Fa-f0-9\?-]/", $oParserState->peek()));
118                 return "U+{$sRange}";
119         }
120         
121         /**
122          * @return int
123          */
124         public function getLineNo() {
125                 return $this->iLineNo;
126         }
128         //Methods are commented out because re-declaring them here is a fatal error in PHP < 5.3.9
129         //public abstract function __toString();
130         //public abstract function render(\Sabberworm\CSS\OutputFormat $oOutputFormat);