1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 18:37:35 +00:00

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.
This commit is contained in:
Sam Atkins 2022-03-02 15:58:16 +00:00 committed by Andreas Kling
parent 6a4978764f
commit 973f3c3642
5 changed files with 123 additions and 18 deletions

View file

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