mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-18 08:20:44 +00:00
LibWeb: Compute pseudo-element style when computing element style
Previously, pseudo-elements had their style computed while the layout tree was being built. Instead, do so inside Element::recompute_style(), using the same invalidation mechanism that the element itself uses. This also has the effect of invalidating the layout much less often.
This commit is contained in:
parent
d58c1c1176
commit
3abd3ef5e2
Notes:
github-actions[bot]
2024-07-31 10:16:35 +00:00
Author: https://github.com/AtkinsSJ
Commit: 3abd3ef5e2
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/908
3 changed files with 54 additions and 28 deletions
|
@ -551,41 +551,31 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style()
|
|||
else
|
||||
invalidation = CSS::RequiredInvalidationAfterStyleChange::full();
|
||||
|
||||
if (!invalidation.is_none())
|
||||
set_computed_css_values(move(new_computed_css_values));
|
||||
|
||||
// Any document change that can cause this element's style to change, could also affect its pseudo-elements.
|
||||
// So determine if any pseudo-elements currently exist, or should now exist, and if so, invalidate everything.
|
||||
// (If we're already invalidating everything, we don't need to do further checks for this.)
|
||||
if (!invalidation.is_full()) {
|
||||
bool pseudo_elements_dirty = false;
|
||||
for (auto i = 0; i < to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount); i++) {
|
||||
style_computer.push_ancestor(*this);
|
||||
|
||||
if (m_pseudo_element_data) {
|
||||
for (auto& pseudo_element : *m_pseudo_element_data) {
|
||||
if (pseudo_element.layout_node) {
|
||||
pseudo_elements_dirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
auto pseudo_element = static_cast<CSS::Selector::PseudoElement::Type>(i);
|
||||
auto pseudo_element_style = pseudo_element_computed_css_values(pseudo_element);
|
||||
auto new_pseudo_element_style = style_computer.compute_pseudo_element_style_if_needed(*this, pseudo_element);
|
||||
|
||||
if (!pseudo_elements_dirty) {
|
||||
for (auto i = 0; i < to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount); i++) {
|
||||
auto style = style_computer.compute_pseudo_element_style_if_needed(*this, static_cast<CSS::Selector::PseudoElement::Type>(i));
|
||||
if (style) {
|
||||
pseudo_elements_dirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pseudo_elements_dirty)
|
||||
// TODO: Can we be smarter about invalidation?
|
||||
if (pseudo_element_style && new_pseudo_element_style) {
|
||||
invalidation |= compute_required_invalidation(*pseudo_element_style, *new_pseudo_element_style);
|
||||
} else if (pseudo_element_style || new_pseudo_element_style) {
|
||||
invalidation = CSS::RequiredInvalidationAfterStyleChange::full();
|
||||
}
|
||||
|
||||
set_pseudo_element_computed_css_values(pseudo_element, move(new_pseudo_element_style));
|
||||
style_computer.pop_ancestor(*this);
|
||||
}
|
||||
|
||||
if (invalidation.is_none())
|
||||
return invalidation;
|
||||
|
||||
m_computed_css_values = move(new_computed_css_values);
|
||||
computed_css_values_changed();
|
||||
|
||||
if (invalidation.repaint)
|
||||
document().set_needs_to_resolve_paint_only_properties();
|
||||
|
||||
|
@ -594,6 +584,24 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style()
|
|||
layout_node()->apply_style(*m_computed_css_values);
|
||||
if (invalidation.repaint && paintable())
|
||||
paintable()->set_needs_display();
|
||||
|
||||
// Do the same for pseudo-elements.
|
||||
for (auto i = 0; i < to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount); i++) {
|
||||
auto pseudo_element_type = static_cast<CSS::Selector::PseudoElement::Type>(i);
|
||||
auto pseudo_element = get_pseudo_element(pseudo_element_type);
|
||||
if (!pseudo_element.has_value() || !pseudo_element->layout_node)
|
||||
continue;
|
||||
|
||||
auto pseudo_element_style = pseudo_element_computed_css_values(pseudo_element_type);
|
||||
if (!pseudo_element_style)
|
||||
continue;
|
||||
|
||||
if (auto* node_with_style = dynamic_cast<Layout::NodeWithStyle*>(pseudo_element->layout_node.ptr())) {
|
||||
node_with_style->apply_style(*pseudo_element_style);
|
||||
if (invalidation.repaint && node_with_style->paintable())
|
||||
node_with_style->paintable()->set_needs_display();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return invalidation;
|
||||
|
@ -2253,6 +2261,21 @@ void Element::set_computed_css_values(RefPtr<CSS::StyleProperties> style)
|
|||
computed_css_values_changed();
|
||||
}
|
||||
|
||||
void Element::set_pseudo_element_computed_css_values(CSS::Selector::PseudoElement::Type pseudo_element, RefPtr<CSS::StyleProperties> style)
|
||||
{
|
||||
if (!m_pseudo_element_data && !style)
|
||||
return;
|
||||
ensure_pseudo_element(pseudo_element).computed_css_values = move(style);
|
||||
}
|
||||
|
||||
RefPtr<CSS::StyleProperties> Element::pseudo_element_computed_css_values(CSS::Selector::PseudoElement::Type type)
|
||||
{
|
||||
auto pseudo_element = get_pseudo_element(type);
|
||||
if (pseudo_element.has_value())
|
||||
return pseudo_element->computed_css_values;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Optional<Element::PseudoElement&> Element::get_pseudo_element(CSS::Selector::PseudoElement::Type type) const
|
||||
{
|
||||
if (!m_pseudo_element_data)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue