mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2026-04-18 18:00:31 +00:00
Replace flat InvalidationSet with recursive InvalidationPlan trees
that preserve selector combinator structure. Previously, selectors
with sibling combinators (+ and ~) fell back to whole-subtree
invalidation. Now the StyleInvalidator walks the DOM following
combinator-specific rules, so ".a + .b" only invalidates the
adjacent sibling matching ".b" rather than the entire subtree.
Plans are compiled at stylesheet parse time by walking selector
compounds right-to-left. For ".a .b + .c":
```
[.c]: plan = { invalidate_self }
register: "c" → plan
[.b]: wrap("+", righthand)
plan = { sibling_rules: [match ".c", adjacent, {self}] }
register: "b" → plan
[.a]: wrap(" ", righthand)
plan = { descendant_rules: [match ".b", <sibling plan>] }
register: "a" → plan
```
Changing class "a" produces a plan that walks descendants for ".b",
checks ".b"'s adjacent sibling for ".c", and invalidates only that
element.
42 lines
1.5 KiB
C++
42 lines
1.5 KiB
C++
/*
|
|
* Copyright (c) 2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <LibGC/CellAllocator.h>
|
|
#include <LibWeb/CSS/StyleInvalidationData.h>
|
|
#include <LibWeb/DOM/StyleInvalidationReason.h>
|
|
#include <LibWeb/Forward.h>
|
|
|
|
namespace Web::DOM {
|
|
|
|
class StyleInvalidator : public GC::Cell {
|
|
GC_CELL(StyleInvalidator, GC::Cell);
|
|
GC_DECLARE_ALLOCATOR(StyleInvalidator);
|
|
|
|
public:
|
|
void invalidate(Node& node);
|
|
bool enqueue_invalidation_plan(Node&, StyleInvalidationReason, CSS::InvalidationPlan const&);
|
|
bool has_pending_invalidations() const { return !m_pending_invalidations.is_empty(); }
|
|
|
|
virtual void visit_edges(Cell::Visitor& visitor) override;
|
|
|
|
private:
|
|
struct PendingDescendantInvalidation {
|
|
StyleInvalidationReason reason;
|
|
CSS::DescendantInvalidationRule rule;
|
|
};
|
|
|
|
void add_pending_invalidation(GC::Ref<Node>, StyleInvalidationReason, CSS::InvalidationPlan const&);
|
|
void apply_invalidation_plan(Element&, StyleInvalidationReason, CSS::InvalidationPlan const&, bool& invalidate_entire_subtree);
|
|
void apply_sibling_invalidation(Element&, StyleInvalidationReason, CSS::SiblingInvalidationRule const&);
|
|
void perform_pending_style_invalidations(Node& node, bool invalidate_entire_subtree);
|
|
|
|
HashMap<GC::Ref<Node>, Vector<PendingDescendantInvalidation>> m_pending_invalidations;
|
|
Vector<PendingDescendantInvalidation> m_active_descendant_invalidations;
|
|
};
|
|
|
|
}
|