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