mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-19 16:59:47 +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
|
else
|
||||||
invalidation = CSS::RequiredInvalidationAfterStyleChange::full();
|
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.
|
// 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;
|
|
||||||
|
|
||||||
if (m_pseudo_element_data) {
|
|
||||||
for (auto& pseudo_element : *m_pseudo_element_data) {
|
|
||||||
if (pseudo_element.layout_node) {
|
|
||||||
pseudo_elements_dirty = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pseudo_elements_dirty) {
|
|
||||||
for (auto i = 0; i < to_underlying(CSS::Selector::PseudoElement::Type::KnownPseudoElementCount); i++) {
|
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));
|
style_computer.push_ancestor(*this);
|
||||||
if (style) {
|
|
||||||
pseudo_elements_dirty = true;
|
auto pseudo_element = static_cast<CSS::Selector::PseudoElement::Type>(i);
|
||||||
break;
|
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);
|
||||||
}
|
|
||||||
|
// 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pseudo_elements_dirty)
|
set_pseudo_element_computed_css_values(pseudo_element, move(new_pseudo_element_style));
|
||||||
invalidation = CSS::RequiredInvalidationAfterStyleChange::full();
|
style_computer.pop_ancestor(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (invalidation.is_none())
|
if (invalidation.is_none())
|
||||||
return invalidation;
|
return invalidation;
|
||||||
|
|
||||||
m_computed_css_values = move(new_computed_css_values);
|
|
||||||
computed_css_values_changed();
|
|
||||||
|
|
||||||
if (invalidation.repaint)
|
if (invalidation.repaint)
|
||||||
document().set_needs_to_resolve_paint_only_properties();
|
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);
|
layout_node()->apply_style(*m_computed_css_values);
|
||||||
if (invalidation.repaint && paintable())
|
if (invalidation.repaint && paintable())
|
||||||
paintable()->set_needs_display();
|
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;
|
return invalidation;
|
||||||
|
@ -2253,6 +2261,21 @@ void Element::set_computed_css_values(RefPtr<CSS::StyleProperties> style)
|
||||||
computed_css_values_changed();
|
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
|
Optional<Element::PseudoElement&> Element::get_pseudo_element(CSS::Selector::PseudoElement::Type type) const
|
||||||
{
|
{
|
||||||
if (!m_pseudo_element_data)
|
if (!m_pseudo_element_data)
|
||||||
|
|
|
@ -188,6 +188,9 @@ public:
|
||||||
void set_computed_css_values(RefPtr<CSS::StyleProperties>);
|
void set_computed_css_values(RefPtr<CSS::StyleProperties>);
|
||||||
NonnullRefPtr<CSS::StyleProperties> resolved_css_values();
|
NonnullRefPtr<CSS::StyleProperties> resolved_css_values();
|
||||||
|
|
||||||
|
void set_pseudo_element_computed_css_values(CSS::Selector::PseudoElement::Type, RefPtr<CSS::StyleProperties>);
|
||||||
|
RefPtr<CSS::StyleProperties> pseudo_element_computed_css_values(CSS::Selector::PseudoElement::Type);
|
||||||
|
|
||||||
void reset_animated_css_properties();
|
void reset_animated_css_properties();
|
||||||
|
|
||||||
JS::GCPtr<CSS::ElementInlineCSSStyleDeclaration const> inline_style() const { return m_inline_style; }
|
JS::GCPtr<CSS::ElementInlineCSSStyleDeclaration const> inline_style() const { return m_inline_style; }
|
||||||
|
@ -451,6 +454,7 @@ private:
|
||||||
|
|
||||||
struct PseudoElement {
|
struct PseudoElement {
|
||||||
JS::GCPtr<Layout::Node> layout_node;
|
JS::GCPtr<Layout::Node> layout_node;
|
||||||
|
RefPtr<CSS::StyleProperties> computed_css_values;
|
||||||
HashMap<FlyString, CSS::StyleProperty> custom_properties;
|
HashMap<FlyString, CSS::StyleProperty> custom_properties;
|
||||||
};
|
};
|
||||||
// TODO: CSS::Selector::PseudoElement::Type includes a lot of pseudo-elements that exist in shadow trees,
|
// TODO: CSS::Selector::PseudoElement::Type includes a lot of pseudo-elements that exist in shadow trees,
|
||||||
|
|
|
@ -191,9 +191,8 @@ void TreeBuilder::insert_node_into_inline_or_block_ancestor(Layout::Node& node,
|
||||||
void TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element, CSS::Selector::PseudoElement::Type pseudo_element, AppendOrPrepend mode)
|
void TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element, CSS::Selector::PseudoElement::Type pseudo_element, AppendOrPrepend mode)
|
||||||
{
|
{
|
||||||
auto& document = element.document();
|
auto& document = element.document();
|
||||||
auto& style_computer = document.style_computer();
|
|
||||||
|
|
||||||
auto pseudo_element_style = style_computer.compute_pseudo_element_style_if_needed(element, pseudo_element);
|
auto pseudo_element_style = element.pseudo_element_computed_css_values(pseudo_element);
|
||||||
if (!pseudo_element_style)
|
if (!pseudo_element_style)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue