Track the synthetic pseudo-elements that matched while computing an originating element's normal style. Store the transient match set as a bitfield, then copy those bits into ComputedProperties. Use them during style invalidation to skip pseudo style recomputation when neither the old nor new originating style matched pseudo rules and no pseudo style already exists. This shaves roughly 500 ms off loading the Ladybird GitHub repository. Materialize synthetic pseudo styles on demand for CSSOM reads so getComputedStyle(element, "::before") still computes skipped styles when script asks for them. Add coverage for a universal pseudo selector, and update style invalidation counter expectations for the reduced work.
63 lines
2.2 KiB
C++
63 lines
2.2 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::ShadowRoot const> rule_shadow_root {}; // Shadow root the matched rule belongs to
|
|
bool collect_per_element_selector_involvement_metadata { false };
|
|
// True while we are evaluating the argument of a :has() pseudo-class.
|
|
// Elements visited by selector walks (descendants, siblings, etc.) while
|
|
// this is set get marked as in_has_scope so the invalidation walker can
|
|
// later terminate once it leaves the scope. Transparent to callers; set
|
|
// by matches_has_pseudo_class with a ScopeGuard.
|
|
bool inside_has_argument_match { false };
|
|
HasResultCache* has_result_cache { nullptr };
|
|
};
|
|
|
|
bool matches(CSS::Selector const&, DOM::AbstractElement const&, GC::Ptr<DOM::Element const> shadow_host, MatchContext& context, GC::Ptr<DOM::ParentNode const> scope = {}, SelectorKind selector_kind = SelectorKind::Normal, GC::Ptr<DOM::Element const> anchor = nullptr);
|
|
bool matches_originating_element_for_pseudo_element(CSS::Selector const&, CSS::PseudoElement, DOM::AbstractElement const&, GC::Ptr<DOM::Element const> shadow_host, MatchContext&, GC::Ptr<DOM::ParentNode const> scope = {});
|
|
|
|
}
|