From 2bf1f41805660effbce3ef4bc4bd23b84b24e4b6 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 19 Jun 2026 16:49:20 +0200 Subject: [PATCH] LibWeb: Make computed properties immutable Move CSS animation values into a mutable overlay on computed properties and make base computed style data immutable after construction. Base style mutation now goes through a builder that is consumed on publish, so installed styles no longer expose mutation APIs. Build new base style data for inherited style updates instead of cloning and mutating installed computed properties. Element-specific computed style adjustments now run before publication, while animation and transition updates continue to mutate only the animated overlay. --- .../LibWeb/Animations/AnimationEffect.cpp | 47 ++- Libraries/LibWeb/Animations/AnimationEffect.h | 16 +- .../LibWeb/Animations/KeyframeEffect.cpp | 17 +- Libraries/LibWeb/Animations/KeyframeEffect.h | 1 + Libraries/LibWeb/CSS/CSSAnimation.cpp | 2 +- Libraries/LibWeb/CSS/CSSAnimation.h | 4 +- Libraries/LibWeb/CSS/CSSAnimationProperties.h | 32 ++ Libraries/LibWeb/CSS/CSSStyleProperties.cpp | 1 + Libraries/LibWeb/CSS/ComputedProperties.cpp | 343 +++++++++++++----- Libraries/LibWeb/CSS/ComputedProperties.h | 211 +++++++---- Libraries/LibWeb/CSS/StyleComputer.cpp | 173 +++++---- Libraries/LibWeb/CSS/StyleComputer.h | 12 +- Libraries/LibWeb/DOM/AbstractElement.cpp | 1 + Libraries/LibWeb/DOM/AbstractElement.h | 1 - Libraries/LibWeb/DOM/Element.cpp | 86 +++-- Libraries/LibWeb/DOM/Element.h | 14 +- Libraries/LibWeb/DOM/PseudoElement.cpp | 56 ++- Libraries/LibWeb/DOM/PseudoElement.h | 37 +- .../HTML/Canvas/AbstractCanvasMixin.cpp | 1 + .../LibWeb/HTML/CanvasRenderingContext2D.cpp | 1 + Libraries/LibWeb/HTML/HTMLAudioElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLAudioElement.h | 2 +- Libraries/LibWeb/HTML/HTMLBRElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLBRElement.h | 2 +- Libraries/LibWeb/HTML/HTMLButtonElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLButtonElement.h | 2 +- Libraries/LibWeb/HTML/HTMLCanvasElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLCanvasElement.h | 2 +- Libraries/LibWeb/HTML/HTMLElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLElement.h | 4 +- Libraries/LibWeb/HTML/HTMLEmbedElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLEmbedElement.h | 2 +- Libraries/LibWeb/HTML/HTMLFrameElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLFrameElement.h | 2 +- Libraries/LibWeb/HTML/HTMLFrameSetElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLFrameSetElement.h | 2 +- Libraries/LibWeb/HTML/HTMLIFrameElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLIFrameElement.h | 2 +- Libraries/LibWeb/HTML/HTMLImageElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLImageElement.h | 2 +- Libraries/LibWeb/HTML/HTMLInputElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLInputElement.h | 2 +- Libraries/LibWeb/HTML/HTMLMediaElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLMediaElement.h | 2 +- Libraries/LibWeb/HTML/HTMLMeterElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLMeterElement.h | 2 +- Libraries/LibWeb/HTML/HTMLObjectElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLObjectElement.h | 2 +- Libraries/LibWeb/HTML/HTMLProgressElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLProgressElement.h | 2 +- Libraries/LibWeb/HTML/HTMLSelectElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLSelectElement.h | 2 +- Libraries/LibWeb/HTML/HTMLTableElement.cpp | 11 + Libraries/LibWeb/HTML/HTMLTableElement.h | 1 + Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp | 2 +- Libraries/LibWeb/HTML/HTMLTextAreaElement.h | 2 +- Libraries/LibWeb/Layout/TreeBuilder.cpp | 3 +- Libraries/LibWeb/SVG/SVGElement.cpp | 2 +- Libraries/LibWeb/SVG/SVGElement.h | 2 +- Libraries/LibWeb/SVG/SVGSymbolElement.cpp | 2 +- Libraries/LibWeb/SVG/SVGSymbolElement.h | 2 +- .../LibWeb/ViewTransition/ViewTransition.cpp | 1 + ...port-resize-animation-targeted-restyle.txt | 2 + ...ort-resize-animation-targeted-restyle.html | 12 + 64 files changed, 834 insertions(+), 330 deletions(-) create mode 100644 Libraries/LibWeb/CSS/CSSAnimationProperties.h diff --git a/Libraries/LibWeb/Animations/AnimationEffect.cpp b/Libraries/LibWeb/Animations/AnimationEffect.cpp index 44a1a2e407..baaaf8ee8a 100644 --- a/Libraries/LibWeb/Animations/AnimationEffect.cpp +++ b/Libraries/LibWeb/Animations/AnimationEffect.cpp @@ -31,6 +31,22 @@ namespace Web::Animations { GC_DEFINE_ALLOCATOR(AnimationEffect); +AnimationUpdateContext::ElementData::ElementData() = default; + +AnimationUpdateContext::ElementData::ElementData(RefPtr animated_properties_before_update, RefPtr target_style) + : animated_properties_before_update(move(animated_properties_before_update)) + , target_style(move(target_style)) +{ +} + +AnimationUpdateContext::ElementData::ElementData(ElementData&&) = default; + +AnimationUpdateContext::ElementData& AnimationUpdateContext::ElementData::operator=(ElementData&&) = default; + +AnimationUpdateContext::ElementData::~ElementData() = default; + +AnimationUpdateContext::AnimationUpdateContext() = default; + Bindings::FillMode css_fill_mode_to_bindings_fill_mode(CSS::AnimationFillMode mode) { switch (mode) { @@ -787,20 +803,34 @@ void AnimationEffect::visit_edges(JS::Cell::Visitor& visitor) visitor.visit(m_associated_animation); } -static CSS::RequiredInvalidationAfterStyleChange compute_required_invalidation_for_animated_properties(HashMap> const& old_properties, HashMap> const& new_properties) +static CSS::StyleValue const* animated_property_value(CSS::AnimatedProperties const* properties, CSS::PropertyID property_id) +{ + if (!properties) + return nullptr; + auto value = properties->values().get(property_id); + if (!value.has_value()) + return nullptr; + return value.value(); +} + +static CSS::RequiredInvalidationAfterStyleChange compute_required_invalidation_for_animated_properties(CSS::AnimatedProperties const* old_properties, CSS::AnimatedProperties const* new_properties) { CSS::RequiredInvalidationAfterStyleChange invalidation; auto old_and_new_properties = MUST(Bitmap::create(CSS::number_of_longhand_properties, 0)); - for (auto const& [property_id, _] : old_properties) - old_and_new_properties.set(to_underlying(property_id) - to_underlying(CSS::first_longhand_property_id), 1); - for (auto const& [property_id, _] : new_properties) - old_and_new_properties.set(to_underlying(property_id) - to_underlying(CSS::first_longhand_property_id), 1); + if (old_properties) { + for (auto const& [property_id, _] : old_properties->values()) + old_and_new_properties.set(to_underlying(property_id) - to_underlying(CSS::first_longhand_property_id), 1); + } + if (new_properties) { + for (auto const& [property_id, _] : new_properties->values()) + old_and_new_properties.set(to_underlying(property_id) - to_underlying(CSS::first_longhand_property_id), 1); + } for (auto i = to_underlying(CSS::first_longhand_property_id); i <= to_underlying(CSS::last_longhand_property_id); ++i) { if (!old_and_new_properties.get(i - to_underlying(CSS::first_longhand_property_id))) continue; auto property_id = static_cast(i); - auto const* old_value = old_properties.get(property_id).value_or({}); - auto const* new_value = new_properties.get(property_id).value_or({}); + auto const* old_value = animated_property_value(old_properties, property_id); + auto const* new_value = animated_property_value(new_properties, property_id); if (!old_value && !new_value) continue; auto property_invalidation = compute_property_invalidation(property_id, old_value, new_value); @@ -819,7 +849,8 @@ AnimationUpdateContext::~AnimationUpdateContext() continue; auto& element = it.key; GC::Ref target = element.element(); - auto invalidation = compute_required_invalidation_for_animated_properties(it.value.animated_properties_before_update, style->animated_property_values()); + auto animated_properties_after_update = style->animated_properties_snapshot(); + auto invalidation = compute_required_invalidation_for_animated_properties(it.value.animated_properties_before_update.ptr(), animated_properties_after_update.ptr()); if (invalidation.is_none()) continue; diff --git a/Libraries/LibWeb/Animations/AnimationEffect.h b/Libraries/LibWeb/Animations/AnimationEffect.h index 0d6f1eaa4f..596d709953 100644 --- a/Libraries/LibWeb/Animations/AnimationEffect.h +++ b/Libraries/LibWeb/Animations/AnimationEffect.h @@ -15,6 +15,12 @@ #include #include +namespace Web::CSS { + +class AnimatedProperties; + +} + namespace Web::Animations { enum class AnimationDirection { @@ -29,11 +35,17 @@ Bindings::OptionalEffectTiming to_optional_effect_timing(Bindings::EffectTiming // This object lives for the duration of an animation update, and is used to store per-element data about animated CSS properties. struct AnimationUpdateContext { struct ElementData { - using PropertyMap = HashMap>; - PropertyMap animated_properties_before_update; + ElementData(); + ElementData(RefPtr, RefPtr); + ElementData(ElementData&&); + ElementData& operator=(ElementData&&); + ~ElementData(); + + RefPtr animated_properties_before_update; RefPtr target_style; }; + AnimationUpdateContext(); ~AnimationUpdateContext(); // NOTE: This is lazily populated by KeyframeEffects as their respective animations are applied to an element. diff --git a/Libraries/LibWeb/Animations/KeyframeEffect.cpp b/Libraries/LibWeb/Animations/KeyframeEffect.cpp index ce93caafe8..668e3d2677 100644 --- a/Libraries/LibWeb/Animations/KeyframeEffect.cpp +++ b/Libraries/LibWeb/Animations/KeyframeEffect.cpp @@ -970,17 +970,18 @@ void KeyframeEffect::update_computed_properties(AnimationUpdateContext& context) return; } - auto computed_properties = target->computed_properties(pseudo_element_type()); - if (!computed_properties) - return; - DOM::AbstractElement abstract_element { *target, pseudo_element_type() }; - context.elements.ensure(abstract_element, [computed_properties] { - auto old_animated_properties = computed_properties->animated_property_values(); - computed_properties->reset_non_inherited_animated_properties({}); + target->update_animated_properties({}, pseudo_element_type(), *this, context); +} + +void KeyframeEffect::update_computed_properties_for_style(AnimationUpdateContext& context, DOM::AbstractElement abstract_element, CSS::ComputedProperties& computed_properties) +{ + context.elements.ensure(abstract_element, [&computed_properties] { + auto old_animated_properties = computed_properties.animated_properties_snapshot(); + computed_properties.reset_non_inherited_animated_properties({}); return AnimationUpdateContext::ElementData { move(old_animated_properties), computed_properties }; }); - target->document().style_computer().collect_animation_into(abstract_element, *this, *computed_properties); + abstract_element.element().document().style_computer().collect_animation_into(abstract_element, *this, computed_properties); } Bindings::CompositeOperation css_animation_composition_to_bindings_composite_operation(CSS::AnimationComposition composition) diff --git a/Libraries/LibWeb/Animations/KeyframeEffect.h b/Libraries/LibWeb/Animations/KeyframeEffect.h index aa0fc5c556..500e1b2d13 100644 --- a/Libraries/LibWeb/Animations/KeyframeEffect.h +++ b/Libraries/LibWeb/Animations/KeyframeEffect.h @@ -107,6 +107,7 @@ public: virtual bool is_keyframe_effect() const override { return true; } virtual void update_computed_properties(AnimationUpdateContext&) override; + void update_computed_properties_for_style(AnimationUpdateContext&, DOM::AbstractElement, CSS::ComputedProperties&); private: KeyframeEffect(JS::Realm&); diff --git a/Libraries/LibWeb/CSS/CSSAnimation.cpp b/Libraries/LibWeb/CSS/CSSAnimation.cpp index 11581017cb..72876cf253 100644 --- a/Libraries/LibWeb/CSS/CSSAnimation.cpp +++ b/Libraries/LibWeb/CSS/CSSAnimation.cpp @@ -85,7 +85,7 @@ static bool should_update_timeline(GC::Ptr old_ti return true; } -void CSSAnimation::apply_css_properties(ComputedProperties::AnimationProperties const& animation_properties) +void CSSAnimation::apply_css_properties(AnimationProperties const& animation_properties) { // FIXME: Don't apply overridden properties as defined here: https://drafts.csswg.org/css-animations-2/#animations diff --git a/Libraries/LibWeb/CSS/CSSAnimation.h b/Libraries/LibWeb/CSS/CSSAnimation.h index 2bb8a931e0..ecceaf96f5 100644 --- a/Libraries/LibWeb/CSS/CSSAnimation.h +++ b/Libraries/LibWeb/CSS/CSSAnimation.h @@ -7,7 +7,7 @@ #pragma once #include -#include +#include #include #include @@ -27,7 +27,7 @@ public: virtual Animations::AnimationClass animation_class() const override; virtual int class_specific_composite_order(GC::Ref other) const override; - void apply_css_properties(ComputedProperties::AnimationProperties const&); + void apply_css_properties(AnimationProperties const&); EasingFunction const& default_easing() const { return m_default_easing; } diff --git a/Libraries/LibWeb/CSS/CSSAnimationProperties.h b/Libraries/LibWeb/CSS/CSSAnimationProperties.h new file mode 100644 index 0000000000..bd269d0a90 --- /dev/null +++ b/Libraries/LibWeb/CSS/CSSAnimationProperties.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2026-present, the Ladybird developers. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +namespace Web::CSS { + +struct AnimationProperties { + Variant duration; + EasingFunction timing_function; + double iteration_count; + AnimationDirection direction; + AnimationPlayState play_state; + double delay; + AnimationFillMode fill_mode; + AnimationComposition composition; + FlyString name; + GC::Ptr timeline; +}; + +} diff --git a/Libraries/LibWeb/CSS/CSSStyleProperties.cpp b/Libraries/LibWeb/CSS/CSSStyleProperties.cpp index 2cfa376767..7a241d93bb 100644 --- a/Libraries/LibWeb/CSS/CSSStyleProperties.cpp +++ b/Libraries/LibWeb/CSS/CSSStyleProperties.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index 8daa990743..baa24ce547 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -58,112 +59,247 @@ namespace Web::CSS { static_assert(to_underlying(PseudoElement::KnownPseudoElementCount) <= sizeof(u64) * 8); -ComputedProperties::ComputedProperties() = default; +static size_t property_bitmap_index(PropertyID property_id) +{ + VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); + return to_underlying(property_id) - to_underlying(first_longhand_property_id); +} + +ComputedProperties::Builder::Builder() + : m_data(adopt_ref(*new Data)) + , m_style(adopt_ref(*new ComputedProperties(m_data, false, false))) +{ +} + +ComputedProperties::Builder::Builder(ComputedProperties const& style) + : Builder() +{ + m_data->property_values = style.data().property_values; + m_data->property_important = style.data().property_important; + m_data->property_inherited = style.data().property_inherited; + m_data->display_before_box_type_transformation = style.data().display_before_box_type_transformation; + m_data->pseudo_element_styles = style.data().pseudo_element_styles; + m_data->line_height = style.data().line_height; + m_data->inheritance_dependent_specified_values = style.data().inheritance_dependent_specified_values; + m_data->raw_cascaded_font_size = style.data().raw_cascaded_font_size; + m_depends_on_viewport_metrics = style.depends_on_viewport_metrics(); + m_font_metrics_depend_on_viewport_metrics = style.font_metrics_depend_on_viewport_metrics(); + m_style->m_depends_on_viewport_metrics = m_depends_on_viewport_metrics; + m_style->m_font_metrics_depend_on_viewport_metrics = m_font_metrics_depend_on_viewport_metrics; + if (style.m_animated_properties) + m_style->m_animated_properties = adopt_ref(*new AnimatedProperties(*style.m_animated_properties)); +} + +NonnullRefPtr ComputedProperties::Builder::build() && +{ + m_style->m_depends_on_viewport_metrics = m_depends_on_viewport_metrics; + m_style->m_font_metrics_depend_on_viewport_metrics = m_font_metrics_depend_on_viewport_metrics; + return move(m_style); +} + +ComputedProperties::Builder ComputedProperties::create_builder() +{ + return Builder {}; +} + +ComputedProperties::Builder ComputedProperties::create_builder_with_base_values_from(ComputedProperties const& style) +{ + return Builder { style }; +} + +NonnullRefPtr ComputedProperties::create(Builder&& builder) +{ + return move(builder).build(); +} + +AnimatedProperties::AnimatedProperties(AnimatedProperties const& other) + : m_has_property(other.m_has_property) + , m_property_inherited(other.m_property_inherited) + , m_property_result_of_transition(other.m_property_result_of_transition) + , m_values(other.m_values) +{ +} + +ComputedProperties::ComputedProperties(NonnullRefPtr data, bool depends_on_viewport_metrics, bool font_metrics_depend_on_viewport_metrics) + : m_data(move(data)) + , m_depends_on_viewport_metrics(depends_on_viewport_metrics) + , m_font_metrics_depend_on_viewport_metrics(font_metrics_depend_on_viewport_metrics) +{ +} ComputedProperties::~ComputedProperties() = default; -NonnullRefPtr ComputedProperties::create() +AnimatedProperties const& ComputedProperties::animated_properties() const { - return adopt_ref(*new ComputedProperties); + static NeverDestroyed empty_animated_properties; + if (!m_animated_properties) + return *empty_animated_properties; + return *m_animated_properties; +} + +AnimatedProperties& ComputedProperties::mutable_animated_properties() +{ + if (!m_animated_properties) + m_animated_properties = adopt_ref(*new AnimatedProperties); + if (m_animated_properties->ref_count() > 1) + m_animated_properties = adopt_ref(*new AnimatedProperties(*m_animated_properties)); + return *m_animated_properties; +} + +bool AnimatedProperties::has_property(PropertyID property_id) const +{ + return m_has_property.get(property_bitmap_index(property_id)); +} + +bool AnimatedProperties::is_property_inherited(PropertyID property_id) const +{ + return m_property_inherited.get(property_bitmap_index(property_id)); +} + +bool AnimatedProperties::is_property_result_of_transition(PropertyID property_id) const +{ + return m_property_result_of_transition.get(property_bitmap_index(property_id)); +} + +StyleValue const& AnimatedProperties::property(PropertyID property_id) const +{ + VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); + VERIFY(has_property(property_id)); + + auto animated_value = m_values.get(property_id); + VERIFY(animated_value.has_value()); + return *animated_value.value(); +} + +void AnimatedProperties::set_property_inherited(PropertyID property_id, ComputedProperties::Inherited inherited) +{ + m_property_inherited.set(property_bitmap_index(property_id), inherited == ComputedProperties::Inherited::Yes); +} + +void AnimatedProperties::set_property_result_of_transition(PropertyID property_id, AnimatedPropertyResultOfTransition animated_value_result_of_transition) +{ + m_property_result_of_transition.set(property_bitmap_index(property_id), animated_value_result_of_transition == AnimatedPropertyResultOfTransition::Yes); +} + +void AnimatedProperties::set_property(PropertyID id, NonnullRefPtr value, AnimatedPropertyResultOfTransition animated_property_result_of_transition, ComputedProperties::Inherited inherited) +{ + VERIFY(id >= first_longhand_property_id && id <= last_longhand_property_id); + + m_values.set(id, move(value)); + + m_has_property.set(property_bitmap_index(id), true); + + set_property_inherited(id, inherited); + set_property_result_of_transition(id, animated_property_result_of_transition); +} + +void AnimatedProperties::remove_property(PropertyID id) +{ + VERIFY(id >= first_longhand_property_id && id <= last_longhand_property_id); + + m_values.remove(id); + + m_has_property.set(property_bitmap_index(id), false); + set_property_inherited(id, ComputedProperties::Inherited::No); + set_property_result_of_transition(id, AnimatedPropertyResultOfTransition::No); +} + +void AnimatedProperties::reset_non_inherited_properties() +{ + for (auto property_id : m_values.keys()) { + if (!is_property_inherited(property_id)) + remove_property(property_id); + } } bool ComputedProperties::is_property_important(PropertyID property_id) const { - VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); - - size_t n = to_underlying(property_id) - to_underlying(first_longhand_property_id); - return m_property_important[n / 8] & (1 << (n % 8)); + return data().property_important.get(property_bitmap_index(property_id)); } -void ComputedProperties::set_property_important(PropertyID property_id, Important important) +void ComputedProperties::Builder::set_property_important(PropertyID property_id, Important important) { - VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); - - size_t n = to_underlying(property_id) - to_underlying(first_longhand_property_id); - if (important == Important::Yes) - m_property_important[n / 8] |= (1 << (n % 8)); - else - m_property_important[n / 8] &= ~(1 << (n % 8)); + data().property_important.set(property_bitmap_index(property_id), important == Important::Yes); } bool ComputedProperties::is_property_inherited(PropertyID property_id) const { - VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); + return data().property_inherited.get(property_bitmap_index(property_id)); +} - size_t n = to_underlying(property_id) - to_underlying(first_longhand_property_id); - return m_property_inherited[n / 8] & (1 << (n % 8)); +HashMap> const& ComputedProperties::animated_property_values() const +{ + return animated_properties().values(); +} + +RefPtr ComputedProperties::animated_properties_snapshot() const +{ + return m_animated_properties; +} + +bool ComputedProperties::has_animated_property(PropertyID property_id) const +{ + return animated_properties().has_property(property_id); } bool ComputedProperties::is_animated_property_inherited(PropertyID property_id) const { - VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); - - size_t n = to_underlying(property_id) - to_underlying(first_longhand_property_id); - return m_animated_property_inherited[n / 8] & (1 << (n % 8)); + return animated_properties().is_property_inherited(property_id); } bool ComputedProperties::is_animated_property_result_of_transition(PropertyID property_id) const { - VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); - - size_t n = to_underlying(property_id) - to_underlying(first_longhand_property_id); - return m_animated_property_result_of_transition[n / 8] & (1 << (n % 8)); + return animated_properties().is_property_result_of_transition(property_id); } bool ComputedProperties::has_pseudo_element_style(PseudoElement pseudo_element) const { VERIFY(to_underlying(pseudo_element) < to_underlying(PseudoElement::KnownPseudoElementCount)); - return m_pseudo_element_styles & (1ull << to_underlying(pseudo_element)); + return data().pseudo_element_styles & (1ull << to_underlying(pseudo_element)); } -void ComputedProperties::set_has_pseudo_element_styles(u64 pseudo_element_styles) +void ComputedProperties::Builder::set_has_pseudo_element_styles(u64 pseudo_element_styles) { constexpr auto known_pseudo_element_count = to_underlying(PseudoElement::KnownPseudoElementCount); if constexpr (known_pseudo_element_count < sizeof(u64) * 8) VERIFY((pseudo_element_styles >> known_pseudo_element_count) == 0); - m_pseudo_element_styles |= pseudo_element_styles; + data().pseudo_element_styles |= pseudo_element_styles; } -void ComputedProperties::set_property_inherited(PropertyID property_id, Inherited inherited) +void ComputedProperties::Builder::set_property_inherited(PropertyID property_id, Inherited inherited) { - VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); - - size_t n = to_underlying(property_id) - to_underlying(first_longhand_property_id); - if (inherited == Inherited::Yes) - m_property_inherited[n / 8] |= (1 << (n % 8)); - else - m_property_inherited[n / 8] &= ~(1 << (n % 8)); + data().property_inherited.set(property_bitmap_index(property_id), inherited == Inherited::Yes); } -void ComputedProperties::set_animated_property_inherited(PropertyID property_id, Inherited inherited) +void ComputedProperties::Builder::set_depends_on_viewport_metrics() { - VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); - - size_t n = to_underlying(property_id) - to_underlying(first_longhand_property_id); - if (inherited == Inherited::Yes) - m_animated_property_inherited[n / 8] |= (1 << (n % 8)); - else - m_animated_property_inherited[n / 8] &= ~(1 << (n % 8)); + m_depends_on_viewport_metrics = true; + m_style->m_depends_on_viewport_metrics = true; } -void ComputedProperties::set_animated_property_result_of_transition(PropertyID property_id, AnimatedPropertyResultOfTransition animated_value_result_of_transition) +void ComputedProperties::Builder::set_font_metrics_depend_on_viewport_metrics() { - VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); - - size_t n = to_underlying(property_id) - to_underlying(first_longhand_property_id); - if (animated_value_result_of_transition == AnimatedPropertyResultOfTransition::Yes) - m_animated_property_result_of_transition[n / 8] |= (1 << (n % 8)); - else - m_animated_property_result_of_transition[n / 8] &= ~(1 << (n % 8)); + m_font_metrics_depend_on_viewport_metrics = true; + m_style->m_font_metrics_depend_on_viewport_metrics = true; } -void ComputedProperties::set_has_pseudo_element_style(PseudoElement pseudo_element) +void ComputedProperties::set_depends_on_viewport_metrics(Badge) +{ + m_depends_on_viewport_metrics = true; +} + +void ComputedProperties::set_font_metrics_depend_on_viewport_metrics(Badge) +{ + m_font_metrics_depend_on_viewport_metrics = true; +} + +void ComputedProperties::Builder::set_has_pseudo_element_style(PseudoElement pseudo_element) { VERIFY(to_underlying(pseudo_element) < to_underlying(PseudoElement::KnownPseudoElementCount)); - m_pseudo_element_styles |= 1ull << to_underlying(pseudo_element); + data().pseudo_element_styles |= 1ull << to_underlying(pseudo_element); } -void ComputedProperties::set_property(PropertyID id, NonnullRefPtr value, Inherited inherited, Important important) +void ComputedProperties::Builder::set_property(PropertyID id, NonnullRefPtr value, Inherited inherited, Important important) { VERIFY(id >= first_longhand_property_id && id <= last_longhand_property_id); @@ -177,56 +313,97 @@ static bool property_affects_computed_font_list(PropertyID id) return first_is_one_of(id, PropertyID::FontFamily, PropertyID::FontSize, PropertyID::FontStyle, PropertyID::FontWeight, PropertyID::FontWidth, PropertyID::FontVariationSettings); } -void ComputedProperties::set_property_without_modifying_flags(PropertyID id, NonnullRefPtr value) +void ComputedProperties::Builder::set_property_without_modifying_flags(PropertyID id, NonnullRefPtr value) { VERIFY(id >= first_longhand_property_id && id <= last_longhand_property_id); - m_property_values[to_underlying(id) - to_underlying(first_longhand_property_id)] = move(value); + data().property_values[to_underlying(id) - to_underlying(first_longhand_property_id)] = move(value); if (property_affects_computed_font_list(id)) - clear_computed_font_list_cache(); + style().clear_computed_font_list_cache(); } -void ComputedProperties::revert_property(PropertyID id, ComputedProperties const& style_for_revert) +void ComputedProperties::Builder::revert_property(PropertyID id, ComputedProperties const& style_for_revert) { VERIFY(id >= first_longhand_property_id && id <= last_longhand_property_id); - m_property_values[to_underlying(id) - to_underlying(first_longhand_property_id)] = style_for_revert.m_property_values[to_underlying(id) - to_underlying(first_longhand_property_id)]; + data().property_values[to_underlying(id) - to_underlying(first_longhand_property_id)] = style_for_revert.data().property_values[to_underlying(id) - to_underlying(first_longhand_property_id)]; set_property_important(id, style_for_revert.is_property_important(id) ? Important::Yes : Important::No); set_property_inherited(id, style_for_revert.is_property_inherited(id) ? Inherited::Yes : Inherited::No); + + if (property_affects_computed_font_list(id)) + style().clear_computed_font_list_cache(); } Display ComputedProperties::display_before_box_type_transformation() const { - return m_display_before_box_type_transformation; + return data().display_before_box_type_transformation; } -void ComputedProperties::set_display_before_box_type_transformation(Display value) +void ComputedProperties::Builder::set_display_before_box_type_transformation(Display value) { - m_display_before_box_type_transformation = value; + data().display_before_box_type_transformation = value; } -void ComputedProperties::set_animated_property(PropertyID id, NonnullRefPtr value, AnimatedPropertyResultOfTransition animated_property_result_of_transition, Inherited inherited) +void ComputedProperties::set_animated_property_internal(PropertyID id, NonnullRefPtr value, AnimatedPropertyResultOfTransition animated_property_result_of_transition, Inherited inherited) { - m_animated_property_values.set(id, move(value)); - set_animated_property_inherited(id, inherited); - set_animated_property_result_of_transition(id, animated_property_result_of_transition); + VERIFY(id >= first_longhand_property_id && id <= last_longhand_property_id); + + mutable_animated_properties().set_property(id, move(value), animated_property_result_of_transition, inherited); if (property_affects_computed_font_list(id)) clear_computed_font_list_cache(); } -void ComputedProperties::remove_animated_property(PropertyID id) +void ComputedProperties::set_animated_property(Badge, PropertyID id, NonnullRefPtr value, AnimatedPropertyResultOfTransition animated_property_result_of_transition, Inherited inherited) { - m_animated_property_values.remove(id); + set_animated_property_internal(id, move(value), animated_property_result_of_transition, inherited); +} + +void ComputedProperties::set_animated_property(Badge, PropertyID id, NonnullRefPtr value, AnimatedPropertyResultOfTransition animated_property_result_of_transition, Inherited inherited) +{ + set_animated_property_internal(id, move(value), animated_property_result_of_transition, inherited); +} + +void ComputedProperties::remove_animated_property(Badge, PropertyID id) +{ + if (!has_animated_property(id)) + return; + + bool should_clear_computed_font_list_cache = property_affects_computed_font_list(id); + auto& animated_properties = mutable_animated_properties(); + animated_properties.remove_property(id); + if (animated_properties.is_empty()) + m_animated_properties = nullptr; + + if (should_clear_computed_font_list_cache) + clear_computed_font_list_cache(); } void ComputedProperties::reset_non_inherited_animated_properties(Badge) { - for (auto property_id : m_animated_property_values.keys()) { - if (!is_animated_property_inherited(property_id)) - m_animated_property_values.remove(property_id); + bool has_non_inherited_property = false; + bool should_clear_computed_font_list_cache = false; + for (auto const& property : animated_property_values()) { + if (is_animated_property_inherited(property.key)) + continue; + has_non_inherited_property = true; + if (property_affects_computed_font_list(property.key)) { + should_clear_computed_font_list_cache = true; + break; + } } + + if (!has_non_inherited_property) + return; + + auto& animated_properties = mutable_animated_properties(); + animated_properties.reset_non_inherited_properties(); + if (animated_properties.is_empty()) + m_animated_properties = nullptr; + + if (should_clear_computed_font_list_cache) + clear_computed_font_list_cache(); } StyleValue const& ComputedProperties::property(PropertyID property_id, WithAnimationsApplied return_animated_value) const @@ -234,14 +411,14 @@ StyleValue const& ComputedProperties::property(PropertyID property_id, WithAnima VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id); // Important properties override animated but not transitioned properties - if (!m_animated_property_values.is_empty() && return_animated_value == WithAnimationsApplied::Yes + if (return_animated_value == WithAnimationsApplied::Yes + && has_animated_property(property_id) && (!is_property_important(property_id) || is_animated_property_result_of_transition(property_id))) { - if (auto animated_value = m_animated_property_values.get(property_id); animated_value.has_value()) - return *animated_value.value(); + return animated_properties().property(property_id); } // By the time we call this method, the property should have been assigned - return *m_property_values[to_underlying(property_id) - to_underlying(first_longhand_property_id)]; + return *data().property_values[to_underlying(property_id) - to_underlying(first_longhand_property_id)]; } Variant ComputedProperties::gap_value(PropertyID id) const @@ -1017,9 +1194,9 @@ Positioning ComputedProperties::position() const bool ComputedProperties::operator==(ComputedProperties const& other) const { - for (size_t i = 0; i < m_property_values.size(); ++i) { - auto const& my_style = m_property_values[i]; - auto const& other_style = other.m_property_values[i]; + for (size_t i = 0; i < data().property_values.size(); ++i) { + auto const& my_style = data().property_values[i]; + auto const& other_style = other.data().property_values[i]; if (!my_style) { if (other_style) return false; @@ -2052,7 +2229,7 @@ Optional ComputedProperties::view_transition_name() const return {}; } -Vector ComputedProperties::animations(DOM::AbstractElement const& abstract_element) const +Vector ComputedProperties::animations(DOM::AbstractElement const& abstract_element) const { auto const& animation_name_values = property(PropertyID::AnimationName).as_value_list().values(); @@ -2435,7 +2612,7 @@ WillChange ComputedProperties::will_change() const ValueComparingNonnullRefPtr ComputedProperties::computed_font_list(FontComputer const& font_computer) const { if (!m_cached_computed_font_list) { - const_cast(this)->m_cached_computed_font_list = font_computer.compute_font_for_style_values(property(PropertyID::FontFamily), font_size(), font_slope(), font_weight(), font_width(), font_optical_sizing(), font_variation_settings(), font_feature_data()); + m_cached_computed_font_list = font_computer.compute_font_for_style_values(property(PropertyID::FontFamily), font_size(), font_slope(), font_weight(), font_width(), font_optical_sizing(), font_variation_settings(), font_feature_data()); VERIFY(!m_cached_computed_font_list->is_empty()); } @@ -2447,7 +2624,7 @@ ValueComparingNonnullRefPtr ComputedProperties::first_available if (!m_cached_first_available_computed_font) { // https://drafts.csswg.org/css-fonts/#first-available-font // First font for which the character U+0020 (space) is not excluded by a unicode-range - const_cast(this)->m_cached_first_available_computed_font = computed_font_list(font_computer)->font_for_code_point(' '); + m_cached_first_available_computed_font = computed_font_list(font_computer)->font_for_code_point(' '); } return *m_cached_first_available_computed_font; diff --git a/Libraries/LibWeb/CSS/ComputedProperties.h b/Libraries/LibWeb/CSS/ComputedProperties.h index 5bc2694e4a..db37eca104 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.h +++ b/Libraries/LibWeb/CSS/ComputedProperties.h @@ -7,6 +7,7 @@ #pragma once +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -27,6 +29,19 @@ namespace Web::CSS { +class AnimatedProperties; +class StyleComputer; + +} + +namespace Web::DOM { + +class Element; + +} + +namespace Web::CSS { + struct TransitionProperties { Vector properties; double duration; @@ -42,29 +57,89 @@ enum class AnimatedPropertyResultOfTransition : u8 { class WEB_API ComputedProperties final : public RefCounted { public: - static NonnullRefPtr create(); - static constexpr double normal_line_height_scale = 1.15; ~ComputedProperties(); - template - inline void for_each_property(Callback callback) const - { - for (size_t i = 0; i < m_property_values.size(); ++i) { - if (m_property_values[i]) - callback(static_cast(i + to_underlying(first_longhand_property_id)), *m_property_values[i]); - } - } - - void for_each_anchor_name(Function) const; + enum class WithAnimationsApplied { + No, + Yes, + }; enum class Inherited { No, Yes }; - HashMap> const& animated_property_values() const { return m_animated_property_values; } +private: + class Data; + +public: + class Builder { + public: + Builder(); + + ComputedProperties& style() { return *m_style; } + ComputedProperties const& style() const { return *m_style; } + NonnullRefPtr build() &&; + + bool depends_on_viewport_metrics() const { return m_depends_on_viewport_metrics; } + bool font_metrics_depend_on_viewport_metrics() const { return m_font_metrics_depend_on_viewport_metrics; } + Display display() const { return style().display(); } + StyleValue const& property(PropertyID property_id, WithAnimationsApplied with_animations_applied = WithAnimationsApplied::Yes) const { return style().property(property_id, with_animations_applied); } + [[nodiscard]] CSSPixels line_height() const { return style().line_height(); } + ValueComparingNonnullRefPtr first_available_computed_font(FontComputer const& font_computer) const { return style().first_available_computed_font(font_computer); } + + void set_has_pseudo_element_styles(u64); + void set_property_important(PropertyID, Important); + void set_property_inherited(PropertyID, Inherited); + void set_depends_on_viewport_metrics(); + void set_font_metrics_depend_on_viewport_metrics(); + void set_has_pseudo_element_style(PseudoElement); + + void set_property(PropertyID, NonnullRefPtr value, Inherited = Inherited::No, Important = Important::No); + void set_property_without_modifying_flags(PropertyID, NonnullRefPtr value); + void revert_property(PropertyID, ComputedProperties const& style_for_revert); + + void set_display_before_box_type_transformation(Display); + + HashMap> const& inheritance_dependent_specified_values() const { return m_data->inheritance_dependent_specified_values; } + void add_inheritance_dependent_specified_value(PropertyID property_id, NonnullRefPtr value) { m_data->inheritance_dependent_specified_values.set(property_id, move(value)); } + + RefPtr raw_cascaded_font_size() const { return m_data->raw_cascaded_font_size; } + void set_raw_cascaded_font_size(NonnullRefPtr value) { m_data->raw_cascaded_font_size = move(value); } + + private: + friend class ComputedProperties; + + Builder(ComputedProperties const&); + Data& data() { return *m_data; } + Data const& data() const { return *m_data; } + + NonnullRefPtr m_data; + NonnullRefPtr m_style; + bool m_depends_on_viewport_metrics { false }; + bool m_font_metrics_depend_on_viewport_metrics { false }; + }; + + static NonnullRefPtr create(Builder&&); + static Builder create_builder(); + static Builder create_builder_with_base_values_from(ComputedProperties const&); + + template + inline void for_each_property(Callback callback) const + { + for (size_t i = 0; i < m_data->property_values.size(); ++i) { + if (m_data->property_values[i]) + callback(static_cast(i + to_underlying(first_longhand_property_id)), *m_data->property_values[i]); + } + } + + void for_each_anchor_name(Function) const; + + HashMap> const& animated_property_values() const; + RefPtr animated_properties_snapshot() const; + bool has_animated_property(PropertyID property_id) const; void reset_non_inherited_animated_properties(Badge); bool is_property_important(PropertyID property_id) const; @@ -74,25 +149,12 @@ public: bool depends_on_viewport_metrics() const { return m_depends_on_viewport_metrics; } bool font_metrics_depend_on_viewport_metrics() const { return m_font_metrics_depend_on_viewport_metrics; } bool has_pseudo_element_style(PseudoElement) const; - void set_has_pseudo_element_styles(u64); - void set_property_important(PropertyID, Important); - void set_property_inherited(PropertyID, Inherited); - void set_animated_property_inherited(PropertyID, Inherited); - void set_animated_property_result_of_transition(PropertyID, AnimatedPropertyResultOfTransition); - void set_depends_on_viewport_metrics() { m_depends_on_viewport_metrics = true; } - void set_font_metrics_depend_on_viewport_metrics() { m_font_metrics_depend_on_viewport_metrics = true; } - void set_has_pseudo_element_style(PseudoElement); - - void set_property(PropertyID, NonnullRefPtr value, Inherited = Inherited::No, Important = Important::No); - void set_property_without_modifying_flags(PropertyID, NonnullRefPtr value); - void set_animated_property(PropertyID, NonnullRefPtr value, AnimatedPropertyResultOfTransition, Inherited = Inherited::No); - void remove_animated_property(PropertyID); - enum class WithAnimationsApplied { - No, - Yes, - }; + void set_depends_on_viewport_metrics(Badge); + void set_font_metrics_depend_on_viewport_metrics(Badge); + void set_animated_property(Badge, PropertyID, NonnullRefPtr value, AnimatedPropertyResultOfTransition, Inherited = Inherited::No); + void set_animated_property(Badge, PropertyID, NonnullRefPtr value, AnimatedPropertyResultOfTransition, Inherited = Inherited::No); + void remove_animated_property(Badge, PropertyID); StyleValue const& property(PropertyID, WithAnimationsApplied = WithAnimationsApplied::Yes) const; - void revert_property(PropertyID, ComputedProperties const& style_for_revert); Size size_value(PropertyID) const; [[nodiscard]] Variant gap_value(PropertyID) const; @@ -210,23 +272,10 @@ public: ContainerType container_type() const; MixBlendMode mix_blend_mode() const; Optional view_transition_name() const; - struct AnimationProperties { - Variant duration; - EasingFunction timing_function; - double iteration_count; - AnimationDirection direction; - AnimationPlayState play_state; - double delay; - AnimationFillMode fill_mode; - AnimationComposition composition; - FlyString name; - GC::Ptr timeline; - }; Vector animations(DOM::AbstractElement const&) const; Vector transitions() const; Display display_before_box_type_transformation() const; - void set_display_before_box_type_transformation(Display value); static Vector> transformations_for_style_value(StyleValue const& value); Vector> transformations() const; @@ -284,44 +333,80 @@ public: static NonnullRefPtr font_fallback(bool monospace, bool bold, float point_size); - HashMap> const& inheritance_dependent_specified_values() const { return m_inheritance_dependent_specified_values; } - void add_inheritance_dependent_specified_value(PropertyID property_id, NonnullRefPtr value) { m_inheritance_dependent_specified_values.set(property_id, move(value)); } + HashMap> const& inheritance_dependent_specified_values() const { return m_data->inheritance_dependent_specified_values; } - RefPtr raw_cascaded_font_size() const { return m_raw_cascaded_font_size; } - void set_raw_cascaded_font_size(NonnullRefPtr value) { m_raw_cascaded_font_size = move(value); } + RefPtr raw_cascaded_font_size() const { return m_data->raw_cascaded_font_size; } private: - ComputedProperties(); + class Data final : public RefCounted { + public: + Data() = default; + + Array, number_of_longhand_properties> property_values; + AK::FixedBitmap property_important { false }; + AK::FixedBitmap property_inherited { false }; + + Display display_before_box_type_transformation { InitialValues::display() }; + u64 pseudo_element_styles { 0 }; + + Optional line_height; + + HashMap> inheritance_dependent_specified_values; + RefPtr raw_cascaded_font_size; + }; + + ComputedProperties(NonnullRefPtr, bool depends_on_viewport_metrics, bool font_metrics_depend_on_viewport_metrics); Overflow overflow(PropertyID) const; Vector shadow(PropertyID, Layout::Node const&) const; Position position_value(PropertyID) const; - Array, number_of_longhand_properties> m_property_values; - Array m_property_important {}; - Array m_property_inherited {}; - Array m_animated_property_inherited {}; - Array m_animated_property_result_of_transition {}; + Data const& data() const { return *m_data; } + AnimatedProperties const& animated_properties() const; + AnimatedProperties& mutable_animated_properties(); + void set_animated_property_internal(PropertyID, NonnullRefPtr, AnimatedPropertyResultOfTransition, Inherited); - HashMap> m_animated_property_values; - - Display m_display_before_box_type_transformation { InitialValues::display() }; + NonnullRefPtr m_data; + RefPtr m_animated_properties; bool m_depends_on_viewport_metrics { false }; bool m_font_metrics_depend_on_viewport_metrics { false }; - u64 m_pseudo_element_styles { 0 }; - RefPtr m_cached_computed_font_list; - RefPtr m_cached_first_available_computed_font; + mutable RefPtr m_cached_computed_font_list; + mutable RefPtr m_cached_first_available_computed_font; void clear_computed_font_list_cache() { m_cached_computed_font_list = nullptr; m_cached_first_available_computed_font = nullptr; } +}; - Optional m_line_height; +class AnimatedProperties final : public RefCounted { +public: + using PropertyMap = HashMap>; - HashMap> m_inheritance_dependent_specified_values; - RefPtr m_raw_cascaded_font_size; + AnimatedProperties() = default; + AnimatedProperties(AnimatedProperties const&); + + bool is_empty() const { return m_values.is_empty(); } + PropertyMap const& values() const { return m_values; } + + bool has_property(PropertyID) const; + bool is_property_inherited(PropertyID) const; + bool is_property_result_of_transition(PropertyID) const; + StyleValue const& property(PropertyID) const; + + void set_property(PropertyID, NonnullRefPtr, AnimatedPropertyResultOfTransition, ComputedProperties::Inherited); + void remove_property(PropertyID); + void reset_non_inherited_properties(); + +private: + void set_property_inherited(PropertyID, ComputedProperties::Inherited); + void set_property_result_of_transition(PropertyID, AnimatedPropertyResultOfTransition); + + AK::FixedBitmap m_has_property { false }; + AK::FixedBitmap m_property_inherited { false }; + AK::FixedBitmap m_property_result_of_transition { false }; + PropertyMap m_values; }; } diff --git a/Libraries/LibWeb/CSS/StyleComputer.cpp b/Libraries/LibWeb/CSS/StyleComputer.cpp index 1ff96c8366..3045d292ed 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -1006,7 +1006,17 @@ static Optional resolve_keyframe_easing(CSS::StyleValue con return {}; } +void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element, GC::Ref effect, ComputedProperties::Builder& builder) const +{ + collect_animation_into(abstract_element, effect, builder.style(), &builder); +} + void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element, GC::Ref effect, ComputedProperties& computed_properties) const +{ + collect_animation_into(abstract_element, effect, computed_properties, nullptr); +} + +void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element, GC::Ref effect, ComputedProperties& computed_properties, ComputedProperties::Builder* builder) const { auto animation = effect->associated_animation(); if (!animation) @@ -1083,7 +1093,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element } // FIXME: Follow https://drafts.csswg.org/web-animations-1/#ref-for-computed-keyframes in whatever the right place is. - auto compute_keyframe_values = [&computed_properties, &abstract_element, this](auto const& keyframe_values) { + auto compute_keyframe_values = [&computed_properties, &abstract_element, builder, this](auto const& keyframe_values) { HashMap> result; HashMap longhands_set_by_property_id; AK::FixedBitmap property_is_set_by_use_initial(false); @@ -1215,9 +1225,15 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element computation_context.reset_viewport_metric_dependency_tracking(); result.set(property_id, compute_value_of_property(property_id, *style_value, get_property_specified_value, computation_context, m_document->page().client().device_pixels_per_css_pixel())); if (computation_context.depends_on_viewport_metrics()) { - computed_properties.set_depends_on_viewport_metrics(); - if (property_affects_font_metrics(property_id)) - computed_properties.set_font_metrics_depend_on_viewport_metrics(); + if (builder) { + builder->set_depends_on_viewport_metrics(); + if (property_affects_font_metrics(property_id)) + builder->set_font_metrics_depend_on_viewport_metrics(); + } else { + computed_properties.set_depends_on_viewport_metrics(Badge {}); + if (property_affects_font_metrics(property_id)) + computed_properties.set_font_metrics_depend_on_viewport_metrics(Badge {}); + } } } @@ -1253,7 +1269,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element if (!resolved_end_property) { if (resolved_start_property) { - computed_properties.set_animated_property(it.key, *resolved_start_property, is_result_of_transition); + computed_properties.set_animated_property(Badge {}, it.key, *resolved_start_property, is_result_of_transition); dbgln_if(LIBWEB_CSS_ANIMATION_DEBUG, "No end property for property {}, using {}", string_from_property_id(it.key), resolved_start_property->to_string(SerializationMode::Normal)); } continue; @@ -1283,11 +1299,11 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element if (auto next_value = interpolate_property(*effect->target(), it.key, *start, *end, progress_in_keyframe, AllowDiscrete::Yes)) { dbgln_if(LIBWEB_CSS_ANIMATION_DEBUG, "Interpolated value for property {} at {}: {} -> {} = {}", string_from_property_id(it.key), progress_in_keyframe, start->to_string(SerializationMode::Normal), end->to_string(SerializationMode::Normal), next_value->to_string(SerializationMode::Normal)); - computed_properties.set_animated_property(it.key, *next_value, is_result_of_transition); + computed_properties.set_animated_property(Badge {}, it.key, *next_value, is_result_of_transition); } else { // If interpolate_property() fails, the element should not be rendered dbgln_if(LIBWEB_CSS_ANIMATION_DEBUG, "Interpolated value for property {} at {}: {} -> {} is invalid", string_from_property_id(it.key), progress_in_keyframe, start->to_string(SerializationMode::Normal), end->to_string(SerializationMode::Normal)); - computed_properties.set_animated_property(PropertyID::Visibility, KeywordStyleValue::create(Keyword::Hidden), is_result_of_transition); + computed_properties.set_animated_property(Badge {}, PropertyID::Visibility, KeywordStyleValue::create(Keyword::Hidden), is_result_of_transition); } } } @@ -1431,8 +1447,10 @@ static void compute_transitioned_properties(ComputedProperties const& style, DOM } // https://drafts.csswg.org/css-transitions/#starting -void StyleComputer::start_needed_transitions(ComputedProperties const& previous_style, ComputedProperties& new_style, DOM::AbstractElement abstract_element) const +void StyleComputer::start_needed_transitions(ComputedProperties const& previous_style, ComputedProperties::Builder& new_style_builder, DOM::AbstractElement abstract_element) const { + auto& new_style = new_style_builder.style(); + // https://drafts.csswg.org/css-transitions/#transition-combined-duration auto combined_duration = [](Animations::Animatable::TransitionAttributes const& transition_attributes) { // Define the combined duration of the transition as the sum of max(matching transition duration, 0s) and the matching transition delay. @@ -1468,7 +1486,7 @@ void StyleComputer::start_needed_transitions(ComputedProperties const& previous_ auto transition = CSSTransition::start_a_transition(abstract_element, property_id, document().transition_generation(), delay, start_time, end_time, start_value, end_value, reversing_adjusted_start_value, reversing_shortening_factor); // Immediately set the property's value to the transition's current value, to prevent single-frame jumps. - collect_animation_into(abstract_element, as(*transition->effect()), new_style); + collect_animation_into(abstract_element, as(*transition->effect()), new_style_builder); }; // 1. If all of the following are true: @@ -2257,6 +2275,9 @@ Optional StyleComputer::get_animated_inheri if (!parent_element.has_value() || !parent_element->computed_properties()) return {}; + if (!parent_element->computed_properties()->has_animated_property(property_id)) + return {}; + if (auto animated_value = parent_element->computed_properties()->animated_property_values().get(property_id); animated_value.has_value()) return AnimatedInheritValue { .value = *animated_value.value(), @@ -2349,9 +2370,10 @@ static bool line_height_value_depends_on_computed_font_size(StyleValue const& va || (value.is_calculated() && value.as_calculated().contains_percentage()); } -void StyleComputer::compute_property_values(ComputedProperties& style, Optional abstract_element) const +void StyleComputer::compute_property_values(ComputedProperties::Builder& builder, Optional abstract_element) const { VERIFY(computation_context_cache_is_empty()); + auto& style = builder.style(); // NOTE: This doesn't necessarily return the specified value if we have already computed this property but that // doesn't matter as a computed value is always valid as a specified value. Function(PropertyID)> const get_property_specified_value = [&](auto property_id) -> NonnullRefPtr { @@ -2367,19 +2389,19 @@ void StyleComputer::compute_property_values(ComputedProperties& style, Optional< computation_context.reset_viewport_metric_dependency_tracking(); auto const& computed_value = compute_value_of_property(property_id, specified_value, get_property_specified_value, computation_context, device_pixels_per_css_pixel); if (computation_context.depends_on_viewport_metrics()) { - style.set_depends_on_viewport_metrics(); + builder.set_depends_on_viewport_metrics(); if (property_affects_font_metrics(property_id)) - style.set_font_metrics_depend_on_viewport_metrics(); + builder.set_font_metrics_depend_on_viewport_metrics(); } - style.set_property_without_modifying_flags(property_id, computed_value); + builder.set_property_without_modifying_flags(property_id, computed_value); } clear_computation_context_caches(); if (abstract_element.has_value() && is(abstract_element->element())) { m_root_element_font_metrics = calculate_root_element_font_metrics(style); - m_root_element_font_metrics_depend_on_viewport_metrics = style.font_metrics_depend_on_viewport_metrics(); + m_root_element_font_metrics_depend_on_viewport_metrics = builder.font_metrics_depend_on_viewport_metrics(); } } @@ -2490,8 +2512,9 @@ ComputationContext const& StyleComputer::get_computation_context_for_property(Pr VERIFY_NOT_REACHED(); } -void StyleComputer::resolve_effective_overflow_values(ComputedProperties& style) const +void StyleComputer::resolve_effective_overflow_values(ComputedProperties::Builder& builder) const { + auto& style = builder.style(); // https://www.w3.org/TR/css-overflow-3/#overflow-control // The visible/clip values of overflow compute to auto/hidden (respectively) if one of overflow-x or // overflow-y is neither visible nor clip. @@ -2501,18 +2524,19 @@ void StyleComputer::resolve_effective_overflow_values(ComputedProperties& style) auto overflow_y_is_visible_or_clip = overflow_y == Overflow::Visible || overflow_y == Overflow::Clip; if (!overflow_x_is_visible_or_clip || !overflow_y_is_visible_or_clip) { if (overflow_x == CSS::Overflow::Visible) - style.set_property(CSS::PropertyID::OverflowX, KeywordStyleValue::create(Keyword::Auto)); + builder.set_property(CSS::PropertyID::OverflowX, KeywordStyleValue::create(Keyword::Auto)); if (overflow_x == CSS::Overflow::Clip) - style.set_property(CSS::PropertyID::OverflowX, KeywordStyleValue::create(Keyword::Hidden)); + builder.set_property(CSS::PropertyID::OverflowX, KeywordStyleValue::create(Keyword::Hidden)); if (overflow_y == CSS::Overflow::Visible) - style.set_property(CSS::PropertyID::OverflowY, KeywordStyleValue::create(Keyword::Auto)); + builder.set_property(CSS::PropertyID::OverflowY, KeywordStyleValue::create(Keyword::Auto)); if (overflow_y == CSS::Overflow::Clip) - style.set_property(CSS::PropertyID::OverflowY, KeywordStyleValue::create(Keyword::Hidden)); + builder.set_property(CSS::PropertyID::OverflowY, KeywordStyleValue::create(Keyword::Hidden)); } } -static void compute_text_align(ComputedProperties& style, DOM::AbstractElement abstract_element) +static void compute_text_align(ComputedProperties::Builder& builder, DOM::AbstractElement abstract_element) { + auto& style = builder.style(); auto text_align_keyword = style.property(PropertyID::TextAlign).to_keyword(); // https://drafts.csswg.org/css-text-4/#valdef-text-align-match-parent @@ -2526,25 +2550,25 @@ static void compute_text_align(ComputedProperties& style, DOM::AbstractElement a switch (parent_text_align.to_keyword()) { case Keyword::Start: if (parent_direction == Direction::Ltr) { - style.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Left)); + builder.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Left)); } else { - style.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Right)); + builder.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Right)); } break; case Keyword::End: if (parent_direction == Direction::Ltr) { - style.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Right)); + builder.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Right)); } else { - style.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Left)); + builder.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Left)); } break; default: - style.set_property(PropertyID::TextAlign, parent_text_align); + builder.set_property(PropertyID::TextAlign, parent_text_align); } } else { - style.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Start)); + builder.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Start)); } } @@ -2555,11 +2579,11 @@ static void compute_text_align(ComputedProperties& style, DOM::AbstractElement a if (parent_element.has_value() && parent_element->computed_properties()) { auto const& parent_text_align = parent_element->computed_properties()->property(PropertyID::TextAlign); if (parent_text_align.to_keyword() != Keyword::Start) { - style.set_property(PropertyID::TextAlign, parent_text_align, ComputedProperties::Inherited::Yes); + builder.set_property(PropertyID::TextAlign, parent_text_align, ComputedProperties::Inherited::Yes); return; } } - style.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Center)); + builder.set_property(PropertyID::TextAlign, KeywordStyleValue::create(Keyword::Center)); } } @@ -2601,8 +2625,9 @@ static BoxTypeTransformation required_box_type_transformation(ComputedProperties } // https://drafts.csswg.org/css-display/#transformations -void StyleComputer::transform_box_type_if_needed(ComputedProperties& style, DOM::AbstractElement abstract_element) const +void StyleComputer::transform_box_type_if_needed(ComputedProperties::Builder& builder, DOM::AbstractElement abstract_element) const { + auto& style = builder.style(); // 2.7. Automatic Box Type Transformations // Some layout effects require blockification or inlinification of the box type, @@ -2611,7 +2636,7 @@ void StyleComputer::transform_box_type_if_needed(ComputedProperties& style, DOM: auto display = style.display(); - style.set_display_before_box_type_transformation(display); + builder.set_display_before_box_type_transformation(display); if (display.is_none() || (display.is_contents() && !abstract_element.element().is_document_element())) return; @@ -2619,7 +2644,7 @@ void StyleComputer::transform_box_type_if_needed(ComputedProperties& style, DOM: // https://drafts.csswg.org/css-display/#root // The root element’s display type is always blockified, and its principal box always establishes an independent formatting context. if (abstract_element.element().is_document_element() && !display.is_block_outside()) { - style.set_property(PropertyID::Display, DisplayStyleValue::create(Display::from_short(Display::Short::Block))); + builder.set_property(PropertyID::Display, DisplayStyleValue::create(Display::from_short(Display::Short::Block))); return; } @@ -2645,7 +2670,7 @@ void StyleComputer::transform_box_type_if_needed(ComputedProperties& style, DOM: // https://www.w3.org/TR/CSS2/visuren.html#dis-pos-flo // If 'position' has the value 'absolute' or 'fixed', [...] 'float' is set to 'none' if (style.position() == Positioning::Absolute || style.position() == Positioning::Fixed) - style.set_property(PropertyID::Float, KeywordStyleValue::create(Keyword::None)); + builder.set_property(PropertyID::Float, KeywordStyleValue::create(Keyword::None)); switch (required_box_type_transformation(style, abstract_element)) { case BoxTypeTransformation::None: @@ -2694,22 +2719,22 @@ void StyleComputer::transform_box_type_if_needed(ComputedProperties& style, DOM: } if (new_display != display) - style.set_property(PropertyID::Display, DisplayStyleValue::create(new_display)); + builder.set_property(PropertyID::Display, DisplayStyleValue::create(new_display)); } NonnullRefPtr StyleComputer::create_document_style() const { - auto style = CSS::ComputedProperties::create(); + auto builder = CSS::ComputedProperties::create_builder(); for (auto i = to_underlying(CSS::first_longhand_property_id); i <= to_underlying(CSS::last_longhand_property_id); ++i) { auto property_id = static_cast(i); - style->set_property(property_id, property_initial_value(property_id)); + builder.set_property(property_id, property_initial_value(property_id)); } - compute_property_values(style, {}); - style->set_property(CSS::PropertyID::Width, CSS::LengthStyleValue::create(CSS::Length::make_px(viewport_rect().width()))); - style->set_property(CSS::PropertyID::Height, CSS::LengthStyleValue::create(CSS::Length::make_px(viewport_rect().height()))); - style->set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::Block))); - return style; + compute_property_values(builder, {}); + builder.set_property(CSS::PropertyID::Width, CSS::LengthStyleValue::create(CSS::Length::make_px(viewport_rect().width()))); + builder.set_property(CSS::PropertyID::Height, CSS::LengthStyleValue::create(CSS::Length::make_px(viewport_rect().height()))); + builder.set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::Block))); + return CSS::ComputedProperties::create(move(builder)); } NonnullRefPtr StyleComputer::compute_style(DOM::AbstractElement abstract_element, Optional did_change_custom_properties) const @@ -2762,10 +2787,11 @@ RefPtr StyleComputer::compute_style_impl(DOM::AbstractElemen else abstract_element_for_pseudo_element.set_inheritance_override(host_element); - auto style = compute_style(abstract_element_for_pseudo_element); + auto inherited_pseudo_element_style = compute_style(abstract_element_for_pseudo_element); + auto builder = ComputedProperties::create_builder_with_base_values_from(*inherited_pseudo_element_style); - abstract_element.element().adjust_computed_style(style); - return style; + abstract_element.element().adjust_computed_style(builder); + return ComputedProperties::create(move(builder)); } ScopeGuard guard { [&abstract_element]() { abstract_element.element().set_needs_style_update(false); } }; @@ -2871,8 +2897,7 @@ RefPtr StyleComputer::compute_style_impl(DOM::AbstractElemen } } - auto computed_properties = compute_properties(abstract_element, cascaded_properties); - computed_properties->set_has_pseudo_element_styles(matching_rule_set.matching_pseudo_element_styles); + auto computed_properties = compute_properties(abstract_element, cascaded_properties, matching_rule_set.matching_pseudo_element_styles); if (did_change_custom_properties.has_value()) { auto new_custom_property_data = abstract_element.custom_property_data(); @@ -3001,32 +3026,34 @@ RefPtr StyleComputer::recascade_font_size_if_needed(DOM::Abstr return CSS::LengthStyleValue::create(CSS::Length::make_px(current_size_in_px)); } -NonnullRefPtr StyleComputer::compute_properties(DOM::AbstractElement abstract_element, CascadedProperties& cascaded_properties) const +NonnullRefPtr StyleComputer::compute_properties(DOM::AbstractElement abstract_element, CascadedProperties& cascaded_properties, u64 matching_pseudo_element_styles) const { VERIFY(computation_context_cache_is_empty()); - auto computed_style = CSS::ComputedProperties::create(); + auto builder = CSS::ComputedProperties::create_builder(); + auto& computed_style = builder.style(); + builder.set_has_pseudo_element_styles(matching_pseudo_element_styles); bool recascaded_font_size_depends_on_viewport_metrics = false; auto new_font_size = recascade_font_size_if_needed(abstract_element, cascaded_properties, recascaded_font_size_depends_on_viewport_metrics); if (new_font_size) { - computed_style->set_property(PropertyID::FontSize, *new_font_size, ComputedProperties::Inherited::No, Important::No); + builder.set_property(PropertyID::FontSize, *new_font_size, ComputedProperties::Inherited::No, Important::No); if (recascaded_font_size_depends_on_viewport_metrics) { - computed_style->set_depends_on_viewport_metrics(); - computed_style->set_font_metrics_depend_on_viewport_metrics(); + builder.set_depends_on_viewport_metrics(); + builder.set_font_metrics_depend_on_viewport_metrics(); } } auto const& computed_properties_to_inherit_from = abstract_element.element_to_inherit_style_from().map([](auto const& element) { return element.computed_properties(); }).value_or(nullptr); Function(PropertyID)> const get_property_specified_value = [&](auto property_id) -> NonnullRefPtr { - return computed_style->property(property_id); + return computed_style.property(property_id); }; auto const device_pixels_per_css_pixel = m_document->page().client().device_pixels_per_css_pixel(); auto const compute_property = [&](PropertyID property_id, NonnullRefPtr const& style_value, bool& depends_on_viewport_metrics) { - auto const& computation_context = get_computation_context_for_property(property_id, *computed_style, abstract_element); + auto const& computation_context = get_computation_context_for_property(property_id, computed_style, abstract_element); computation_context.reset_viewport_metric_dependency_tracking(); auto computed_value = compute_value_of_property(property_id, style_value, get_property_specified_value, computation_context, device_pixels_per_css_pixel); if (computation_context.depends_on_viewport_metrics()) @@ -3037,7 +3064,7 @@ NonnullRefPtr StyleComputer::compute_properties(DOM::Abstrac Optional logical_alias_mapping_context; auto const get_logical_alias_mapping_context = [&]() { if (!logical_alias_mapping_context.has_value()) - logical_alias_mapping_context = LogicalAliasMappingContext { computed_style->writing_mode(), computed_style->direction() }; + logical_alias_mapping_context = LogicalAliasMappingContext { computed_style.writing_mode(), computed_style.direction() }; return *logical_alias_mapping_context; }; @@ -3074,7 +3101,7 @@ NonnullRefPtr StyleComputer::compute_properties(DOM::Abstrac if (auto cascaded_style_property = cascaded_properties.style_property(cascaded_property_id); cascaded_style_property.has_value()) { if (cascaded_style_property->important == Important::Yes) - computed_style->set_property_important(property_id, Important::Yes); + builder.set_property_important(property_id, Important::Yes); value = cascaded_style_property->value; requires_computation = property_requires_computation_with_cascaded_value(property_id); @@ -3082,7 +3109,7 @@ NonnullRefPtr StyleComputer::compute_properties(DOM::Abstrac // font-size when font-family is monospace. // See the recascade_font_size_if_needed() function for further details. if (property_id == PropertyID::FontSize) - computed_style->set_raw_cascaded_font_size(*cascaded_style_property->value); + builder.set_raw_cascaded_font_size(*cascaded_style_property->value); } // NOTE: We've already handled font-size above. @@ -3109,21 +3136,25 @@ NonnullRefPtr StyleComputer::compute_properties(DOM::Abstrac if (auto* parent = abstract_element.element().parent(); parent && is(*parent)) parent->set_children_may_depend_on_non_inherited_property_inheritance(); } - computed_style->set_property_inherited(property_id, ComputedProperties::Inherited::Yes); + builder.set_property_inherited(property_id, ComputedProperties::Inherited::Yes); value = computed_properties_to_inherit_from->property(inherited_property_id, ComputedProperties::WithAnimationsApplied::No); requires_computation = property_requires_computation_with_inherited_value(property_id); if (property_affects_font_metrics(inherited_property_id) && computed_properties_to_inherit_from->font_metrics_depend_on_viewport_metrics()) - computed_style->set_font_metrics_depend_on_viewport_metrics(); + builder.set_font_metrics_depend_on_viewport_metrics(); // FIXME: Do we need to recompute animated inherited values? - if (auto animated_value = computed_properties_to_inherit_from->animated_property_values().get(inherited_property_id); animated_value.has_value()) - computed_style->set_animated_property( + if (computed_properties_to_inherit_from->has_animated_property(inherited_property_id)) { + auto animated_value = computed_properties_to_inherit_from->animated_property_values().get(inherited_property_id); + VERIFY(animated_value.has_value()); + computed_style.set_animated_property( + Badge {}, property_id, *animated_value.value(), computed_properties_to_inherit_from->is_animated_property_result_of_transition(inherited_property_id) ? AnimatedPropertyResultOfTransition::Yes : AnimatedPropertyResultOfTransition::No, ComputedProperties::Inherited::Yes); + } } if (!value || value->is_initial() || value->is_unset() || (should_inherit && !computed_properties_to_inherit_from)) { @@ -3138,7 +3169,7 @@ NonnullRefPtr StyleComputer::compute_properties(DOM::Abstrac || (property_id == PropertyID::FontSize && font_size_value_depends_on_inherited_font_size(*value)) || (property_id == PropertyID::LineHeight && line_height_value_depends_on_computed_font_size(*value)); if (depends_on_inherited_info) - computed_style->add_inheritance_dependent_specified_value(property_id, *value); + builder.add_inheritance_dependent_specified_value(property_id, *value); // NB: We compute using the inherited (physical) property to avoid having to add cases for all the logical // alias properties in `compute_value_of_property` @@ -3147,16 +3178,16 @@ NonnullRefPtr StyleComputer::compute_properties(DOM::Abstrac ? compute_property(inherited_property_id, value.release_nonnull(), depends_on_viewport_metrics) : value.release_nonnull(); if (depends_on_viewport_metrics) { - computed_style->set_depends_on_viewport_metrics(); + builder.set_depends_on_viewport_metrics(); if (property_affects_font_metrics(inherited_property_id)) - computed_style->set_font_metrics_depend_on_viewport_metrics(); + builder.set_font_metrics_depend_on_viewport_metrics(); } - computed_style->set_property_without_modifying_flags(property_id, move(computed_value)); + builder.set_property_without_modifying_flags(property_id, move(computed_value)); } if (is(abstract_element.element())) { m_root_element_font_metrics = calculate_root_element_font_metrics(computed_style); - m_root_element_font_metrics_depend_on_viewport_metrics = computed_style->font_metrics_depend_on_viewport_metrics(); + m_root_element_font_metrics_depend_on_viewport_metrics = builder.font_metrics_depend_on_viewport_metrics(); } // Compute the value of custom properties @@ -3177,30 +3208,30 @@ NonnullRefPtr StyleComputer::compute_properties(DOM::Abstrac if (auto effect = animation->effect(); effect && effect->is_keyframe_effect()) { auto& keyframe_effect = *static_cast(effect.ptr()); if (keyframe_effect.pseudo_element_type() == abstract_element.pseudo_element()) - collect_animation_into(abstract_element, keyframe_effect, computed_style); + collect_animation_into(abstract_element, keyframe_effect, builder); } } } // Run automatic box type transformations - transform_box_type_if_needed(computed_style, abstract_element); + transform_box_type_if_needed(builder, abstract_element); // Apply any property-specific computed value logic - resolve_effective_overflow_values(computed_style); - compute_text_align(computed_style, abstract_element); + resolve_effective_overflow_values(builder); + compute_text_align(builder, abstract_element); // Let the element adjust computed style if (!abstract_element.pseudo_element().has_value()) - abstract_element.element().adjust_computed_style(computed_style); + abstract_element.element().adjust_computed_style(builder); // Transition declarations [css-transitions-1] // Theoretically this should be part of the cascade, but it works with computed values, which we don't have until now. compute_transitioned_properties(computed_style, abstract_element); if (auto previous_style = abstract_element.computed_properties()) { - start_needed_transitions(*previous_style, computed_style, abstract_element); + start_needed_transitions(*previous_style, builder, abstract_element); } - return computed_style; + return CSS::ComputedProperties::create(move(builder)); } struct SimplifiedSelectorForBucketing { diff --git a/Libraries/LibWeb/CSS/StyleComputer.h b/Libraries/LibWeb/CSS/StyleComputer.h index 75f24ad48e..e24f0bb61c 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.h +++ b/Libraries/LibWeb/CSS/StyleComputer.h @@ -128,10 +128,11 @@ public: void set_viewport_rect(Badge, CSSPixelRect const& viewport_rect) { m_viewport_rect = viewport_rect; } void collect_animation_into(DOM::AbstractElement, GC::Ref animation, ComputedProperties&) const; + void collect_animation_into(DOM::AbstractElement, GC::Ref animation, ComputedProperties::Builder&) const; - [[nodiscard]] NonnullRefPtr compute_properties(DOM::AbstractElement, CascadedProperties&) const; + [[nodiscard]] NonnullRefPtr compute_properties(DOM::AbstractElement, CascadedProperties&, u64 matching_pseudo_element_styles) const; - void compute_property_values(ComputedProperties&, Optional) const; + void compute_property_values(ComputedProperties::Builder&, Optional) const; void process_animation_definitions(ComputedProperties const& computed_properties, CascadedProperties const&, DOM::AbstractElement& abstract_element) const; [[nodiscard]] inline bool should_reject_with_ancestor_filter(Selector const&) const; @@ -185,10 +186,11 @@ private: [[nodiscard]] RefPtr compute_style_impl(DOM::AbstractElement, ComputeStyleMode, Optional did_change_custom_properties, StyleScope const&) const; [[nodiscard]] NonnullRefPtr compute_cascaded_values(DOM::AbstractElement, bool did_match_any_pseudo_element_rules, ComputeStyleMode, MatchingRuleSet const&) const; + void collect_animation_into(DOM::AbstractElement, GC::Ref animation, ComputedProperties&, ComputedProperties::Builder*) const; void compute_custom_properties(ComputedProperties&, DOM::AbstractElement) const; - void start_needed_transitions(ComputedProperties const& old_style, ComputedProperties& new_style, DOM::AbstractElement) const; - void resolve_effective_overflow_values(ComputedProperties&) const; - void transform_box_type_if_needed(ComputedProperties&, DOM::AbstractElement) const; + void start_needed_transitions(ComputedProperties const& old_style, ComputedProperties::Builder& new_style, DOM::AbstractElement) const; + void resolve_effective_overflow_values(ComputedProperties::Builder&) const; + void transform_box_type_if_needed(ComputedProperties::Builder&, DOM::AbstractElement) const; [[nodiscard]] CSSPixelRect viewport_rect() const { return m_viewport_rect; } diff --git a/Libraries/LibWeb/DOM/AbstractElement.cpp b/Libraries/LibWeb/DOM/AbstractElement.cpp index 96cb8ca39e..9a5c972b71 100644 --- a/Libraries/LibWeb/DOM/AbstractElement.cpp +++ b/Libraries/LibWeb/DOM/AbstractElement.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include diff --git a/Libraries/LibWeb/DOM/AbstractElement.h b/Libraries/LibWeb/DOM/AbstractElement.h index ede860654e..9e1dba8386 100644 --- a/Libraries/LibWeb/DOM/AbstractElement.h +++ b/Libraries/LibWeb/DOM/AbstractElement.h @@ -7,7 +7,6 @@ #pragma once #include -#include #include #include diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index a148737596..11e9c9bc08 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1071,14 +1072,6 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_style(bool& did_cha auto& style_computer = document().style_computer(); auto new_computed_properties = style_computer.compute_style({ *this }, did_change_custom_properties); - // Tables must not inherit -libweb-* values for text-align. - // FIXME: Find the spec for this. - if (is(*this)) { - auto text_align = new_computed_properties->text_align(); - if (text_align == CSS::TextAlign::LibwebLeft || text_align == CSS::TextAlign::LibwebCenter || text_align == CSS::TextAlign::LibwebRight) - new_computed_properties->set_property(CSS::PropertyID::TextAlign, CSS::KeywordStyleValue::create(CSS::Keyword::Start)); - } - auto old_computed_properties = m_computed_properties; bool had_list_marker = false; @@ -1140,63 +1133,81 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style(Sch auto& counters = document().style_invalidation_counters(); counters.element_inherited_style_recomputations++; - auto computed_properties = this->computed_properties(); - VERIFY(computed_properties); - auto had_list_marker = computed_properties->display().is_list_item(); + auto old_computed_properties = this->computed_properties(); + VERIFY(old_computed_properties); + auto computed_properties_builder = CSS::ComputedProperties::create_builder_with_base_values_from(*old_computed_properties); + auto& new_computed_properties = computed_properties_builder.style(); + auto had_list_marker = old_computed_properties->display().is_list_item(); CSS::RequiredInvalidationAfterStyleChange invalidation; HashMap> property_values_affected_by_inherited_style; - for (auto const& [property_id, specified_value] : computed_properties->inheritance_dependent_specified_values()) { - RefPtr old_value = computed_properties->property(property_id); - computed_properties->set_property_without_modifying_flags(property_id, specified_value); + for (auto const& [property_id, specified_value] : old_computed_properties->inheritance_dependent_specified_values()) { + RefPtr old_value = old_computed_properties->property(property_id); + computed_properties_builder.set_property_without_modifying_flags(property_id, specified_value); property_values_affected_by_inherited_style.set(to_underlying(property_id), old_value); } + bool did_update_animated_properties = false; for (auto i = to_underlying(CSS::first_longhand_property_id); i <= to_underlying(CSS::last_longhand_property_id); ++i) { auto property_id = static_cast(i); - RefPtr old_value = computed_properties->property(property_id); + RefPtr old_value = old_computed_properties->property(property_id); - if (!computed_properties->is_property_inherited(property_id)) + if (!new_computed_properties.is_property_inherited(property_id)) continue; - if (computed_properties->is_animated_property_inherited(property_id) || !computed_properties->animated_property_values().contains(property_id)) { - if (auto new_animated_value = CSS::StyleComputer::get_animated_inherit_value(property_id, { *this }); new_animated_value.has_value()) - computed_properties->set_animated_property(property_id, new_animated_value->value, new_animated_value->is_result_of_transition, CSS::ComputedProperties::Inherited::Yes); - else if (computed_properties->animated_property_values().contains(property_id)) - computed_properties->remove_animated_property(property_id); + if (new_computed_properties.is_animated_property_inherited(property_id) || !new_computed_properties.has_animated_property(property_id)) { + RefPtr old_animated_value; + if (old_computed_properties->has_animated_property(property_id)) { + auto animated_value = old_computed_properties->animated_property_values().get(property_id); + VERIFY(animated_value.has_value()); + old_animated_value = *animated_value.value(); + } + if (auto new_animated_value = CSS::StyleComputer::get_animated_inherit_value(property_id, { *this }); new_animated_value.has_value()) { + if (!old_animated_value + || style_value_changed(*old_animated_value, *new_animated_value->value) + || old_computed_properties->is_animated_property_result_of_transition(property_id) != (new_animated_value->is_result_of_transition == CSS::AnimatedPropertyResultOfTransition::Yes) + || !old_computed_properties->is_animated_property_inherited(property_id)) + did_update_animated_properties = true; + new_computed_properties.set_animated_property(Badge {}, property_id, new_animated_value->value, new_animated_value->is_result_of_transition, CSS::ComputedProperties::Inherited::Yes); + } else if (old_animated_value) { + did_update_animated_properties = true; + new_computed_properties.remove_animated_property(Badge {}, property_id); + } } RefPtr new_value = CSS::StyleComputer::get_non_animated_inherit_value(property_id, { *this }); - computed_properties->set_property(property_id, *new_value, CSS::ComputedProperties::Inherited::Yes); - if (style_value_changed(*old_value, computed_properties->property(property_id))) + computed_properties_builder.set_property(property_id, *new_value, CSS::ComputedProperties::Inherited::Yes); + if (style_value_changed(*old_value, new_computed_properties.property(property_id))) invalidation.inherited_style_changed = true; - invalidation |= CSS::compute_property_invalidation(property_id, old_value.ptr(), &computed_properties->property(property_id)); + invalidation |= CSS::compute_property_invalidation(property_id, old_value.ptr(), &new_computed_properties.property(property_id)); } if (schedule_animation_update == ScheduleAnimationUpdate::Yes && has_relevant_animations()) document().set_needs_animated_style_update(); - if (invalidation.is_none() && property_values_affected_by_inherited_style.is_empty()) { + if (invalidation.is_none() && property_values_affected_by_inherited_style.is_empty() && !did_update_animated_properties) { counters.element_inherited_style_noop_recomputations++; return invalidation; } AbstractElement abstract_element { *this }; - document().style_computer().compute_property_values(*computed_properties, abstract_element); + document().style_computer().compute_property_values(computed_properties_builder, abstract_element); for (auto const& [property_id_value, old_value] : property_values_affected_by_inherited_style) { auto property_id = static_cast(property_id_value); - auto const& new_value = computed_properties->property(property_id); + auto const& new_value = new_computed_properties.property(property_id); if (CSS::is_inherited_property(property_id) && style_value_changed(*old_value, new_value)) invalidation.inherited_style_changed = true; invalidation |= CSS::compute_property_invalidation(property_id, old_value.ptr(), &new_value); } + m_computed_properties = CSS::ComputedProperties::create(move(computed_properties_builder)); + bool did_change_custom_properties = false; - invalidation |= recompute_pseudo_element_styles(did_change_custom_properties, had_list_marker, computed_properties.ptr()); + invalidation |= recompute_pseudo_element_styles(did_change_custom_properties, had_list_marker, old_computed_properties.ptr()); if (invalidation.is_none()) { counters.element_inherited_style_noop_recomputations++; @@ -3665,7 +3676,7 @@ size_t Element::attribute_list_size() const return m_attributes ? m_attributes->length() : 0; } -RefPtr Element::computed_properties(Optional pseudo_element_type) +RefPtr Element::computed_properties(Optional pseudo_element_type) const { if (pseudo_element_type.has_value()) { if (auto pseudo_element = get_pseudo_element(*pseudo_element_type); pseudo_element.has_value()) @@ -3675,14 +3686,23 @@ RefPtr Element::computed_properties(Optional Element::computed_properties(Optional pseudo_element_type) const +void Element::update_animated_properties(Badge const& badge, Optional pseudo_element_type, Web::Animations::KeyframeEffect& effect, Web::Animations::AnimationUpdateContext& context) { + DOM::AbstractElement abstract_element { *this, pseudo_element_type }; if (pseudo_element_type.has_value()) { if (auto pseudo_element = get_pseudo_element(*pseudo_element_type); pseudo_element.has_value()) - return pseudo_element->computed_properties(); - return {}; + pseudo_element->update_animated_properties(badge, abstract_element, effect, context); + return; } - return m_computed_properties; + + update_animated_properties_for_abstract_element(badge, abstract_element, effect, context); +} + +void Element::update_animated_properties_for_abstract_element(Badge const&, DOM::AbstractElement abstract_element, Web::Animations::KeyframeEffect& effect, Web::Animations::AnimationUpdateContext& context) +{ + if (!m_computed_properties) + return; + effect.update_computed_properties_for_style(context, abstract_element, *m_computed_properties); } void Element::set_computed_properties(Optional pseudo_element_type, RefPtr style) diff --git a/Libraries/LibWeb/DOM/Element.h b/Libraries/LibWeb/DOM/Element.h index 5b7362c6f2..d4b456d856 100644 --- a/Libraries/LibWeb/DOM/Element.h +++ b/Libraries/LibWeb/DOM/Element.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +39,13 @@ #include #include +namespace Web::Animations { + +struct AnimationUpdateContext; +class KeyframeEffect; + +} + namespace Web::DOM { // https://html.spec.whatwg.org/multipage/custom-elements.html#upgrade-reaction @@ -208,9 +217,10 @@ public: Layout::NodeWithStyle* unsafe_layout_node(); Layout::NodeWithStyle const* unsafe_layout_node() const; - RefPtr computed_properties(Optional = {}); RefPtr computed_properties(Optional = {}) const; void set_computed_properties(Optional, RefPtr); + void update_animated_properties(Badge const&, Optional, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&); + void update_animated_properties_for_abstract_element(Badge const&, DOM::AbstractElement, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&); Optional get_synthetic_pseudo_element(CSS::PseudoElement) const; Optional get_pseudo_element(CSS::PseudoElement) const; @@ -362,7 +372,7 @@ public: [[nodiscard]] CSSPixelRect bounding_client_rect_assuming_layout_clean() const; virtual RefPtr create_layout_node(CSS::ComputedProperties const&); - virtual void adjust_computed_style(CSS::ComputedProperties&) { } + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) { } virtual void did_receive_focus() { } virtual void did_lose_focus() { } diff --git a/Libraries/LibWeb/DOM/PseudoElement.cpp b/Libraries/LibWeb/DOM/PseudoElement.cpp index 034f8e9c35..c3abbd29f2 100644 --- a/Libraries/LibWeb/DOM/PseudoElement.cpp +++ b/Libraries/LibWeb/DOM/PseudoElement.cpp @@ -4,7 +4,10 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include +#include +#include #include #include #include @@ -16,6 +19,13 @@ GC_DEFINE_ALLOCATOR(SyntheticPseudoElement); GC_DEFINE_ALLOCATOR(SyntheticPseudoElementTreeNode); GC_DEFINE_ALLOCATOR(ElementReferencePseudoElement); +struct SyntheticPseudoElement::CustomPropertyDataStorage { + RefPtr data; +}; + +SyntheticPseudoElement::SyntheticPseudoElement() = default; +SyntheticPseudoElement::~SyntheticPseudoElement() = default; + void SyntheticPseudoElement::visit_edges(JS::Cell::Visitor& visitor) { Base::visit_edges(visitor); @@ -29,6 +39,42 @@ void SyntheticPseudoElement::set_layout_node(Layout::NodeWithStyle* value) m_layout_node = value; } +RefPtr SyntheticPseudoElement::computed_properties() const +{ + return m_computed_properties; +} + +void SyntheticPseudoElement::update_animated_properties(Badge const&, DOM::AbstractElement abstract_element, Web::Animations::KeyframeEffect& effect, Web::Animations::AnimationUpdateContext& context) +{ + if (!m_computed_properties) + return; + effect.update_computed_properties_for_style(context, abstract_element, *m_computed_properties); +} + +void SyntheticPseudoElement::set_computed_properties(RefPtr value) +{ + m_computed_properties = value; +} + +RefPtr SyntheticPseudoElement::custom_property_data() const +{ + if (!m_custom_property_data) + return nullptr; + return m_custom_property_data->data; +} + +void SyntheticPseudoElement::set_custom_property_data(RefPtr value) +{ + if (!value) { + m_custom_property_data = nullptr; + return; + } + + if (!m_custom_property_data) + m_custom_property_data = make(); + m_custom_property_data->data = move(value); +} + Optional SyntheticPseudoElement::counters_set() const { if (!m_counters_set) @@ -48,6 +94,9 @@ void SyntheticPseudoElement::set_counters_set(OwnPtr&& counter m_counters_set = move(counters_set); } +SyntheticPseudoElementTreeNode::SyntheticPseudoElementTreeNode() = default; +SyntheticPseudoElementTreeNode::~SyntheticPseudoElementTreeNode() = default; + void SyntheticPseudoElementTreeNode::visit_edges(JS::Cell::Visitor& visitor) { Base::visit_edges(visitor); @@ -64,11 +113,16 @@ Layout::NodeWithStyle* ElementReferencePseudoElement::unsafe_layout_node() const return m_referenced_element->unsafe_layout_node(); } -RefPtr ElementReferencePseudoElement::computed_properties() const +RefPtr ElementReferencePseudoElement::computed_properties() const { return m_referenced_element->computed_properties({}); } +void ElementReferencePseudoElement::update_animated_properties(Badge const& badge, DOM::AbstractElement abstract_element, Web::Animations::KeyframeEffect& effect, Web::Animations::AnimationUpdateContext& context) +{ + m_referenced_element->update_animated_properties_for_abstract_element(badge, abstract_element, effect, context); +} + RefPtr ElementReferencePseudoElement::custom_property_data() const { return m_referenced_element->custom_property_data({}); diff --git a/Libraries/LibWeb/DOM/PseudoElement.h b/Libraries/LibWeb/DOM/PseudoElement.h index cead1b390f..b5c0148d38 100644 --- a/Libraries/LibWeb/DOM/PseudoElement.h +++ b/Libraries/LibWeb/DOM/PseudoElement.h @@ -6,17 +6,23 @@ #pragma once +#include #include #include #include #include -#include -#include #include #include #include #include +namespace Web::Animations { + +struct AnimationUpdateContext; +class KeyframeEffect; + +} + namespace Web::DOM { class WEB_API PseudoElement : public JS::Cell { @@ -27,7 +33,8 @@ public: virtual Layout::NodeWithStyle* layout_node() const = 0; virtual Layout::NodeWithStyle* unsafe_layout_node() const = 0; - virtual RefPtr computed_properties() const = 0; + virtual RefPtr computed_properties() const = 0; + virtual void update_animated_properties(Badge const&, DOM::AbstractElement, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&) = 0; virtual RefPtr custom_property_data() const = 0; virtual void set_custom_property_data(RefPtr value) = 0; @@ -37,15 +44,20 @@ class WEB_API SyntheticPseudoElement : public PseudoElement { GC_CELL(SyntheticPseudoElement, PseudoElement); GC_DECLARE_ALLOCATOR(SyntheticPseudoElement); +public: + SyntheticPseudoElement(); + virtual ~SyntheticPseudoElement() override; + Layout::NodeWithStyle* layout_node() const override { return m_layout_node.ptr(); } Layout::NodeWithStyle* unsafe_layout_node() const override { return m_layout_node.ptr(); } void set_layout_node(Layout::NodeWithStyle*); - RefPtr computed_properties() const override { return m_computed_properties; } - void set_computed_properties(RefPtr value) { m_computed_properties = value; } + RefPtr computed_properties() const override; + void update_animated_properties(Badge const&, DOM::AbstractElement, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&) override; + void set_computed_properties(RefPtr value); - RefPtr custom_property_data() const override { return m_custom_property_data; } - void set_custom_property_data(RefPtr value) override { m_custom_property_data = move(value); } + RefPtr custom_property_data() const override; + void set_custom_property_data(RefPtr value) override; bool has_non_empty_counters_set() const { return m_counters_set; } Optional counters_set() const; @@ -58,9 +70,11 @@ class WEB_API SyntheticPseudoElement : public PseudoElement { virtual void visit_edges(JS::Cell::Visitor&) override; private: + struct CustomPropertyDataStorage; + WeakPtr m_layout_node; RefPtr m_computed_properties; - RefPtr m_custom_property_data; + OwnPtr m_custom_property_data; OwnPtr m_counters_set; CSSPixelPoint m_scroll_offset {}; }; @@ -72,6 +86,10 @@ class SyntheticPseudoElementTreeNode GC_CELL(SyntheticPseudoElementTreeNode, SyntheticPseudoElement); GC_DECLARE_ALLOCATOR(SyntheticPseudoElementTreeNode); +public: + SyntheticPseudoElementTreeNode(); + virtual ~SyntheticPseudoElementTreeNode() override; + protected: virtual void visit_edges(JS::Cell::Visitor& visitor) override; }; @@ -88,7 +106,8 @@ class WEB_API ElementReferencePseudoElement : public PseudoElement { Layout::NodeWithStyle* layout_node() const override; Layout::NodeWithStyle* unsafe_layout_node() const override; - RefPtr computed_properties() const override; + RefPtr computed_properties() const override; + void update_animated_properties(Badge const&, DOM::AbstractElement, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&) override; RefPtr custom_property_data() const override; void set_custom_property_data(RefPtr value) override; diff --git a/Libraries/LibWeb/HTML/Canvas/AbstractCanvasMixin.cpp b/Libraries/LibWeb/HTML/Canvas/AbstractCanvasMixin.cpp index 969f5bbc49..ef1c2d558d 100644 --- a/Libraries/LibWeb/HTML/Canvas/AbstractCanvasMixin.cpp +++ b/Libraries/LibWeb/HTML/Canvas/AbstractCanvasMixin.cpp @@ -5,6 +5,7 @@ */ #include "AbstractCanvasMixin.h" +#include #include #include #include diff --git a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index d463fbdfe9..7ae8e723fb 100644 --- a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include diff --git a/Libraries/LibWeb/HTML/HTMLAudioElement.cpp b/Libraries/LibWeb/HTML/HTMLAudioElement.cpp index ae34d9a3cd..2f1526f1dc 100644 --- a/Libraries/LibWeb/HTML/HTMLAudioElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLAudioElement.cpp @@ -28,7 +28,7 @@ void HTMLAudioElement::initialize(JS::Realm& realm) Base::initialize(realm); } -void HTMLAudioElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLAudioElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { Base::adjust_computed_style(style); diff --git a/Libraries/LibWeb/HTML/HTMLAudioElement.h b/Libraries/LibWeb/HTML/HTMLAudioElement.h index 24eacd25e3..b46edaa10c 100644 --- a/Libraries/LibWeb/HTML/HTMLAudioElement.h +++ b/Libraries/LibWeb/HTML/HTMLAudioElement.h @@ -17,7 +17,7 @@ class HTMLAudioElement final : public HTMLMediaElement { public: virtual ~HTMLAudioElement() override; - virtual void adjust_computed_style(CSS::ComputedProperties& style) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder& style) override; Layout::AudioBox* layout_node(); Layout::AudioBox const* layout_node() const; diff --git a/Libraries/LibWeb/HTML/HTMLBRElement.cpp b/Libraries/LibWeb/HTML/HTMLBRElement.cpp index 561f86950b..5c37db8dd1 100644 --- a/Libraries/LibWeb/HTML/HTMLBRElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLBRElement.cpp @@ -58,7 +58,7 @@ void HTMLBRElement::apply_presentational_hints(Vector& prope }); } -void HTMLBRElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLBRElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLBRElement.h b/Libraries/LibWeb/HTML/HTMLBRElement.h index 6c15a40c21..8d0b8be92e 100644 --- a/Libraries/LibWeb/HTML/HTMLBRElement.h +++ b/Libraries/LibWeb/HTML/HTMLBRElement.h @@ -20,7 +20,7 @@ public: virtual RefPtr create_layout_node(CSS::ComputedProperties const&) override; virtual bool is_presentational_hint(FlyString const&) const override; virtual void apply_presentational_hints(Vector&) const override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; private: virtual bool is_html_br_element() const override { return true; } diff --git a/Libraries/LibWeb/HTML/HTMLButtonElement.cpp b/Libraries/LibWeb/HTML/HTMLButtonElement.cpp index ed5c68363c..80163e2573 100644 --- a/Libraries/LibWeb/HTML/HTMLButtonElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLButtonElement.cpp @@ -31,7 +31,7 @@ void HTMLButtonElement::initialize(JS::Realm& realm) Base::initialize(realm); } -void HTMLButtonElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLButtonElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://html.spec.whatwg.org/multipage/rendering.html#button-layout // If the computed value of 'display' is 'inline-grid', 'grid', 'inline-flex', 'flex', 'none', or 'contents', then behave as the computed value. diff --git a/Libraries/LibWeb/HTML/HTMLButtonElement.h b/Libraries/LibWeb/HTML/HTMLButtonElement.h index edfa4ff80d..190c1425de 100644 --- a/Libraries/LibWeb/HTML/HTMLButtonElement.h +++ b/Libraries/LibWeb/HTML/HTMLButtonElement.h @@ -28,7 +28,7 @@ public: virtual ~HTMLButtonElement() override; virtual void initialize(JS::Realm&) override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; enum class TypeAttributeState { #define __ENUMERATE_HTML_BUTTON_TYPE_ATTRIBUTE(_, state) state, diff --git a/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp b/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp index 68ba78fb06..dda018c6e6 100644 --- a/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLCanvasElement.cpp @@ -248,7 +248,7 @@ RefPtr HTMLCanvasElement::create_layout_node(CSS::ComputedProperti return make_ref_counted(document(), *this, style); } -void HTMLCanvasElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLCanvasElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLCanvasElement.h b/Libraries/LibWeb/HTML/HTMLCanvasElement.h index 71cea78363..1e09c76082 100644 --- a/Libraries/LibWeb/HTML/HTMLCanvasElement.h +++ b/Libraries/LibWeb/HTML/HTMLCanvasElement.h @@ -78,7 +78,7 @@ private: virtual void apply_presentational_hints(Vector&) const override; virtual RefPtr create_layout_node(CSS::ComputedProperties const&) override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; template JS::ThrowCompletionOr create_webgl_context(JS::Value options); diff --git a/Libraries/LibWeb/HTML/HTMLElement.cpp b/Libraries/LibWeb/HTML/HTMLElement.cpp index fc83c7bf2e..03f6076020 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLElement.cpp @@ -1158,7 +1158,7 @@ void HTMLElement::set_popover(Optional value) remove_attribute(HTML::AttributeNames::popover); } -void HTMLElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (local_name() == HTML::TagNames::wbr) { diff --git a/Libraries/LibWeb/HTML/HTMLElement.h b/Libraries/LibWeb/HTML/HTMLElement.h index 730cf3bd76..4f85942de4 100644 --- a/Libraries/LibWeb/HTML/HTMLElement.h +++ b/Libraries/LibWeb/HTML/HTMLElement.h @@ -206,14 +206,14 @@ protected: [[nodiscard]] Utf16String get_the_text_steps(); + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; + private: virtual bool is_html_element() const final { return true; } // ^FormAssociatedElement virtual HTMLElement& form_associated_element_to_html_element() override { return *this; } - virtual void adjust_computed_style(CSS::ComputedProperties&) override; - // ^HTML::GlobalEventHandlers virtual GC::Ptr global_event_handlers_to_event_target(FlyString const&) override { return *this; } virtual void did_receive_focus() override; diff --git a/Libraries/LibWeb/HTML/HTMLEmbedElement.cpp b/Libraries/LibWeb/HTML/HTMLEmbedElement.cpp index d58cf4456e..2f8c55df16 100644 --- a/Libraries/LibWeb/HTML/HTMLEmbedElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLEmbedElement.cpp @@ -79,7 +79,7 @@ void HTMLEmbedElement::apply_presentational_hints(Vector& pr }); } -void HTMLEmbedElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLEmbedElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLEmbedElement.h b/Libraries/LibWeb/HTML/HTMLEmbedElement.h index 6f523e10b9..41eae1c999 100644 --- a/Libraries/LibWeb/HTML/HTMLEmbedElement.h +++ b/Libraries/LibWeb/HTML/HTMLEmbedElement.h @@ -24,7 +24,7 @@ private: virtual void initialize(JS::Realm&) override; virtual bool is_presentational_hint(FlyString const&) const override; virtual void apply_presentational_hints(Vector&) const override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; }; } diff --git a/Libraries/LibWeb/HTML/HTMLFrameElement.cpp b/Libraries/LibWeb/HTML/HTMLFrameElement.cpp index ccc08660d2..98562e0b50 100644 --- a/Libraries/LibWeb/HTML/HTMLFrameElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLFrameElement.cpp @@ -82,7 +82,7 @@ i32 HTMLFrameElement::default_tab_index_value() const return 0; } -void HTMLFrameElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLFrameElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLFrameElement.h b/Libraries/LibWeb/HTML/HTMLFrameElement.h index e8381a1932..2716ed367e 100644 --- a/Libraries/LibWeb/HTML/HTMLFrameElement.h +++ b/Libraries/LibWeb/HTML/HTMLFrameElement.h @@ -29,7 +29,7 @@ private: virtual void removed_from(IsSubtreeRoot, Node* old_ancestor, Node& old_root) override; virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value, Optional const& namespace_) override; virtual i32 default_tab_index_value() const override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; void process_the_frame_attributes(InitialInsertion = InitialInsertion::No); }; diff --git a/Libraries/LibWeb/HTML/HTMLFrameSetElement.cpp b/Libraries/LibWeb/HTML/HTMLFrameSetElement.cpp index c22f56dbda..72a6b98285 100644 --- a/Libraries/LibWeb/HTML/HTMLFrameSetElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLFrameSetElement.cpp @@ -23,7 +23,7 @@ HTMLFrameSetElement::HTMLFrameSetElement(DOM::Document& document, DOM::Qualified HTMLFrameSetElement::~HTMLFrameSetElement() = default; -void HTMLFrameSetElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLFrameSetElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLFrameSetElement.h b/Libraries/LibWeb/HTML/HTMLFrameSetElement.h index d2f88bc22e..a7526f5771 100644 --- a/Libraries/LibWeb/HTML/HTMLFrameSetElement.h +++ b/Libraries/LibWeb/HTML/HTMLFrameSetElement.h @@ -26,7 +26,7 @@ private: virtual bool is_html_frameset_element() const override { return true; } - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; virtual void initialize(JS::Realm&) override; virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value, Optional const& namespace_) override; diff --git a/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp b/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp index bde3745e4e..797518f6a1 100644 --- a/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLIFrameElement.cpp @@ -46,7 +46,7 @@ RefPtr HTMLIFrameElement::create_layout_node(CSS::ComputedProperti return make_ref_counted(document(), *this, style); } -void HTMLIFrameElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLIFrameElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLIFrameElement.h b/Libraries/LibWeb/HTML/HTMLIFrameElement.h index bb884d65af..1f9cf7490a 100644 --- a/Libraries/LibWeb/HTML/HTMLIFrameElement.h +++ b/Libraries/LibWeb/HTML/HTMLIFrameElement.h @@ -24,7 +24,7 @@ public: virtual ~HTMLIFrameElement() override; virtual RefPtr create_layout_node(CSS::ComputedProperties const&) override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; // ^EventTarget virtual bool is_focusable() const override diff --git a/Libraries/LibWeb/HTML/HTMLImageElement.cpp b/Libraries/LibWeb/HTML/HTMLImageElement.cpp index 7cc67a1baf..a3361a7654 100644 --- a/Libraries/LibWeb/HTML/HTMLImageElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLImageElement.cpp @@ -290,7 +290,7 @@ RefPtr HTMLImageElement::create_layout_node(CSS::ComputedPropertie return make_ref_counted(document(), *this, style, *this); } -void HTMLImageElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLImageElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLImageElement.h b/Libraries/LibWeb/HTML/HTMLImageElement.h index fc3aa464f0..be978dc805 100644 --- a/Libraries/LibWeb/HTML/HTMLImageElement.h +++ b/Libraries/LibWeb/HTML/HTMLImageElement.h @@ -128,7 +128,7 @@ private: virtual bool supports_dimension_attributes() const override { return true; } virtual RefPtr create_layout_node(CSS::ComputedProperties const&) override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; virtual void did_set_viewport_rect(CSSPixelRect const&) override; diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 11c678bc1c..8cf6f7e161 100644 --- a/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -178,7 +178,7 @@ RefPtr HTMLInputElement::create_layout_node(CSS::ComputedPropertie } } -void HTMLInputElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLInputElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { if (type_state() == TypeAttributeState::Hidden || type_state() == TypeAttributeState::SubmitButton || type_state() == TypeAttributeState::Button || type_state() == TypeAttributeState::ResetButton || type_state() == TypeAttributeState::ImageButton || type_state() == TypeAttributeState::Checkbox || type_state() == TypeAttributeState::RadioButton) return; diff --git a/Libraries/LibWeb/HTML/HTMLInputElement.h b/Libraries/LibWeb/HTML/HTMLInputElement.h index dd36cfffc0..0ea53becca 100644 --- a/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -65,7 +65,7 @@ public: virtual ~HTMLInputElement() override; virtual RefPtr create_layout_node(CSS::ComputedProperties const&) override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; virtual void set_being_activated(bool) override; enum class TypeAttributeState { diff --git a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index 8a70a8a642..7328f0a310 100644 --- a/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -137,7 +137,7 @@ void HTMLMediaElement::finalize() document().page().unregister_media_element({}, unique_id()); } -void HTMLMediaElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLMediaElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLMediaElement.h b/Libraries/LibWeb/HTML/HTMLMediaElement.h index d3302e860c..6eb47cad5a 100644 --- a/Libraries/LibWeb/HTML/HTMLMediaElement.h +++ b/Libraries/LibWeb/HTML/HTMLMediaElement.h @@ -50,7 +50,7 @@ public: return meets_focusable_area_rendering_requirements(); } - virtual void adjust_computed_style(CSS::ComputedProperties& style) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder& style) override; // NOTE: The function is wrapped in a GC::HeapFunction immediately. void queue_a_media_element_task(Function); diff --git a/Libraries/LibWeb/HTML/HTMLMeterElement.cpp b/Libraries/LibWeb/HTML/HTMLMeterElement.cpp index 2cac156626..928bd547f7 100644 --- a/Libraries/LibWeb/HTML/HTMLMeterElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLMeterElement.cpp @@ -170,7 +170,7 @@ void HTMLMeterElement::inserted() create_shadow_tree_if_needed(); } -void HTMLMeterElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLMeterElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLMeterElement.h b/Libraries/LibWeb/HTML/HTMLMeterElement.h index ba1dbdbb21..034895bfb5 100644 --- a/Libraries/LibWeb/HTML/HTMLMeterElement.h +++ b/Libraries/LibWeb/HTML/HTMLMeterElement.h @@ -36,7 +36,7 @@ public: // ^HTMLElement virtual void inserted() override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; // https://html.spec.whatwg.org/multipage/forms.html#category-label virtual bool is_labelable() const override { return true; } diff --git a/Libraries/LibWeb/HTML/HTMLObjectElement.cpp b/Libraries/LibWeb/HTML/HTMLObjectElement.cpp index 43b88eb3dd..7f1770fdf7 100644 --- a/Libraries/LibWeb/HTML/HTMLObjectElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLObjectElement.cpp @@ -221,7 +221,7 @@ RefPtr HTMLObjectElement::create_layout_node(CSS::ComputedProperti return nullptr; } -void HTMLObjectElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLObjectElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLObjectElement.h b/Libraries/LibWeb/HTML/HTMLObjectElement.h index c141031a89..9acfe24d41 100644 --- a/Libraries/LibWeb/HTML/HTMLObjectElement.h +++ b/Libraries/LibWeb/HTML/HTMLObjectElement.h @@ -64,7 +64,7 @@ private: virtual void apply_presentational_hints(Vector&) const override; virtual RefPtr create_layout_node(CSS::ComputedProperties const&) override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; bool has_ancestor_media_element_or_object_element_not_showing_fallback_content() const; diff --git a/Libraries/LibWeb/HTML/HTMLProgressElement.cpp b/Libraries/LibWeb/HTML/HTMLProgressElement.cpp index ebe9d4ced5..aed3079352 100644 --- a/Libraries/LibWeb/HTML/HTMLProgressElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLProgressElement.cpp @@ -95,7 +95,7 @@ void HTMLProgressElement::inserted() create_shadow_tree_if_needed(); } -void HTMLProgressElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLProgressElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLProgressElement.h b/Libraries/LibWeb/HTML/HTMLProgressElement.h index e50ed8ea90..8f4067920c 100644 --- a/Libraries/LibWeb/HTML/HTMLProgressElement.h +++ b/Libraries/LibWeb/HTML/HTMLProgressElement.h @@ -30,7 +30,7 @@ public: // ^HTMLElement virtual void inserted() override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; // https://html.spec.whatwg.org/multipage/forms.html#category-label virtual bool is_labelable() const override { return true; } diff --git a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp index a3ba53a266..988048a392 100644 --- a/Libraries/LibWeb/HTML/HTMLSelectElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLSelectElement.cpp @@ -79,7 +79,7 @@ void HTMLSelectElement::visit_edges(Cell::Visitor& visitor) } } -void HTMLSelectElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLSelectElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLSelectElement.h b/Libraries/LibWeb/HTML/HTMLSelectElement.h index f2d727b6f2..0f8baf1931 100644 --- a/Libraries/LibWeb/HTML/HTMLSelectElement.h +++ b/Libraries/LibWeb/HTML/HTMLSelectElement.h @@ -30,7 +30,7 @@ public: virtual bool is_html_select_element() const final { return true; } - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; WebIDL::UnsignedLong size() const; void set_size(WebIDL::UnsignedLong); diff --git a/Libraries/LibWeb/HTML/HTMLTableElement.cpp b/Libraries/LibWeb/HTML/HTMLTableElement.cpp index f1c74d23ed..a2ac2788a9 100644 --- a/Libraries/LibWeb/HTML/HTMLTableElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTableElement.cpp @@ -49,6 +49,17 @@ void HTMLTableElement::visit_edges(Cell::Visitor& visitor) visitor.visit(m_t_bodies); } +void HTMLTableElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) +{ + Base::adjust_computed_style(style); + + // Tables must not inherit -libweb-* values for text-align. + // FIXME: Find the spec for this. + auto text_align = style.style().text_align(); + if (text_align == CSS::TextAlign::LibwebLeft || text_align == CSS::TextAlign::LibwebCenter || text_align == CSS::TextAlign::LibwebRight) + style.set_property(CSS::PropertyID::TextAlign, CSS::KeywordStyleValue::create(CSS::Keyword::Start)); +} + static unsigned parse_border(StringView value) { return value.to_number().value_or(0); diff --git a/Libraries/LibWeb/HTML/HTMLTableElement.h b/Libraries/LibWeb/HTML/HTMLTableElement.h index 6ceb07241f..51ba2abf73 100644 --- a/Libraries/LibWeb/HTML/HTMLTableElement.h +++ b/Libraries/LibWeb/HTML/HTMLTableElement.h @@ -61,6 +61,7 @@ private: virtual bool is_presentational_hint(FlyString const&) const override; virtual void apply_presentational_hints(Vector&) const override; virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value, Optional const& namespace_) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; GC::Ptr mutable m_rows; GC::Ptr mutable m_t_bodies; diff --git a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp index 0a8640857e..db670a3593 100644 --- a/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp +++ b/Libraries/LibWeb/HTML/HTMLTextAreaElement.cpp @@ -40,7 +40,7 @@ HTMLTextAreaElement::HTMLTextAreaElement(DOM::Document& document, DOM::Qualified HTMLTextAreaElement::~HTMLTextAreaElement() = default; -void HTMLTextAreaElement::adjust_computed_style(CSS::ComputedProperties& style) +void HTMLTextAreaElement::adjust_computed_style(CSS::ComputedProperties::Builder& style) { // https://drafts.csswg.org/css-display-3/#unbox if (style.display().is_contents()) diff --git a/Libraries/LibWeb/HTML/HTMLTextAreaElement.h b/Libraries/LibWeb/HTML/HTMLTextAreaElement.h index 7f3b21431a..55e161b669 100644 --- a/Libraries/LibWeb/HTML/HTMLTextAreaElement.h +++ b/Libraries/LibWeb/HTML/HTMLTextAreaElement.h @@ -32,7 +32,7 @@ class WEB_API HTMLTextAreaElement final public: virtual ~HTMLTextAreaElement() override; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; String const& type() const { diff --git a/Libraries/LibWeb/Layout/TreeBuilder.cpp b/Libraries/LibWeb/Layout/TreeBuilder.cpp index db77d9816b..d8017ae5cf 100644 --- a/Libraries/LibWeb/Layout/TreeBuilder.cpp +++ b/Libraries/LibWeb/Layout/TreeBuilder.cpp @@ -514,7 +514,6 @@ RefPtr TreeBuilder::create_pseudo_element_if_needed(DOM::Element& element, *pseudo_element_style); list_box->set_marker(list_item_marker); - element.set_computed_properties(CSS::PseudoElement::Marker, pseudo_element_style); element.set_synthetic_pseudo_element_node({}, CSS::PseudoElement::Marker, list_item_marker); list_box->prepend_child(*list_item_marker); return list_item_marker; @@ -877,7 +876,7 @@ void TreeBuilder::update_layout_tree(DOM::Node& dom_node, TreeBuilder::Context& } auto& style_computer = document.style_computer(); - RefPtr style; + RefPtr style; CSS::Display display; if (!should_create_layout_node) { diff --git a/Libraries/LibWeb/SVG/SVGElement.cpp b/Libraries/LibWeb/SVG/SVGElement.cpp index 10feec7bf5..e732d63c16 100644 --- a/Libraries/LibWeb/SVG/SVGElement.cpp +++ b/Libraries/LibWeb/SVG/SVGElement.cpp @@ -294,7 +294,7 @@ void SVGElement::remove_from_use_element_that_reference_this() } } -void SVGElement::adjust_computed_style(CSS::ComputedProperties& computed_properties) +void SVGElement::adjust_computed_style(CSS::ComputedProperties::Builder& computed_properties) { Base::adjust_computed_style(computed_properties); diff --git a/Libraries/LibWeb/SVG/SVGElement.h b/Libraries/LibWeb/SVG/SVGElement.h index 02f6de475e..6ed2945511 100644 --- a/Libraries/LibWeb/SVG/SVGElement.h +++ b/Libraries/LibWeb/SVG/SVGElement.h @@ -48,7 +48,7 @@ protected: virtual void children_changed(ChildrenChangedMetadata const&) override; virtual void inserted() override; virtual void removed_from(IsSubtreeRoot, Node* old_ancestor, Node& old_root) override; - MUST_UPCALL virtual void adjust_computed_style(CSS::ComputedProperties&) override; + MUST_UPCALL virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; void update_use_elements_that_reference_this(); void remove_from_use_element_that_reference_this(); diff --git a/Libraries/LibWeb/SVG/SVGSymbolElement.cpp b/Libraries/LibWeb/SVG/SVGSymbolElement.cpp index c7826b7710..a81e314962 100644 --- a/Libraries/LibWeb/SVG/SVGSymbolElement.cpp +++ b/Libraries/LibWeb/SVG/SVGSymbolElement.cpp @@ -35,7 +35,7 @@ void SVGSymbolElement::visit_edges(Cell::Visitor& visitor) SVGFitToViewBox::visit_edges(visitor); } -void SVGSymbolElement::adjust_computed_style(CSS::ComputedProperties& computed_properties) +void SVGSymbolElement::adjust_computed_style(CSS::ComputedProperties::Builder& computed_properties) { Base::adjust_computed_style(computed_properties); diff --git a/Libraries/LibWeb/SVG/SVGSymbolElement.h b/Libraries/LibWeb/SVG/SVGSymbolElement.h index 9d87e4daeb..14e0a37693 100644 --- a/Libraries/LibWeb/SVG/SVGSymbolElement.h +++ b/Libraries/LibWeb/SVG/SVGSymbolElement.h @@ -19,7 +19,7 @@ class SVGSymbolElement final : public SVGGraphicsElement public: virtual ~SVGSymbolElement() override = default; - virtual void adjust_computed_style(CSS::ComputedProperties&) override; + virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override; private: virtual bool is_svg_symbol_element() const final { return true; } diff --git a/Libraries/LibWeb/ViewTransition/ViewTransition.cpp b/Libraries/LibWeb/ViewTransition/ViewTransition.cpp index 651536f4f5..879a151c40 100644 --- a/Libraries/LibWeb/ViewTransition/ViewTransition.cpp +++ b/Libraries/LibWeb/ViewTransition/ViewTransition.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include diff --git a/Tests/LibWeb/Text/expected/css/style-invalidation/viewport-resize-animation-targeted-restyle.txt b/Tests/LibWeb/Text/expected/css/style-invalidation/viewport-resize-animation-targeted-restyle.txt index c1f69ad6ac..58c392ea07 100644 --- a/Tests/LibWeb/Text/expected/css/style-invalidation/viewport-resize-animation-targeted-restyle.txt +++ b/Tests/LibWeb/Text/expected/css/style-invalidation/viewport-resize-animation-targeted-restyle.txt @@ -3,11 +3,13 @@ initial inherited-font animated width: 45px initial root-font animated width: 45px initial animated font size: 45px initial animated inherited-font width: 67.5px +initial post-style animated width: 45px targeted pending animated outline width: 75px resized viewport animated width: 75px resized inherited-font animated width: 75px resized root-font animated width: 75px resized animated font size: 75px resized animated inherited-font width: 112.5px +resized post-style animated width: 75px full invalidations: 0 style recomputations bounded: true diff --git a/Tests/LibWeb/Text/input/css/style-invalidation/viewport-resize-animation-targeted-restyle.html b/Tests/LibWeb/Text/input/css/style-invalidation/viewport-resize-animation-targeted-restyle.html index 19dd4482a6..4df8c3e174 100644 --- a/Tests/LibWeb/Text/input/css/style-invalidation/viewport-resize-animation-targeted-restyle.html +++ b/Tests/LibWeb/Text/input/css/style-invalidation/viewport-resize-animation-targeted-restyle.html @@ -32,6 +32,7 @@
+