diff options
author | Sam Atkins <atkinssj@serenityos.org> | 2022-03-02 15:58:16 +0000 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-03-02 17:39:57 +0100 |
commit | 973f3c3642446022e7baa4b566555e9c09540214 (patch) | |
tree | 7a238815a8bd51e40d6cee75706ab690da3c4d2b | |
parent | 6a4978764f502c6c56ad9c7d9a09a58e62740cf0 (diff) | |
download | serenity-973f3c3642446022e7baa4b566555e9c09540214.zip |
LibWeb: Correct handling of negative step values in nth-foo() selectors
This should be 1% on Acid3. :^)
Added the `-5n+3` case to all `nth-of-whatever()` selector test pages,
so we can easily check that it works.
-rw-r--r-- | Base/res/html/misc/nth-child.html | 22 | ||||
-rw-r--r-- | Base/res/html/misc/nth-last-child.html | 22 | ||||
-rw-r--r-- | Base/res/html/misc/nth-last-of-type.html | 32 | ||||
-rw-r--r-- | Base/res/html/misc/nth-of-type.html | 32 | ||||
-rw-r--r-- | Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp | 33 |
5 files changed, 123 insertions, 18 deletions
diff --git a/Base/res/html/misc/nth-child.html b/Base/res/html/misc/nth-child.html index c5e6492dcb..ed1051700b 100644 --- a/Base/res/html/misc/nth-child.html +++ b/Base/res/html/misc/nth-child.html @@ -17,7 +17,8 @@ .plus-n > div:nth-child(+n), /** "+n" is special case inside parser. */ .minus-n > div:nth-child(-n), /** "-n" is special case inside parser. */ ._0n-plus-1 > div:nth-child(-0n+1), - .n-plus-2__minus-n-plus-4 > div:nth-child(+n + 2 ):nth-child( -n+4) { + .n-plus-2__minus-n-plus-4 > div:nth-child(+n + 2 ):nth-child( -n+4), + .acid3 > div:nth-child(-5n+3) { background-color: lightblue; } </style> @@ -136,5 +137,24 @@ <div>4 +</div> <div>5</div> </div> + +<h4>:nth-child(-5n+3) - Acid3</h4> +<div class="acid3"> + <div>1</div> + <div>2</div> + <div>3+</div> + <div>4</div> + <div>5</div> + <div>6</div> + <div>7</div> + <div>8</div> + <div>9</div> + <div>10</div> + <div>11</div> + <div>12</div> + <div>13</div> + <div>14</div> + <div>15</div> +</div> </body> </html> diff --git a/Base/res/html/misc/nth-last-child.html b/Base/res/html/misc/nth-last-child.html index 24bff73546..6c514a0a18 100644 --- a/Base/res/html/misc/nth-last-child.html +++ b/Base/res/html/misc/nth-last-child.html @@ -17,7 +17,8 @@ .plus-n > div:nth-last-child(+n), /** "+n" is special case inside parser. */ .minus-n > div:nth-last-child(-n), /** "-n" is special case inside parser. */ ._0n-plus-1 > div:nth-last-child(-0n+1), - .n-plus-2__minus-n-plus-3 > div:nth-last-child(+n + 2 ):nth-last-child( -n+3) { + .n-plus-2__minus-n-plus-3 > div:nth-last-child(+n + 2 ):nth-last-child( -n+3), + .acid3 > div:nth-last-child(-5n+3) { background-color: lightblue; } </style> @@ -136,5 +137,24 @@ <div>4 +</div> <div>5</div> </div> + +<h4>:nth-last-child(-5n+3) - Acid3</h4> +<div class="acid3"> + <div>1</div> + <div>2</div> + <div>3</div> + <div>4</div> + <div>5</div> + <div>6</div> + <div>7</div> + <div>8</div> + <div>9</div> + <div>10</div> + <div>11</div> + <div>12</div> + <div>13+</div> + <div>14</div> + <div>15</div> +</div> </body> </html> diff --git a/Base/res/html/misc/nth-last-of-type.html b/Base/res/html/misc/nth-last-of-type.html index 9112a3545a..4b22cc8157 100644 --- a/Base/res/html/misc/nth-last-of-type.html +++ b/Base/res/html/misc/nth-last-of-type.html @@ -21,7 +21,8 @@ .plus-n > p:nth-last-of-type(+n), /** "+n" is special case inside parser. */ .minus-n > p:nth-last-of-type(-n), /** "-n" is special case inside parser. */ ._0n-plus-1 > p:nth-last-of-type(-0n+1), - .n-plus-2__minus-n-plus-3 > p:nth-last-of-type(+n + 2 ):nth-last-of-type( -n+3) { + .n-plus-2__minus-n-plus-3 > p:nth-last-of-type(+n + 2 ):nth-last-of-type( -n+3), + .acid3 > p:nth-last-of-type(-5n+3) { background-color: lightblue; } </style> @@ -171,5 +172,34 @@ <div>(div)</div> <p>5</p> </div> + +<h4>:nth-last-of-type(-5n+3) - Acid3</h4> +<div class="acid3"> + <p>1</p> + <div>(div)</div> + <div>(div)</div> + <p>2</p> + <div>(div)</div> + <p>3</p> + <div>(div)</div> + <div>(div)</div> + <div>(div)</div> + <p>4</p> + <p>5</p> + <p>6</p> + <div>(div)</div> + <p>7</p> + <div>(div)</div> + <div>(div)</div> + <p>8</p> + <div>(div)</div> + <p>9</p> + <p>10</p> + <p>11</p> + <p>12</p> + <p>13 +</p> + <p>14</p> + <p>15</p> +</div> </body> </html> diff --git a/Base/res/html/misc/nth-of-type.html b/Base/res/html/misc/nth-of-type.html index 1a3bc68f06..d93a525bd4 100644 --- a/Base/res/html/misc/nth-of-type.html +++ b/Base/res/html/misc/nth-of-type.html @@ -22,7 +22,8 @@ .plus-n > p:nth-of-type(+n), /** "+n" is special case inside parser. */ .minus-n > p:nth-of-type(-n), /** "-n" is special case inside parser. */ ._0n-plus-1 > p:nth-of-type(-0n+1), - .n-plus-2__minus-n-plus-4 > p:nth-of-type(+n + 2 ):nth-of-type( -n+4) { + .n-plus-2__minus-n-plus-4 > p:nth-of-type(+n + 2 ):nth-of-type( -n+4), + .acid3 > p:nth-of-type(-5n+3) { background-color: lightblue; } </style> @@ -172,5 +173,34 @@ <p>4 +</p> <p>5</p> </div> + +<h4>:nth-of-type(-5n+3) - Acid3</h4> +<div class="acid3"> + <p>1</p> + <div>(div)</div> + <div>(div)</div> + <p>2</p> + <div>(div)</div> + <p>3 +</p> + <div>(div)</div> + <div>(div)</div> + <div>(div)</div> + <p>4</p> + <p>5</p> + <p>6</p> + <div>(div)</div> + <p>7</p> + <div>(div)</div> + <div>(div)</div> + <p>8</p> + <div>(div)</div> + <p>9</p> + <p>10</p> + <p>11</p> + <p>12</p> + <p>13</p> + <p>14</p> + <p>15</p> +</div> </body> </html> diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp index 52b4965ab9..14f4776149 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -179,13 +179,21 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla VERIFY_NOT_REACHED(); } - if (step_size < 0) { - // When "step_size" is negative, selector represents first "offset" elements in document tree. + // When "step_size == -1", selector represents first "offset" elements in document tree. + if (step_size == -1) return !(offset <= 0 || index > offset); - } else if (step_size == 1) { - // When "step_size == 1", selector represents last "offset" elements in document tree. + + // When "step_size == 1", selector represents last "offset" elements in document tree. + if (step_size == 1) return !(offset < 0 || index < offset); - } + + // When "step_size == 0", selector picks only the "offset" element. + if (step_size == 0) + return index == offset; + + // If both are negative, nothing can match. + if (step_size < 0 && offset < 0) + return false; // Like "a % b", but handles negative integers correctly. auto const canonical_modulo = [](int a, int b) -> int { @@ -196,15 +204,12 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla return c; }; - if (step_size == 0) { - // Avoid divide by zero. - if (index != offset) { - return false; - } - } else if (canonical_modulo(index - offset, step_size) != 0) { - return false; - } - return true; + // When "step_size < 0", we start at "offset" and count backwards. + if (step_size < 0) + return index <= offset && canonical_modulo(index - offset, -step_size) == 0; + + // Otherwise, we start at "offset" and count forwards. + return index >= offset && canonical_modulo(index - offset, step_size) == 0; } return false; |