mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-09-29 08:11:13 +00:00
LibWeb: Include siblings+descendants when invalidating style
When an element is invalidated, it's possible for any subsequent sibling or any of their descendants to also need invalidation. (Due to the CSS sibling combinators, `+` and `~`) For DOM node insertion/removal, we must also invalidate preceding siblings, since they could be affected by :first-child, :last-child or :nth-child() selectors. This increases the amount of invalidation we do, but it's more correct. In the future, we will implement optimizations that drastically reduce the number of elements invalidated.
This commit is contained in:
parent
5d71758742
commit
df048e10f5
Notes:
github-actions[bot]
2024-09-22 18:08:54 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/df048e10f5a Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/1483 Reviewed-by: https://github.com/kalenikaliaksandr
|
@ -405,18 +405,42 @@ void Node::invalidate_style(StyleInvalidationReason reason)
|
|||
return;
|
||||
}
|
||||
|
||||
for_each_in_inclusive_subtree([&](Node& node) {
|
||||
node.m_needs_style_update = true;
|
||||
if (node.has_children())
|
||||
node.m_child_needs_style_update = true;
|
||||
if (auto shadow_root = node.is_element() ? static_cast<DOM::Element&>(node).shadow_root() : nullptr) {
|
||||
node.m_child_needs_style_update = true;
|
||||
shadow_root->m_needs_style_update = true;
|
||||
if (shadow_root->has_children())
|
||||
shadow_root->m_child_needs_style_update = true;
|
||||
// When invalidating style for a node, we actually invalidate:
|
||||
// - the node itself
|
||||
// - all of its descendants
|
||||
// - all of its preceding siblings and their descendants (only on DOM insert/remove)
|
||||
// - all of its subsequent siblings and their descendants
|
||||
// FIXME: This is a lot of invalidation and we should implement more sophisticated invalidation to do less work!
|
||||
|
||||
auto invalidate_entire_subtree = [&](Node& subtree_root) {
|
||||
subtree_root.for_each_in_inclusive_subtree([&](Node& node) {
|
||||
node.m_needs_style_update = true;
|
||||
if (node.has_children())
|
||||
node.m_child_needs_style_update = true;
|
||||
if (auto shadow_root = node.is_element() ? static_cast<DOM::Element&>(node).shadow_root() : nullptr) {
|
||||
node.m_child_needs_style_update = true;
|
||||
shadow_root->m_needs_style_update = true;
|
||||
if (shadow_root->has_children())
|
||||
shadow_root->m_child_needs_style_update = true;
|
||||
}
|
||||
return TraversalDecision::Continue;
|
||||
});
|
||||
};
|
||||
|
||||
invalidate_entire_subtree(*this);
|
||||
|
||||
if (reason == StyleInvalidationReason::NodeInsertBefore || reason == StyleInvalidationReason::NodeRemove) {
|
||||
for (auto* sibling = previous_sibling(); sibling; sibling = sibling->previous_sibling()) {
|
||||
if (sibling->is_element())
|
||||
invalidate_entire_subtree(*sibling);
|
||||
}
|
||||
return TraversalDecision::Continue;
|
||||
});
|
||||
}
|
||||
|
||||
for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) {
|
||||
if (sibling->is_element())
|
||||
invalidate_entire_subtree(*sibling);
|
||||
}
|
||||
|
||||
for (auto* ancestor = parent_or_shadow_host(); ancestor; ancestor = ancestor->parent_or_shadow_host())
|
||||
ancestor->m_child_needs_style_update = true;
|
||||
document().schedule_style_update();
|
||||
|
|
Loading…
Reference in a new issue