diff --git a/Tests/LibWeb/Text/expected/css/update-pseudo-elements-on-hover.txt b/Tests/LibWeb/Text/expected/css/update-pseudo-elements-on-hover.txt new file mode 100644 index 00000000000..4ed1a777f64 --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/update-pseudo-elements-on-hover.txt @@ -0,0 +1,3 @@ +Hi Not hovering: 16 +Hovering: 78 +Not hovering: 16 diff --git a/Tests/LibWeb/Text/input/css/update-pseudo-elements-on-hover.html b/Tests/LibWeb/Text/input/css/update-pseudo-elements-on-hover.html new file mode 100644 index 00000000000..ddebf3f40bb --- /dev/null +++ b/Tests/LibWeb/Text/input/css/update-pseudo-elements-on-hover.html @@ -0,0 +1,33 @@ + + + +
+ diff --git a/Userland/Libraries/LibWeb/CSS/StyleInvalidation.h b/Userland/Libraries/LibWeb/CSS/StyleInvalidation.h index c116781b875..4fa23d5fb9c 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleInvalidation.h +++ b/Userland/Libraries/LibWeb/CSS/StyleInvalidation.h @@ -25,6 +25,7 @@ struct RequiredInvalidationAfterStyleChange { } [[nodiscard]] bool is_none() const { return !repaint && !rebuild_stacking_context_tree && !relayout && !rebuild_layout_tree; } + [[nodiscard]] bool is_full() const { return repaint && rebuild_stacking_context_tree && relayout && rebuild_layout_tree; } static RequiredInvalidationAfterStyleChange full() { return { true, true, true, true }; } }; diff --git a/Userland/Libraries/LibWeb/DOM/Element.cpp b/Userland/Libraries/LibWeb/DOM/Element.cpp index 5816582d54d..9a21d30b64a 100644 --- a/Userland/Libraries/LibWeb/DOM/Element.cpp +++ b/Userland/Libraries/LibWeb/DOM/Element.cpp @@ -534,7 +534,8 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style() set_needs_style_update(false); VERIFY(parent()); - auto new_computed_css_values = document().style_computer().compute_style(*this); + auto& style_computer = document().style_computer(); + auto new_computed_css_values = style_computer.compute_style(*this); // Tables must not inherit -libweb-* values for text-align. // FIXME: Find the spec for this. @@ -550,6 +551,35 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style() else invalidation = CSS::RequiredInvalidationAfterStyleChange::full(); + // 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++) { + auto style = style_computer.compute_pseudo_element_style_if_needed(*this, static_cast(i)); + if (style) { + pseudo_elements_dirty = true; + break; + } + } + } + + if (pseudo_elements_dirty) + invalidation = CSS::RequiredInvalidationAfterStyleChange::full(); + } + if (invalidation.is_none()) return invalidation;