diff --git a/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp b/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp index 61c686b4ba..83366ae1f7 100644 --- a/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp +++ b/Userland/Libraries/LibWeb/CSS/Parser/DeprecatedCSSParser.cpp @@ -566,6 +566,9 @@ public: } else if (pseudo_name.starts_with("nth-child", CaseSensitivity::CaseInsensitive)) { simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::NthChild; simple_selector.nth_child_pattern = CSS::Selector::SimpleSelector::NthChildPattern::parse(capture_selector_args(pseudo_name)); + } else if (pseudo_name.starts_with("nth-last-child", CaseSensitivity::CaseInsensitive)) { + simple_selector.pseudo_class = CSS::Selector::SimpleSelector::PseudoClass::NthLastChild; + simple_selector.nth_child_pattern = CSS::Selector::SimpleSelector::NthChildPattern::parse(capture_selector_args(pseudo_name)); } else if (pseudo_name.equals_ignoring_case("before")) { simple_selector.pseudo_element = CSS::Selector::SimpleSelector::PseudoElement::Before; } else if (pseudo_name.equals_ignoring_case("after")) { diff --git a/Userland/Libraries/LibWeb/CSS/Selector.h b/Userland/Libraries/LibWeb/CSS/Selector.h index d64909a4c1..7a132fde25 100644 --- a/Userland/Libraries/LibWeb/CSS/Selector.h +++ b/Userland/Libraries/LibWeb/CSS/Selector.h @@ -37,6 +37,7 @@ public: FirstOfType, LastOfType, NthChild, + NthLastChild, }; PseudoClass pseudo_class { PseudoClass::None }; @@ -69,7 +70,7 @@ public: }; // FIXME: We don't need this field on every single SimpleSelector, but it's also annoying to malloc it somewhere. - // Only used when "pseudo_class" == PseudoClass::NthChild. + // Only used when "pseudo_class" is "NthChild" or "NthLastChild". NthChildPattern nth_child_pattern; }; diff --git a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp index a1b77a8019..6807f40eae 100644 --- a/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Userland/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -83,6 +83,7 @@ static bool matches(const CSS::Selector::SimpleSelector& component, const DOM::E } break; case CSS::Selector::SimpleSelector::PseudoClass::NthChild: + case CSS::Selector::SimpleSelector::PseudoClass::NthLastChild: const auto step_size = component.nth_child_pattern.step_size; const auto offset = component.nth_child_pattern.offset; if (step_size == 0 && offset == 0) @@ -93,8 +94,12 @@ static bool matches(const CSS::Selector::SimpleSelector& component, const DOM::E return false; int index = 1; - for (auto* child = parent->first_child_of_type(); child && child != &element; child = child->next_element_sibling()) { - ++index; + if (component.pseudo_class == CSS::Selector::SimpleSelector::PseudoClass::NthChild) { + for (auto* child = parent->first_child_of_type(); child && child != &element; child = child->next_element_sibling()) + ++index; + } else { + for (auto* child = parent->last_child_of_type(); child && child != &element; child = child->previous_element_sibling()) + ++index; } if (step_size < 0) { diff --git a/Userland/Libraries/LibWeb/Dump.cpp b/Userland/Libraries/LibWeb/Dump.cpp index a290178944..3a1868d8b2 100644 --- a/Userland/Libraries/LibWeb/Dump.cpp +++ b/Userland/Libraries/LibWeb/Dump.cpp @@ -354,6 +354,9 @@ void dump_selector(StringBuilder& builder, const CSS::Selector& selector) case CSS::Selector::SimpleSelector::PseudoClass::NthChild: pseudo_class_description = "NthChild"; break; + case CSS::Selector::SimpleSelector::PseudoClass::NthLastChild: + pseudo_class_description = "NthLastChild"; + break; case CSS::Selector::SimpleSelector::PseudoClass::Focus: pseudo_class_description = "Focus"; break;