mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-11 10:41:30 +00:00
LibWeb: Postpone :has()
style invalidation until update_style()
This allows to do ancestors traversal only once even if `invalidate_style()` was called multiple times for the same node.
This commit is contained in:
parent
f926604cc3
commit
90ba4b16c2
Notes:
github-actions[bot]
2025-02-11 09:23:25 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: 90ba4b16c2
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3532
3 changed files with 36 additions and 13 deletions
|
@ -1438,7 +1438,7 @@ void Document::update_style()
|
||||||
// style change event. [CSS-Transitions-2]
|
// style change event. [CSS-Transitions-2]
|
||||||
m_transition_generation++;
|
m_transition_generation++;
|
||||||
|
|
||||||
invalidate_elements_affected_by_has_in_non_subject_position();
|
invalidate_style_of_elements_affected_by_has();
|
||||||
|
|
||||||
if (!needs_full_style_update() && !needs_style_update() && !child_needs_style_update())
|
if (!needs_full_style_update() && !needs_style_update() && !child_needs_style_update())
|
||||||
return;
|
return;
|
||||||
|
@ -1659,11 +1659,18 @@ static Node* find_common_ancestor(Node* a, Node* b)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::invalidate_elements_affected_by_has_in_non_subject_position()
|
void Document::invalidate_style_of_elements_affected_by_has()
|
||||||
{
|
{
|
||||||
if (!m_needs_invalidate_elements_affected_by_has_in_non_subject_position)
|
if (m_pending_nodes_for_style_invalidation_due_to_presence_of_has.is_empty()) {
|
||||||
return;
|
return;
|
||||||
m_needs_invalidate_elements_affected_by_has_in_non_subject_position = false;
|
}
|
||||||
|
|
||||||
|
for (auto const& node : m_pending_nodes_for_style_invalidation_due_to_presence_of_has) {
|
||||||
|
if (node.is_null())
|
||||||
|
continue;
|
||||||
|
node->invalidate_ancestors_affected_by_has_in_subject_position();
|
||||||
|
}
|
||||||
|
m_pending_nodes_for_style_invalidation_due_to_presence_of_has.clear();
|
||||||
|
|
||||||
// Take care of elements that affected by :has() in non-subject position, i.e., ".a:has(.b) > .c".
|
// Take care of elements that affected by :has() in non-subject position, i.e., ".a:has(.b) > .c".
|
||||||
// Elements affected by :has() in subject position, i.e., ".a:has(.b)", are handled by
|
// Elements affected by :has() in subject position, i.e., ".a:has(.b)", are handled by
|
||||||
|
|
|
@ -510,9 +510,6 @@ public:
|
||||||
[[nodiscard]] bool needs_full_layout_tree_update() const { return m_needs_full_layout_tree_update; }
|
[[nodiscard]] bool needs_full_layout_tree_update() const { return m_needs_full_layout_tree_update; }
|
||||||
void set_needs_full_layout_tree_update(bool b) { m_needs_full_layout_tree_update = b; }
|
void set_needs_full_layout_tree_update(bool b) { m_needs_full_layout_tree_update = b; }
|
||||||
|
|
||||||
bool needs_invalidate_elements_affected_by_has_in_non_subject_position() const { return m_needs_invalidate_elements_affected_by_has_in_non_subject_position; }
|
|
||||||
void set_needs_invalidate_elements_affected_by_has_in_non_subject_position(bool b) { m_needs_invalidate_elements_affected_by_has_in_non_subject_position = b; }
|
|
||||||
|
|
||||||
void set_needs_to_refresh_scroll_state(bool b);
|
void set_needs_to_refresh_scroll_state(bool b);
|
||||||
|
|
||||||
bool has_active_favicon() const { return m_active_favicon; }
|
bool has_active_favicon() const { return m_active_favicon; }
|
||||||
|
@ -807,6 +804,11 @@ public:
|
||||||
void add_render_blocking_element(GC::Ref<Element>);
|
void add_render_blocking_element(GC::Ref<Element>);
|
||||||
void remove_render_blocking_element(GC::Ref<Element>);
|
void remove_render_blocking_element(GC::Ref<Element>);
|
||||||
|
|
||||||
|
void schedule_ancestors_style_invalidation_due_to_presence_of_has(Node& node)
|
||||||
|
{
|
||||||
|
m_pending_nodes_for_style_invalidation_due_to_presence_of_has.set(node.make_weak_ptr<Node>());
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
virtual void visit_edges(Cell::Visitor&) override;
|
virtual void visit_edges(Cell::Visitor&) override;
|
||||||
|
@ -817,7 +819,7 @@ private:
|
||||||
// ^HTML::GlobalEventHandlers
|
// ^HTML::GlobalEventHandlers
|
||||||
virtual GC::Ptr<EventTarget> global_event_handlers_to_event_target(FlyString const&) final { return *this; }
|
virtual GC::Ptr<EventTarget> global_event_handlers_to_event_target(FlyString const&) final { return *this; }
|
||||||
|
|
||||||
void invalidate_elements_affected_by_has_in_non_subject_position();
|
void invalidate_style_of_elements_affected_by_has();
|
||||||
|
|
||||||
void tear_down_layout_tree();
|
void tear_down_layout_tree();
|
||||||
|
|
||||||
|
@ -961,7 +963,6 @@ private:
|
||||||
|
|
||||||
bool m_needs_full_style_update { false };
|
bool m_needs_full_style_update { false };
|
||||||
bool m_needs_full_layout_tree_update { false };
|
bool m_needs_full_layout_tree_update { false };
|
||||||
bool m_needs_invalidate_elements_affected_by_has_in_non_subject_position { false };
|
|
||||||
|
|
||||||
bool m_needs_animated_style_update { false };
|
bool m_needs_animated_style_update { false };
|
||||||
|
|
||||||
|
@ -1146,6 +1147,8 @@ private:
|
||||||
|
|
||||||
// https://html.spec.whatwg.org/multipage/dom.html#render-blocking-element-set
|
// https://html.spec.whatwg.org/multipage/dom.html#render-blocking-element-set
|
||||||
HashTable<GC::Ref<Element>> m_render_blocking_elements;
|
HashTable<GC::Ref<Element>> m_render_blocking_elements;
|
||||||
|
|
||||||
|
HashTable<WeakPtr<Node>> m_pending_nodes_for_style_invalidation_due_to_presence_of_has;
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -430,8 +430,22 @@ void Node::invalidate_style(StyleInvalidationReason reason)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (document().style_computer().may_have_has_selectors()) {
|
if (document().style_computer().may_have_has_selectors()) {
|
||||||
invalidate_ancestors_affected_by_has_in_subject_position();
|
if (reason == StyleInvalidationReason::NodeRemove) {
|
||||||
document().set_needs_invalidate_elements_affected_by_has_in_non_subject_position(true);
|
for (auto* previous_sibling = this->previous_sibling(); previous_sibling; previous_sibling = previous_sibling->previous_sibling()) {
|
||||||
|
if (!previous_sibling->is_element())
|
||||||
|
continue;
|
||||||
|
auto& element = static_cast<Element&>(*previous_sibling);
|
||||||
|
if (element.affected_by_has_pseudo_class_with_relative_selector_that_has_sibling_combinator()) {
|
||||||
|
element.set_needs_style_update(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto parent = parent_or_shadow_host(); parent) {
|
||||||
|
document().schedule_ancestors_style_invalidation_due_to_presence_of_has(*parent);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
document().schedule_ancestors_style_invalidation_due_to_presence_of_has(*this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!needs_style_update() && !document().needs_full_style_update()) {
|
if (!needs_style_update() && !document().needs_full_style_update()) {
|
||||||
|
@ -493,8 +507,7 @@ void Node::invalidate_style(StyleInvalidationReason, Vector<CSS::InvalidationSet
|
||||||
properties_used_in_has_selectors |= document().style_computer().invalidation_property_used_in_has_selector(property);
|
properties_used_in_has_selectors |= document().style_computer().invalidation_property_used_in_has_selector(property);
|
||||||
}
|
}
|
||||||
if (properties_used_in_has_selectors) {
|
if (properties_used_in_has_selectors) {
|
||||||
invalidate_ancestors_affected_by_has_in_subject_position();
|
document().schedule_ancestors_style_invalidation_due_to_presence_of_has(*this);
|
||||||
document().set_needs_invalidate_elements_affected_by_has_in_non_subject_position(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto invalidation_set = document().style_computer().invalidation_set_for_properties(properties);
|
auto invalidation_set = document().style_computer().invalidation_set_for_properties(properties);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue