|
14 | 14 | use Sabberworm\CSS\CSSList\AtRuleBlockList; |
15 | 15 | use Sabberworm\CSS\RuleSet\DeclarationBlock; |
16 | 16 | use Sabberworm\CSS\Value\CSSFunction; |
| 17 | +use Sabberworm\CSS\Value\CalcFunction; |
17 | 18 | use Sabberworm\CSS\Value\RuleValueList; |
| 19 | +use Sabberworm\CSS\Value\CalcRuleValueList; |
18 | 20 | use Sabberworm\CSS\Value\Size; |
19 | 21 | use Sabberworm\CSS\Value\Color; |
20 | 22 | use Sabberworm\CSS\Value\URL; |
@@ -434,6 +436,8 @@ private function parsePrimitiveValue() { |
434 | 436 | $oValue = $this->parseColorValue(); |
435 | 437 | } else if ($this->comes('url', true)) { |
436 | 438 | $oValue = $this->parseURLValue(); |
| 439 | + } else if ($this->comes('calc', true) || $this->comes('-webkit-calc', true) || $this->comes('-moz-calc', true)) { |
| 440 | + $oValue = $this->parseCalcValue(); |
437 | 441 | } else if ($this->comes("'") || $this->comes('"')) { |
438 | 442 | $oValue = $this->parseStringValue(); |
439 | 443 | } else if ($this->comes("progid:") && $this->oParserSettings->bLenientParsing) { |
@@ -520,6 +524,42 @@ private function parseURLValue() { |
520 | 524 | return $oResult; |
521 | 525 | } |
522 | 526 |
|
| 527 | + private function parseCalcValue() { |
| 528 | + $aOperators = array('+', '-', '*', '/', '(', ')'); |
| 529 | + $sFunction = trim($this->consumeUntil('(', false, true)); |
| 530 | + $oCalcList = new CalcRuleValueList($this->iLineNo); |
| 531 | + $oList = new RuleValueList(',', $this->iLineNo); |
| 532 | + $iNestingLevel = 0; |
| 533 | + $iLastComponentType = NULL; |
| 534 | + while(!$this->comes(')') || $iNestingLevel > 0) { |
| 535 | + $this->consumeWhiteSpace(); |
| 536 | + if (in_array($this->peek(), $aOperators)) { |
| 537 | + if (($this->comes('-') || $this->comes('+'))) { |
| 538 | + if ($this->peek(1, -1) != ' ' || !($this->comes('- ') || $this->comes('+ '))) { |
| 539 | + throw new UnexpectedTokenException(" {$this->peek()} ", $this->peek(1, -1) . $this->peek(2), 'literal', $this->iLineNo); |
| 540 | + } |
| 541 | + } else if ($this->comes('(')) { |
| 542 | + $iNestingLevel++; |
| 543 | + } else if ($this->comes(')')) { |
| 544 | + $iNestingLevel--; |
| 545 | + } |
| 546 | + $oCalcList->addListComponent($this->consume(1)); |
| 547 | + $iLastComponentType = CalcFunction::T_OPERATOR; |
| 548 | + } else { |
| 549 | + $oVal = $this->parsePrimitiveValue(); |
| 550 | + if ($iLastComponentType == CalcFunction::T_OPERAND) { |
| 551 | + throw new UnexpectedTokenException(sprintf('Next token was expected to be an operand of type %s. Instead "%s" was found.', implode(', ', $aOperators), $oVal), '', 'custom', $this->iLineNo); |
| 552 | + } |
| 553 | + |
| 554 | + $oCalcList->addListComponent($oVal); |
| 555 | + $iLastComponentType = CalcFunction::T_OPERAND; |
| 556 | + } |
| 557 | + } |
| 558 | + $oList->addListComponent($oCalcList); |
| 559 | + $this->consume(')'); |
| 560 | + return new CalcFunction($sFunction, $oList, ',', $this->iLineNo); |
| 561 | + } |
| 562 | + |
523 | 563 | /** |
524 | 564 | * Tests an identifier for a given value. Since identifiers are all keywords, they can be vendor-prefixed. We need to check for these versions too. |
525 | 565 | */ |
|
0 commit comments