mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
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.
This commit is contained in:
parent
e66332c07a
commit
6a9c8d7767
Notes:
github-actions[bot]
2025-07-16 12:06:47 +00:00
Author: https://github.com/Calme1709
Commit: 6a9c8d7767
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5305
Reviewed-by: https://github.com/AtkinsSJ ✅
30 changed files with 278 additions and 129 deletions
|
@ -393,7 +393,7 @@ public:
|
|||
|
||||
virtual ValueComparingNonnullRefPtr<CSSStyleValue const> absolutized(CSSPixelRect const& viewport_rect, Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const;
|
||||
|
||||
virtual Color to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const { return {}; }
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const { return {}; }
|
||||
Keyword to_keyword() const;
|
||||
|
||||
virtual String to_string(SerializationMode) const = 0;
|
||||
|
|
|
@ -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<ShadowData> 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::NodeWithStyle>(layout_node), { .length_resolution_context = Length::ResolutionContext::for_layout_node(layout_node) }),
|
||||
value.color()->to_color(as<Layout::NodeWithStyle>(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 };
|
||||
}
|
||||
|
||||
|
|
|
@ -688,13 +688,25 @@ RefPtr<CSSStyleValue const> 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<CSSStyleValue const> 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);
|
||||
|
|
|
@ -52,16 +52,26 @@ Optional<double> 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<double> CSSColorValue::resolve_with_reference_value(CSSStyleValue const& style_value, float one_hundred_percent_value, CalculationResolutionContext const& resolution_context)
|
||||
|
@ -79,16 +89,26 @@ Optional<double> 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<double> CSSColorValue::resolve_alpha(CSSStyleValue const& style_value, CalculationResolutionContext const& resolution_context)
|
||||
|
@ -108,16 +128,29 @@ Optional<double> 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<double> clamp_min, Optional<double> 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());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,14 +11,17 @@
|
|||
|
||||
namespace Web::CSS {
|
||||
|
||||
Color CSSHSL::to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> CSSHSL::to_color(Optional<Layout::NodeWithStyle const&>, 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
||||
|
|
|
@ -11,24 +11,30 @@
|
|||
|
||||
namespace Web::CSS {
|
||||
|
||||
Color CSSHWB::to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> CSSHWB::to_color(Optional<Layout::NodeWithStyle const&>, 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<u8>(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ bool CSSKeywordValue::has_color() const
|
|||
return is_color(keyword());
|
||||
}
|
||||
|
||||
Color CSSKeywordValue::to_color(Optional<Layout::NodeWithStyle const&> node, CalculationResolutionContext const&) const
|
||||
Optional<Color> CSSKeywordValue::to_color(Optional<Layout::NodeWithStyle const&> node, CalculationResolutionContext const&) const
|
||||
{
|
||||
if (keyword() == Keyword::Currentcolor) {
|
||||
if (!node.has_value() || !node->has_style())
|
||||
|
|
|
@ -51,7 +51,7 @@ public:
|
|||
|
||||
static bool is_color(Keyword);
|
||||
virtual bool has_color() const override;
|
||||
virtual Color to_color(Optional<Layout::NodeWithStyle const&> node, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&> 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; }
|
||||
|
|
|
@ -27,14 +27,20 @@ bool CSSLCHLike::equals(CSSStyleValue const& other) const
|
|||
return m_properties == other_oklch_like.m_properties;
|
||||
}
|
||||
|
||||
Color CSSLCH::to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> CSSLCH::to_color(Optional<Layout::NodeWithStyle const&>, 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<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> CSSOKLCH::to_color(Optional<Layout::NodeWithStyle const&>, 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
|
||||
|
|
|
@ -56,7 +56,7 @@ public:
|
|||
}
|
||||
virtual ~CSSLCH() override = default;
|
||||
|
||||
virtual Color to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, 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<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
};
|
||||
|
|
|
@ -26,14 +26,17 @@ bool CSSLabLike::equals(CSSStyleValue const& other) const
|
|||
return m_properties == other_lab_like.m_properties;
|
||||
}
|
||||
|
||||
Color CSSOKLab::to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> CSSOKLab::to_color(Optional<Layout::NodeWithStyle const&>, 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<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> CSSLab::to_color(Optional<Layout::NodeWithStyle const&>, 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
|
||||
|
|
|
@ -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<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
||||
CSSOKLab(Badge<CSSLabLike>, ValueComparingNonnullRefPtr<CSSStyleValue const> l, ValueComparingNonnullRefPtr<CSSStyleValue const> a, ValueComparingNonnullRefPtr<CSSStyleValue const> b, ValueComparingNonnullRefPtr<CSSStyleValue const> 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<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
||||
CSSLab(Badge<CSSLabLike>, ValueComparingNonnullRefPtr<CSSStyleValue const> l, ValueComparingNonnullRefPtr<CSSStyleValue const> a, ValueComparingNonnullRefPtr<CSSStyleValue const> b, ValueComparingNonnullRefPtr<CSSStyleValue const> alpha)
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
namespace Web::CSS {
|
||||
|
||||
Color CSSLightDark::to_color(Optional<Layout::NodeWithStyle const&> node, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> CSSLightDark::to_color(Optional<Layout::NodeWithStyle const&> 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);
|
||||
|
|
|
@ -21,7 +21,7 @@ public:
|
|||
}
|
||||
|
||||
virtual bool equals(CSSStyleValue const&) const override;
|
||||
virtual Color to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
namespace Web::CSS {
|
||||
|
||||
Color CSSRGB::to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> CSSRGB::to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const
|
||||
{
|
||||
auto resolve_rgb_to_u8 = [&resolution_context](CSSStyleValue const& style_value) -> Optional<u8> {
|
||||
// <number> | <percentage> | none
|
||||
|
@ -32,16 +32,26 @@ Color CSSRGB::to_color(Optional<Layout::NodeWithStyle const&>, 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<u8> {
|
||||
|
@ -51,12 +61,15 @@ Color CSSRGB::to_color(Optional<Layout::NodeWithStyle const&>, 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
||||
|
|
|
@ -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::Resolved> 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<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> ColorFunctionStyleValue::to_color(Optional<Layout::NodeWithStyle const&>, 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];
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
static ValueComparingNonnullRefPtr<ColorFunctionStyleValue const> create(StringView color_space, ValueComparingNonnullRefPtr<CSSStyleValue const> c1, ValueComparingNonnullRefPtr<CSSStyleValue const> c2, ValueComparingNonnullRefPtr<CSSStyleValue const> c3, ValueComparingRefPtr<CSSStyleValue const> alpha = {});
|
||||
|
||||
virtual bool equals(CSSStyleValue const&) const override;
|
||||
virtual Color to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const& resolution_context) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, 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<Resolved> resolve_properties(CalculationResolutionContext const& resolution_context) const;
|
||||
|
||||
Properties m_properties;
|
||||
};
|
||||
|
|
|
@ -175,15 +175,19 @@ ColorMixStyleValue::PercentageNormalizationResult ColorMixStyleValue::normalize_
|
|||
}
|
||||
|
||||
// https://drafts.csswg.org/css-color-5/#color-mix-result
|
||||
Color ColorMixStyleValue::to_color(Optional<Layout::NodeWithStyle const&> node, CalculationResolutionContext const& resolution_context) const
|
||||
Optional<Color> ColorMixStyleValue::to_color(Optional<Layout::NodeWithStyle const&> 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
static ValueComparingNonnullRefPtr<ColorMixStyleValue const> create(ColorInterpolationMethod, ColorMixComponent first_component, ColorMixComponent second_component);
|
||||
|
||||
virtual bool equals(CSSStyleValue const&) const override;
|
||||
virtual Color to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual Optional<Color> to_color(Optional<Layout::NodeWithStyle const&>, CalculationResolutionContext const&) const override;
|
||||
virtual String to_string(SerializationMode) const override;
|
||||
|
||||
private:
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1175,7 +1175,7 @@ Optional<String> effective_command_value(GC::Ptr<DOM::Node> node, FlyString cons
|
|||
return NumericLimits<u8>::max();
|
||||
VERIFY(is<Layout::NodeWithStyle>(node->layout_node()));
|
||||
auto& layout_node = *static_cast<Layout::NodeWithStyle*>(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<DOM::Element>(*node->parent()))
|
||||
node = node->parent();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -587,7 +587,7 @@ Optional<BordersData> 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::NodeWithStyle const*>(&layout_node), {});
|
||||
outline_color = CSS::CSSKeywordValue::create(CSS::Keyword::Accentcolor)->to_color(*static_cast<Layout::NodeWithStyle const*>(&layout_node), {}).value();
|
||||
outline_width = 2;
|
||||
} else {
|
||||
line_style = CSS::keyword_to_line_style(CSS::to_keyword(outline_style)).value_or(CSS::LineStyle::None);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue