From 6a9c8d776711cc87ca68246b77d4b79278c4c782 Mon Sep 17 00:00:00 2001 From: Callum Law Date: Thu, 3 Jul 2025 12:59:24 +1200 Subject: [PATCH] LibWeb: Don't resolve colors with unresolved components `CSSColorValue`s which have unresolved `calc` components should be able to be resolved. Previously we would always resolve them but with incorrect values. This is useful as we will now be able to now whether we should serialize colors in their normalized form or not. Slight regression in that we now serialize (RGB, HSL and HWB) colors with components that rely on compute-time information as an empty string, but that will be fixed in the next commit. --- Libraries/LibWeb/CSS/CSSStyleValue.h | 2 +- Libraries/LibWeb/CSS/ComputedProperties.cpp | 14 +-- Libraries/LibWeb/CSS/Interpolation.cpp | 27 ++++- .../LibWeb/CSS/StyleValues/CSSColorValue.cpp | 105 ++++++++++++++---- Libraries/LibWeb/CSS/StyleValues/CSSHSL.cpp | 20 ++-- Libraries/LibWeb/CSS/StyleValues/CSSHSL.h | 2 +- Libraries/LibWeb/CSS/StyleValues/CSSHWB.cpp | 25 +++-- Libraries/LibWeb/CSS/StyleValues/CSSHWB.h | 2 +- .../CSS/StyleValues/CSSKeywordValue.cpp | 2 +- .../LibWeb/CSS/StyleValues/CSSKeywordValue.h | 2 +- .../LibWeb/CSS/StyleValues/CSSLCHLike.cpp | 37 ++++-- Libraries/LibWeb/CSS/StyleValues/CSSLCHLike.h | 4 +- .../LibWeb/CSS/StyleValues/CSSLabLike.cpp | 30 +++-- Libraries/LibWeb/CSS/StyleValues/CSSLabLike.h | 4 +- .../LibWeb/CSS/StyleValues/CSSLightDark.cpp | 2 +- .../LibWeb/CSS/StyleValues/CSSLightDark.h | 2 +- Libraries/LibWeb/CSS/StyleValues/CSSRGB.cpp | 49 +++++--- Libraries/LibWeb/CSS/StyleValues/CSSRGB.h | 2 +- .../StyleValues/ColorFunctionStyleValue.cpp | 34 ++++-- .../CSS/StyleValues/ColorFunctionStyleValue.h | 4 +- .../CSS/StyleValues/ColorMixStyleValue.cpp | 12 +- .../CSS/StyleValues/ColorMixStyleValue.h | 2 +- Libraries/LibWeb/DOM/Document.cpp | 2 +- .../LibWeb/Editing/Internal/Algorithms.cpp | 2 +- .../HTML/Canvas/CanvasFillStrokeStyles.h | 4 +- .../LibWeb/HTML/CanvasRenderingContext2D.cpp | 2 +- .../OffscreenCanvasRenderingContext2D.cpp | 2 +- Libraries/LibWeb/Layout/Node.cpp | 8 +- Libraries/LibWeb/Painting/BorderPainting.cpp | 2 +- .../LibWeb/Painting/GradientPainting.cpp | 2 +- 30 files changed, 278 insertions(+), 129 deletions(-) diff --git a/Libraries/LibWeb/CSS/CSSStyleValue.h b/Libraries/LibWeb/CSS/CSSStyleValue.h index bda98af5a53..44270280333 100644 --- a/Libraries/LibWeb/CSS/CSSStyleValue.h +++ b/Libraries/LibWeb/CSS/CSSStyleValue.h @@ -393,7 +393,7 @@ public: virtual ValueComparingNonnullRefPtr absolutized(CSSPixelRect const& viewport_rect, Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const; - virtual Color to_color(Optional, CalculationResolutionContext const&) const { return {}; } + virtual Optional to_color(Optional, CalculationResolutionContext const&) const { return {}; } Keyword to_keyword() const; virtual String to_string(SerializationMode) const = 0; diff --git a/Libraries/LibWeb/CSS/ComputedProperties.cpp b/Libraries/LibWeb/CSS/ComputedProperties.cpp index 89fcae0c53f..047c43c8450 100644 --- a/Libraries/LibWeb/CSS/ComputedProperties.cpp +++ b/Libraries/LibWeb/CSS/ComputedProperties.cpp @@ -226,7 +226,7 @@ Color ComputedProperties::color_or_fallback(PropertyID id, Layout::NodeWithStyle auto const& value = property(id); if (!value.has_color()) return fallback; - return value.to_color(node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(node) }); + return value.to_color(node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(node) }).value(); } // https://drafts.csswg.org/css-color-adjust-1/#determine-the-used-color-scheme @@ -447,7 +447,7 @@ Color ComputedProperties::flood_color(Layout::NodeWithStyle const& node) const { auto const& value = property(PropertyID::FloodColor); if (value.has_color()) { - return value.to_color(node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(node) }); + return value.to_color(node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(node) }).value(); } return InitialValues::flood_color(); @@ -940,7 +940,7 @@ Color ComputedProperties::caret_color(Layout::NodeWithStyle const& node) const return node.computed_values().color(); if (value.has_color()) - return value.to_color(node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(node) }); + return value.to_color(node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(node) }).value(); return InitialValues::caret_color(); } @@ -1203,7 +1203,7 @@ Vector ComputedProperties::shadow(PropertyID property_id, Layout::No maybe_offset_y.release_value(), maybe_blur_radius.release_value(), maybe_spread_distance.release_value(), - value.color()->to_color(as(layout_node), { .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }), + value.color()->to_color(as(layout_node), { .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }).value(), value.placement() }; }; @@ -1826,7 +1826,7 @@ Color ComputedProperties::stop_color() const // FIXME: This is used by the SVGStopElement, which does not participate in layout, so we can't pass a layout // node or CalculationResolutionContext. This means we don't support all valid colors (e.g. palette // colors, calculated values which depend on length resolution, etc) - return value->to_color({}, {}); + return value->to_color({}, {}).value_or(Color::Black); } return Color::Black; } @@ -1910,8 +1910,8 @@ ScrollbarColorData ComputedProperties::scrollbar_color(Layout::NodeWithStyle con if (value.is_scrollbar_color()) { auto& scrollbar_color_value = value.as_scrollbar_color(); - auto thumb_color = scrollbar_color_value.thumb_color()->to_color(layout_node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }); - auto track_color = scrollbar_color_value.track_color()->to_color(layout_node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }); + auto thumb_color = scrollbar_color_value.thumb_color()->to_color(layout_node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }).value(); + auto track_color = scrollbar_color_value.track_color()->to_color(layout_node, { .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }).value(); return { thumb_color, track_color }; } diff --git a/Libraries/LibWeb/CSS/Interpolation.cpp b/Libraries/LibWeb/CSS/Interpolation.cpp index 4e16edda07d..568fd1e1021 100644 --- a/Libraries/LibWeb/CSS/Interpolation.cpp +++ b/Libraries/LibWeb/CSS/Interpolation.cpp @@ -688,13 +688,25 @@ RefPtr interpolate_box_shadow(DOM::Element& element, Calcul auto interpolated_spread_distance = interpolate_value(element, calculation_context, from_shadow.spread_distance(), to_shadow.spread_distance(), delta, allow_discrete); if (!interpolated_offset_x || !interpolated_offset_y || !interpolated_blur_radius || !interpolated_spread_distance) return {}; + auto color_syntax = ColorSyntax::Legacy; if ((!from_shadow.color()->is_keyword() && from_shadow.color()->as_color().color_syntax() == ColorSyntax::Modern) || (!to_shadow.color()->is_keyword() && to_shadow.color()->as_color().color_syntax() == ColorSyntax::Modern)) { color_syntax = ColorSyntax::Modern; } + + // FIXME: If we aren't able to resolve the colors here, we should postpone interpolation until we can (perhaps + // by creating something similar to a ColorMixStyleValue). + auto from_color = from_shadow.color()->to_color(layout_node, resolution_context); + auto to_color = to_shadow.color()->to_color(layout_node, resolution_context); + + Color interpolated_color = Color::Black; + + if (from_color.has_value() && to_color.has_value()) + interpolated_color = interpolate_color(from_color.value(), to_color.value(), delta, color_syntax); + auto result_shadow = ShadowStyleValue::create( - CSSColorValue::create_from_color(interpolate_color(from_shadow.color()->to_color(layout_node, resolution_context), to_shadow.color()->to_color(layout_node, resolution_context), delta, color_syntax), ColorSyntax::Modern), + CSSColorValue::create_from_color(interpolated_color, ColorSyntax::Modern), *interpolated_offset_x, *interpolated_offset_y, *interpolated_blur_radius, @@ -817,7 +829,18 @@ static RefPtr interpolate_value_impl(DOM::Element& element, || (!to.is_keyword() && to.as_color().color_syntax() == ColorSyntax::Modern)) { color_syntax = ColorSyntax::Modern; } - return CSSColorValue::create_from_color(interpolate_color(from.to_color(layout_node, resolution_context), to.to_color(layout_node, resolution_context), delta, color_syntax), ColorSyntax::Modern); + + // FIXME: If we aren't able to resolve the colors here, we should postpone interpolation until we can (perhaps + // by creating something similar to a ColorMixStyleValue). + auto from_color = from.to_color(layout_node, resolution_context); + auto to_color = to.to_color(layout_node, resolution_context); + + Color interpolated_color = Color::Black; + + if (from_color.has_value() && to_color.has_value()) + interpolated_color = interpolate_color(from_color.value(), to_color.value(), delta, color_syntax); + + return CSSColorValue::create_from_color(interpolated_color, ColorSyntax::Modern); } case CSSStyleValue::Type::Edge: { auto resolved_from = from.as_edge().resolved_value(calculation_context); diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSColorValue.cpp b/Libraries/LibWeb/CSS/StyleValues/CSSColorValue.cpp index 4822f04ffe5..a5e4048b0a5 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSColorValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CSSColorValue.cpp @@ -52,16 +52,26 @@ Optional CSSColorValue::resolve_hue(CSSStyleValue const& style_value, Ca return normalized(style_value.as_angle().angle().to_degrees()); if (style_value.is_calculated()) { - if (style_value.as_calculated().resolves_to_number()) - return normalized(style_value.as_calculated().resolve_number_deprecated(resolution_context).value()); + if (style_value.as_calculated().resolves_to_number()) { + auto maybe_number = style_value.as_calculated().resolve_number(resolution_context); - if (style_value.as_calculated().resolves_to_angle()) - return normalized(style_value.as_calculated().resolve_angle_deprecated(resolution_context).value().to_degrees()); + if (!maybe_number.has_value()) + return {}; + + return normalized(maybe_number.value()); + } + + if (style_value.as_calculated().resolves_to_angle()) { + auto maybe_angle = style_value.as_calculated().resolve_angle(resolution_context); + + if (!maybe_angle.has_value()) + return {}; + + return normalized(maybe_angle.value().to_degrees()); + } } - if (style_value.is_keyword() && style_value.to_keyword() == Keyword::None) - return 0; - return {}; + return 0; } Optional CSSColorValue::resolve_with_reference_value(CSSStyleValue const& style_value, float one_hundred_percent_value, CalculationResolutionContext const& resolution_context) @@ -79,16 +89,26 @@ Optional CSSColorValue::resolve_with_reference_value(CSSStyleValue const if (style_value.is_calculated()) { auto const& calculated = style_value.as_calculated(); - if (calculated.resolves_to_number()) - return calculated.resolve_number_deprecated(resolution_context).value(); - if (calculated.resolves_to_percentage()) - return normalize_percentage(calculated.resolve_percentage_deprecated(resolution_context).value()); + if (calculated.resolves_to_number()) { + auto maybe_number = calculated.resolve_number(resolution_context); + + if (!maybe_number.has_value()) + return {}; + + return maybe_number.value(); + } + + if (calculated.resolves_to_percentage()) { + auto percentage = calculated.resolve_percentage(resolution_context); + + if (!percentage.has_value()) + return {}; + + return normalize_percentage(percentage.value()); + } } - if (style_value.is_keyword() && style_value.to_keyword() == Keyword::None) - return 0; - - return {}; + return 0; } Optional CSSColorValue::resolve_alpha(CSSStyleValue const& style_value, CalculationResolutionContext const& resolution_context) @@ -108,16 +128,29 @@ Optional CSSColorValue::resolve_alpha(CSSStyleValue const& style_value, if (style_value.is_calculated()) { auto const& calculated = style_value.as_calculated(); - if (calculated.resolves_to_number()) - return normalized(calculated.resolve_number_deprecated(resolution_context).value()); - if (calculated.resolves_to_percentage()) - return normalized(calculated.resolve_percentage_deprecated(resolution_context).value().as_fraction()); + if (calculated.resolves_to_number()) { + auto maybe_number = calculated.resolve_number(resolution_context); + + if (!maybe_number.has_value()) + return {}; + + return normalized(maybe_number.value()); + } + + if (calculated.resolves_to_percentage()) { + auto percentage = calculated.resolve_percentage(resolution_context); + + if (!percentage.has_value()) + return {}; + + return normalized(percentage.value().as_fraction()); + } } if (style_value.is_keyword() && style_value.to_keyword() == Keyword::None) return 0; - return {}; + return 1; } void CSSColorValue::serialize_color_component(StringBuilder& builder, SerializationMode mode, CSSStyleValue const& component, float one_hundred_percent_value, Optional clamp_min, Optional clamp_max) const @@ -130,7 +163,16 @@ void CSSColorValue::serialize_color_component(StringBuilder& builder, Serializat builder.append(component.to_string(mode)); return; } - auto resolved_value = resolve_with_reference_value(component, one_hundred_percent_value, {}).value_or(0); + + auto maybe_resolved_value = resolve_with_reference_value(component, one_hundred_percent_value, {}); + + if (!maybe_resolved_value.has_value()) { + builder.append(component.to_string(mode)); + return; + } + + auto resolved_value = maybe_resolved_value.value(); + if (clamp_min.has_value() && resolved_value < *clamp_min) resolved_value = *clamp_min; if (clamp_max.has_value() && resolved_value > *clamp_max) @@ -153,8 +195,15 @@ void CSSColorValue::serialize_alpha_component(StringBuilder& builder, Serializat builder.append(component.to_string(mode)); return; } - auto resolved_value = resolve_alpha(component, {}).value_or(0); - builder.appendff("{}", resolved_value); + + auto maybe_resolved_value = resolve_alpha(component, {}); + + if (!maybe_resolved_value.has_value()) { + builder.append(component.to_string(mode)); + return; + } + + builder.appendff("{}", maybe_resolved_value.value()); } void CSSColorValue::serialize_hue_component(StringBuilder& builder, SerializationMode mode, CSSStyleValue const& component) const @@ -167,7 +216,15 @@ void CSSColorValue::serialize_hue_component(StringBuilder& builder, Serializatio builder.append(component.to_string(mode)); return; } - builder.appendff("{:.4}", resolve_hue(component, {}).value_or(0)); + + auto maybe_resolved_value = resolve_hue(component, {}); + + if (!maybe_resolved_value.has_value()) { + builder.append(component.to_string(mode)); + return; + } + + builder.appendff("{:.4}", maybe_resolved_value.value()); } } diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSHSL.cpp b/Libraries/LibWeb/CSS/StyleValues/CSSHSL.cpp index 255d957fb93..8407592dc39 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSHSL.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CSSHSL.cpp @@ -11,14 +11,17 @@ namespace Web::CSS { -Color CSSHSL::to_color(Optional, CalculationResolutionContext const& resolution_context) const +Optional CSSHSL::to_color(Optional, CalculationResolutionContext const& resolution_context) const { - auto const h_val = resolve_hue(m_properties.h, resolution_context).value_or(0); - auto const s_val = resolve_with_reference_value(m_properties.s, 100.0, resolution_context).value_or(0); - auto const l_val = resolve_with_reference_value(m_properties.l, 100.0, resolution_context).value_or(0); - auto const alpha_val = resolve_alpha(m_properties.alpha, resolution_context).value_or(1); + auto h_val = resolve_hue(m_properties.h, resolution_context); + auto s_val = resolve_with_reference_value(m_properties.s, 100.0, resolution_context); + auto l_val = resolve_with_reference_value(m_properties.l, 100.0, resolution_context); + auto alpha_val = resolve_alpha(m_properties.alpha, resolution_context); - return Color::from_hsla(h_val, s_val / 100.0f, l_val / 100.0f, alpha_val); + if (!h_val.has_value() || !s_val.has_value() || !l_val.has_value() || !alpha_val.has_value()) + return {}; + + return Color::from_hsla(h_val.value(), s_val.value() / 100.0f, l_val.value() / 100.0f, alpha_val.value()); } bool CSSHSL::equals(CSSStyleValue const& other) const @@ -35,8 +38,11 @@ bool CSSHSL::equals(CSSStyleValue const& other) const // https://www.w3.org/TR/css-color-4/#serializing-sRGB-values String CSSHSL::to_string(SerializationMode) const { + if (auto color = to_color({}, {}); color.has_value()) + return serialize_a_srgb_value(color.value()); + // FIXME: Do this properly, taking unresolved calculated values into account. - return serialize_a_srgb_value(to_color({}, {})); + return ""_string; } } diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSHSL.h b/Libraries/LibWeb/CSS/StyleValues/CSSHSL.h index ba39cd44a9f..2238ee1bce5 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSHSL.h +++ b/Libraries/LibWeb/CSS/StyleValues/CSSHSL.h @@ -29,7 +29,7 @@ public: CSSStyleValue const& l() const { return *m_properties.l; } CSSStyleValue const& alpha() const { return *m_properties.alpha; } - virtual Color to_color(Optional, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSHWB.cpp b/Libraries/LibWeb/CSS/StyleValues/CSSHWB.cpp index 8c4ea5fb62c..7dfb31d83ef 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSHWB.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CSSHWB.cpp @@ -11,24 +11,30 @@ namespace Web::CSS { -Color CSSHWB::to_color(Optional, CalculationResolutionContext const& resolution_context) const +Optional CSSHWB::to_color(Optional, CalculationResolutionContext const& resolution_context) const { - auto const h_val = resolve_hue(m_properties.h, resolution_context).value_or(0); - auto const w_val = clamp(resolve_with_reference_value(m_properties.w, 100.0, resolution_context).value_or(0), 0, 100) / 100.0f; - auto const b_val = clamp(resolve_with_reference_value(m_properties.b, 100.0, resolution_context).value_or(0), 0, 100) / 100.0f; - auto const alpha_val = resolve_alpha(m_properties.alpha, resolution_context).value_or(1); + auto h_val = resolve_hue(m_properties.h, resolution_context); + auto raw_w_value = resolve_with_reference_value(m_properties.w, 100.0, resolution_context); + auto raw_b_value = resolve_with_reference_value(m_properties.b, 100.0, resolution_context); + auto alpha_val = resolve_alpha(m_properties.alpha, resolution_context); + + if (!h_val.has_value() || !raw_w_value.has_value() || !raw_b_value.has_value() || !alpha_val.has_value()) + return {}; + + auto w_val = clamp(raw_w_value.value(), 0, 100) / 100.0f; + auto b_val = clamp(raw_b_value.value(), 0, 100) / 100.0f; if (w_val + b_val >= 1.0f) { auto to_byte = [](float value) { return round_to(clamp(value * 255.0f, 0.0f, 255.0f)); }; u8 gray = to_byte(w_val / (w_val + b_val)); - return Color(gray, gray, gray, to_byte(alpha_val)); + return Color(gray, gray, gray, to_byte(alpha_val.value())); } auto value = 1 - b_val; auto saturation = 1 - (w_val / value); - return Color::from_hsv(h_val, saturation, value).with_opacity(alpha_val); + return Color::from_hsv(h_val.value(), saturation, value).with_opacity(alpha_val.value()); } bool CSSHWB::equals(CSSStyleValue const& other) const @@ -45,8 +51,11 @@ bool CSSHWB::equals(CSSStyleValue const& other) const // https://www.w3.org/TR/css-color-4/#serializing-sRGB-values String CSSHWB::to_string(SerializationMode) const { + if (auto color = to_color({}, {}); color.has_value()) + return serialize_a_srgb_value(color.value()); + // FIXME: Do this properly, taking unresolved calculated values into account. - return serialize_a_srgb_value(to_color({}, {})); + return ""_string; } } diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSHWB.h b/Libraries/LibWeb/CSS/StyleValues/CSSHWB.h index 16e4aaf5755..6561d54d9a5 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSHWB.h +++ b/Libraries/LibWeb/CSS/StyleValues/CSSHWB.h @@ -29,7 +29,7 @@ public: CSSStyleValue const& b() const { return *m_properties.b; } CSSStyleValue const& alpha() const { return *m_properties.alpha; } - virtual Color to_color(Optional, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSKeywordValue.cpp b/Libraries/LibWeb/CSS/StyleValues/CSSKeywordValue.cpp index e72405745fc..d31abe32497 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSKeywordValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CSSKeywordValue.cpp @@ -135,7 +135,7 @@ bool CSSKeywordValue::has_color() const return is_color(keyword()); } -Color CSSKeywordValue::to_color(Optional node, CalculationResolutionContext const&) const +Optional CSSKeywordValue::to_color(Optional node, CalculationResolutionContext const&) const { if (keyword() == Keyword::Currentcolor) { if (!node.has_value() || !node->has_style()) diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSKeywordValue.h b/Libraries/LibWeb/CSS/StyleValues/CSSKeywordValue.h index 5a8ab43caba..6dc79386250 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSKeywordValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/CSSKeywordValue.h @@ -51,7 +51,7 @@ public: static bool is_color(Keyword); virtual bool has_color() const override; - virtual Color to_color(Optional node, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional node, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; bool properties_equal(CSSKeywordValue const& other) const { return m_keyword == other.m_keyword; } diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSLCHLike.cpp b/Libraries/LibWeb/CSS/StyleValues/CSSLCHLike.cpp index b466473bc14..03f6fe5713f 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSLCHLike.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CSSLCHLike.cpp @@ -27,14 +27,20 @@ bool CSSLCHLike::equals(CSSStyleValue const& other) const return m_properties == other_oklch_like.m_properties; } -Color CSSLCH::to_color(Optional, CalculationResolutionContext const& resolution_context) const +Optional CSSLCH::to_color(Optional, CalculationResolutionContext const& resolution_context) const { - auto const l_val = clamp(resolve_with_reference_value(m_properties.l, 100, resolution_context).value_or(0), 0, 100); - auto const c_val = resolve_with_reference_value(m_properties.c, 150, resolution_context).value_or(0); - auto const h_val = AK::to_radians(resolve_hue(m_properties.h, resolution_context).value_or(0)); - auto const alpha_val = resolve_alpha(m_properties.alpha, resolution_context).value_or(1); + auto raw_l_val = resolve_with_reference_value(m_properties.l, 100, resolution_context); + auto c_val = resolve_with_reference_value(m_properties.c, 150, resolution_context); + auto raw_h_val = resolve_hue(m_properties.h, resolution_context); + auto alpha_val = resolve_alpha(m_properties.alpha, resolution_context); - return Color::from_lab(l_val, c_val * cos(h_val), c_val * sin(h_val), alpha_val); + if (!raw_l_val.has_value() || !c_val.has_value() || !raw_h_val.has_value() || !alpha_val.has_value()) + return {}; + + auto l_val = clamp(raw_l_val.value(), 0, 100); + auto h_val = AK::to_radians(raw_h_val.value()); + + return Color::from_lab(l_val, c_val.value() * cos(h_val), c_val.value() * sin(h_val), alpha_val.value()); } // https://www.w3.org/TR/css-color-4/#serializing-lab-lch @@ -57,14 +63,21 @@ String CSSLCH::to_string(SerializationMode mode) const return MUST(builder.to_string()); } -Color CSSOKLCH::to_color(Optional, CalculationResolutionContext const& resolution_context) const +Optional CSSOKLCH::to_color(Optional, CalculationResolutionContext const& resolution_context) const { - auto const l_val = clamp(resolve_with_reference_value(m_properties.l, 1.0, resolution_context).value_or(0), 0, 1); - auto const c_val = max(resolve_with_reference_value(m_properties.c, 0.4, resolution_context).value_or(0), 0); - auto const h_val = AK::to_radians(resolve_hue(m_properties.h, resolution_context).value_or(0)); - auto const alpha_val = resolve_alpha(m_properties.alpha, resolution_context).value_or(1); + auto raw_l_val = resolve_with_reference_value(m_properties.l, 1.0, resolution_context); + auto raw_c_val = resolve_with_reference_value(m_properties.c, 0.4, resolution_context); + auto raw_h_val = resolve_hue(m_properties.h, resolution_context); + auto alpha_val = resolve_alpha(m_properties.alpha, resolution_context); - return Color::from_oklab(l_val, c_val * cos(h_val), c_val * sin(h_val), alpha_val); + if (!raw_l_val.has_value() || !raw_c_val.has_value() || !raw_h_val.has_value() || !alpha_val.has_value()) + return {}; + + auto l_val = clamp(raw_l_val.value(), 0, 1); + auto c_val = max(raw_c_val.value(), 0); + auto h_val = AK::to_radians(raw_h_val.value()); + + return Color::from_oklab(l_val, c_val * cos(h_val), c_val * sin(h_val), alpha_val.value()); } // https://www.w3.org/TR/css-color-4/#serializing-oklab-oklch diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSLCHLike.h b/Libraries/LibWeb/CSS/StyleValues/CSSLCHLike.h index a054846ba34..37acfcf616a 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSLCHLike.h +++ b/Libraries/LibWeb/CSS/StyleValues/CSSLCHLike.h @@ -56,7 +56,7 @@ public: } virtual ~CSSLCH() override = default; - virtual Color to_color(Optional, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; }; @@ -70,7 +70,7 @@ public: } virtual ~CSSOKLCH() override = default; - virtual Color to_color(Optional, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; }; diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSLabLike.cpp b/Libraries/LibWeb/CSS/StyleValues/CSSLabLike.cpp index 8e40560ec2c..918b72b8225 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSLabLike.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CSSLabLike.cpp @@ -26,14 +26,17 @@ bool CSSLabLike::equals(CSSStyleValue const& other) const return m_properties == other_lab_like.m_properties; } -Color CSSOKLab::to_color(Optional, CalculationResolutionContext const& resolution_context) const +Optional CSSOKLab::to_color(Optional, CalculationResolutionContext const& resolution_context) const { - auto const l_val = clamp(resolve_with_reference_value(m_properties.l, 1.0, resolution_context).value_or(0), 0, 1); - auto const a_val = resolve_with_reference_value(m_properties.a, 0.4, resolution_context).value_or(0); - auto const b_val = resolve_with_reference_value(m_properties.b, 0.4, resolution_context).value_or(0); - auto const alpha_val = resolve_alpha(m_properties.alpha, resolution_context).value_or(1); + auto const l_val = resolve_with_reference_value(m_properties.l, 1.0, resolution_context); + auto const a_val = resolve_with_reference_value(m_properties.a, 0.4, resolution_context); + auto const b_val = resolve_with_reference_value(m_properties.b, 0.4, resolution_context); + auto const alpha_val = resolve_alpha(m_properties.alpha, resolution_context); - return Color::from_oklab(l_val, a_val, b_val, alpha_val); + if (!l_val.has_value() || !a_val.has_value() || !b_val.has_value() || !alpha_val.has_value()) + return {}; + + return Color::from_oklab(clamp(l_val.value(), 0, 1), a_val.value(), b_val.value(), alpha_val.value()); } // https://www.w3.org/TR/css-color-4/#serializing-oklab-oklch @@ -56,14 +59,17 @@ String CSSOKLab::to_string(SerializationMode mode) const return MUST(builder.to_string()); } -Color CSSLab::to_color(Optional, CalculationResolutionContext const& resolution_context) const +Optional CSSLab::to_color(Optional, CalculationResolutionContext const& resolution_context) const { - auto const l_val = clamp(resolve_with_reference_value(m_properties.l, 100, resolution_context).value_or(0), 0, 100); - auto const a_val = resolve_with_reference_value(m_properties.a, 125, resolution_context).value_or(0); - auto const b_val = resolve_with_reference_value(m_properties.b, 125, resolution_context).value_or(0); - auto const alpha_val = resolve_alpha(m_properties.alpha, resolution_context).value_or(1); + auto l_val = resolve_with_reference_value(m_properties.l, 100, resolution_context); + auto a_val = resolve_with_reference_value(m_properties.a, 125, resolution_context); + auto b_val = resolve_with_reference_value(m_properties.b, 125, resolution_context); + auto alpha_val = resolve_alpha(m_properties.alpha, resolution_context); - return Color::from_lab(l_val, a_val, b_val, alpha_val); + if (!l_val.has_value() || !a_val.has_value() || !b_val.has_value() || !alpha_val.has_value()) + return {}; + + return Color::from_lab(clamp(l_val.value(), 0, 100), a_val.value(), b_val.value(), alpha_val.value()); } // https://www.w3.org/TR/css-color-4/#serializing-lab-lch diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSLabLike.h b/Libraries/LibWeb/CSS/StyleValues/CSSLabLike.h index 4dde22cff55..ea476950df7 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSLabLike.h +++ b/Libraries/LibWeb/CSS/StyleValues/CSSLabLike.h @@ -51,7 +51,7 @@ protected: // https://drafts.css-houdini.org/css-typed-om-1/#cssoklab class CSSOKLab final : public CSSLabLike { public: - virtual Color to_color(Optional, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; CSSOKLab(Badge, ValueComparingNonnullRefPtr l, ValueComparingNonnullRefPtr a, ValueComparingNonnullRefPtr b, ValueComparingNonnullRefPtr alpha) @@ -63,7 +63,7 @@ public: // https://drafts.css-houdini.org/css-typed-om-1/#csslab class CSSLab final : public CSSLabLike { public: - virtual Color to_color(Optional, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; CSSLab(Badge, ValueComparingNonnullRefPtr l, ValueComparingNonnullRefPtr a, ValueComparingNonnullRefPtr b, ValueComparingNonnullRefPtr alpha) diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.cpp b/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.cpp index 4341c7689dc..faa4e86b5bb 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.cpp @@ -9,7 +9,7 @@ namespace Web::CSS { -Color CSSLightDark::to_color(Optional node, CalculationResolutionContext const& resolution_context) const +Optional CSSLightDark::to_color(Optional node, CalculationResolutionContext const& resolution_context) const { if (node.has_value() && node.value().computed_values().color_scheme() == PreferredColorScheme::Dark) return m_properties.dark->to_color(node, resolution_context); diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.h b/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.h index 6477b429cea..090235cbe16 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.h +++ b/Libraries/LibWeb/CSS/StyleValues/CSSLightDark.h @@ -21,7 +21,7 @@ public: } virtual bool equals(CSSStyleValue const&) const override; - virtual Color to_color(Optional, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; private: diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSRGB.cpp b/Libraries/LibWeb/CSS/StyleValues/CSSRGB.cpp index 0b094cc8983..b7dd0f3928e 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSRGB.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/CSSRGB.cpp @@ -14,7 +14,7 @@ namespace Web::CSS { -Color CSSRGB::to_color(Optional, CalculationResolutionContext const& resolution_context) const +Optional CSSRGB::to_color(Optional, CalculationResolutionContext const& resolution_context) const { auto resolve_rgb_to_u8 = [&resolution_context](CSSStyleValue const& style_value) -> Optional { // | | none @@ -32,16 +32,26 @@ Color CSSRGB::to_color(Optional, CalculationResolu if (style_value.is_calculated()) { auto const& calculated = style_value.as_calculated(); - if (calculated.resolves_to_number()) - return normalized(calculated.resolve_number_deprecated(resolution_context).value()); - if (calculated.resolves_to_percentage()) - return normalized(calculated.resolve_percentage_deprecated(resolution_context).value().value() * 255 / 100); + if (calculated.resolves_to_number()) { + auto maybe_number = calculated.resolve_number(resolution_context); + + if (!maybe_number.has_value()) + return {}; + + return normalized(maybe_number.value()); + } + + if (calculated.resolves_to_percentage()) { + auto maybe_percentage = calculated.resolve_percentage(resolution_context); + + if (!maybe_percentage.has_value()) + return {}; + + return normalized(maybe_percentage.value().value() * 255 / 100); + } } - if (style_value.is_keyword() && style_value.to_keyword() == Keyword::None) - return 0; - - return {}; + return 0; }; auto resolve_alpha_to_u8 = [&resolution_context](CSSStyleValue const& style_value) -> Optional { @@ -51,12 +61,15 @@ Color CSSRGB::to_color(Optional, CalculationResolu return {}; }; - u8 const r_val = resolve_rgb_to_u8(m_properties.r).value_or(0); - u8 const g_val = resolve_rgb_to_u8(m_properties.g).value_or(0); - u8 const b_val = resolve_rgb_to_u8(m_properties.b).value_or(0); - u8 const alpha_val = resolve_alpha_to_u8(m_properties.alpha).value_or(255); + auto r_val = resolve_rgb_to_u8(m_properties.r); + auto g_val = resolve_rgb_to_u8(m_properties.g); + auto b_val = resolve_rgb_to_u8(m_properties.b); + auto alpha_val = resolve_alpha_to_u8(m_properties.alpha); - return Color(r_val, g_val, b_val, alpha_val); + if (!r_val.has_value() || !g_val.has_value() || !b_val.has_value() || !alpha_val.has_value()) + return {}; + + return Color(r_val.value(), g_val.value(), b_val.value(), alpha_val.value()); } bool CSSRGB::equals(CSSStyleValue const& other) const @@ -73,10 +86,14 @@ bool CSSRGB::equals(CSSStyleValue const& other) const // https://www.w3.org/TR/css-color-4/#serializing-sRGB-values String CSSRGB::to_string(SerializationMode mode) const { - // FIXME: Do this properly, taking unresolved calculated values into account. if (mode != SerializationMode::ResolvedValue && m_properties.name.has_value()) return m_properties.name.value().to_string().to_ascii_lowercase(); - return serialize_a_srgb_value(to_color({}, {})); + + if (auto color = to_color({}, {}); color.has_value()) + return serialize_a_srgb_value(color.value()); + + // FIXME: Do this properly, taking unresolved calculated values into account. + return ""_string; } } diff --git a/Libraries/LibWeb/CSS/StyleValues/CSSRGB.h b/Libraries/LibWeb/CSS/StyleValues/CSSRGB.h index 67d6892343b..e1ba07efa9f 100644 --- a/Libraries/LibWeb/CSS/StyleValues/CSSRGB.h +++ b/Libraries/LibWeb/CSS/StyleValues/CSSRGB.h @@ -29,7 +29,7 @@ public: CSSStyleValue const& b() const { return *m_properties.b; } CSSStyleValue const& alpha() const { return *m_properties.alpha; } - virtual Color to_color(Optional, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; diff --git a/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.cpp index 6c3a4475496..b95b0f2e260 100644 --- a/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.cpp @@ -82,13 +82,22 @@ bool ColorFunctionStyleValue::equals(CSSStyleValue const& other) const return m_properties == other_lab_like.m_properties; } -ColorFunctionStyleValue::Resolved ColorFunctionStyleValue::resolve_properties(CalculationResolutionContext const& resolution_context) const +Optional ColorFunctionStyleValue::resolve_properties(CalculationResolutionContext const& resolution_context) const { - float const c1 = resolve_with_reference_value(m_properties.channels[0], 1, resolution_context).value_or(0); - float const c2 = resolve_with_reference_value(m_properties.channels[1], 1, resolution_context).value_or(0); - float const c3 = resolve_with_reference_value(m_properties.channels[2], 1, resolution_context).value_or(0); - float const alpha_val = resolve_alpha(m_properties.alpha, resolution_context).value_or(1); - return { .channels = { c1, c2, c3 }, .alpha = alpha_val }; + auto c1 = resolve_with_reference_value(m_properties.channels[0], 1, resolution_context); + auto c2 = resolve_with_reference_value(m_properties.channels[1], 1, resolution_context); + auto c3 = resolve_with_reference_value(m_properties.channels[2], 1, resolution_context); + auto alpha = resolve_alpha(m_properties.alpha, resolution_context); + + if (!c1.has_value() || !c2.has_value() || !c3.has_value() || !alpha.has_value()) + return {}; + + float const c1_value = c1.value(); + float const c2_value = c2.value(); + float const c3_value = c3.value(); + float const alpha_value = alpha.value(); + + return ColorFunctionStyleValue::Resolved { .channels = { c1_value, c2_value, c3_value }, .alpha = alpha_value }; } // https://www.w3.org/TR/css-color-4/#serializing-color-function-values @@ -102,14 +111,14 @@ String ColorFunctionStyleValue::to_string(SerializationMode mode) const CalculationResolutionContext context {}; auto const& calculated = value->as_calculated(); if (calculated.resolves_to_percentage()) { - if (auto resolved_percentage = calculated.resolve_percentage_deprecated(context); resolved_percentage.has_value()) { + if (auto resolved_percentage = calculated.resolve_percentage(context); resolved_percentage.has_value()) { auto resolved_number = resolved_percentage->value() / 100; if (!isfinite(resolved_number)) resolved_number = 0; return NumberStyleValue::create(resolved_number); } } else if (calculated.resolves_to_number()) { - if (auto resolved_number = calculated.resolve_number_deprecated(context); resolved_number.has_value()) + if (auto resolved_number = calculated.resolve_number(context); resolved_number.has_value()) return NumberStyleValue::create(*resolved_number); } } @@ -144,9 +153,14 @@ String ColorFunctionStyleValue::to_string(SerializationMode mode) const convert_percentage(m_properties.channels[2])->to_string(mode))); } -Color ColorFunctionStyleValue::to_color(Optional, CalculationResolutionContext const& resolution_context) const +Optional ColorFunctionStyleValue::to_color(Optional, CalculationResolutionContext const& resolution_context) const { - auto [channels, alpha_val] = resolve_properties(resolution_context); + auto properties = resolve_properties(resolution_context); + + if (!properties.has_value()) + return {}; + + auto [channels, alpha_val] = properties.value(); auto c1 = channels[0]; auto c2 = channels[1]; auto c3 = channels[2]; diff --git a/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.h index 7f1489a6833..7c6a1e22e68 100644 --- a/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/ColorFunctionStyleValue.h @@ -18,7 +18,7 @@ public: static ValueComparingNonnullRefPtr create(StringView color_space, ValueComparingNonnullRefPtr c1, ValueComparingNonnullRefPtr c2, ValueComparingNonnullRefPtr c3, ValueComparingRefPtr alpha = {}); virtual bool equals(CSSStyleValue const&) const override; - virtual Color to_color(Optional, CalculationResolutionContext const& resolution_context) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const& resolution_context) const override; virtual String to_string(SerializationMode) const override; virtual bool is_color_function() const override { return true; } @@ -43,7 +43,7 @@ private: float alpha {}; }; - Resolved resolve_properties(CalculationResolutionContext const& resolution_context) const; + Optional resolve_properties(CalculationResolutionContext const& resolution_context) const; Properties m_properties; }; diff --git a/Libraries/LibWeb/CSS/StyleValues/ColorMixStyleValue.cpp b/Libraries/LibWeb/CSS/StyleValues/ColorMixStyleValue.cpp index a8f65d1d62e..05dfcbe67b0 100644 --- a/Libraries/LibWeb/CSS/StyleValues/ColorMixStyleValue.cpp +++ b/Libraries/LibWeb/CSS/StyleValues/ColorMixStyleValue.cpp @@ -175,15 +175,19 @@ ColorMixStyleValue::PercentageNormalizationResult ColorMixStyleValue::normalize_ } // https://drafts.csswg.org/css-color-5/#color-mix-result -Color ColorMixStyleValue::to_color(Optional node, CalculationResolutionContext const& resolution_context) const +Optional ColorMixStyleValue::to_color(Optional node, CalculationResolutionContext const& resolution_context) const { // FIXME: Take the color space and hue interpolation method into account. // The current implementation only uses oklab interpolation. auto normalized_percentages = normalize_percentages(); - auto from_color = m_properties.first_component.color; - auto to_color = m_properties.second_component.color; + auto from_color = m_properties.first_component.color->to_color(node, resolution_context); + auto to_color = m_properties.second_component.color->to_color(node, resolution_context); auto delta = normalized_percentages.p2.value() / 100; - return interpolate_color(from_color->to_color(node, resolution_context), to_color->to_color(node, resolution_context), delta, ColorSyntax::Modern); + + if (!from_color.has_value() || !to_color.has_value()) + return {}; + + return interpolate_color(from_color.value(), to_color.value(), delta, ColorSyntax::Modern); } } diff --git a/Libraries/LibWeb/CSS/StyleValues/ColorMixStyleValue.h b/Libraries/LibWeb/CSS/StyleValues/ColorMixStyleValue.h index 6ed7d495346..a540527c01c 100644 --- a/Libraries/LibWeb/CSS/StyleValues/ColorMixStyleValue.h +++ b/Libraries/LibWeb/CSS/StyleValues/ColorMixStyleValue.h @@ -30,7 +30,7 @@ public: static ValueComparingNonnullRefPtr create(ColorInterpolationMethod, ColorMixComponent first_component, ColorMixComponent second_component); virtual bool equals(CSSStyleValue const&) const override; - virtual Color to_color(Optional, CalculationResolutionContext const&) const override; + virtual Optional to_color(Optional, CalculationResolutionContext const&) const override; virtual String to_string(SerializationMode) const override; private: diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index ec3e67991f0..0b8d767ceb3 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1677,7 +1677,7 @@ void Document::obtain_theme_color() resolution_context.length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*html_element()->layout_node()); } - theme_color = css_value->to_color(root_node, resolution_context); + theme_color = css_value->to_color(root_node, resolution_context).value(); return TraversalDecision::Break; } } diff --git a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp index 1f7e5619efd..cc8d165d5ab 100644 --- a/Libraries/LibWeb/Editing/Internal/Algorithms.cpp +++ b/Libraries/LibWeb/Editing/Internal/Algorithms.cpp @@ -1175,7 +1175,7 @@ Optional effective_command_value(GC::Ptr node, FlyString cons return NumericLimits::max(); VERIFY(is(node->layout_node())); auto& layout_node = *static_cast(node->layout_node()); - return background_color.value()->to_color(layout_node, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(layout_node) }).alpha(); + return background_color.value()->to_color(layout_node, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(layout_node) }).value().alpha(); }; while (resolved_background_alpha() == 0 && node->parent() && is(*node->parent())) node = node->parent(); diff --git a/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h b/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h index 4991abc51f7..315affbfab1 100644 --- a/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h +++ b/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h @@ -52,7 +52,7 @@ public: resolution_context.length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*context->layout_node()); } - auto parsedValue = style_value->to_color(layout_node, resolution_context); + auto parsedValue = style_value->to_color(layout_node, resolution_context).value_or(Color::Black); // 4. Set this's fill style to parsedValue. my_drawing_state().fill_style = parsedValue; @@ -105,7 +105,7 @@ public: resolution_context.length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*context->layout_node()); } - auto parsedValue = style_value->to_color(layout_node, resolution_context); + auto parsedValue = style_value->to_color(layout_node, resolution_context).value_or(Color::Black); // 4. Set this's stroke style to parsedValue. my_drawing_state().stroke_style = parsedValue; diff --git a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index 9add19b58fe..dde096c4fd1 100644 --- a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -950,7 +950,7 @@ void CanvasRenderingContext2D::set_shadow_color(String color) resolution_context.length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*node); } - auto parsedValue = style_value->to_color(layout_node, resolution_context); + auto parsedValue = style_value->to_color(layout_node, resolution_context).value_or(Color::Black); // 4. Set this's shadow color to parsedValue. drawing_state().shadow_color = parsedValue; diff --git a/Libraries/LibWeb/HTML/OffscreenCanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/OffscreenCanvasRenderingContext2D.cpp index 2018f6e4f22..2a256ff34bd 100644 --- a/Libraries/LibWeb/HTML/OffscreenCanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/OffscreenCanvasRenderingContext2D.cpp @@ -288,7 +288,7 @@ void OffscreenCanvasRenderingContext2D::set_shadow_color(String color) // 2. Let parsedValue be the result of parsing the given value with context if non-null. auto style_value = parse_css_value(CSS::Parser::ParsingParams(), color, CSS::PropertyID::Color); if (style_value && style_value->has_color()) { - auto parsedValue = style_value->to_color({}, {}); + auto parsedValue = style_value->to_color({}, {}).value_or(Color::Black); // 4. Set this's shadow color to parsedValue. drawing_state().shadow_color = parsedValue; diff --git a/Libraries/LibWeb/Layout/Node.cpp b/Libraries/LibWeb/Layout/Node.cpp index 92879bdafb0..07820f08737 100644 --- a/Libraries/LibWeb/Layout/Node.cpp +++ b/Libraries/LibWeb/Layout/Node.cpp @@ -835,7 +835,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style) do_border_style(computed_values.border_bottom(), CSS::PropertyID::BorderBottomWidth, CSS::PropertyID::BorderBottomColor, CSS::PropertyID::BorderBottomStyle); if (auto const& outline_color = computed_style.property(CSS::PropertyID::OutlineColor); outline_color.has_color()) - computed_values.set_outline_color(outline_color.to_color(*this, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) })); + computed_values.set_outline_color(outline_color.to_color(*this, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) }).value()); if (auto const& outline_offset = computed_style.property(CSS::PropertyID::OutlineOffset); outline_offset.is_length()) computed_values.set_outline_offset(outline_offset.as_length().length()); computed_values.set_outline_style(computed_style.outline_style()); @@ -875,16 +875,16 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style) auto const& fill = computed_style.property(CSS::PropertyID::Fill); if (fill.has_color()) - computed_values.set_fill(fill.to_color(*this, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) })); + computed_values.set_fill(fill.to_color(*this, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) }).value()); else if (fill.is_url()) computed_values.set_fill(fill.as_url().url()); auto const& stroke = computed_style.property(CSS::PropertyID::Stroke); if (stroke.has_color()) - computed_values.set_stroke(stroke.to_color(*this, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) })); + computed_values.set_stroke(stroke.to_color(*this, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) }).value()); else if (stroke.is_url()) computed_values.set_stroke(stroke.as_url().url()); if (auto const& stop_color = computed_style.property(CSS::PropertyID::StopColor); stop_color.has_color()) - computed_values.set_stop_color(stop_color.to_color(*this, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) })); + computed_values.set_stop_color(stop_color.to_color(*this, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*this) }).value()); auto const& stroke_width = computed_style.property(CSS::PropertyID::StrokeWidth); // FIXME: Converting to pixels isn't really correct - values should be in "user units" // https://svgwg.org/svg2-draft/coords.html#TermUserUnits diff --git a/Libraries/LibWeb/Painting/BorderPainting.cpp b/Libraries/LibWeb/Painting/BorderPainting.cpp index 087ba2c33a5..70a307cc152 100644 --- a/Libraries/LibWeb/Painting/BorderPainting.cpp +++ b/Libraries/LibWeb/Painting/BorderPainting.cpp @@ -587,7 +587,7 @@ Optional borders_data_for_outline(Layout::Node const& layout_node, // `auto` lets us do whatever we want for the outline. 2px of the accent colour seems reasonable. line_style = CSS::LineStyle::Solid; // NOTE: CalculationResolutionContext is not required here as Accentcolor keyword value is guaranteed to not rely on it to resolve. - outline_color = CSS::CSSKeywordValue::create(CSS::Keyword::Accentcolor)->to_color(*static_cast(&layout_node), {}); + outline_color = CSS::CSSKeywordValue::create(CSS::Keyword::Accentcolor)->to_color(*static_cast(&layout_node), {}).value(); outline_width = 2; } else { line_style = CSS::keyword_to_line_style(CSS::to_keyword(outline_style)).value_or(CSS::LineStyle::None); diff --git a/Libraries/LibWeb/Painting/GradientPainting.cpp b/Libraries/LibWeb/Painting/GradientPainting.cpp index 8e92bb4bf5e..8febcea5809 100644 --- a/Libraries/LibWeb/Painting/GradientPainting.cpp +++ b/Libraries/LibWeb/Painting/GradientPainting.cpp @@ -30,7 +30,7 @@ static ColorStopData resolve_color_stop_positions(Layout::NodeWithStyle const& n resolved_color_stops.ensure_capacity(expanded_size); for (auto& stop : color_stop_list) { - auto resolved_stop = Gfx::ColorStop { .color = stop.color_stop.color->to_color(node, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(node) }) }; + auto resolved_stop = Gfx::ColorStop { .color = stop.color_stop.color->to_color(node, { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(node) }).value() }; for (int i = 0; i < color_stop_length(stop); i++) resolved_color_stops.append(resolved_stop); }