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.
This commit is contained in:
parent
d7c08964cb
commit
2bf1f41805
64 changed files with 834 additions and 330 deletions
|
|
@ -31,6 +31,22 @@ namespace Web::Animations {
|
|||
|
||||
GC_DEFINE_ALLOCATOR(AnimationEffect);
|
||||
|
||||
AnimationUpdateContext::ElementData::ElementData() = default;
|
||||
|
||||
AnimationUpdateContext::ElementData::ElementData(RefPtr<CSS::AnimatedProperties const> animated_properties_before_update, RefPtr<CSS::ComputedProperties> 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<CSS::PropertyID, NonnullRefPtr<CSS::StyleValue const>> const& old_properties, HashMap<CSS::PropertyID, NonnullRefPtr<CSS::StyleValue const>> 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<CSS::PropertyID>(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<DOM::Element> 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;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,12 @@
|
|||
#include <LibWeb/Bindings/PlatformObject.h>
|
||||
#include <LibWeb/CSS/EasingFunction.h>
|
||||
|
||||
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<CSS::PropertyID, NonnullRefPtr<CSS::StyleValue const>>;
|
||||
PropertyMap animated_properties_before_update;
|
||||
ElementData();
|
||||
ElementData(RefPtr<CSS::AnimatedProperties const>, RefPtr<CSS::ComputedProperties>);
|
||||
ElementData(ElementData&&);
|
||||
ElementData& operator=(ElementData&&);
|
||||
~ElementData();
|
||||
|
||||
RefPtr<CSS::AnimatedProperties const> animated_properties_before_update;
|
||||
RefPtr<CSS::ComputedProperties> target_style;
|
||||
};
|
||||
|
||||
AnimationUpdateContext();
|
||||
~AnimationUpdateContext();
|
||||
|
||||
// NOTE: This is lazily populated by KeyframeEffects as their respective animations are applied to an element.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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&);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ static bool should_update_timeline(GC::Ptr<Animations::AnimationTimeline> 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
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibWeb/Animations/Animation.h>
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/CSS/CSSAnimationProperties.h>
|
||||
#include <LibWeb/CSS/EasingFunction.h>
|
||||
#include <LibWeb/CSS/StyleValues/StyleValue.h>
|
||||
|
||||
|
|
@ -27,7 +27,7 @@ public:
|
|||
virtual Animations::AnimationClass animation_class() const override;
|
||||
virtual int class_specific_composite_order(GC::Ref<Animations::Animation> 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; }
|
||||
|
||||
|
|
|
|||
32
Libraries/LibWeb/CSS/CSSAnimationProperties.h
Normal file
32
Libraries/LibWeb/CSS/CSSAnimationProperties.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2026-present, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/String.h>
|
||||
#include <AK/Variant.h>
|
||||
#include <LibGC/Ptr.h>
|
||||
#include <LibWeb/CSS/ComputedValues.h>
|
||||
#include <LibWeb/CSS/EasingFunction.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
struct AnimationProperties {
|
||||
Variant<double, String> duration;
|
||||
EasingFunction timing_function;
|
||||
double iteration_count;
|
||||
AnimationDirection direction;
|
||||
AnimationPlayState play_state;
|
||||
double delay;
|
||||
AnimationFillMode fill_mode;
|
||||
AnimationComposition composition;
|
||||
FlyString name;
|
||||
GC::Ptr<Animations::AnimationTimeline> timeline;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@
|
|||
#include <LibWeb/CSS/CSSStyleProperties.h>
|
||||
#include <LibWeb/CSS/CSSStyleSheet.h>
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/CSS/CustomPropertyData.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/PropertyNameAndID.h>
|
||||
#include <LibWeb/CSS/StyleComputer.h>
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NonnullRawPtr.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibCore/DirIterator.h>
|
||||
|
|
@ -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> 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> 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 const> 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> ComputedProperties::create()
|
||||
AnimatedProperties const& ComputedProperties::animated_properties() const
|
||||
{
|
||||
return adopt_ref(*new ComputedProperties);
|
||||
static NeverDestroyed<AnimatedProperties> 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<StyleValue const> 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<PropertyID, NonnullRefPtr<StyleValue const>> const& ComputedProperties::animated_property_values() const
|
||||
{
|
||||
return animated_properties().values();
|
||||
}
|
||||
|
||||
RefPtr<AnimatedProperties const> 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<StyleComputer>)
|
||||
{
|
||||
m_depends_on_viewport_metrics = true;
|
||||
}
|
||||
|
||||
void ComputedProperties::set_font_metrics_depend_on_viewport_metrics(Badge<StyleComputer>)
|
||||
{
|
||||
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<StyleValue const> value, Inherited inherited, Important important)
|
||||
void ComputedProperties::Builder::set_property(PropertyID id, NonnullRefPtr<StyleValue const> 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<StyleValue const> value)
|
||||
void ComputedProperties::Builder::set_property_without_modifying_flags(PropertyID id, NonnullRefPtr<StyleValue const> 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<StyleValue const> value, AnimatedPropertyResultOfTransition animated_property_result_of_transition, Inherited inherited)
|
||||
void ComputedProperties::set_animated_property_internal(PropertyID id, NonnullRefPtr<StyleValue const> 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<StyleComputer>, PropertyID id, NonnullRefPtr<StyleValue const> 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<DOM::Element>, PropertyID id, NonnullRefPtr<StyleValue const> 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<DOM::Element>, 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<Animations::KeyframeEffect>)
|
||||
{
|
||||
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<LengthPercentage, NormalGap> 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<FlyString> ComputedProperties::view_transition_name() const
|
|||
return {};
|
||||
}
|
||||
|
||||
Vector<ComputedProperties::AnimationProperties> ComputedProperties::animations(DOM::AbstractElement const& abstract_element) const
|
||||
Vector<AnimationProperties> 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<Gfx::FontCascadeList const> ComputedProperties::computed_font_list(FontComputer const& font_computer) const
|
||||
{
|
||||
if (!m_cached_computed_font_list) {
|
||||
const_cast<ComputedProperties*>(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<Gfx::Font const> 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<ComputedProperties*>(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;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/FixedBitmap.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/RefCounted.h>
|
||||
|
|
@ -14,6 +15,7 @@
|
|||
#include <LibGfx/Font/Font.h>
|
||||
#include <LibGfx/FontCascadeList.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibWeb/CSS/CSSAnimationProperties.h>
|
||||
#include <LibWeb/CSS/ComputedValues.h>
|
||||
#include <LibWeb/CSS/EasingFunction.h>
|
||||
#include <LibWeb/CSS/FontFeatureData.h>
|
||||
|
|
@ -27,6 +29,19 @@
|
|||
|
||||
namespace Web::CSS {
|
||||
|
||||
class AnimatedProperties;
|
||||
class StyleComputer;
|
||||
|
||||
}
|
||||
|
||||
namespace Web::DOM {
|
||||
|
||||
class Element;
|
||||
|
||||
}
|
||||
|
||||
namespace Web::CSS {
|
||||
|
||||
struct TransitionProperties {
|
||||
Vector<PropertyID> properties;
|
||||
double duration;
|
||||
|
|
@ -42,29 +57,89 @@ enum class AnimatedPropertyResultOfTransition : u8 {
|
|||
|
||||
class WEB_API ComputedProperties final : public RefCounted<ComputedProperties> {
|
||||
public:
|
||||
static NonnullRefPtr<ComputedProperties> create();
|
||||
|
||||
static constexpr double normal_line_height_scale = 1.15;
|
||||
|
||||
~ComputedProperties();
|
||||
|
||||
template<typename Callback>
|
||||
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<PropertyID>(i + to_underlying(first_longhand_property_id)), *m_property_values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void for_each_anchor_name(Function<void(FlyString const&)>) const;
|
||||
enum class WithAnimationsApplied {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
|
||||
enum class Inherited {
|
||||
No,
|
||||
Yes
|
||||
};
|
||||
|
||||
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> 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<ComputedProperties> 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<Gfx::Font const> 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<StyleValue const> value, Inherited = Inherited::No, Important = Important::No);
|
||||
void set_property_without_modifying_flags(PropertyID, NonnullRefPtr<StyleValue const> value);
|
||||
void revert_property(PropertyID, ComputedProperties const& style_for_revert);
|
||||
|
||||
void set_display_before_box_type_transformation(Display);
|
||||
|
||||
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> const& inheritance_dependent_specified_values() const { return m_data->inheritance_dependent_specified_values; }
|
||||
void add_inheritance_dependent_specified_value(PropertyID property_id, NonnullRefPtr<StyleValue const> value) { m_data->inheritance_dependent_specified_values.set(property_id, move(value)); }
|
||||
|
||||
RefPtr<StyleValue const> raw_cascaded_font_size() const { return m_data->raw_cascaded_font_size; }
|
||||
void set_raw_cascaded_font_size(NonnullRefPtr<StyleValue const> 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<Data> m_data;
|
||||
NonnullRefPtr<ComputedProperties> m_style;
|
||||
bool m_depends_on_viewport_metrics { false };
|
||||
bool m_font_metrics_depend_on_viewport_metrics { false };
|
||||
};
|
||||
|
||||
static NonnullRefPtr<ComputedProperties> create(Builder&&);
|
||||
static Builder create_builder();
|
||||
static Builder create_builder_with_base_values_from(ComputedProperties const&);
|
||||
|
||||
template<typename Callback>
|
||||
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<PropertyID>(i + to_underlying(first_longhand_property_id)), *m_data->property_values[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void for_each_anchor_name(Function<void(FlyString const&)>) const;
|
||||
|
||||
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> const& animated_property_values() const;
|
||||
RefPtr<AnimatedProperties const> animated_properties_snapshot() const;
|
||||
bool has_animated_property(PropertyID property_id) const;
|
||||
void reset_non_inherited_animated_properties(Badge<Animations::KeyframeEffect>);
|
||||
|
||||
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<StyleValue const> value, Inherited = Inherited::No, Important = Important::No);
|
||||
void set_property_without_modifying_flags(PropertyID, NonnullRefPtr<StyleValue const> value);
|
||||
void set_animated_property(PropertyID, NonnullRefPtr<StyleValue const> value, AnimatedPropertyResultOfTransition, Inherited = Inherited::No);
|
||||
void remove_animated_property(PropertyID);
|
||||
enum class WithAnimationsApplied {
|
||||
No,
|
||||
Yes,
|
||||
};
|
||||
void set_depends_on_viewport_metrics(Badge<StyleComputer>);
|
||||
void set_font_metrics_depend_on_viewport_metrics(Badge<StyleComputer>);
|
||||
void set_animated_property(Badge<StyleComputer>, PropertyID, NonnullRefPtr<StyleValue const> value, AnimatedPropertyResultOfTransition, Inherited = Inherited::No);
|
||||
void set_animated_property(Badge<DOM::Element>, PropertyID, NonnullRefPtr<StyleValue const> value, AnimatedPropertyResultOfTransition, Inherited = Inherited::No);
|
||||
void remove_animated_property(Badge<DOM::Element>, 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<LengthPercentage, NormalGap> gap_value(PropertyID) const;
|
||||
|
|
@ -210,23 +272,10 @@ public:
|
|||
ContainerType container_type() const;
|
||||
MixBlendMode mix_blend_mode() const;
|
||||
Optional<FlyString> view_transition_name() const;
|
||||
struct AnimationProperties {
|
||||
Variant<double, String> duration;
|
||||
EasingFunction timing_function;
|
||||
double iteration_count;
|
||||
AnimationDirection direction;
|
||||
AnimationPlayState play_state;
|
||||
double delay;
|
||||
AnimationFillMode fill_mode;
|
||||
AnimationComposition composition;
|
||||
FlyString name;
|
||||
GC::Ptr<Animations::AnimationTimeline> timeline;
|
||||
};
|
||||
Vector<AnimationProperties> animations(DOM::AbstractElement const&) const;
|
||||
Vector<TransitionProperties> transitions() const;
|
||||
|
||||
Display display_before_box_type_transformation() const;
|
||||
void set_display_before_box_type_transformation(Display value);
|
||||
|
||||
static Vector<NonnullRefPtr<TransformationStyleValue const>> transformations_for_style_value(StyleValue const& value);
|
||||
Vector<NonnullRefPtr<TransformationStyleValue const>> transformations() const;
|
||||
|
|
@ -284,44 +333,80 @@ public:
|
|||
|
||||
static NonnullRefPtr<Gfx::Font const> font_fallback(bool monospace, bool bold, float point_size);
|
||||
|
||||
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> const& inheritance_dependent_specified_values() const { return m_inheritance_dependent_specified_values; }
|
||||
void add_inheritance_dependent_specified_value(PropertyID property_id, NonnullRefPtr<StyleValue const> value) { m_inheritance_dependent_specified_values.set(property_id, move(value)); }
|
||||
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> const& inheritance_dependent_specified_values() const { return m_data->inheritance_dependent_specified_values; }
|
||||
|
||||
RefPtr<StyleValue const> raw_cascaded_font_size() const { return m_raw_cascaded_font_size; }
|
||||
void set_raw_cascaded_font_size(NonnullRefPtr<StyleValue const> value) { m_raw_cascaded_font_size = move(value); }
|
||||
RefPtr<StyleValue const> raw_cascaded_font_size() const { return m_data->raw_cascaded_font_size; }
|
||||
|
||||
private:
|
||||
ComputedProperties();
|
||||
class Data final : public RefCounted<Data> {
|
||||
public:
|
||||
Data() = default;
|
||||
|
||||
Array<RefPtr<StyleValue const>, number_of_longhand_properties> property_values;
|
||||
AK::FixedBitmap<number_of_longhand_properties> property_important { false };
|
||||
AK::FixedBitmap<number_of_longhand_properties> property_inherited { false };
|
||||
|
||||
Display display_before_box_type_transformation { InitialValues::display() };
|
||||
u64 pseudo_element_styles { 0 };
|
||||
|
||||
Optional<CSSPixels> line_height;
|
||||
|
||||
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> inheritance_dependent_specified_values;
|
||||
RefPtr<StyleValue const> raw_cascaded_font_size;
|
||||
};
|
||||
|
||||
ComputedProperties(NonnullRefPtr<Data const>, bool depends_on_viewport_metrics, bool font_metrics_depend_on_viewport_metrics);
|
||||
|
||||
Overflow overflow(PropertyID) const;
|
||||
Vector<ShadowData> shadow(PropertyID, Layout::Node const&) const;
|
||||
Position position_value(PropertyID) const;
|
||||
|
||||
Array<RefPtr<StyleValue const>, number_of_longhand_properties> m_property_values;
|
||||
Array<u8, ceil_div(number_of_longhand_properties, 8uz)> m_property_important {};
|
||||
Array<u8, ceil_div(number_of_longhand_properties, 8uz)> m_property_inherited {};
|
||||
Array<u8, ceil_div(number_of_longhand_properties, 8uz)> m_animated_property_inherited {};
|
||||
Array<u8, ceil_div(number_of_longhand_properties, 8uz)> 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<StyleValue const>, AnimatedPropertyResultOfTransition, Inherited);
|
||||
|
||||
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> m_animated_property_values;
|
||||
|
||||
Display m_display_before_box_type_transformation { InitialValues::display() };
|
||||
NonnullRefPtr<Data const> m_data;
|
||||
RefPtr<AnimatedProperties> 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<Gfx::FontCascadeList const> m_cached_computed_font_list;
|
||||
RefPtr<Gfx::Font const> m_cached_first_available_computed_font;
|
||||
mutable RefPtr<Gfx::FontCascadeList const> m_cached_computed_font_list;
|
||||
mutable RefPtr<Gfx::Font const> 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<CSSPixels> m_line_height;
|
||||
class AnimatedProperties final : public RefCounted<AnimatedProperties> {
|
||||
public:
|
||||
using PropertyMap = HashMap<PropertyID, NonnullRefPtr<StyleValue const>>;
|
||||
|
||||
HashMap<PropertyID, NonnullRefPtr<StyleValue const>> m_inheritance_dependent_specified_values;
|
||||
RefPtr<StyleValue const> 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<StyleValue const>, 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<number_of_longhand_properties> m_has_property { false };
|
||||
AK::FixedBitmap<number_of_longhand_properties> m_property_inherited { false };
|
||||
AK::FixedBitmap<number_of_longhand_properties> m_property_result_of_transition { false };
|
||||
PropertyMap m_values;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1006,7 +1006,17 @@ static Optional<CSS::EasingFunction> resolve_keyframe_easing(CSS::StyleValue con
|
|||
return {};
|
||||
}
|
||||
|
||||
void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element, GC::Ref<Animations::KeyframeEffect> 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<Animations::KeyframeEffect> 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<Animations::KeyframeEffect> 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<PropertyID, RefPtr<StyleValue const>> result;
|
||||
HashMap<PropertyID, PropertyID> longhands_set_by_property_id;
|
||||
AK::FixedBitmap<number_of_longhand_properties> 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<StyleComputer> {});
|
||||
if (property_affects_font_metrics(property_id))
|
||||
computed_properties.set_font_metrics_depend_on_viewport_metrics(Badge<StyleComputer> {});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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<StyleComputer> {}, 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<StyleComputer> {}, 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<StyleComputer> {}, 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<Animations::KeyframeEffect>(*transition->effect()), new_style);
|
||||
collect_animation_into(abstract_element, as<Animations::KeyframeEffect>(*transition->effect()), new_style_builder);
|
||||
};
|
||||
|
||||
// 1. If all of the following are true:
|
||||
|
|
@ -2257,6 +2275,9 @@ Optional<StyleComputer::AnimatedInheritValue> 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<DOM::AbstractElement> abstract_element) const
|
||||
void StyleComputer::compute_property_values(ComputedProperties::Builder& builder, Optional<DOM::AbstractElement> 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<NonnullRefPtr<StyleValue const>(PropertyID)> const get_property_specified_value = [&](auto property_id) -> NonnullRefPtr<StyleValue const> {
|
||||
|
|
@ -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<HTML::HTMLHtmlElement>(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<ComputedProperties> 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<PropertyID>(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<ComputedProperties> StyleComputer::compute_style(DOM::AbstractElement abstract_element, Optional<bool&> did_change_custom_properties) const
|
||||
|
|
@ -2762,10 +2787,11 @@ RefPtr<ComputedProperties> 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<ComputedProperties> 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<StyleValue const> StyleComputer::recascade_font_size_if_needed(DOM::Abstr
|
|||
return CSS::LengthStyleValue::create(CSS::Length::make_px(current_size_in_px));
|
||||
}
|
||||
|
||||
NonnullRefPtr<ComputedProperties> StyleComputer::compute_properties(DOM::AbstractElement abstract_element, CascadedProperties& cascaded_properties) const
|
||||
NonnullRefPtr<ComputedProperties> 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<NonnullRefPtr<StyleValue const>(PropertyID)> const get_property_specified_value = [&](auto property_id) -> NonnullRefPtr<StyleValue const> {
|
||||
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<StyleValue const> 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<ComputedProperties> StyleComputer::compute_properties(DOM::Abstrac
|
|||
Optional<LogicalAliasMappingContext> 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<ComputedProperties> 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<ComputedProperties> 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<ComputedProperties> StyleComputer::compute_properties(DOM::Abstrac
|
|||
if (auto* parent = abstract_element.element().parent(); parent && is<DOM::ShadowRoot>(*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<StyleComputer> {},
|
||||
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<ComputedProperties> 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<ComputedProperties> 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<HTML::HTMLHtmlElement>(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<ComputedProperties> StyleComputer::compute_properties(DOM::Abstrac
|
|||
if (auto effect = animation->effect(); effect && effect->is_keyframe_effect()) {
|
||||
auto& keyframe_effect = *static_cast<Animations::KeyframeEffect*>(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 {
|
||||
|
|
|
|||
|
|
@ -128,10 +128,11 @@ public:
|
|||
void set_viewport_rect(Badge<DOM::Document>, CSSPixelRect const& viewport_rect) { m_viewport_rect = viewport_rect; }
|
||||
|
||||
void collect_animation_into(DOM::AbstractElement, GC::Ref<Animations::KeyframeEffect> animation, ComputedProperties&) const;
|
||||
void collect_animation_into(DOM::AbstractElement, GC::Ref<Animations::KeyframeEffect> animation, ComputedProperties::Builder&) const;
|
||||
|
||||
[[nodiscard]] NonnullRefPtr<ComputedProperties> compute_properties(DOM::AbstractElement, CascadedProperties&) const;
|
||||
[[nodiscard]] NonnullRefPtr<ComputedProperties> compute_properties(DOM::AbstractElement, CascadedProperties&, u64 matching_pseudo_element_styles) const;
|
||||
|
||||
void compute_property_values(ComputedProperties&, Optional<DOM::AbstractElement>) const;
|
||||
void compute_property_values(ComputedProperties::Builder&, Optional<DOM::AbstractElement>) 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<ComputedProperties> compute_style_impl(DOM::AbstractElement, ComputeStyleMode, Optional<bool&> did_change_custom_properties, StyleScope const&) const;
|
||||
[[nodiscard]] NonnullRefPtr<CascadedProperties> compute_cascaded_values(DOM::AbstractElement, bool did_match_any_pseudo_element_rules, ComputeStyleMode, MatchingRuleSet const&) const;
|
||||
void collect_animation_into(DOM::AbstractElement, GC::Ref<Animations::KeyframeEffect> 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; }
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/CSS/CustomPropertyData.h>
|
||||
#include <LibWeb/DOM/AbstractElement.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibGC/Cell.h>
|
||||
#include <LibWeb/CSS/CustomPropertyData.h>
|
||||
#include <LibWeb/CSS/PseudoElement.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
#include <LibURL/Parser.h>
|
||||
#include <LibUnicode/CharacterTypes.h>
|
||||
#include <LibUnicode/Locale.h>
|
||||
#include <LibWeb/Animations/KeyframeEffect.h>
|
||||
#include <LibWeb/Bindings/Element.h>
|
||||
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||
#include <LibWeb/Bindings/MainThreadVM.h>
|
||||
|
|
@ -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<HTML::HTMLTableElement>(*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<size_t, RefPtr<CSS::StyleValue const>> 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<CSS::PropertyID>(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<CSS::StyleValue const> 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<DOM::Element> {}, 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<DOM::Element> {}, 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<CSS::PropertyID>(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<CSS::ComputedProperties> Element::computed_properties(Optional<CSS::PseudoElement> pseudo_element_type)
|
||||
RefPtr<CSS::ComputedProperties const> Element::computed_properties(Optional<CSS::PseudoElement> 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<CSS::ComputedProperties> Element::computed_properties(Optional<CSS::Pseud
|
|||
return m_computed_properties;
|
||||
}
|
||||
|
||||
RefPtr<CSS::ComputedProperties const> Element::computed_properties(Optional<CSS::PseudoElement> pseudo_element_type) const
|
||||
void Element::update_animated_properties(Badge<Web::Animations::KeyframeEffect> const& badge, Optional<CSS::PseudoElement> 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<Web::Animations::KeyframeEffect> 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<CSS::PseudoElement> pseudo_element_type, RefPtr<CSS::ComputedProperties> style)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/Concepts.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
|
|
@ -14,6 +15,7 @@
|
|||
#include <LibWeb/Bindings/Element.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/Bindings/ShadowRoot.h>
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/CSS/Selector.h>
|
||||
#include <LibWeb/CSS/StyleProperty.h>
|
||||
#include <LibWeb/DOM/ChildNode.h>
|
||||
|
|
@ -37,6 +39,13 @@
|
|||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||
#include <LibWeb/WebIDL/Types.h>
|
||||
|
||||
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<CSS::ComputedProperties> computed_properties(Optional<CSS::PseudoElement> = {});
|
||||
RefPtr<CSS::ComputedProperties const> computed_properties(Optional<CSS::PseudoElement> = {}) const;
|
||||
void set_computed_properties(Optional<CSS::PseudoElement>, RefPtr<CSS::ComputedProperties>);
|
||||
void update_animated_properties(Badge<Web::Animations::KeyframeEffect> const&, Optional<CSS::PseudoElement>, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&);
|
||||
void update_animated_properties_for_abstract_element(Badge<Web::Animations::KeyframeEffect> const&, DOM::AbstractElement, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&);
|
||||
|
||||
Optional<SyntheticPseudoElement&> get_synthetic_pseudo_element(CSS::PseudoElement) const;
|
||||
Optional<PseudoElement&> get_pseudo_element(CSS::PseudoElement) const;
|
||||
|
|
@ -362,7 +372,7 @@ public:
|
|||
[[nodiscard]] CSSPixelRect bounding_client_rect_assuming_layout_clean() const;
|
||||
|
||||
virtual RefPtr<Layout::Node> 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() { }
|
||||
|
|
|
|||
|
|
@ -4,7 +4,10 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibWeb/Animations/KeyframeEffect.h>
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/CSS/CustomPropertyData.h>
|
||||
#include <LibWeb/DOM/AbstractElement.h>
|
||||
#include <LibWeb/DOM/Element.h>
|
||||
#include <LibWeb/DOM/PseudoElement.h>
|
||||
#include <LibWeb/Layout/Node.h>
|
||||
|
|
@ -16,6 +19,13 @@ GC_DEFINE_ALLOCATOR(SyntheticPseudoElement);
|
|||
GC_DEFINE_ALLOCATOR(SyntheticPseudoElementTreeNode);
|
||||
GC_DEFINE_ALLOCATOR(ElementReferencePseudoElement);
|
||||
|
||||
struct SyntheticPseudoElement::CustomPropertyDataStorage {
|
||||
RefPtr<CSS::CustomPropertyData const> 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<CSS::ComputedProperties const> SyntheticPseudoElement::computed_properties() const
|
||||
{
|
||||
return m_computed_properties;
|
||||
}
|
||||
|
||||
void SyntheticPseudoElement::update_animated_properties(Badge<Web::Animations::KeyframeEffect> 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<CSS::ComputedProperties> value)
|
||||
{
|
||||
m_computed_properties = value;
|
||||
}
|
||||
|
||||
RefPtr<CSS::CustomPropertyData const> 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<CSS::CustomPropertyData const> value)
|
||||
{
|
||||
if (!value) {
|
||||
m_custom_property_data = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_custom_property_data)
|
||||
m_custom_property_data = make<CustomPropertyDataStorage>();
|
||||
m_custom_property_data->data = move(value);
|
||||
}
|
||||
|
||||
Optional<CSS::CountersSet const&> SyntheticPseudoElement::counters_set() const
|
||||
{
|
||||
if (!m_counters_set)
|
||||
|
|
@ -48,6 +94,9 @@ void SyntheticPseudoElement::set_counters_set(OwnPtr<CSS::CountersSet>&& 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<CSS::ComputedProperties> ElementReferencePseudoElement::computed_properties() const
|
||||
RefPtr<CSS::ComputedProperties const> ElementReferencePseudoElement::computed_properties() const
|
||||
{
|
||||
return m_referenced_element->computed_properties({});
|
||||
}
|
||||
|
||||
void ElementReferencePseudoElement::update_animated_properties(Badge<Web::Animations::KeyframeEffect> 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<CSS::CustomPropertyData const> ElementReferencePseudoElement::custom_property_data() const
|
||||
{
|
||||
return m_referenced_element->custom_property_data({});
|
||||
|
|
|
|||
|
|
@ -6,17 +6,23 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/WeakPtr.h>
|
||||
#include <LibGC/CellAllocator.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/CSS/CustomPropertyData.h>
|
||||
#include <LibWeb/Export.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/PixelUnits.h>
|
||||
#include <LibWeb/TreeNode.h>
|
||||
|
||||
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<CSS::ComputedProperties> computed_properties() const = 0;
|
||||
virtual RefPtr<CSS::ComputedProperties const> computed_properties() const = 0;
|
||||
virtual void update_animated_properties(Badge<Web::Animations::KeyframeEffect> const&, DOM::AbstractElement, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&) = 0;
|
||||
|
||||
virtual RefPtr<CSS::CustomPropertyData const> custom_property_data() const = 0;
|
||||
virtual void set_custom_property_data(RefPtr<CSS::CustomPropertyData const> 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<CSS::ComputedProperties> computed_properties() const override { return m_computed_properties; }
|
||||
void set_computed_properties(RefPtr<CSS::ComputedProperties> value) { m_computed_properties = value; }
|
||||
RefPtr<CSS::ComputedProperties const> computed_properties() const override;
|
||||
void update_animated_properties(Badge<Web::Animations::KeyframeEffect> const&, DOM::AbstractElement, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&) override;
|
||||
void set_computed_properties(RefPtr<CSS::ComputedProperties> value);
|
||||
|
||||
RefPtr<CSS::CustomPropertyData const> custom_property_data() const override { return m_custom_property_data; }
|
||||
void set_custom_property_data(RefPtr<CSS::CustomPropertyData const> value) override { m_custom_property_data = move(value); }
|
||||
RefPtr<CSS::CustomPropertyData const> custom_property_data() const override;
|
||||
void set_custom_property_data(RefPtr<CSS::CustomPropertyData const> value) override;
|
||||
|
||||
bool has_non_empty_counters_set() const { return m_counters_set; }
|
||||
Optional<CSS::CountersSet const&> 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<Layout::NodeWithStyle> m_layout_node;
|
||||
RefPtr<CSS::ComputedProperties> m_computed_properties;
|
||||
RefPtr<CSS::CustomPropertyData const> m_custom_property_data;
|
||||
OwnPtr<CustomPropertyDataStorage> m_custom_property_data;
|
||||
OwnPtr<CSS::CountersSet> 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<CSS::ComputedProperties> computed_properties() const override;
|
||||
RefPtr<CSS::ComputedProperties const> computed_properties() const override;
|
||||
void update_animated_properties(Badge<Web::Animations::KeyframeEffect> const&, DOM::AbstractElement, Web::Animations::KeyframeEffect&, Web::Animations::AnimationUpdateContext&) override;
|
||||
|
||||
RefPtr<CSS::CustomPropertyData const> custom_property_data() const override;
|
||||
void set_custom_property_data(RefPtr<CSS::CustomPropertyData const> value) override;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "AbstractCanvasMixin.h"
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/ValueType.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <LibWeb/Bindings/CanvasRenderingContext2D.h>
|
||||
#include <LibWeb/Bindings/DOMRectReadOnly.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/CSS/Parser/Parser.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
#include <LibWeb/CSS/StyleValues/FilterValueListStyleValue.h>
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ void HTMLBRElement::apply_presentational_hints(Vector<CSS::StyleProperty>& 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())
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ public:
|
|||
virtual RefPtr<Layout::Node> create_layout_node(CSS::ComputedProperties const&) override;
|
||||
virtual bool is_presentational_hint(FlyString const&) const override;
|
||||
virtual void apply_presentational_hints(Vector<CSS::StyleProperty>&) 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; }
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ RefPtr<Layout::Node> HTMLCanvasElement::create_layout_node(CSS::ComputedProperti
|
|||
return make_ref_counted<Layout::CanvasBox>(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())
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ private:
|
|||
virtual void apply_presentational_hints(Vector<CSS::StyleProperty>&) const override;
|
||||
|
||||
virtual RefPtr<Layout::Node> 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<typename ContextType>
|
||||
JS::ThrowCompletionOr<HasOrCreatedContext> create_webgl_context(JS::Value options);
|
||||
|
|
|
|||
|
|
@ -1158,7 +1158,7 @@ void HTMLElement::set_popover(Optional<String> 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) {
|
||||
|
|
|
|||
|
|
@ -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<DOM::EventTarget> global_event_handlers_to_event_target(FlyString const&) override { return *this; }
|
||||
virtual void did_receive_focus() override;
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ void HTMLEmbedElement::apply_presentational_hints(Vector<CSS::StyleProperty>& 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())
|
||||
|
|
|
|||
|
|
@ -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<CSS::StyleProperty>&) const override;
|
||||
virtual void adjust_computed_style(CSS::ComputedProperties&) override;
|
||||
virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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<String> const& old_value, Optional<String> const& value, Optional<FlyString> 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);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ RefPtr<Layout::Node> HTMLIFrameElement::create_layout_node(CSS::ComputedProperti
|
|||
return make_ref_counted<Layout::NavigableContainerViewport>(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())
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public:
|
|||
virtual ~HTMLIFrameElement() override;
|
||||
|
||||
virtual RefPtr<Layout::Node> 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
|
||||
|
|
|
|||
|
|
@ -290,7 +290,7 @@ RefPtr<Layout::Node> HTMLImageElement::create_layout_node(CSS::ComputedPropertie
|
|||
return make_ref_counted<Layout::ImageBox>(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())
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ private:
|
|||
virtual bool supports_dimension_attributes() const override { return true; }
|
||||
|
||||
virtual RefPtr<Layout::Node> 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ RefPtr<Layout::Node> 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;
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ public:
|
|||
virtual ~HTMLInputElement() override;
|
||||
|
||||
virtual RefPtr<Layout::Node> 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 {
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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<void(HTMLMediaElement&)>);
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ RefPtr<Layout::Node> 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())
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ private:
|
|||
virtual void apply_presentational_hints(Vector<CSS::StyleProperty>&) const override;
|
||||
|
||||
virtual RefPtr<Layout::Node> 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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<unsigned>().value_or(0);
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ private:
|
|||
virtual bool is_presentational_hint(FlyString const&) const override;
|
||||
virtual void apply_presentational_hints(Vector<CSS::StyleProperty>&) const override;
|
||||
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
|
||||
virtual void adjust_computed_style(CSS::ComputedProperties::Builder&) override;
|
||||
|
||||
GC::Ptr<DOM::HTMLCollection> mutable m_rows;
|
||||
GC::Ptr<DOM::HTMLCollection> mutable m_t_bodies;
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -514,7 +514,6 @@ RefPtr<NodeWithStyle> 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<CSS::ComputedProperties> style;
|
||||
RefPtr<CSS::ComputedProperties const> style;
|
||||
CSS::Display display;
|
||||
|
||||
if (!should_create_layout_node) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <LibWeb/CSS/CSSKeyframesRule.h>
|
||||
#include <LibWeb/CSS/CSSStyleRule.h>
|
||||
#include <LibWeb/CSS/CSSStyleSheet.h>
|
||||
#include <LibWeb/CSS/ComputedProperties.h>
|
||||
#include <LibWeb/CSS/PropertyID.h>
|
||||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/HTML/EventLoop/EventLoop.h>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
<div id="root-font-target"></div>
|
||||
<div id="animated-font-source"><div id="animated-inherited-font-target"></div></div>
|
||||
<div id="pending-outline-animation-target"></div>
|
||||
<div id="post-style-animation-target"></div>
|
||||
<script>
|
||||
function pauseHalfway(animation) {
|
||||
animation.pause();
|
||||
|
|
@ -70,6 +71,7 @@
|
|||
const animatedFontSource = child.document.getElementById("animated-font-source");
|
||||
const animatedInheritedFontTarget = child.document.getElementById("animated-inherited-font-target");
|
||||
const pendingOutlineAnimationTarget = child.document.getElementById("pending-outline-animation-target");
|
||||
const postStyleAnimationTarget = child.document.getElementById("post-style-animation-target");
|
||||
|
||||
child.internals.updateStyle();
|
||||
println(`initial viewport animated width: ${child.getComputedStyle(viewportTarget).width}`);
|
||||
|
|
@ -78,6 +80,15 @@
|
|||
println(`initial animated font size: ${child.getComputedStyle(animatedFontSource).fontSize}`);
|
||||
println(`initial animated inherited-font width: ${child.getComputedStyle(animatedInheritedFontTarget).width}`);
|
||||
|
||||
const postStyleAnimation = postStyleAnimationTarget.animate([{ width: "10vw" }, { width: "20vw" }], {
|
||||
duration: 1000,
|
||||
fill: "both",
|
||||
});
|
||||
postStyleAnimation.pause();
|
||||
postStyleAnimation.currentTime = 500;
|
||||
child.internals.updateStyle();
|
||||
println(`initial post-style animated width: ${child.getComputedStyle(postStyleAnimationTarget).width}`);
|
||||
|
||||
const pendingOutlineAnimation = pendingOutlineAnimationTarget.animate([{ outlineWidth: "10vw" }, { outlineWidth: "20vw" }], {
|
||||
duration: 1000,
|
||||
fill: "both",
|
||||
|
|
@ -101,6 +112,7 @@
|
|||
println(`resized root-font animated width: ${child.getComputedStyle(rootFontTarget).width}`);
|
||||
println(`resized animated font size: ${child.getComputedStyle(animatedFontSource).fontSize}`);
|
||||
println(`resized animated inherited-font width: ${child.getComputedStyle(animatedInheritedFontTarget).width}`);
|
||||
println(`resized post-style animated width: ${child.getComputedStyle(postStyleAnimationTarget).width}`);
|
||||
println(`full invalidations: ${counters.fullStyleInvalidations}`);
|
||||
println(`style recomputations bounded: ${counters.elementStyleRecomputations < elementCount}`);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue