mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-09 09:39:39 +00:00
LibWeb: Add mechanism to invalidate only inherited styles
We can now mark an element as needing an "inherited style update" rather than a full "style update". This effectively means that the next style update will visit the element and pull all of its inherited properties from the relevant ancestor element. This is now used for descendants of elements with animated style.
This commit is contained in:
parent
92ac702c0c
commit
dc8343cc23
Notes:
github-actions[bot]
2024-12-23 16:06:18 +00:00
Author: https://github.com/awesomekling
Commit: dc8343cc23
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3023
7 changed files with 55 additions and 16 deletions
|
@ -935,25 +935,14 @@ void KeyframeEffect::update_computed_properties()
|
||||||
auto& document = target->document();
|
auto& document = target->document();
|
||||||
document.style_computer().collect_animation_into(*target, pseudo_element_type(), *this, *style, CSS::StyleComputer::AnimationRefresh::Yes);
|
document.style_computer().collect_animation_into(*target, pseudo_element_type(), *this, *style, CSS::StyleComputer::AnimationRefresh::Yes);
|
||||||
|
|
||||||
|
auto invalidation = compute_required_invalidation(animated_properties_before_update, style->animated_property_values());
|
||||||
|
|
||||||
// Traversal of the subtree is necessary to update the animated properties inherited from the target element.
|
// Traversal of the subtree is necessary to update the animated properties inherited from the target element.
|
||||||
target->for_each_in_subtree_of_type<DOM::Element>([&](auto& element) {
|
target->for_each_in_subtree_of_type<DOM::Element>([&](auto& element) {
|
||||||
auto element_style = element.computed_properties();
|
invalidation |= element.recompute_inherited_style();
|
||||||
if (!element_style || !element.layout_node())
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
|
|
||||||
for (auto i = to_underlying(CSS::first_property_id); i <= to_underlying(CSS::last_property_id); ++i) {
|
|
||||||
if (element_style->is_property_inherited(static_cast<CSS::PropertyID>(i))) {
|
|
||||||
auto new_value = CSS::StyleComputer::get_inherit_value(static_cast<CSS::PropertyID>(i), &element);
|
|
||||||
element_style->set_property(static_cast<CSS::PropertyID>(i), *new_value, CSS::ComputedProperties::Inherited::Yes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
element.layout_node()->apply_style(*element_style);
|
|
||||||
return TraversalDecision::Continue;
|
return TraversalDecision::Continue;
|
||||||
});
|
});
|
||||||
|
|
||||||
auto invalidation = compute_required_invalidation(animated_properties_before_update, style->animated_property_values());
|
|
||||||
|
|
||||||
if (!pseudo_element_type().has_value()) {
|
if (!pseudo_element_type().has_value()) {
|
||||||
if (target->layout_node())
|
if (target->layout_node())
|
||||||
target->layout_node()->apply_style(*style);
|
target->layout_node()->apply_style(*style);
|
||||||
|
|
|
@ -175,6 +175,8 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] GC::Ref<ComputedProperties> compute_properties(DOM::Element&, Optional<Selector::PseudoElement::Type>, CascadedProperties&) const;
|
[[nodiscard]] GC::Ref<ComputedProperties> compute_properties(DOM::Element&, Optional<Selector::PseudoElement::Type>, CascadedProperties&) const;
|
||||||
|
|
||||||
|
void absolutize_values(ComputedProperties&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class ComputeStyleMode {
|
enum class ComputeStyleMode {
|
||||||
Normal,
|
Normal,
|
||||||
|
@ -194,7 +196,6 @@ private:
|
||||||
void compute_math_depth(ComputedProperties&, DOM::Element const*, Optional<CSS::Selector::PseudoElement::Type>) const;
|
void compute_math_depth(ComputedProperties&, DOM::Element const*, Optional<CSS::Selector::PseudoElement::Type>) const;
|
||||||
void compute_defaulted_values(ComputedProperties&, DOM::Element const*, Optional<CSS::Selector::PseudoElement::Type>) const;
|
void compute_defaulted_values(ComputedProperties&, DOM::Element const*, Optional<CSS::Selector::PseudoElement::Type>) const;
|
||||||
void start_needed_transitions(ComputedProperties const& old_style, ComputedProperties& new_style, DOM::Element&, Optional<Selector::PseudoElement::Type>) const;
|
void start_needed_transitions(ComputedProperties const& old_style, ComputedProperties& new_style, DOM::Element&, Optional<Selector::PseudoElement::Type>) const;
|
||||||
void absolutize_values(ComputedProperties&) const;
|
|
||||||
void resolve_effective_overflow_values(ComputedProperties&) const;
|
void resolve_effective_overflow_values(ComputedProperties&) const;
|
||||||
void transform_box_type_if_needed(ComputedProperties&, DOM::Element const&, Optional<CSS::Selector::PseudoElement::Type>) const;
|
void transform_box_type_if_needed(ComputedProperties&, DOM::Element const&, Optional<CSS::Selector::PseudoElement::Type>) const;
|
||||||
|
|
||||||
|
|
|
@ -1297,10 +1297,13 @@ void Document::update_layout()
|
||||||
if (is<Element>(node)) {
|
if (is<Element>(node)) {
|
||||||
if (needs_full_style_update || node.needs_style_update()) {
|
if (needs_full_style_update || node.needs_style_update()) {
|
||||||
invalidation |= static_cast<Element&>(node).recompute_style();
|
invalidation |= static_cast<Element&>(node).recompute_style();
|
||||||
|
} else if (node.needs_inherited_style_update()) {
|
||||||
|
invalidation |= static_cast<Element&>(node).recompute_inherited_style();
|
||||||
}
|
}
|
||||||
is_display_none = static_cast<Element&>(node).computed_properties()->display().is_none();
|
is_display_none = static_cast<Element&>(node).computed_properties()->display().is_none();
|
||||||
}
|
}
|
||||||
node.set_needs_style_update(false);
|
node.set_needs_style_update(false);
|
||||||
|
node.set_needs_inherited_style_update(false);
|
||||||
|
|
||||||
if (needs_full_style_update || node.child_needs_style_update()) {
|
if (needs_full_style_update || node.child_needs_style_update()) {
|
||||||
if (node.is_element()) {
|
if (node.is_element()) {
|
||||||
|
@ -1314,7 +1317,7 @@ void Document::update_layout()
|
||||||
}
|
}
|
||||||
|
|
||||||
node.for_each_child([&](auto& child) {
|
node.for_each_child([&](auto& child) {
|
||||||
if (needs_full_style_update || child.needs_style_update() || child.child_needs_style_update()) {
|
if (needs_full_style_update || child.needs_style_update() || child.needs_inherited_style_update() || child.child_needs_style_update()) {
|
||||||
auto subtree_invalidation = update_style_recursively(child, style_computer);
|
auto subtree_invalidation = update_style_recursively(child, style_computer);
|
||||||
if (!is_display_none)
|
if (!is_display_none)
|
||||||
invalidation |= subtree_invalidation;
|
invalidation |= subtree_invalidation;
|
||||||
|
|
|
@ -554,6 +554,31 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style()
|
||||||
return invalidation;
|
return invalidation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style()
|
||||||
|
{
|
||||||
|
// Traversal of the subtree is necessary to update the animated properties inherited from the target element.
|
||||||
|
auto computed_properties = this->computed_properties();
|
||||||
|
if (!computed_properties || !layout_node())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
CSS::RequiredInvalidationAfterStyleChange invalidation;
|
||||||
|
|
||||||
|
for (auto i = to_underlying(CSS::first_property_id); i <= to_underlying(CSS::last_property_id); ++i) {
|
||||||
|
auto property_id = static_cast<CSS::PropertyID>(i);
|
||||||
|
if (!computed_properties->is_property_inherited(property_id))
|
||||||
|
continue;
|
||||||
|
RefPtr old_value = computed_properties->maybe_null_property(property_id);
|
||||||
|
RefPtr new_value = CSS::StyleComputer::get_inherit_value(property_id, this);
|
||||||
|
computed_properties->set_property(property_id, *new_value, CSS::ComputedProperties::Inherited::Yes);
|
||||||
|
invalidation |= CSS::compute_property_invalidation(property_id, old_value, new_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
document().style_computer().absolutize_values(*computed_properties);
|
||||||
|
|
||||||
|
layout_node()->apply_style(*computed_properties);
|
||||||
|
return invalidation;
|
||||||
|
}
|
||||||
|
|
||||||
GC::Ref<CSS::ComputedProperties> Element::resolved_css_values(Optional<CSS::Selector::PseudoElement::Type> type)
|
GC::Ref<CSS::ComputedProperties> Element::resolved_css_values(Optional<CSS::Selector::PseudoElement::Type> type)
|
||||||
{
|
{
|
||||||
auto element_computed_style = CSS::ResolvedCSSStyleDeclaration::create(*this, type);
|
auto element_computed_style = CSS::ResolvedCSSStyleDeclaration::create(*this, type);
|
||||||
|
|
|
@ -178,6 +178,7 @@ public:
|
||||||
void run_attribute_change_steps(FlyString const& local_name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_);
|
void run_attribute_change_steps(FlyString const& local_name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_);
|
||||||
|
|
||||||
CSS::RequiredInvalidationAfterStyleChange recompute_style();
|
CSS::RequiredInvalidationAfterStyleChange recompute_style();
|
||||||
|
CSS::RequiredInvalidationAfterStyleChange recompute_inherited_style();
|
||||||
|
|
||||||
Optional<CSS::Selector::PseudoElement::Type> use_pseudo_element() const { return m_use_pseudo_element; }
|
Optional<CSS::Selector::PseudoElement::Type> use_pseudo_element() const { return m_use_pseudo_element; }
|
||||||
void set_use_pseudo_element(Optional<CSS::Selector::PseudoElement::Type> use_pseudo_element) { m_use_pseudo_element = move(use_pseudo_element); }
|
void set_use_pseudo_element(Optional<CSS::Selector::PseudoElement::Type> use_pseudo_element) { m_use_pseudo_element = move(use_pseudo_element); }
|
||||||
|
|
|
@ -1249,6 +1249,22 @@ EventTarget* Node::get_parent(Event const&)
|
||||||
return parent();
|
return parent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Node::set_needs_inherited_style_update(bool value)
|
||||||
|
{
|
||||||
|
if (m_needs_inherited_style_update == value)
|
||||||
|
return;
|
||||||
|
m_needs_inherited_style_update = value;
|
||||||
|
|
||||||
|
if (m_needs_inherited_style_update) {
|
||||||
|
for (auto* ancestor = parent_or_shadow_host(); ancestor; ancestor = ancestor->parent_or_shadow_host()) {
|
||||||
|
if (ancestor->m_child_needs_style_update)
|
||||||
|
break;
|
||||||
|
ancestor->m_child_needs_style_update = true;
|
||||||
|
}
|
||||||
|
document().schedule_style_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Node::set_needs_style_update(bool value)
|
void Node::set_needs_style_update(bool value)
|
||||||
{
|
{
|
||||||
if (m_needs_style_update == value)
|
if (m_needs_style_update == value)
|
||||||
|
|
|
@ -275,6 +275,9 @@ public:
|
||||||
bool needs_style_update() const { return m_needs_style_update; }
|
bool needs_style_update() const { return m_needs_style_update; }
|
||||||
void set_needs_style_update(bool);
|
void set_needs_style_update(bool);
|
||||||
|
|
||||||
|
bool needs_inherited_style_update() const { return m_needs_inherited_style_update; }
|
||||||
|
void set_needs_inherited_style_update(bool);
|
||||||
|
|
||||||
bool child_needs_style_update() const { return m_child_needs_style_update; }
|
bool child_needs_style_update() const { return m_child_needs_style_update; }
|
||||||
void set_child_needs_style_update(bool b) { m_child_needs_style_update = b; }
|
void set_child_needs_style_update(bool b) { m_child_needs_style_update = b; }
|
||||||
|
|
||||||
|
@ -746,6 +749,7 @@ protected:
|
||||||
GC::Ptr<Painting::Paintable> m_paintable;
|
GC::Ptr<Painting::Paintable> m_paintable;
|
||||||
NodeType m_type { NodeType::INVALID };
|
NodeType m_type { NodeType::INVALID };
|
||||||
bool m_needs_style_update { false };
|
bool m_needs_style_update { false };
|
||||||
|
bool m_needs_inherited_style_update { false };
|
||||||
bool m_child_needs_style_update { false };
|
bool m_child_needs_style_update { false };
|
||||||
|
|
||||||
UniqueNodeID m_unique_id;
|
UniqueNodeID m_unique_id;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue