summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@serenityos.org>2022-03-02 15:58:16 +0000
committerAndreas Kling <kling@serenityos.org>2022-03-02 17:39:57 +0100
commit973f3c3642446022e7baa4b566555e9c09540214 (patch)
tree7a238815a8bd51e40d6cee75706ab690da3c4d2b
parent6a4978764f502c6c56ad9c7d9a09a58e62740cf0 (diff)
downloadserenity-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.html22
-rw-r--r--Base/res/html/misc/nth-last-child.html22
-rw-r--r--Base/res/html/misc/nth-last-of-type.html32
-rw-r--r--Base/res/html/misc/nth-of-type.html32
-rw-r--r--Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp33
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;