From 3bc5ded67d77a52b81608cfc97f23b1bb0678e2f Mon Sep 17 00:00:00 2001 From: Pierre Gordon Date: Wed, 6 May 2020 15:41:19 -0400 Subject: [PATCH 1/7] Change turns to turn --- lib/Sabberworm/CSS/Value/Size.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sabberworm/CSS/Value/Size.php b/lib/Sabberworm/CSS/Value/Size.php index 8490cc35..05f41ea7 100644 --- a/lib/Sabberworm/CSS/Value/Size.php +++ b/lib/Sabberworm/CSS/Value/Size.php @@ -8,7 +8,7 @@ class Size extends PrimitiveValue { const ABSOLUTE_SIZE_UNITS = 'px/cm/mm/mozmm/in/pt/pc/vh/vw/vmin/vmax/rem'; //vh/vw/vm(ax)/vmin/rem are absolute insofar as they don’t scale to the immediate parent (only the viewport) const RELATIVE_SIZE_UNITS = '%/em/ex/ch/fr'; - const NON_SIZE_UNITS = 'deg/grad/rad/s/ms/turns/Hz/kHz'; + const NON_SIZE_UNITS = 'deg/grad/rad/s/ms/turn/Hz/kHz'; private static $SIZE_UNITS = null; From a47aecb81c11459a6f7b955fb54a0b240bdf1ae8 Mon Sep 17 00:00:00 2001 From: Pierre Gordon Date: Mon, 11 May 2020 03:16:27 -0400 Subject: [PATCH 2/7] Output correct size unit in lenient mode; fail if unit not valid --- lib/Sabberworm/CSS/Value/Size.php | 15 +++++++++++++-- tests/Sabberworm/CSS/ParserTest.php | 18 ++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/Sabberworm/CSS/Value/Size.php b/lib/Sabberworm/CSS/Value/Size.php index 05f41ea7..26ce9aa1 100644 --- a/lib/Sabberworm/CSS/Value/Size.php +++ b/lib/Sabberworm/CSS/Value/Size.php @@ -3,6 +3,7 @@ namespace Sabberworm\CSS\Value; use Sabberworm\CSS\Parsing\ParserState; +use Sabberworm\CSS\Parsing\UnexpectedTokenException; class Size extends PrimitiveValue { @@ -38,11 +39,21 @@ public static function parse(ParserState $oParserState, $bIsColorComponent = fal $sUnit = null; $aSizeUnits = self::getSizeUnits(); - foreach($aSizeUnits as $iLength => &$aValues) { + $sUnit = strtolower($oParserState->parseIdentifier()); + $oParserState->backtrack(strlen($sUnit)); + + foreach($aSizeUnits as $iLength => $aValues) { + $iConsumeLength = $iLength; $sKey = strtolower($oParserState->peek($iLength)); if(array_key_exists($sKey, $aValues)) { + if ($sUnit !== $sKey) { + if (!$oParserState->getSettings()->bLenientParsing) { + throw new UnexpectedTokenException('Unit', $sUnit, 'identifier', $oParserState->currentLine()); + } + $iConsumeLength = strlen($sUnit); + } if (($sUnit = $aValues[$sKey]) !== null) { - $oParserState->consume($iLength); + $oParserState->consume($iConsumeLength); break; } } diff --git a/tests/Sabberworm/CSS/ParserTest.php b/tests/Sabberworm/CSS/ParserTest.php index 4a690196..e457f99d 100644 --- a/tests/Sabberworm/CSS/ParserTest.php +++ b/tests/Sabberworm/CSS/ParserTest.php @@ -787,4 +787,22 @@ function testLonelyImport() { $sExpected = "@import url(\"example.css\") only screen and (max-width: 600px);"; $this->assertSame($sExpected, $oDoc->render()); } + + function testTurnUnitLenient() { + $sText = ".foo {transform: rotate(1turn);}\n.bar {transform: rotate(1turns);}"; + $sExpected = ".foo {transform: rotate(1turn);}\n.bar {transform: rotate(1turn);}"; + + $oParser = new Parser($sText); + $this->assertSame($sExpected, $oParser->parse()->render()); + } + + function testTurnUnitStrict() { + $sText = ".foo {transform: rotate(1turn);}\n.bar {transform: rotate(1turns);}"; + + $oParser = new Parser($sText, Settings::create()->beStrict()); + + // Line 2 contains the invalid unit and so should be reported. + $this->setExpectedException( 'Sabberworm\CSS\Parsing\UnexpectedTokenException', 'Identifier expected. Got “turns” [line no: 2]' ); + $oParser->parse(); + } } From 0d97ce8ae1d2e52dceefe3598aad539d1499cdc3 Mon Sep 17 00:00:00 2001 From: Pierre Gordon Date: Mon, 11 May 2020 11:50:58 -0400 Subject: [PATCH 3/7] Fix parsing unit --- lib/Sabberworm/CSS/Value/Size.php | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/lib/Sabberworm/CSS/Value/Size.php b/lib/Sabberworm/CSS/Value/Size.php index 26ce9aa1..ef128984 100644 --- a/lib/Sabberworm/CSS/Value/Size.php +++ b/lib/Sabberworm/CSS/Value/Size.php @@ -37,20 +37,36 @@ public static function parse(ParserState $oParserState, $bIsColorComponent = fal } } - $sUnit = null; - $aSizeUnits = self::getSizeUnits(); - $sUnit = strtolower($oParserState->parseIdentifier()); - $oParserState->backtrack(strlen($sUnit)); + $sParsedUnit = ''; + $iOffset = 0; + while (true) { + $sChar = $oParserState->peek(1, $iOffset); + $iPeek = ord($sChar); + + // Ranges: a-z A-Z 0-9 % + if (($iPeek >= 97 && $iPeek <= 122) || + ($iPeek >= 65 && $iPeek <= 90) || + ($iPeek >= 48 && $iPeek <= 57) || + ($iPeek === 37)) { + $sParsedUnit .= $sChar; + $iOffset++; + } else { + break; + } + } + + $sUnit = null; + $aSizeUnits = self::getSizeUnits(); foreach($aSizeUnits as $iLength => $aValues) { $iConsumeLength = $iLength; $sKey = strtolower($oParserState->peek($iLength)); if(array_key_exists($sKey, $aValues)) { - if ($sUnit !== $sKey) { + if (strtolower($sParsedUnit) !== $sKey) { if (!$oParserState->getSettings()->bLenientParsing) { - throw new UnexpectedTokenException('Unit', $sUnit, 'identifier', $oParserState->currentLine()); + throw new UnexpectedTokenException('Unit', $sParsedUnit, 'identifier', $oParserState->currentLine()); } - $iConsumeLength = strlen($sUnit); + $iConsumeLength = strlen($sParsedUnit); } if (($sUnit = $aValues[$sKey]) !== null) { $oParserState->consume($iConsumeLength); From 44e0e30a0e1b4b322fa6fae39eb26854d44c83bb Mon Sep 17 00:00:00 2001 From: Pierre Gordon Date: Mon, 11 May 2020 15:21:45 -0400 Subject: [PATCH 4/7] Revert truncation of unit --- lib/Sabberworm/CSS/Value/Size.php | 50 +++++++++++++---------------- tests/Sabberworm/CSS/ParserTest.php | 26 +++++++-------- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/lib/Sabberworm/CSS/Value/Size.php b/lib/Sabberworm/CSS/Value/Size.php index ef128984..e26a3541 100644 --- a/lib/Sabberworm/CSS/Value/Size.php +++ b/lib/Sabberworm/CSS/Value/Size.php @@ -37,39 +37,35 @@ public static function parse(ParserState $oParserState, $bIsColorComponent = fal } } - $sParsedUnit = ''; - $iOffset = 0; + $sParsedUnit = ''; + $iOffset = 0; while (true) { - $sChar = $oParserState->peek(1, $iOffset); - $iPeek = ord($sChar); - - // Ranges: a-z A-Z 0-9 % - if (($iPeek >= 97 && $iPeek <= 122) || - ($iPeek >= 65 && $iPeek <= 90) || - ($iPeek >= 48 && $iPeek <= 57) || - ($iPeek === 37)) { - $sParsedUnit .= $sChar; - $iOffset++; - } else { - break; - } - } - - $sUnit = null; - $aSizeUnits = self::getSizeUnits(); + $sChar = $oParserState->peek(1, $iOffset); + $iPeek = ord($sChar); + + // Ranges: a-z A-Z 0-9 % + if (($iPeek >= 97 && $iPeek <= 122) || + ($iPeek >= 65 && $iPeek <= 90) || + ($iPeek >= 48 && $iPeek <= 57) || + ($iPeek === 37)) { + $sParsedUnit .= $sChar; + $iOffset++; + } else { + break; + } + } + + $sUnit = null; + $aSizeUnits = self::getSizeUnits(); foreach($aSizeUnits as $iLength => $aValues) { - $iConsumeLength = $iLength; $sKey = strtolower($oParserState->peek($iLength)); if(array_key_exists($sKey, $aValues)) { - if (strtolower($sParsedUnit) !== $sKey) { - if (!$oParserState->getSettings()->bLenientParsing) { - throw new UnexpectedTokenException('Unit', $sParsedUnit, 'identifier', $oParserState->currentLine()); - } - $iConsumeLength = strlen($sParsedUnit); - } + if (strtolower($sParsedUnit) !== $sKey) { + throw new UnexpectedTokenException('Unit', $sParsedUnit, 'identifier', $oParserState->currentLine()); + } if (($sUnit = $aValues[$sKey]) !== null) { - $oParserState->consume($iConsumeLength); + $oParserState->consume($iLength); break; } } diff --git a/tests/Sabberworm/CSS/ParserTest.php b/tests/Sabberworm/CSS/ParserTest.php index e457f99d..6ef74bbb 100644 --- a/tests/Sabberworm/CSS/ParserTest.php +++ b/tests/Sabberworm/CSS/ParserTest.php @@ -788,21 +788,21 @@ function testLonelyImport() { $this->assertSame($sExpected, $oDoc->render()); } - function testTurnUnitLenient() { - $sText = ".foo {transform: rotate(1turn);}\n.bar {transform: rotate(1turns);}"; - $sExpected = ".foo {transform: rotate(1turn);}\n.bar {transform: rotate(1turn);}"; + function testTurnUnitLenient() { + $sText = ".foo {transform: rotate(1turn);}\n.bar {transform: rotate(1turns);}"; + $sExpected = ".foo {transform: rotate(1turn);}\n.bar {}"; - $oParser = new Parser($sText); - $this->assertSame($sExpected, $oParser->parse()->render()); - } + $oParser = new Parser($sText); + $this->assertSame($sExpected, $oParser->parse()->render()); + } - function testTurnUnitStrict() { - $sText = ".foo {transform: rotate(1turn);}\n.bar {transform: rotate(1turns);}"; + function testTurnUnitStrict() { + $sText = ".foo {transform: rotate(1turn);}\n.bar {transform: rotate(1turns);}"; - $oParser = new Parser($sText, Settings::create()->beStrict()); + $oParser = new Parser($sText, Settings::create()->beStrict()); - // Line 2 contains the invalid unit and so should be reported. - $this->setExpectedException( 'Sabberworm\CSS\Parsing\UnexpectedTokenException', 'Identifier expected. Got “turns” [line no: 2]' ); - $oParser->parse(); - } + // Line 2 contains the invalid unit and so should be reported. + $this->setExpectedException( 'Sabberworm\CSS\Parsing\UnexpectedTokenException', 'Identifier expected. Got “turns” [line no: 2]' ); + $oParser->parse(); + } } From de5a660f317fb21ca4d1bfe5b575c591652e49cd Mon Sep 17 00:00:00 2001 From: Pierre Gordon Date: Mon, 11 May 2020 17:10:41 -0400 Subject: [PATCH 5/7] Simplify logic for parsing size unit --- lib/Sabberworm/CSS/Value/Size.php | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/lib/Sabberworm/CSS/Value/Size.php b/lib/Sabberworm/CSS/Value/Size.php index e26a3541..9cfe8909 100644 --- a/lib/Sabberworm/CSS/Value/Size.php +++ b/lib/Sabberworm/CSS/Value/Size.php @@ -37,27 +37,15 @@ public static function parse(ParserState $oParserState, $bIsColorComponent = fal } } - $sParsedUnit = ''; - $iOffset = 0; - while (true) { - $sChar = $oParserState->peek(1, $iOffset); - $iPeek = ord($sChar); - - // Ranges: a-z A-Z 0-9 % - if (($iPeek >= 97 && $iPeek <= 122) || - ($iPeek >= 65 && $iPeek <= 90) || - ($iPeek >= 48 && $iPeek <= 57) || - ($iPeek === 37)) { - $sParsedUnit .= $sChar; - $iOffset++; - } else { - break; - } - } - $sUnit = null; + $sParsedUnit = null; $aSizeUnits = self::getSizeUnits(); + $iMaxSizeUnitLength = max(array_keys($aSizeUnits)); + if ( preg_match( '/^[a-zA-Z0-9%]+/', $oParserState->peek($iMaxSizeUnitLength), $matches ) ) { + $sParsedUnit = $matches[0]; + } + foreach($aSizeUnits as $iLength => $aValues) { $sKey = strtolower($oParserState->peek($iLength)); if(array_key_exists($sKey, $aValues)) { From 3e9732d12d1785c7e28bdf99afbc8b0c6dd945b9 Mon Sep 17 00:00:00 2001 From: Pierre Gordon Date: Mon, 11 May 2020 17:53:50 -0400 Subject: [PATCH 6/7] Refactor size unit parsing logic --- lib/Sabberworm/CSS/Value/Size.php | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/Sabberworm/CSS/Value/Size.php b/lib/Sabberworm/CSS/Value/Size.php index 9cfe8909..26e3eb1d 100644 --- a/lib/Sabberworm/CSS/Value/Size.php +++ b/lib/Sabberworm/CSS/Value/Size.php @@ -38,26 +38,21 @@ public static function parse(ParserState $oParserState, $bIsColorComponent = fal } $sUnit = null; - $sParsedUnit = null; $aSizeUnits = self::getSizeUnits(); - $iMaxSizeUnitLength = max(array_keys($aSizeUnits)); + if ( preg_match( '/^[a-zA-Z0-9%]+/', $oParserState->peek($iMaxSizeUnitLength), $matches ) ) { - $sParsedUnit = $matches[0]; - } + $sUnit = strtolower($matches[0]); + $iUnitLength = strlen($sUnit); - foreach($aSizeUnits as $iLength => $aValues) { - $sKey = strtolower($oParserState->peek($iLength)); - if(array_key_exists($sKey, $aValues)) { - if (strtolower($sParsedUnit) !== $sKey) { - throw new UnexpectedTokenException('Unit', $sParsedUnit, 'identifier', $oParserState->currentLine()); - } - if (($sUnit = $aValues[$sKey]) !== null) { - $oParserState->consume($iLength); - break; - } + if (isset($aSizeUnits[$iUnitLength][$sUnit])) { + $sUnit = $aSizeUnits[$iUnitLength][$sUnit]; + $oParserState->consume($iUnitLength); + } else { + throw new UnexpectedTokenException('Unit', $sUnit, 'identifier', $oParserState->currentLine()); } } + return new Size(floatval($sSize), $sUnit, $bIsColorComponent, $oParserState->currentLine()); } From 468da3441945e9c1bf402a3340b1d8326723f7d9 Mon Sep 17 00:00:00 2001 From: Pierre Gordon <16200219+pierlon@users.noreply.github.com> Date: Mon, 11 May 2020 19:22:45 -0400 Subject: [PATCH 7/7] Match percent symbol or alphanumeric text Co-authored-by: Weston Ruter --- lib/Sabberworm/CSS/Value/Size.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Sabberworm/CSS/Value/Size.php b/lib/Sabberworm/CSS/Value/Size.php index 26e3eb1d..cd1a213c 100644 --- a/lib/Sabberworm/CSS/Value/Size.php +++ b/lib/Sabberworm/CSS/Value/Size.php @@ -41,7 +41,7 @@ public static function parse(ParserState $oParserState, $bIsColorComponent = fal $aSizeUnits = self::getSizeUnits(); $iMaxSizeUnitLength = max(array_keys($aSizeUnits)); - if ( preg_match( '/^[a-zA-Z0-9%]+/', $oParserState->peek($iMaxSizeUnitLength), $matches ) ) { + if ( preg_match( '/^(%|[a-zA-Z0-9]+)/', $oParserState->peek($iMaxSizeUnitLength), $matches ) ) { $sUnit = strtolower($matches[0]); $iUnitLength = strlen($sUnit);