From 973f3c3642446022e7baa4b566555e9c09540214 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 2 Mar 2022 15:58:16 +0000 Subject: [PATCH] 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. --- Base/res/html/misc/nth-child.html | 22 ++++++++++++- Base/res/html/misc/nth-last-child.html | 22 ++++++++++++- Base/res/html/misc/nth-last-of-type.html | 32 +++++++++++++++++- Base/res/html/misc/nth-of-type.html | 32 +++++++++++++++++- .../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; } @@ -136,5 +137,24 @@
4 +
5
+ +

:nth-child(-5n+3) - Acid3

+
+
1
+
2
+
3+
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
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; } @@ -136,5 +137,24 @@
4 +
5
+ +

:nth-last-child(-5n+3) - Acid3

+
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13+
+
14
+
15
+
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; } @@ -171,5 +172,34 @@
(div)

5

+ +

:nth-last-of-type(-5n+3) - Acid3

+
+

1

+
(div)
+
(div)
+

2

+
(div)
+

3

+
(div)
+
(div)
+
(div)
+

4

+

5

+

6

+
(div)
+

7

+
(div)
+
(div)
+

8

+
(div)
+

9

+

10

+

11

+

12

+

13 +

+

14

+

15

+
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; } @@ -172,5 +173,34 @@

4 +

5

+ +

:nth-of-type(-5n+3) - Acid3

+
+

1

+
(div)
+
(div)
+

2

+
(div)
+

3 +

+
(div)
+
(div)
+
(div)
+

4

+

5

+

6

+
(div)
+

7

+
(div)
+
(div)
+

8

+
(div)
+

9

+

10

+

11

+

12

+

13

+

14

+

15

+
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;