LibWeb: Don't include spread distance when serializing text-shadow

We shouldn't include spread distance when serializing `text-shadow` as
it is not supported unlike `box-shadow` - to achieve this we store
whether this is a text or box shadow within the ShadowStyleValue and
serialize appropriately.
This commit is contained in:
Callum Law 2025-09-15 20:52:20 +12:00 committed by Sam Atkins
parent 1ac7b47764
commit c3a78d2884
6 changed files with 27 additions and 23 deletions

View File

@ -360,13 +360,14 @@ static NonnullRefPtr<StyleValue const> style_value_for_size(Size const& size)
TODO();
}
static RefPtr<StyleValue const> style_value_for_shadow(Vector<ShadowData> const& shadow_data)
static RefPtr<StyleValue const> style_value_for_shadow(ShadowStyleValue::ShadowType shadow_type, Vector<ShadowData> const& shadow_data)
{
if (shadow_data.is_empty())
return KeywordStyleValue::create(Keyword::None);
auto make_shadow_style_value = [](ShadowData const& shadow) {
auto make_shadow_style_value = [shadow_type](ShadowData const& shadow) {
return ShadowStyleValue::create(
shadow_type,
ColorStyleValue::create_from_color(shadow.color, ColorSyntax::Modern),
style_value_for_length_percentage(shadow.offset_x),
style_value_for_length_percentage(shadow.offset_y),
@ -582,7 +583,7 @@ RefPtr<StyleValue const> CSSStyleProperties::style_value_for_computed_property(L
case PropertyID::BorderTopColor:
return resolve_color_style_value(get_computed_value(property_id), layout_node.computed_values().border_top().color);
case PropertyID::BoxShadow:
return style_value_for_shadow(layout_node.computed_values().box_shadow());
return style_value_for_shadow(ShadowStyleValue::ShadowType::Normal, layout_node.computed_values().box_shadow());
case PropertyID::CaretColor:
return resolve_color_style_value(get_computed_value(property_id), layout_node.computed_values().caret_color());
case PropertyID::Color:
@ -593,7 +594,7 @@ RefPtr<StyleValue const> CSSStyleProperties::style_value_for_computed_property(L
return resolve_color_style_value(get_computed_value(property_id), layout_node.computed_values().text_decoration_color());
// NB: text-shadow isn't listed, but is computed the same as box-shadow.
case PropertyID::TextShadow:
return style_value_for_shadow(layout_node.computed_values().text_shadow());
return style_value_for_shadow(ShadowStyleValue::ShadowType::Text, layout_node.computed_values().text_shadow());
// -> line-height
// The resolved value is normal if the computed value is normal, or the used value otherwise.

View File

@ -961,6 +961,7 @@ RefPtr<StyleValue const> interpolate_box_shadow(DOM::Element& element, Calculati
values.ensure_capacity(other.size());
for (size_t i = values.size(); i < other.size(); i++) {
values.unchecked_append(ShadowStyleValue::create(
other.get(0).value()->as_shadow().shadow_type(),
ColorStyleValue::create_from_color(Color::Transparent, ColorSyntax::Legacy),
LengthStyleValue::create(Length::make_px(0)),
LengthStyleValue::create(Length::make_px(0)),
@ -1012,6 +1013,7 @@ RefPtr<StyleValue const> interpolate_box_shadow(DOM::Element& element, Calculati
interpolated_color = interpolate_color(from_color.value(), to_color.value(), delta, color_syntax);
auto result_shadow = ShadowStyleValue::create(
from_shadow.shadow_type(),
ColorStyleValue::create_from_color(interpolated_color, ColorSyntax::Modern),
*interpolated_offset_x,
*interpolated_offset_y,

View File

@ -2169,7 +2169,7 @@ RefPtr<StyleValue const> Parser::parse_single_shadow_value(TokenStream<Component
placement = ShadowPlacement::Outer;
transaction.commit();
return ShadowStyleValue::create(color, offset_x.release_nonnull(), offset_y.release_nonnull(), blur_radius, spread_distance, placement.release_value());
return ShadowStyleValue::create(shadow_type, color, offset_x.release_nonnull(), offset_y.release_nonnull(), blur_radius, spread_distance, placement.release_value());
}
RefPtr<StyleValue const> Parser::parse_rotate_value(TokenStream<ComponentValue>& tokens)

View File

@ -24,15 +24,11 @@ String ShadowStyleValue::to_string(SerializationMode mode) const
builder.append(' ');
builder.appendff("{} {}", m_properties.offset_x->to_string(mode), m_properties.offset_y->to_string(mode));
auto append_value = [&](ValueComparingRefPtr<StyleValue const> const& value) {
if (!value)
return;
if (!builder.is_empty())
builder.append(' ');
builder.append(value->to_string(mode));
};
append_value(m_properties.blur_radius);
append_value(m_properties.spread_distance);
if (m_properties.blur_radius)
builder.appendff(" {}", m_properties.blur_radius->to_string(mode));
if (m_properties.spread_distance && m_properties.shadow_type == ShadowType::Normal)
builder.appendff(" {}", m_properties.spread_distance->to_string(mode));
if (m_properties.placement == ShadowPlacement::Inner)
builder.append(" inset"sv);
@ -66,7 +62,7 @@ ValueComparingNonnullRefPtr<StyleValue const> ShadowStyleValue::absolutized(CSSP
auto absolutized_offset_y = offset_y()->absolutized(viewport_rect, font_metrics, root_font_metrics);
auto absolutized_blur_radius = blur_radius()->absolutized(viewport_rect, font_metrics, root_font_metrics);
auto absolutized_spread_distance = spread_distance()->absolutized(viewport_rect, font_metrics, root_font_metrics);
return create(color(), absolutized_offset_x, absolutized_offset_y, absolutized_blur_radius, absolutized_spread_distance, placement());
return create(m_properties.shadow_type, color(), absolutized_offset_x, absolutized_offset_y, absolutized_blur_radius, absolutized_spread_distance, placement());
}
}

View File

@ -30,6 +30,7 @@ public:
};
static ValueComparingNonnullRefPtr<ShadowStyleValue const> create(
ShadowType shadow_type,
ValueComparingRefPtr<StyleValue const> color,
ValueComparingNonnullRefPtr<StyleValue const> offset_x,
ValueComparingNonnullRefPtr<StyleValue const> offset_y,
@ -37,10 +38,11 @@ public:
ValueComparingRefPtr<StyleValue const> spread_distance,
ShadowPlacement placement)
{
return adopt_ref(*new (nothrow) ShadowStyleValue(move(color), move(offset_x), move(offset_y), move(blur_radius), move(spread_distance), placement));
return adopt_ref(*new (nothrow) ShadowStyleValue(shadow_type, move(color), move(offset_x), move(offset_y), move(blur_radius), move(spread_distance), placement));
}
virtual ~ShadowStyleValue() override = default;
ShadowType shadow_type() const { return m_properties.shadow_type; }
ValueComparingNonnullRefPtr<StyleValue const> color() const;
ValueComparingNonnullRefPtr<StyleValue const> offset_x() const { return m_properties.offset_x; }
ValueComparingNonnullRefPtr<StyleValue const> offset_y() const { return m_properties.offset_y; }
@ -54,6 +56,7 @@ public:
private:
ShadowStyleValue(
ShadowType shadow_type,
ValueComparingRefPtr<StyleValue const> color,
ValueComparingNonnullRefPtr<StyleValue const> offset_x,
ValueComparingNonnullRefPtr<StyleValue const> offset_y,
@ -62,6 +65,7 @@ private:
ShadowPlacement placement)
: StyleValueWithDefaultOperators(Type::Shadow)
, m_properties {
.shadow_type = shadow_type,
.color = move(color),
.offset_x = move(offset_x),
.offset_y = move(offset_y),
@ -75,6 +79,7 @@ private:
virtual ValueComparingNonnullRefPtr<StyleValue const> absolutized(CSSPixelRect const& viewport_rect, Length::FontMetrics const& font_metrics, Length::FontMetrics const& root_font_metrics) const override;
struct Properties {
ShadowType shadow_type;
ValueComparingRefPtr<StyleValue const> color;
ValueComparingNonnullRefPtr<StyleValue const> offset_x;
ValueComparingNonnullRefPtr<StyleValue const> offset_y;

View File

@ -2,12 +2,12 @@ Harness status: OK
Found 7 tests
1 Pass
6 Fail
6 Pass
1 Fail
Pass Property text-shadow value 'none'
Fail Property text-shadow value '10px 20px'
Fail Property text-shadow value 'red 10px 20px 30px'
Fail Property text-shadow value 'calc(0.5em + 10px) calc(0.5em + 10px) calc(0.5em + 10px)'
Pass Property text-shadow value '10px 20px'
Pass Property text-shadow value 'red 10px 20px 30px'
Pass Property text-shadow value 'calc(0.5em + 10px) calc(0.5em + 10px) calc(0.5em + 10px)'
Fail Property text-shadow value 'calc(-0.5em + 10px) calc(-0.5em + 10px) calc(-0.5em + 10px)'
Fail Property text-shadow value '10px 20px, 30px 40px'
Fail Property text-shadow value 'lime 10px 20px 30px, red 40px 50px'
Pass Property text-shadow value '10px 20px, 30px 40px'
Pass Property text-shadow value 'lime 10px 20px 30px, red 40px 50px'