diff --git a/Libraries/LibWeb/CSS/Interpolation.cpp b/Libraries/LibWeb/CSS/Interpolation.cpp index eb4ec581a1a..bf4d5565b78 100644 --- a/Libraries/LibWeb/CSS/Interpolation.cpp +++ b/Libraries/LibWeb/CSS/Interpolation.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -60,10 +61,14 @@ ValueComparingRefPtr interpolate_property(DOM::Element& ele auto from = with_keyword_values_resolved(element, property_id, a_from); auto to = with_keyword_values_resolved(element, property_id, a_to); + CalculationContext calculation_context { + .percentages_resolve_as = property_resolves_percentages_relative_to(property_id), + }; + auto animation_type = animation_type_from_longhand_property(property_id); switch (animation_type) { case AnimationType::ByComputedValue: - return interpolate_value(element, from, to, delta); + return interpolate_value(element, calculation_context, from, to, delta); case AnimationType::None: return to; case AnimationType::Custom: { @@ -78,7 +83,7 @@ ValueComparingRefPtr interpolate_property(DOM::Element& ele return {}; } if (property_id == PropertyID::BoxShadow) - return interpolate_box_shadow(element, from, to, delta); + return interpolate_box_shadow(element, calculation_context, from, to, delta); // FIXME: Handle all custom animatable properties [[fallthrough]]; @@ -422,7 +427,7 @@ Color interpolate_color(Color from, Color to, float delta) return color; } -NonnullRefPtr interpolate_box_shadow(DOM::Element& element, CSSStyleValue const& from, CSSStyleValue const& to, float delta) +NonnullRefPtr interpolate_box_shadow(DOM::Element& element, CalculationContext const& calculation_context, CSSStyleValue const& from, CSSStyleValue const& to, float delta) { // https://drafts.csswg.org/css-backgrounds/#box-shadow // Animation type: by computed value, treating none as a zero-item list and appending blank shadows @@ -472,10 +477,10 @@ NonnullRefPtr interpolate_box_shadow(DOM::Element& element, auto const& to_shadow = to_shadows[i]->as_shadow(); auto result_shadow = ShadowStyleValue::create( CSSColorValue::create_from_color(interpolate_color(from_shadow.color()->to_color({}), to_shadow.color()->to_color({}), delta)), - interpolate_value(element, from_shadow.offset_x(), to_shadow.offset_x(), delta), - interpolate_value(element, from_shadow.offset_y(), to_shadow.offset_y(), delta), - interpolate_value(element, from_shadow.blur_radius(), to_shadow.blur_radius(), delta), - interpolate_value(element, from_shadow.spread_distance(), to_shadow.spread_distance(), delta), + interpolate_value(element, calculation_context, from_shadow.offset_x(), to_shadow.offset_x(), delta), + interpolate_value(element, calculation_context, from_shadow.offset_y(), to_shadow.offset_y(), delta), + interpolate_value(element, calculation_context, from_shadow.blur_radius(), to_shadow.blur_radius(), delta), + interpolate_value(element, calculation_context, from_shadow.spread_distance(), to_shadow.spread_distance(), delta), delta >= 0.5f ? to_shadow.placement() : from_shadow.placement()); result_shadows.unchecked_append(result_shadow); } @@ -483,7 +488,7 @@ NonnullRefPtr interpolate_box_shadow(DOM::Element& element, return StyleValueList::create(move(result_shadows), StyleValueList::Separator::Comma); } -NonnullRefPtr interpolate_value(DOM::Element& element, CSSStyleValue const& from, CSSStyleValue const& to, float delta) +NonnullRefPtr interpolate_value(DOM::Element& element, CalculationContext const& calculation_context, CSSStyleValue const& from, CSSStyleValue const& to, float delta) { if (from.type() != to.type()) { // Handle mixed percentage and dimension types @@ -520,18 +525,18 @@ NonnullRefPtr interpolate_value(DOM::Element& element, CSSS } }; - static constexpr auto to_calculation_node = [](CSSStyleValue const& value) -> NonnullOwnPtr { + static auto to_calculation_node = [calculation_context](CSSStyleValue const& value) -> NonnullOwnPtr { switch (value.type()) { case CSSStyleValue::Type::Angle: - return NumericCalculationNode::create(value.as_angle().angle()); + return NumericCalculationNode::create(value.as_angle().angle(), calculation_context); case CSSStyleValue::Type::Frequency: - return NumericCalculationNode::create(value.as_frequency().frequency()); + return NumericCalculationNode::create(value.as_frequency().frequency(), calculation_context); case CSSStyleValue::Type::Length: - return NumericCalculationNode::create(value.as_length().length()); + return NumericCalculationNode::create(value.as_length().length(), calculation_context); case CSSStyleValue::Type::Percentage: - return NumericCalculationNode::create(value.as_percentage().percentage()); + return NumericCalculationNode::create(value.as_percentage().percentage(), calculation_context); case CSSStyleValue::Type::Time: - return NumericCalculationNode::create(value.as_time().time()); + return NumericCalculationNode::create(value.as_time().time(), calculation_context); default: VERIFY_NOT_REACHED(); } @@ -546,15 +551,15 @@ NonnullRefPtr interpolate_value(DOM::Element& element, CSSS // hard to understand how this interpolation works, but if instead we rewrite the values as "30px + 0%" and // "0px + 80%", then it is very simple to understand; we just interpolate each component separately. - auto interpolated_from = interpolate_value(element, from, from_base_type_and_default->default_value, delta); - auto interpolated_to = interpolate_value(element, to_base_type_and_default->default_value, to, delta); + auto interpolated_from = interpolate_value(element, calculation_context, from, from_base_type_and_default->default_value, delta); + auto interpolated_to = interpolate_value(element, calculation_context, to_base_type_and_default->default_value, to, delta); Vector> values; values.ensure_capacity(2); values.unchecked_append(to_calculation_node(interpolated_from)); values.unchecked_append(to_calculation_node(interpolated_to)); auto calc_node = SumCalculationNode::create(move(values)); - return CalculatedStyleValue::create(move(calc_node), CSSNumericType { to_base_type_and_default->base_type, 1 }); + return CalculatedStyleValue::create(move(calc_node), CSSNumericType { to_base_type_and_default->base_type, 1 }, calculation_context); } return delta >= 0.5f ? to : from; @@ -587,8 +592,8 @@ NonnullRefPtr interpolate_value(DOM::Element& element, CSSS auto const& from_position = from.as_position(); auto const& to_position = to.as_position(); return PositionStyleValue::create( - interpolate_value(element, from_position.edge_x(), to_position.edge_x(), delta)->as_edge(), - interpolate_value(element, from_position.edge_y(), to_position.edge_y(), delta)->as_edge()); + interpolate_value(element, calculation_context, from_position.edge_x(), to_position.edge_x(), delta)->as_edge(), + interpolate_value(element, calculation_context, from_position.edge_y(), to_position.edge_y(), delta)->as_edge()); } case CSSStyleValue::Type::Ratio: { auto from_ratio = from.as_ratio().ratio(); @@ -634,7 +639,7 @@ NonnullRefPtr interpolate_value(DOM::Element& element, CSSS StyleValueVector interpolated_values; interpolated_values.ensure_capacity(from_list.size()); for (size_t i = 0; i < from_list.size(); ++i) - interpolated_values.append(interpolate_value(element, from_list.values()[i], to_list.values()[i], delta)); + interpolated_values.append(interpolate_value(element, calculation_context, from_list.values()[i], to_list.values()[i], delta)); return StyleValueList::create(move(interpolated_values), from_list.separator()); } diff --git a/Libraries/LibWeb/CSS/Interpolation.h b/Libraries/LibWeb/CSS/Interpolation.h index 59f9e859e12..d51666c6565 100644 --- a/Libraries/LibWeb/CSS/Interpolation.h +++ b/Libraries/LibWeb/CSS/Interpolation.h @@ -11,13 +11,15 @@ namespace Web::CSS { +struct CalculationContext; + ValueComparingRefPtr interpolate_property(DOM::Element&, PropertyID, CSSStyleValue const& from, CSSStyleValue const& to, float delta); // https://drafts.csswg.org/css-transitions/#transitionable bool property_values_are_transitionable(PropertyID, CSSStyleValue const& old_value, CSSStyleValue const& new_value); -NonnullRefPtr interpolate_value(DOM::Element&, CSSStyleValue const& from, CSSStyleValue const& to, float delta); -NonnullRefPtr interpolate_box_shadow(DOM::Element&, CSSStyleValue const& from, CSSStyleValue const& to, float delta); +NonnullRefPtr interpolate_value(DOM::Element&, CalculationContext const&, CSSStyleValue const& from, CSSStyleValue const& to, float delta); +NonnullRefPtr interpolate_box_shadow(DOM::Element&, CalculationContext const&, CSSStyleValue const& from, CSSStyleValue const& to, float delta); RefPtr interpolate_transform(DOM::Element&, CSSStyleValue const& from, CSSStyleValue const& to, float delta); Color interpolate_color(Color from, Color to, float delta); diff --git a/Libraries/LibWeb/CSS/Parser/Parser.cpp b/Libraries/LibWeb/CSS/Parser/Parser.cpp index 7a4c0a9ac36..356a3e1445f 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.cpp +++ b/Libraries/LibWeb/CSS/Parser/Parser.cpp @@ -1922,7 +1922,30 @@ RefPtr Parser::parse_calculated_value(ComponentValue const auto const& function = component_value.function(); - auto function_node = parse_a_calc_function_node(function); + CalculationContext context {}; + for (auto const& value_context : m_value_context.in_reverse()) { + auto percentages_resolve_as = value_context.visit( + [](PropertyID property_id) -> Optional { + return property_resolves_percentages_relative_to(property_id); + }, + [](FunctionContext const& function) -> Optional { + // Gradients resolve percentages as lengths relative to the gradient-box. + if (function.name.is_one_of_ignoring_ascii_case( + "linear-gradient"sv, "repeating-linear-gradient"sv, + "radial-gradient"sv, "repeating-radial-gradient"sv, + "conic-gradient"sv, "repeating-conic-gradient"sv)) { + return ValueType::Length; + } + // FIXME: Add other functions that provide a context for resolving percentages + return {}; + }); + if (percentages_resolve_as.has_value()) { + context.percentages_resolve_as = move(percentages_resolve_as); + break; + } + } + + auto function_node = parse_a_calc_function_node(function, context); if (!function_node) return nullptr; @@ -1930,17 +1953,17 @@ RefPtr Parser::parse_calculated_value(ComponentValue const if (!function_type.has_value()) return nullptr; - return CalculatedStyleValue::create(function_node.release_nonnull(), function_type.release_value()); + return CalculatedStyleValue::create(function_node.release_nonnull(), function_type.release_value(), context); } -OwnPtr Parser::parse_a_calc_function_node(Function const& function) +OwnPtr Parser::parse_a_calc_function_node(Function const& function, CalculationContext const& context) { auto context_guard = push_temporary_value_parsing_context(FunctionContext { function.name }); if (function.name.equals_ignoring_ascii_case("calc"sv)) - return parse_a_calculation(function.value); + return parse_a_calculation(function.value, context); - if (auto maybe_function = parse_math_function(function)) + if (auto maybe_function = parse_math_function(function, context)) return maybe_function; return nullptr; @@ -9231,15 +9254,15 @@ LengthOrCalculated Parser::Parser::parse_as_sizes_attribute(DOM::Element const& return Length(100, Length::Type::Vw); } -OwnPtr Parser::convert_to_calculation_node(CalcParsing::Node const& node) +OwnPtr Parser::convert_to_calculation_node(CalcParsing::Node const& node, CalculationContext const& context) { return node.visit( - [this](NonnullOwnPtr const& product_node) -> OwnPtr { + [this, &context](NonnullOwnPtr const& product_node) -> OwnPtr { Vector> children; children.ensure_capacity(product_node->children.size()); for (auto const& child : product_node->children) { - if (auto child_as_node = convert_to_calculation_node(child)) { + if (auto child_as_node = convert_to_calculation_node(child, context)) { children.append(child_as_node.release_nonnull()); } else { return nullptr; @@ -9248,12 +9271,12 @@ OwnPtr Parser::convert_to_calculation_node(CalcParsing::Node co return ProductCalculationNode::create(move(children)); }, - [this](NonnullOwnPtr const& sum_node) -> OwnPtr { + [this, &context](NonnullOwnPtr const& sum_node) -> OwnPtr { Vector> children; children.ensure_capacity(sum_node->children.size()); for (auto const& child : sum_node->children) { - if (auto child_as_node = convert_to_calculation_node(child)) { + if (auto child_as_node = convert_to_calculation_node(child, context)) { children.append(child_as_node.release_nonnull()); } else { return nullptr; @@ -9262,24 +9285,24 @@ OwnPtr Parser::convert_to_calculation_node(CalcParsing::Node co return SumCalculationNode::create(move(children)); }, - [this](NonnullOwnPtr const& invert_node) -> OwnPtr { - if (auto child_as_node = convert_to_calculation_node(invert_node->child)) + [this, &context](NonnullOwnPtr const& invert_node) -> OwnPtr { + if (auto child_as_node = convert_to_calculation_node(invert_node->child, context)) return InvertCalculationNode::create(child_as_node.release_nonnull()); return nullptr; }, - [this](NonnullOwnPtr const& negate_node) -> OwnPtr { - if (auto child_as_node = convert_to_calculation_node(negate_node->child)) + [this, &context](NonnullOwnPtr const& negate_node) -> OwnPtr { + if (auto child_as_node = convert_to_calculation_node(negate_node->child, context)) return NegateCalculationNode::create(child_as_node.release_nonnull()); return nullptr; }, - [this](NonnullRawPtr const& component_value) -> OwnPtr { + [this, &context](NonnullRawPtr const& component_value) -> OwnPtr { // NOTE: This is the "process the leaf nodes" part of step 5 of https://drafts.csswg.org/css-values-4/#parse-a-calculation // We divert a little from the spec: Rather than modify an existing tree of values, we construct a new one from that source tree. // This lets us make CalculationNodes immutable. // 1. If leaf is a parenthesized simple block, replace leaf with the result of parsing a calculation from leaf’s contents. if (component_value->is_block() && component_value->block().is_paren()) { - auto leaf_calculation = parse_a_calculation(component_value->block().value); + auto leaf_calculation = parse_a_calculation(component_value->block().value, context); if (!leaf_calculation) return nullptr; @@ -9290,7 +9313,7 @@ OwnPtr Parser::convert_to_calculation_node(CalcParsing::Node co // NOTE: All function tokens at this point should be math functions. if (component_value->is_function()) { auto const& function = component_value->function(); - auto leaf_calculation = parse_a_calc_function_node(function); + auto leaf_calculation = parse_a_calc_function_node(function, context); if (!leaf_calculation) return nullptr; @@ -9307,17 +9330,17 @@ OwnPtr Parser::convert_to_calculation_node(CalcParsing::Node co } if (component_value->is(Token::Type::Number)) - return NumericCalculationNode::create(component_value->token().number()); + return NumericCalculationNode::create(component_value->token().number(), context); if (component_value->is(Token::Type::Dimension)) { auto numeric_value = component_value->token().dimension_value(); auto unit_string = component_value->token().dimension_unit(); if (auto length_type = Length::unit_from_name(unit_string); length_type.has_value()) - return NumericCalculationNode::create(Length { numeric_value, length_type.release_value() }); + return NumericCalculationNode::create(Length { numeric_value, length_type.release_value() }, context); if (auto angle_type = Angle::unit_from_name(unit_string); angle_type.has_value()) - return NumericCalculationNode::create(Angle { numeric_value, angle_type.release_value() }); + return NumericCalculationNode::create(Angle { numeric_value, angle_type.release_value() }, context); if (auto flex_type = Flex::unit_from_name(unit_string); flex_type.has_value()) { // https://www.w3.org/TR/css3-grid-layout/#fr-unit @@ -9329,34 +9352,20 @@ OwnPtr Parser::convert_to_calculation_node(CalcParsing::Node co } if (auto frequency_type = Frequency::unit_from_name(unit_string); frequency_type.has_value()) - return NumericCalculationNode::create(Frequency { numeric_value, frequency_type.release_value() }); + return NumericCalculationNode::create(Frequency { numeric_value, frequency_type.release_value() }, context); if (auto resolution_type = Resolution::unit_from_name(unit_string); resolution_type.has_value()) - return NumericCalculationNode::create(Resolution { numeric_value, resolution_type.release_value() }); + return NumericCalculationNode::create(Resolution { numeric_value, resolution_type.release_value() }, context); if (auto time_type = Time::unit_from_name(unit_string); time_type.has_value()) - return NumericCalculationNode::create(Time { numeric_value, time_type.release_value() }); + return NumericCalculationNode::create(Time { numeric_value, time_type.release_value() }, context); dbgln_if(CSS_PARSER_DEBUG, "Unrecognized dimension type in calc() expression: {}", component_value->to_string()); return nullptr; } - if (component_value->is(Token::Type::Percentage)) { - Optional percentage_resolved_type; - for (auto const& value_context : m_value_context.in_reverse()) { - percentage_resolved_type = value_context.visit( - [](PropertyID property_id) -> Optional { - return property_resolves_percentages_relative_to(property_id); - }, - [](FunctionContext const&) -> Optional { - // FIXME: Some functions provide this. The spec mentions `media-progress()` as an example. - return {}; - }); - if (percentage_resolved_type.has_value()) - break; - } - return NumericCalculationNode::create(Percentage { component_value->token().percentage() }, percentage_resolved_type); - } + if (component_value->is(Token::Type::Percentage)) + return NumericCalculationNode::create(Percentage { component_value->token().percentage() }, context); // NOTE: If we get here, then we have a ComponentValue that didn't get replaced with something else, // so the calc() is invalid. @@ -9370,7 +9379,7 @@ OwnPtr Parser::convert_to_calculation_node(CalcParsing::Node co } // https://drafts.csswg.org/css-values-4/#parse-a-calculation -OwnPtr Parser::parse_a_calculation(Vector const& original_values) +OwnPtr Parser::parse_a_calculation(Vector const& original_values, CalculationContext const& context) { // 1. Discard any s from values. // 2. An item in values is an “operator” if it’s a with the value "+", "-", "*", or "/". Otherwise, it’s a “value”. @@ -9483,7 +9492,7 @@ OwnPtr Parser::parse_a_calculation(Vector const // 5. At this point values is a tree of Sum, Product, Negate, and Invert nodes, with other types of values at the leaf nodes. Process the leaf nodes. // NOTE: We process leaf nodes as part of this conversion. - auto calculation_tree = convert_to_calculation_node(*single_value); + auto calculation_tree = convert_to_calculation_node(*single_value, context); if (!calculation_tree) return nullptr; diff --git a/Libraries/LibWeb/CSS/Parser/Parser.h b/Libraries/LibWeb/CSS/Parser/Parser.h index d66b67bea35..bf4b6a9108c 100644 --- a/Libraries/LibWeb/CSS/Parser/Parser.h +++ b/Libraries/LibWeb/CSS/Parser/Parser.h @@ -276,8 +276,8 @@ private: RefPtr parse_calculated_value(ComponentValue const&); RefPtr parse_custom_ident_value(TokenStream&, std::initializer_list blacklist); // NOTE: Implemented in generated code. (GenerateCSSMathFunctions.cpp) - OwnPtr parse_math_function(Function const&); - OwnPtr parse_a_calc_function_node(Function const&); + OwnPtr parse_math_function(Function const&, CalculationContext const&); + OwnPtr parse_a_calc_function_node(Function const&, CalculationContext const&); RefPtr parse_keyword_value(TokenStream&); RefPtr parse_hue_none_value(TokenStream&); RefPtr parse_solidus_and_alpha_value(TokenStream&); @@ -396,8 +396,8 @@ private: RefPtr parse_grid_area_shorthand_value(TokenStream&); RefPtr parse_grid_shorthand_value(TokenStream&); - OwnPtr convert_to_calculation_node(CalcParsing::Node const&); - OwnPtr parse_a_calculation(Vector const&); + OwnPtr convert_to_calculation_node(CalcParsing::Node const&, CalculationContext const&); + OwnPtr parse_a_calculation(Vector const&, CalculationContext const&); ParseErrorOr> parse_complex_selector(TokenStream&, SelectorType); ParseErrorOr> parse_compound_selector(TokenStream&); diff --git a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp index 36067121644..dd020ef122b 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.cpp @@ -109,7 +109,7 @@ CalculationNode::CalculationNode(Type type, Optional numeric_typ CalculationNode::~CalculationNode() = default; -static CSSNumericType numeric_type_from_calculated_style_value(CalculatedStyleValue::CalculationResult::Value const& value, Optional percentage_resolved_type) +static CSSNumericType numeric_type_from_calculated_style_value(CalculatedStyleValue::CalculationResult::Value const& value, CalculationContext const& context) { // https://drafts.csswg.org/css-values-4/#determine-the-type-of-a-calculation // Anything else is a terminal value, whose type is determined based on its CSS type. @@ -152,14 +152,14 @@ static CSSNumericType numeric_type_from_calculated_style_value(CalculatedStyleVa return CSSNumericType { CSSNumericType::BaseType::Flex, 1 }; }, // NOTE: is a separate node type. (FIXME: Should it be?) - [&percentage_resolved_type](Percentage const&) { + [&context](Percentage const&) { // -> // If, in the context in which the math function containing this calculation is placed, // s are resolved relative to another type of value (such as in width, // where is resolved against a ), and that other type is not , // the type is determined as the other type, but with a percent hint set to that other type. - if (percentage_resolved_type.has_value() && percentage_resolved_type != ValueType::Number && percentage_resolved_type != ValueType::Percentage) { - auto base_type = CSSNumericType::base_type_from_value_type(*percentage_resolved_type); + if (context.percentages_resolve_as.has_value() && context.percentages_resolve_as != ValueType::Number && context.percentages_resolve_as != ValueType::Percentage) { + auto base_type = CSSNumericType::base_type_from_value_type(*context.percentages_resolve_as); VERIFY(base_type.has_value()); auto result = CSSNumericType { base_type.value(), 1 }; result.set_percent_hint(base_type); @@ -174,9 +174,9 @@ static CSSNumericType numeric_type_from_calculated_style_value(CalculatedStyleVa }); } -NonnullOwnPtr NumericCalculationNode::create(NumericValue value, Optional percentage_resolved_type) +NonnullOwnPtr NumericCalculationNode::create(NumericValue value, CalculationContext const& context) { - auto numeric_type = numeric_type_from_calculated_style_value(value, percentage_resolved_type); + auto numeric_type = numeric_type_from_calculated_style_value(value, context); return adopt_own(*new (nothrow) NumericCalculationNode(move(value), numeric_type)); } diff --git a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h index b97b5bacca9..f178f2d0bb9 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/CalculatedStyleValue.h @@ -24,6 +24,11 @@ namespace Web::CSS { class CalculationNode; +// https://drafts.csswg.org/css-values-4/#ref-for-calc-calculation%E2%91%A2%E2%91%A7 +struct CalculationContext { + Optional percentages_resolve_as {}; +}; + class CalculatedStyleValue : public CSSStyleValue { public: using PercentageBasis = Variant; @@ -56,9 +61,9 @@ public: Optional m_type; }; - static ValueComparingNonnullRefPtr create(NonnullOwnPtr calculation, CSSNumericType resolved_type) + static ValueComparingNonnullRefPtr create(NonnullOwnPtr calculation, CSSNumericType resolved_type, CalculationContext context) { - return adopt_ref(*new (nothrow) CalculatedStyleValue(move(calculation), resolved_type)); + return adopt_ref(*new (nothrow) CalculatedStyleValue(move(calculation), move(resolved_type), move(context))); } virtual String to_string(SerializationMode) const override; @@ -113,15 +118,17 @@ public: String dump() const; private: - explicit CalculatedStyleValue(NonnullOwnPtr calculation, CSSNumericType resolved_type) + explicit CalculatedStyleValue(NonnullOwnPtr calculation, CSSNumericType resolved_type, CalculationContext context) : CSSStyleValue(Type::Calculated) - , m_resolved_type(resolved_type) + , m_resolved_type(move(resolved_type)) , m_calculation(move(calculation)) + , m_context(move(context)) { } CSSNumericType m_resolved_type; NonnullOwnPtr m_calculation; + CalculationContext m_context; }; // https://www.w3.org/TR/css-values-4/#calculation-tree @@ -258,7 +265,7 @@ private: class NumericCalculationNode final : public CalculationNode { public: - static NonnullOwnPtr create(NumericValue, Optional percentage_resolved_type = {}); + static NonnullOwnPtr create(NumericValue, CalculationContext const&); ~NumericCalculationNode(); virtual String to_string() const override; diff --git a/Libraries/LibWeb/CSS/StyleValues/EdgeStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/EdgeStyleValue.cpp index af6fcb247ab..6eed3605290 100644 --- a/Libraries/LibWeb/CSS/StyleValues/EdgeStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/EdgeStyleValue.cpp @@ -16,15 +16,19 @@ String EdgeStyleValue::to_string(SerializationMode mode) const auto flipped_percentage = 100 - offset().percentage().value(); return Percentage(flipped_percentage).to_string(); } + + // FIXME: Figure out how to get the proper calculation context here + CalculationContext context = {}; + Vector> sum_parts; - sum_parts.append(NumericCalculationNode::create(Percentage(100))); + sum_parts.append(NumericCalculationNode::create(Percentage(100), context)); if (offset().is_length()) { - sum_parts.append(NegateCalculationNode::create(NumericCalculationNode::create(offset().length()))); + sum_parts.append(NegateCalculationNode::create(NumericCalculationNode::create(offset().length(), context))); } else { // FIXME: Flip calculated offsets (convert CalculatedStyleValue to CalculationNode, then negate and append) return to_string(CSSStyleValue::SerializationMode::Normal); } - auto flipped_absolute = CalculatedStyleValue::create(SumCalculationNode::create(move(sum_parts)), CSSNumericType(CSSNumericType::BaseType::Length, 1)); + auto flipped_absolute = CalculatedStyleValue::create(SumCalculationNode::create(move(sum_parts)), CSSNumericType(CSSNumericType::BaseType::Length, 1), context); return flipped_absolute->to_string(mode); } return offset().to_string(); diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSMathFunctions.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSMathFunctions.cpp index 2bfdc708536..3fa82880bec 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSMathFunctions.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/GenerateCSSMathFunctions.cpp @@ -116,7 +116,7 @@ static Optional parse_rounding_strategy(Vector return keyword_to_rounding_strategy(maybe_keyword.value()); } -OwnPtr Parser::parse_math_function(Function const& function) +OwnPtr Parser::parse_math_function(Function const& function, CalculationContext const& context) { TokenStream stream { function.value }; auto arguments = parse_a_comma_separated_list_of_component_values(stream); @@ -140,7 +140,7 @@ OwnPtr Parser::parse_math_function(Function const& function) parsed_arguments.ensure_capacity(arguments.size()); for (auto& argument : arguments) { - auto calculation_node = parse_a_calculation(argument); + auto calculation_node = parse_a_calculation(argument, context); if (!calculation_node) { dbgln_if(CSS_PARSER_DEBUG, "@name:lowercase@() argument #{} is not a valid calculation", parsed_arguments.size()); return nullptr; @@ -243,7 +243,7 @@ OwnPtr Parser::parse_math_function(Function const& function) // NOTE: This assumes everything not handled above is a calculation node of some kind. parameter_is_calculation = true; parameter_generator.set("parameter_type", "OwnPtr"_string); - parameter_generator.set("parse_function", "parse_a_calculation(arguments[argument_index])"_string); + parameter_generator.set("parse_function", "parse_a_calculation(arguments[argument_index], context)"_string); parameter_generator.set("check_function", " != nullptr"_string); parameter_generator.set("release_function", ".release_nonnull()"_string);