diff --git a/Libraries/LibWeb/CSS/CSSStyleSheet.h b/Libraries/LibWeb/CSS/CSSStyleSheet.h index 638b38969841..0b8841e48afa 100644 --- a/Libraries/LibWeb/CSS/CSSStyleSheet.h +++ b/Libraries/LibWeb/CSS/CSSStyleSheet.h @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index f5085a775a32..bdcf1b2d7cb0 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -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); @@ -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 value, Inherited inherited, Important important) { VERIFY(id >= first_longhand_property_id && id <= last_longhand_property_id); @@ -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 value, Inherited inherited) +void ComputedProperties::set_animated_property(PropertyID id, NonnullRefPtr value, AnimatedPropertyResultOfTransition animated_property_result_of_transition, Inherited inherited) { m_animated_property_values.set(id, move(value)); set_animated_property_inherited(id, inherited); + set_animated_property_result_of_transition(id, animated_property_result_of_transition); } void ComputedProperties::remove_animated_property(PropertyID id) @@ -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(); } diff --git a/Libraries/LibWeb/CSS/ComputedProperties.h b/Libraries/LibWeb/CSS/ComputedProperties.h index 60d47fb25011..faafa7d97e5f 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.h +++ b/Libraries/LibWeb/CSS/ComputedProperties.h @@ -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); @@ -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 value, Inherited = Inherited::No, Important = Important::No); void set_property_without_modifying_flags(PropertyID, NonnullRefPtr value); - void set_animated_property(PropertyID, NonnullRefPtr value, Inherited = Inherited::No); + void set_animated_property(PropertyID, NonnullRefPtr value, AnimatedPropertyResultOfTransition, Inherited = Inherited::No); void remove_animated_property(PropertyID); enum class WithAnimationsApplied { No, @@ -292,6 +299,7 @@ class WEB_API ComputedProperties final : public JS::Cell { Array m_property_important {}; Array m_property_inherited {}; Array m_animated_property_inherited {}; + Array m_animated_property_result_of_transition {}; HashMap> m_animated_property_values; diff --git a/Libraries/LibWeb/CSS/Parser/ArbitrarySubstitutionFunctions.h b/Libraries/LibWeb/CSS/Parser/ArbitrarySubstitutionFunctions.h index 9805764c9f9a..89fa0ceb55a9 100644 --- a/Libraries/LibWeb/CSS/Parser/ArbitrarySubstitutionFunctions.h +++ b/Libraries/LibWeb/CSS/Parser/ArbitrarySubstitutionFunctions.h @@ -6,7 +6,8 @@ #pragma once -#include +#include +#include namespace Web::CSS::Parser { diff --git a/Libraries/LibWeb/CSS/Parser/Parser.h b/Libraries/LibWeb/CSS/Parser/Parser.h index 3fef44412e9e..abbd8a45e0f5 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Libraries/LibWeb/CSS/Parser/Parser.h @@ -533,8 +533,6 @@ class Parser { RefPtr parse_white_space_trim_value(TokenStream&); RefPtr parse_will_change_value(TokenStream&); - RefPtr parse_list_of_time_values(PropertyID, TokenStream&); - RefPtr convert_to_calculation_node(CalcParsing::Node const&, CalculationContext const&); RefPtr parse_a_calculation(Vector const&, CalculationContext const&); diff --git a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp index 916d7117c5f9..f7bd8d43c4dc 100644 --- a/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp +++ b/Libraries/LibWeb/CSS/Parser/PropertyParsing.cpp @@ -734,13 +734,13 @@ Parser::ParseErrorOr> 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: @@ -5050,27 +5050,6 @@ RefPtr Parser::parse_transition_value(TokenStream Parser::parse_list_of_time_values(PropertyID property_id, TokenStream& 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 Parser::parse_transition_property_value(TokenStream& tokens) { // https://drafts.csswg.org/css-transitions/#transition-property-property diff --git a/Libraries/LibWeb/CSS/StyleComputer.cpp b/Libraries/LibWeb/CSS/StyleComputer.cpp index 4222136fdd48..c687e5da9be2 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -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); } @@ -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); @@ -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; @@ -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; } @@ -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); } } } @@ -1606,7 +1610,7 @@ NonnullRefPtr StyleComputer::get_non_animated_inherit_value(Pr return parent_element->computed_properties()->property(property_id, ComputedProperties::WithAnimationsApplied::No); } -Optional> StyleComputer::get_animated_inherit_value(PropertyID property_id, DOM::AbstractElement abstract_element) +Optional StyleComputer::get_animated_inherit_value(PropertyID property_id, DOM::AbstractElement abstract_element) { auto parent_element = abstract_element.element_to_inherit_style_from(); @@ -1614,7 +1618,12 @@ Optional> StyleComputer::get_animated_inherit_va 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 {}; } @@ -2523,7 +2532,6 @@ GC::Ref StyleComputer::compute_properties(DOM::AbstractEleme auto property_id = static_cast(i); auto value = cascaded_properties.property(property_id); auto inherited = ComputedProperties::Inherited::No; - Optional> animated_value; // NOTE: We've already handled font-size above. if (property_id == PropertyID::FontSize && !value && new_font_size) @@ -2545,17 +2553,17 @@ GC::Ref 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 diff --git a/Libraries/LibWeb/CSS/StyleComputer.h b/Libraries/LibWeb/CSS/StyleComputer.h index 690018a3c14f..9eb11b5b286a 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.h +++ b/Libraries/LibWeb/CSS/StyleComputer.h @@ -110,7 +110,11 @@ class WEB_API StyleComputer final : public GC::Cell { public: static void for_each_property_expanding_shorthands(PropertyID, StyleValue const&, Function const& set_longhand_property); static NonnullRefPtr get_non_animated_inherit_value(PropertyID, DOM::AbstractElement); - static Optional> get_animated_inherit_value(PropertyID, DOM::AbstractElement); + struct AnimatedInheritValue { + NonnullRefPtr value; + AnimatedPropertyResultOfTransition is_result_of_transition; + }; + static Optional get_animated_inherit_value(PropertyID, DOM::AbstractElement); static Optional user_agent_style_sheet_source(StringView name); diff --git a/Libraries/LibWeb/CSS/StyleSheetList.cpp b/Libraries/LibWeb/CSS/StyleSheetList.cpp index cfa06660cc9b..60e785690afb 100644 --- a/Libraries/LibWeb/CSS/StyleSheetList.cpp +++ b/Libraries/LibWeb/CSS/StyleSheetList.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/Libraries/LibWeb/CSS/StyleValues/UnresolvedStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/UnresolvedStyleValue.cpp index e5b9cf85c3a3..74eff902b898 100644 --- a/Libraries/LibWeb/CSS/StyleValues/UnresolvedStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/UnresolvedStyleValue.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/Libraries/LibWeb/DOM/Element.cpp b/Libraries/LibWeb/DOM/Element.cpp index 3cfa65a61dd1..7b2a8f5fe47f 100644 --- a/Libraries/LibWeb/DOM/Element.cpp +++ b/Libraries/LibWeb/DOM/Element.cpp @@ -850,8 +850,7 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style() || (property_id == CSS::PropertyID::FontWeight && first_is_one_of(preabsolutized_value->to_keyword(), CSS::Keyword::Bolder, CSS::Keyword::Lighter)) || (property_id == CSS::PropertyID::FontSize && first_is_one_of(preabsolutized_value->to_keyword(), CSS::Keyword::Larger, CSS::Keyword::Smaller)); if (needs_updating) { - auto is_inherited = computed_properties->is_property_inherited(property_id); - computed_properties->set_property(property_id, *preabsolutized_value, is_inherited ? CSS::ComputedProperties::Inherited::Yes : CSS::ComputedProperties::Inherited::No); + computed_properties->set_property_without_modifying_flags(property_id, *preabsolutized_value); property_values_affected_by_inherited_style.set(i, old_value); } } @@ -859,21 +858,16 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style() if (!computed_properties->is_property_inherited(property_id)) continue; - RefPtr old_animated_value = computed_properties->animated_property_values().get(property_id).value_or({}); - RefPtr new_animated_value = CSS::StyleComputer::get_animated_inherit_value(property_id, { *this }) - .map([](auto&& value) { return value.ptr(); }) - .value_or({}); - - invalidation |= CSS::compute_property_invalidation(property_id, old_animated_value, new_animated_value); - - if (new_animated_value) - computed_properties->set_animated_property(property_id, new_animated_value.release_nonnull(), CSS::ComputedProperties::Inherited::Yes); - else if (old_animated_value && computed_properties->is_animated_property_inherited(property_id)) - computed_properties->remove_animated_property(property_id); + 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); + } 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); - invalidation |= CSS::compute_property_invalidation(property_id, old_value, new_value); + invalidation |= CSS::compute_property_invalidation(property_id, old_value, computed_properties->property(property_id)); } if (invalidation.is_none() && property_values_affected_by_inherited_style.is_empty()) diff --git a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp index 1b9e288df3a5..dcec6c19f7b6 100644 --- a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp @@ -1137,19 +1137,19 @@ Optional effective_command_value(GC::Ptr node, FlyString auto resolved_background_color = [&] { return resolved_value(*node, CSS::PropertyID::BackgroundColor); }; auto resolved_background_alpha = [&] { auto background_color = resolved_background_color(); - if (!background_color.has_value()) + if (!background_color) return NumericLimits::max(); VERIFY(is(node->layout_node())); - return background_color.value()->to_color(CSS::ColorResolutionContext::for_layout_node_with_style(*static_cast(node->layout_node()))).value().alpha(); + return background_color->to_color(CSS::ColorResolutionContext::for_layout_node_with_style(*static_cast(node->layout_node()))).value().alpha(); }; while (resolved_background_alpha() == 0 && node->parent() && is(*node->parent())) node = node->parent(); // 2. Return the resolved value of "background-color" for node. auto resolved_value = resolved_background_color(); - if (!resolved_value.has_value()) + if (!resolved_value) return {}; - return Utf16String::from_utf8_without_validation(resolved_value.value()->to_string(CSS::SerializationMode::ResolvedValue)); + return Utf16String::from_utf8_without_validation(resolved_value->to_string(CSS::SerializationMode::ResolvedValue)); } // 5. If command is "subscript" or "superscript": @@ -1196,7 +1196,7 @@ Optional effective_command_value(GC::Ptr node, FlyString auto inclusive_ancestor = node; do { auto text_decoration_line = resolved_value(*node, CSS::PropertyID::TextDecorationLine); - if (text_decoration_line.has_value() && value_contains_keyword(text_decoration_line.value(), CSS::Keyword::LineThrough)) + if (text_decoration_line && value_contains_keyword(*text_decoration_line, CSS::Keyword::LineThrough)) return "line-through"_utf16; inclusive_ancestor = inclusive_ancestor->parent(); } while (inclusive_ancestor); @@ -1210,7 +1210,7 @@ Optional effective_command_value(GC::Ptr node, FlyString auto inclusive_ancestor = node; do { auto text_decoration_line = resolved_value(*node, CSS::PropertyID::TextDecorationLine); - if (text_decoration_line.has_value() && value_contains_keyword(text_decoration_line.value(), CSS::Keyword::Underline)) + if (text_decoration_line && value_contains_keyword(*text_decoration_line, CSS::Keyword::Underline)) return "underline"_utf16; inclusive_ancestor = inclusive_ancestor->parent(); } while (inclusive_ancestor); @@ -1223,9 +1223,9 @@ Optional effective_command_value(GC::Ptr node, FlyString VERIFY(command_definition.relevant_css_property.has_value()); auto optional_value = resolved_value(*node, command_definition.relevant_css_property.value()); - if (!optional_value.has_value()) + if (!optional_value) return {}; - return Utf16String::from_utf8_without_validation(optional_value.value()->to_string(CSS::SerializationMode::ResolvedValue)); + return Utf16String::from_utf8_without_validation(optional_value->to_string(CSS::SerializationMode::ResolvedValue)); } // https://w3c.github.io/editing/docs/execCommand/#first-equivalent-point @@ -2621,7 +2621,7 @@ void justify_the_selection(DOM::Document& document, JustifyAlignment alignment) auto& element = static_cast(*node); if (element.has_attribute_ns(Namespace::HTML, HTML::AttributeNames::align) - || property_in_style_attribute(element, CSS::PropertyID::TextAlign).has_value() + || property_in_style_attribute(element, CSS::PropertyID::TextAlign) || element.local_name() == HTML::TagNames::center) element_list.append(element); @@ -3847,10 +3847,10 @@ Optional specified_command_value(GC::Ref element, Fly // "text-decoration": if (command == CommandNames::strikethrough) { auto text_decoration_style = property_in_style_attribute(element, CSS::PropertyID::TextDecoration); - if (text_decoration_style.has_value()) { + if (text_decoration_style) { // 1. If element's style attribute sets "text-decoration" to a value containing "line-through", return // "line-through". - if (value_contains_keyword(text_decoration_style.value(), CSS::Keyword::LineThrough)) + if (value_contains_keyword(*text_decoration_style, CSS::Keyword::LineThrough)) return "line-through"_utf16; // 2. Return null. @@ -3865,9 +3865,9 @@ Optional specified_command_value(GC::Ref element, Fly // 6. If command is "underline", and element has a style attribute set, and that attribute sets "text-decoration": if (command == CommandNames::underline) { auto text_decoration_style = property_in_style_attribute(element, CSS::PropertyID::TextDecoration); - if (text_decoration_style.has_value()) { + if (text_decoration_style) { // 1. If element's style attribute sets "text-decoration" to a value containing "underline", return "underline". - if (value_contains_keyword(text_decoration_style.value(), CSS::Keyword::Underline)) + if (value_contains_keyword(*text_decoration_style, CSS::Keyword::Underline)) return "underline"_utf16; // 2. Return null. @@ -4683,7 +4683,7 @@ Array named_font_sizes() return { "x-small"sv, "small"sv, "medium"sv, "large"sv, "x-large"sv, "xx-large"sv, "xxx-large"sv }; } -Optional> property_in_style_attribute(GC::Ref element, CSS::PropertyID property_id) +RefPtr property_in_style_attribute(GC::Ref element, CSS::PropertyID property_id) { auto inline_style = element->inline_style(); if (!inline_style) @@ -4699,20 +4699,20 @@ Optional> property_in_style_attribute(GC::R Optional resolved_display(GC::Ref node) { auto resolved_property = resolved_value(node, CSS::PropertyID::Display); - if (!resolved_property.has_value() || !resolved_property.value()->is_display()) + if (!resolved_property || !resolved_property->is_display()) return {}; - return resolved_property.value()->as_display().display(); + return resolved_property->as_display().display(); } Optional resolved_keyword(GC::Ref node, CSS::PropertyID property_id) { auto resolved_property = resolved_value(node, property_id); - if (!resolved_property.has_value() || !resolved_property.value()->is_keyword()) + if (!resolved_property || !resolved_property->is_keyword()) return {}; - return resolved_property.value()->as_keyword().keyword(); + return resolved_property->as_keyword().keyword(); } -Optional> resolved_value(GC::Ref node, CSS::PropertyID property_id) +RefPtr resolved_value(GC::Ref node, CSS::PropertyID property_id) { // Find the nearest inclusive ancestor of node that is an Element. This allows for passing in a DOM::Text node. GC::Ptr element = node; diff --git a/Libraries/LibWeb/Editing/Internal/Algorithms.h b/Libraries/LibWeb/Editing/Internal/Algorithms.h index 577a217b26c6..07efdfc488ae 100644 --- a/Libraries/LibWeb/Editing/Internal/Algorithms.h +++ b/Libraries/LibWeb/Editing/Internal/Algorithms.h @@ -132,10 +132,10 @@ bool has_visible_children(GC::Ref); bool is_heading(FlyString const&); Utf16String justify_alignment_to_string(JustifyAlignment); Array named_font_sizes(); -Optional> property_in_style_attribute(GC::Ref, CSS::PropertyID); +RefPtr property_in_style_attribute(GC::Ref, CSS::PropertyID); Optional resolved_display(GC::Ref); Optional resolved_keyword(GC::Ref, CSS::PropertyID); -Optional> resolved_value(GC::Ref, CSS::PropertyID); +RefPtr resolved_value(GC::Ref, CSS::PropertyID); void take_the_action_for_command(DOM::Document&, FlyString const&, Utf16String const&); bool value_contains_keyword(CSS::StyleValue const&, CSS::Keyword); diff --git a/Libraries/LibWeb/Forward.h b/Libraries/LibWeb/Forward.h index 0dae9f42798d..a40a5ee61f11 100644 --- a/Libraries/LibWeb/Forward.h +++ b/Libraries/LibWeb/Forward.h @@ -398,6 +398,7 @@ enum class MediaFeatureID : u8; enum class PropertyID : u16; enum class PaintOrder : u8; enum class ValueType : u8; +enum class AnimatedPropertyResultOfTransition : u8; struct BackgroundLayerData; struct CalculationContext; diff --git a/Libraries/LibWeb/HTML/Canvas/CanvasShadowStyles.h b/Libraries/LibWeb/HTML/Canvas/CanvasShadowStyles.h index 0b5afe39934f..7d738861d72e 100644 --- a/Libraries/LibWeb/HTML/Canvas/CanvasShadowStyles.h +++ b/Libraries/LibWeb/HTML/Canvas/CanvasShadowStyles.h @@ -7,7 +7,6 @@ #pragma once #include -#include #include #include #include diff --git a/Libraries/LibWeb/HTML/Canvas/CanvasTextDrawingStyles.cpp b/Libraries/LibWeb/HTML/Canvas/CanvasTextDrawingStyles.cpp index 1a352653b297..064d45e62a27 100644 --- a/Libraries/LibWeb/HTML/Canvas/CanvasTextDrawingStyles.cpp +++ b/Libraries/LibWeb/HTML/Canvas/CanvasTextDrawingStyles.cpp @@ -7,6 +7,7 @@ #include "CanvasTextDrawingStyles.h" #include +#include #include #include #include diff --git a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index 09484ccb04e3..53ccad4f74b9 100644 --- a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include diff --git a/Libraries/LibWeb/HTML/OffscreenCanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/OffscreenCanvasRenderingContext2D.cpp index f44d65c45641..c43dc97c020d 100644 --- a/Libraries/LibWeb/HTML/OffscreenCanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/OffscreenCanvasRenderingContext2D.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff --git a/Libraries/LibWeb/SVG/SVGElement.cpp b/Libraries/LibWeb/SVG/SVGElement.cpp index 7a1cbc49c631..a43af232eebd 100644 --- a/Libraries/LibWeb/SVG/SVGElement.cpp +++ b/Libraries/LibWeb/SVG/SVGElement.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/Tests/LibWeb/Ref/expected/css/recomputing-inherited-style-doesnt-remove-important-ref.html b/Tests/LibWeb/Ref/expected/css/recomputing-inherited-style-doesnt-remove-important-ref.html new file mode 100644 index 000000000000..107d75653050 --- /dev/null +++ b/Tests/LibWeb/Ref/expected/css/recomputing-inherited-style-doesnt-remove-important-ref.html @@ -0,0 +1,9 @@ + + +
diff --git a/Tests/LibWeb/Ref/input/css/recomputing-inherited-style-doesnt-remove-important.html b/Tests/LibWeb/Ref/input/css/recomputing-inherited-style-doesnt-remove-important.html new file mode 100644 index 000000000000..ee6b95ce81e8 --- /dev/null +++ b/Tests/LibWeb/Ref/input/css/recomputing-inherited-style-doesnt-remove-important.html @@ -0,0 +1,28 @@ + + + +
+ diff --git a/Tests/LibWeb/Text/expected/css/inherited-animated-values-overwriting-non-inherited.txt b/Tests/LibWeb/Text/expected/css/inherited-animated-values-overwriting-non-inherited.txt new file mode 100644 index 000000000000..74ea9c8de854 --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/inherited-animated-values-overwriting-non-inherited.txt @@ -0,0 +1 @@ +rgb(0, 128, 0) diff --git a/Tests/LibWeb/Text/expected/css/transition-behavior-multiple.txt b/Tests/LibWeb/Text/expected/css/transition-behavior-multiple.txt new file mode 100644 index 000000000000..38657bba5afa --- /dev/null +++ b/Tests/LibWeb/Text/expected/css/transition-behavior-multiple.txt @@ -0,0 +1 @@ +#foo { transition-behavior: allow-discrete, normal; } diff --git a/Tests/LibWeb/Text/expected/wpt-import/css/css-transitions/transition-important.txt b/Tests/LibWeb/Text/expected/wpt-import/css/css-transitions/transition-important.txt new file mode 100644 index 000000000000..77a513caee48 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/css/css-transitions/transition-important.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass !important should not override transition \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/css/inherited-animated-values-overwriting-non-inherited.html b/Tests/LibWeb/Text/input/css/inherited-animated-values-overwriting-non-inherited.html new file mode 100644 index 000000000000..8ec4dfc99cb2 --- /dev/null +++ b/Tests/LibWeb/Text/input/css/inherited-animated-values-overwriting-non-inherited.html @@ -0,0 +1,41 @@ + + + +
+ + + diff --git a/Tests/LibWeb/Text/input/css/transition-behavior-multiple.html b/Tests/LibWeb/Text/input/css/transition-behavior-multiple.html new file mode 100644 index 000000000000..ed1e006c286e --- /dev/null +++ b/Tests/LibWeb/Text/input/css/transition-behavior-multiple.html @@ -0,0 +1,14 @@ + + + + + + diff --git a/Tests/LibWeb/Text/input/wpt-import/css/css-transitions/transition-important.html b/Tests/LibWeb/Text/input/wpt-import/css/css-transitions/transition-important.html new file mode 100644 index 000000000000..6faa74dee152 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/css/css-transitions/transition-important.html @@ -0,0 +1,24 @@ + +CSS Transitions Test: !important property + + + + +
+