mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-19 02:10:26 +00:00
When matching ::part(), only consider shadow trees whose host lies in the same style scope as the rule. Use MatchContext::rule_shadow_root, which is already set when collecting ::part() rules, as that scope. For cross-scope rules, accept a candidate shadow root only if its host's containing_shadow_root() matches the rule's shadow root: the rule's scope is the document when rule_shadow_root is null, or that shadow root when the rule comes from its stylesheet. The one exception is :host::part(): the rule and the part live in the same shadow root, so its host is outside the rule's scope and the comparison would never pass. Allow the check to be skipped for this case by setting MatchContext::for_host_part_matching when the compound selector contains :host (directly or inside :is(), which is how CSS nesting resolves &::part() inside a :host rule). Run that :host pre-scan only when rule_shadow_root is set. Document rules never use the same-shadow-root exception; scanning would otherwise set for_host_part_matching whenever :host appears in the compound and break cross-scope ::part() matching (e.g. multiple-scopes). Previously the engine walked all ancestor shadow roots without this cross-scope check.
60 lines
1.9 KiB
C++
60 lines
1.9 KiB
C++
/*
|
|
* Copyright (c) 2018-2024, Andreas Kling <andreas@ladybird.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/HashMap.h>
|
|
#include <LibWeb/CSS/Selector.h>
|
|
#include <LibWeb/DOM/Element.h>
|
|
|
|
namespace Web::SelectorEngine {
|
|
|
|
enum class SelectorKind {
|
|
Normal,
|
|
Relative,
|
|
};
|
|
|
|
enum class HasMatchResult : u8 {
|
|
Matched,
|
|
NotMatched,
|
|
};
|
|
|
|
struct HasResultCacheKey {
|
|
CSS::Selector const* selector;
|
|
GC::Ptr<DOM::Element const> element;
|
|
|
|
void visit_edges(GC::Cell::Visitor& visitor)
|
|
{
|
|
visitor.visit(element);
|
|
}
|
|
|
|
bool operator==(HasResultCacheKey const&) const = default;
|
|
};
|
|
|
|
struct HasResultCacheKeyTraits : Traits<HasResultCacheKey> {
|
|
static unsigned hash(HasResultCacheKey const& key)
|
|
{
|
|
return pair_int_hash(ptr_hash(key.selector), ptr_hash(key.element.ptr()));
|
|
}
|
|
};
|
|
|
|
using HasResultCache = HashMap<HasResultCacheKey, HasMatchResult, HasResultCacheKeyTraits>;
|
|
|
|
struct MatchContext {
|
|
GC::Ptr<CSS::CSSStyleSheet const> style_sheet_for_rule {};
|
|
GC::Ptr<DOM::Element const> subject {};
|
|
GC::Ptr<DOM::Element const> slotted_element {}; // Only set when matching a ::slotted() pseudo-element
|
|
GC::Ptr<DOM::Element const> part_owning_parent {}; // Only set temporarily when matching a ::part() pseudo-element
|
|
GC::Ptr<DOM::ShadowRoot const> rule_shadow_root {}; // Shadow root the matched rule belongs to
|
|
bool collect_per_element_selector_involvement_metadata { false };
|
|
bool for_host_part_matching { false };
|
|
CSS::PseudoClassBitmap attempted_pseudo_class_matches {};
|
|
HasResultCache* has_result_cache { nullptr };
|
|
};
|
|
|
|
bool matches(CSS::Selector const&, DOM::Element const&, GC::Ptr<DOM::Element const> shadow_host, MatchContext& context, Optional<CSS::PseudoElement> = {}, GC::Ptr<DOM::ParentNode const> scope = {}, SelectorKind selector_kind = SelectorKind::Normal, GC::Ptr<DOM::Element const> anchor = nullptr);
|
|
|
|
}
|