mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-14 05:22:24 +00:00
LibWeb/CSS: Move An+B matching code into ANPlusBPattern::matches()
Not everything we want to match is an "nth element". Also moved its serialization function's implementation out of the header while I was at it.
This commit is contained in:
parent
a59c15481f
commit
fbae3b824a
Notes:
github-actions[bot]
2025-08-13 08:48:55 +00:00
Author: https://github.com/AtkinsSJ
Commit: fbae3b824a
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5830
3 changed files with 77 additions and 70 deletions
|
@ -823,4 +823,77 @@ SelectorList adapt_nested_relative_selector_list(SelectorList const& selectors)
|
||||||
return new_list;
|
return new_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-syntax-3/#anb-microsyntax
|
||||||
|
bool Selector::SimpleSelector::ANPlusBPattern::matches(int index) const
|
||||||
|
{
|
||||||
|
// "If both a and b are equal to zero, the pseudo-class represents no element in the document tree."
|
||||||
|
if (step_size == 0 && offset == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// When "step_size == -1", selector represents first "offset" elements in document tree.
|
||||||
|
if (step_size == -1)
|
||||||
|
return !(offset <= 0 || index > offset);
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
int c = a % b;
|
||||||
|
if ((c < 0 && b > 0) || (c > 0 && b < 0)) {
|
||||||
|
c += b;
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-syntax-3/#serializing-anb
|
||||||
|
String Selector::SimpleSelector::ANPlusBPattern::serialize() const
|
||||||
|
{
|
||||||
|
// 1. If A is zero, return the serialization of B.
|
||||||
|
if (step_size == 0)
|
||||||
|
return String::number(offset);
|
||||||
|
|
||||||
|
// 2. Otherwise, let result initially be an empty string.
|
||||||
|
StringBuilder result;
|
||||||
|
|
||||||
|
// 3.
|
||||||
|
// - A is 1: Append "n" to result.
|
||||||
|
if (step_size == 1)
|
||||||
|
result.append('n');
|
||||||
|
// - A is -1: Append "-n" to result.
|
||||||
|
else if (step_size == -1)
|
||||||
|
result.append("-n"sv);
|
||||||
|
// - A is non-zero: Serialize A and append it to result, then append "n" to result.
|
||||||
|
else if (step_size != 0)
|
||||||
|
result.appendff("{}n", step_size);
|
||||||
|
|
||||||
|
// 4.
|
||||||
|
// - B is greater than zero: Append "+" to result, then append the serialization of B to result.
|
||||||
|
if (offset > 0)
|
||||||
|
result.appendff("+{}", offset);
|
||||||
|
// - B is less than zero: Append the serialization of B to result.
|
||||||
|
else if (offset < 0)
|
||||||
|
result.appendff("{}", offset);
|
||||||
|
|
||||||
|
// 5. Return result.
|
||||||
|
return MUST(result.to_string());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,39 +86,8 @@ public:
|
||||||
int step_size { 0 }; // "A"
|
int step_size { 0 }; // "A"
|
||||||
int offset = { 0 }; // "B"
|
int offset = { 0 }; // "B"
|
||||||
|
|
||||||
// https://www.w3.org/TR/css-syntax-3/#serializing-anb
|
bool matches(int index) const;
|
||||||
String serialize() const
|
String serialize() const;
|
||||||
{
|
|
||||||
// 1. If A is zero, return the serialization of B.
|
|
||||||
if (step_size == 0) {
|
|
||||||
return String::number(offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Otherwise, let result initially be an empty string.
|
|
||||||
StringBuilder result;
|
|
||||||
|
|
||||||
// 3.
|
|
||||||
// - A is 1: Append "n" to result.
|
|
||||||
if (step_size == 1)
|
|
||||||
result.append('n');
|
|
||||||
// - A is -1: Append "-n" to result.
|
|
||||||
else if (step_size == -1)
|
|
||||||
result.append("-n"sv);
|
|
||||||
// - A is non-zero: Serialize A and append it to result, then append "n" to result.
|
|
||||||
else if (step_size != 0)
|
|
||||||
result.appendff("{}n", step_size);
|
|
||||||
|
|
||||||
// 4.
|
|
||||||
// - B is greater than zero: Append "+" to result, then append the serialization of B to result.
|
|
||||||
if (offset > 0)
|
|
||||||
result.appendff("+{}", offset);
|
|
||||||
// - B is less than zero: Append the serialization of B to result.
|
|
||||||
if (offset < 0)
|
|
||||||
result.appendff("{}", offset);
|
|
||||||
|
|
||||||
// 5. Return result.
|
|
||||||
return MUST(result.to_string());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PseudoClassSelector {
|
struct PseudoClassSelector {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018-2024, Andreas Kling <andreas@ladybird.org>
|
* Copyright (c) 2018-2024, Andreas Kling <andreas@ladybird.org>
|
||||||
* Copyright (c) 2021-2024, Sam Atkins <sam@ladybird.org>
|
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
@ -671,10 +671,6 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
|
||||||
case CSS::PseudoClass::NthOfType:
|
case CSS::PseudoClass::NthOfType:
|
||||||
case CSS::PseudoClass::NthLastOfType: {
|
case CSS::PseudoClass::NthLastOfType: {
|
||||||
auto& an_plus_b = pseudo_class.an_plus_b_patterns.first();
|
auto& an_plus_b = pseudo_class.an_plus_b_patterns.first();
|
||||||
auto const step_size = an_plus_b.step_size;
|
|
||||||
auto const offset = an_plus_b.offset;
|
|
||||||
if (step_size == 0 && offset == 0)
|
|
||||||
return false; // "If both a and b are equal to zero, the pseudo-class represents no element in the document tree."
|
|
||||||
|
|
||||||
auto const* parent = element.parent();
|
auto const* parent = element.parent();
|
||||||
if (!parent)
|
if (!parent)
|
||||||
|
@ -730,38 +726,7 @@ static inline bool matches_pseudo_class(CSS::Selector::SimpleSelector::PseudoCla
|
||||||
default:
|
default:
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
return an_plus_b.matches(index);
|
||||||
// When "step_size == -1", selector represents first "offset" elements in document tree.
|
|
||||||
if (step_size == -1)
|
|
||||||
return !(offset <= 0 || index > offset);
|
|
||||||
|
|
||||||
// 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 {
|
|
||||||
int c = a % b;
|
|
||||||
if ((c < 0 && b > 0) || (c > 0 && b < 0)) {
|
|
||||||
c += b;
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
case CSS::PseudoClass::Playing: {
|
case CSS::PseudoClass::Playing: {
|
||||||
if (!is<HTML::HTMLMediaElement>(element))
|
if (!is<HTML::HTMLMediaElement>(element))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue