Skip to content
1 change: 0 additions & 1 deletion Libraries/LibWeb/CSS/CSSStyleSheet.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include <LibWeb/CSS/CSSRule.h>
#include <LibWeb/CSS/CSSRuleList.h>
#include <LibWeb/CSS/CSSStyleRule.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/StyleSheet.h>
#include <LibWeb/DOM/Node.h>
#include <LibWeb/Export.h>
Expand Down
26 changes: 23 additions & 3 deletions Libraries/LibWeb/CSS/ComputedProperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,14 @@ bool ComputedProperties::is_animated_property_inherited(PropertyID property_id)
return m_animated_property_inherited[n / 8] & (1 << (n % 8));
}

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));
}

void ComputedProperties::set_property_inherited(PropertyID property_id, Inherited inherited)
{
VERIFY(property_id >= first_longhand_property_id && property_id <= last_longhand_property_id);
Expand All @@ -114,6 +122,17 @@ void ComputedProperties::set_animated_property_inherited(PropertyID property_id,
m_animated_property_inherited[n / 8] &= ~(1 << (n % 8));
}

void ComputedProperties::set_animated_property_result_of_transition(PropertyID property_id, AnimatedPropertyResultOfTransition animated_value_result_of_transition)
{
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));
}

void ComputedProperties::set_property(PropertyID id, NonnullRefPtr<StyleValue const> value, Inherited inherited, Important important)
{
VERIFY(id >= first_longhand_property_id && id <= last_longhand_property_id);
Expand Down Expand Up @@ -149,10 +168,11 @@ void ComputedProperties::set_display_before_box_type_transformation(Display valu
m_display_before_box_type_transformation = value;
}

void ComputedProperties::set_animated_property(PropertyID id, NonnullRefPtr<StyleValue const> value, Inherited inherited)
void ComputedProperties::set_animated_property(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);
}

void ComputedProperties::remove_animated_property(PropertyID id)
Expand All @@ -172,8 +192,8 @@ 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 properties
if (!is_property_important(property_id) && return_animated_value == WithAnimationsApplied::Yes) {
// Important properties override animated but not transitioned properties
if ((!is_property_important(property_id) || is_animated_property_result_of_transition(property_id)) && return_animated_value == WithAnimationsApplied::Yes) {
if (auto animated_value = m_animated_property_values.get(property_id); animated_value.has_value())
return *animated_value.value();
}
Expand Down
10 changes: 9 additions & 1 deletion Libraries/LibWeb/CSS/ComputedProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@

namespace Web::CSS {

enum class AnimatedPropertyResultOfTransition : u8 {
No,
Yes
};

class WEB_API ComputedProperties final : public JS::Cell {
GC_CELL(ComputedProperties, JS::Cell);
GC_DECLARE_ALLOCATOR(ComputedProperties);
Expand Down Expand Up @@ -55,13 +60,15 @@ class WEB_API ComputedProperties final : public JS::Cell {
bool is_property_important(PropertyID property_id) const;
bool is_property_inherited(PropertyID property_id) const;
bool is_animated_property_inherited(PropertyID property_id) const;
bool is_animated_property_result_of_transition(PropertyID property_id) const;
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_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, Inherited = Inherited::No);
void set_animated_property(PropertyID, NonnullRefPtr<StyleValue const> value, AnimatedPropertyResultOfTransition, Inherited = Inherited::No);
void remove_animated_property(PropertyID);
enum class WithAnimationsApplied {
No,
Expand Down Expand Up @@ -292,6 +299,7 @@ class WEB_API ComputedProperties final : public JS::Cell {
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 {};

HashMap<PropertyID, NonnullRefPtr<StyleValue const>> m_animated_property_values;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@

#pragma once

#include <LibWeb/CSS/Parser/Parser.h>
#include <AK/String.h>
#include <LibWeb/Forward.h>

namespace Web::CSS::Parser {

Expand Down
2 changes: 0 additions & 2 deletions Libraries/LibWeb/CSS/Parser/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -533,8 +533,6 @@ class Parser {
RefPtr<StyleValue const> parse_white_space_trim_value(TokenStream<ComponentValue>&);
RefPtr<StyleValue const> parse_will_change_value(TokenStream<ComponentValue>&);

RefPtr<StyleValue const> parse_list_of_time_values(PropertyID, TokenStream<ComponentValue>&);

RefPtr<CalculationNode const> convert_to_calculation_node(CalcParsing::Node const&, CalculationContext const&);
RefPtr<CalculationNode const> parse_a_calculation(Vector<ComponentValue> const&, CalculationContext const&);

Expand Down
29 changes: 4 additions & 25 deletions Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -734,13 +734,13 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue const>> Parser::parse_css_value(Pr
return parse_all_as(tokens, [this](auto& tokens) { return parse_transform_origin_value(tokens); });
case PropertyID::Transition:
return parse_all_as(tokens, [this](auto& tokens) { return parse_transition_value(tokens); });
case PropertyID::TransitionDelay:
case PropertyID::TransitionDuration:
return parse_all_as(tokens, [this, property_id](auto& tokens) { return parse_list_of_time_values(property_id, tokens); });
case PropertyID::TransitionProperty:
return parse_all_as(tokens, [this](auto& tokens) { return parse_transition_property_value(tokens); });
case PropertyID::TransitionDelay:
case PropertyID::TransitionDuration:
case PropertyID::TransitionTimingFunction:
return parse_all_as(tokens, [this](auto& tokens) { return parse_simple_comma_separated_value_list(PropertyID::TransitionTimingFunction, tokens); });
case PropertyID::TransitionBehavior:
return parse_all_as(tokens, [this, property_id](auto& tokens) { return parse_simple_comma_separated_value_list(property_id, tokens); });
case PropertyID::Translate:
return parse_all_as(tokens, [this](auto& tokens) { return parse_translate_value(tokens); });
case PropertyID::Scale:
Expand Down Expand Up @@ -5050,27 +5050,6 @@ RefPtr<StyleValue const> Parser::parse_transition_value(TokenStream<ComponentVal
return parsed_value;
}

RefPtr<StyleValue const> Parser::parse_list_of_time_values(PropertyID property_id, TokenStream<ComponentValue>& tokens)
{
auto transaction = tokens.begin_transaction();
auto time_values = parse_a_comma_separated_list_of_component_values(tokens);
StyleValueVector time_value_list;
for (auto const& value : time_values) {
TokenStream time_value_tokens { value };
auto time_style_value = parse_time_value(time_value_tokens);
if (!time_style_value)
return nullptr;
if (time_value_tokens.has_next_token())
return nullptr;
if (!time_style_value->is_calculated() && !property_accepts_time(property_id, time_style_value->as_time().time()))
return nullptr;
time_value_list.append(*time_style_value);
}

transaction.commit();
return StyleValueList::create(move(time_value_list), StyleValueList::Separator::Comma);
}

RefPtr<StyleValue const> Parser::parse_transition_property_value(TokenStream<ComponentValue>& tokens)
{
// https://drafts.csswg.org/css-transitions/#transition-property-property
Expand Down
32 changes: 20 additions & 12 deletions Libraries/LibWeb/CSS/StyleComputer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -950,7 +950,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
auto const& specified_value_with_css_wide_keywords_applied = [&]() -> StyleValue const& {
if (longhand_value.is_inherit() || (longhand_value.is_unset() && is_inherited_property(longhand_id))) {
if (auto inherited_animated_value = get_animated_inherit_value(longhand_id, abstract_element); inherited_animated_value.has_value())
return inherited_animated_value.value();
return inherited_animated_value->value;

return get_non_animated_inherit_value(longhand_id, abstract_element);
}
Expand Down Expand Up @@ -1070,6 +1070,8 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
VERIFY_NOT_REACHED();
};

auto is_result_of_transition = animation->is_css_transition() ? AnimatedPropertyResultOfTransition::Yes : AnimatedPropertyResultOfTransition::No;

auto start_composite_operation = to_composite_operation(keyframe_values.composite);
auto end_composite_operation = to_composite_operation(keyframe_end_values.composite);

Expand All @@ -1079,7 +1081,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);
computed_properties.set_animated_property(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;
Expand All @@ -1094,7 +1096,9 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
auto start = resolved_start_property.release_nonnull();
auto end = resolved_end_property.release_nonnull();

if (computed_properties.is_property_important(it.key)) {
// OPTIMIZATION: Values resulting from animations other than CSS transitions are overriden by important
// properties so there's no need to calculate them
if (!animation->is_css_transition() && computed_properties.is_property_important(it.key)) {
continue;
}

Expand All @@ -1107,11 +1111,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);
computed_properties.set_animated_property(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));
computed_properties.set_animated_property(PropertyID::Visibility, KeywordStyleValue::create(Keyword::Hidden), is_result_of_transition);
}
}
}
Expand Down Expand Up @@ -1606,15 +1610,20 @@ NonnullRefPtr<StyleValue const> StyleComputer::get_non_animated_inherit_value(Pr
return parent_element->computed_properties()->property(property_id, ComputedProperties::WithAnimationsApplied::No);
}

Optional<NonnullRefPtr<StyleValue const>> StyleComputer::get_animated_inherit_value(PropertyID property_id, DOM::AbstractElement abstract_element)
Optional<StyleComputer::AnimatedInheritValue> StyleComputer::get_animated_inherit_value(PropertyID property_id, DOM::AbstractElement abstract_element)
{
auto parent_element = abstract_element.element_to_inherit_style_from();

if (!parent_element.has_value() || !parent_element->computed_properties())
return {};

if (auto animated_value = parent_element->computed_properties()->animated_property_values().get(property_id); animated_value.has_value())
return *animated_value.value();
return AnimatedInheritValue {
.value = *animated_value.value(),
.is_result_of_transition = parent_element->computed_properties()->is_animated_property_result_of_transition(property_id)
? AnimatedPropertyResultOfTransition::Yes
: AnimatedPropertyResultOfTransition::No
};

return {};
}
Expand Down Expand Up @@ -2523,7 +2532,6 @@ GC::Ref<ComputedProperties> StyleComputer::compute_properties(DOM::AbstractEleme
auto property_id = static_cast<CSS::PropertyID>(i);
auto value = cascaded_properties.property(property_id);
auto inherited = ComputedProperties::Inherited::No;
Optional<NonnullRefPtr<StyleValue const>> animated_value;

// NOTE: We've already handled font-size above.
if (property_id == PropertyID::FontSize && !value && new_font_size)
Expand All @@ -2545,17 +2553,17 @@ GC::Ref<ComputedProperties> StyleComputer::compute_properties(DOM::AbstractEleme

// FIXME: Logical properties should inherit from their parent's equivalent unmapped logical property.
if (should_inherit) {
value = get_non_animated_inherit_value(property_id, abstract_element);
animated_value = get_animated_inherit_value(property_id, abstract_element);
inherited = ComputedProperties::Inherited::Yes;
value = get_non_animated_inherit_value(property_id, abstract_element);

if (auto animated_value = get_animated_inherit_value(property_id, abstract_element); animated_value.has_value())
computed_style->set_animated_property(property_id, animated_value->value, animated_value->is_result_of_transition, ComputedProperties::Inherited::Yes);
}

if (!value || value->is_initial() || value->is_unset())
value = property_initial_value(property_id);

computed_style->set_property(property_id, value.release_nonnull(), inherited, cascaded_properties.is_property_important(property_id) ? Important::Yes : Important::No);
if (animated_value.has_value())
computed_style->set_animated_property(property_id, animated_value.value(), inherited);
}

// Compute the value of custom properties
Expand Down
6 changes: 5 additions & 1 deletion Libraries/LibWeb/CSS/StyleComputer.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,11 @@ class WEB_API StyleComputer final : public GC::Cell {
public:
static void for_each_property_expanding_shorthands(PropertyID, StyleValue const&, Function<void(PropertyID, StyleValue const&)> const& set_longhand_property);
static NonnullRefPtr<StyleValue const> get_non_animated_inherit_value(PropertyID, DOM::AbstractElement);
static Optional<NonnullRefPtr<StyleValue const>> get_animated_inherit_value(PropertyID, DOM::AbstractElement);
struct AnimatedInheritValue {
NonnullRefPtr<StyleValue const> value;
AnimatedPropertyResultOfTransition is_result_of_transition;
};
static Optional<AnimatedInheritValue> get_animated_inherit_value(PropertyID, DOM::AbstractElement);

static Optional<String> user_agent_style_sheet_source(StringView name);

Expand Down
1 change: 1 addition & 0 deletions Libraries/LibWeb/CSS/StyleSheetList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/Bindings/StyleSheetListPrototype.h>
#include <LibWeb/CSS/Parser/Parser.h>
#include <LibWeb/CSS/StyleComputer.h>
#include <LibWeb/CSS/StyleSheetList.h>
#include <LibWeb/DOM/Document.h>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <LibWeb/CSS/CSSUnparsedValue.h>
#include <LibWeb/CSS/CSSVariableReferenceValue.h>
#include <LibWeb/CSS/Parser/ArbitrarySubstitutionFunctions.h>
#include <LibWeb/CSS/Parser/TokenStream.h>
#include <LibWeb/CSS/PropertyName.h>
#include <LibWeb/CSS/Serialize.h>
#include <LibWeb/CSS/StyleValues/UnresolvedStyleValue.h>
Expand Down
Loading
Loading