1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 06:17:35 +00:00

LibWeb: Implement SVG opacity properties

This implements the stop-opacity, fill-opacity, and stroke-opacity
properties (in CSS). This replaces the existing more ad-hoc
fill-opacity attribute handling.
This commit is contained in:
MacDue 2023-05-19 20:35:39 +01:00 committed by Andreas Kling
parent 120e5b6b6f
commit 00cda96e2d
13 changed files with 141 additions and 29 deletions

View file

@ -23,10 +23,14 @@ public:
Gfx::Color fill_color() const { return state().fill_color; }
Gfx::Color stroke_color() const { return state().stroke_color; }
float stroke_width() const { return state().stroke_width; }
float fill_opacity() const { return state().fill_opacity; }
float stroke_opacity() const { return state().stroke_opacity; }
void set_fill_color(Gfx::Color color) { state().fill_color = color; }
void set_stroke_color(Gfx::Color color) { state().stroke_color = color; }
void set_stroke_width(float width) { state().stroke_width = width; }
void set_fill_opacity(float opacity) { state().fill_opacity = opacity; }
void set_stroke_opacity(float opacity) { state().stroke_opacity = opacity; }
CSSPixelPoint svg_element_position() const { return m_svg_element_bounds.top_left(); }
CSSPixelSize svg_element_size() const { return m_svg_element_bounds.size(); }
@ -38,7 +42,9 @@ private:
struct State {
Gfx::Color fill_color { Gfx::Color::Transparent };
Gfx::Color stroke_color { Gfx::Color::Transparent };
float stroke_width { 1.0 };
float stroke_width { 1.0f };
float fill_opacity { 1.0f };
float stroke_opacity { 1.0f };
};
State const& state() const { return m_states.last(); }

View file

@ -74,7 +74,7 @@ void SVGGradientElement::add_color_stops(Gfx::SVGGradientPaintStyle& paint_style
// stop's offset value. If a given gradient stop's offset value is not equal to or greater than all
// previous offset values, then the offset value is adjusted to be equal to the largest of all previous
// offset values.
paint_style.add_color_stop(stop_offset, stop.stop_color()).release_value_but_fixme_should_propagate_errors();
paint_style.add_color_stop(stop_offset, stop.stop_color().with_opacity(stop.stop_opacity())).release_value_but_fixme_should_propagate_errors();
});
}

View file

@ -33,9 +33,7 @@ JS::ThrowCompletionOr<void> SVGGraphicsElement::initialize(JS::Realm& realm)
void SVGGraphicsElement::parse_attribute(DeprecatedFlyString const& name, DeprecatedString const& value)
{
SVGElement::parse_attribute(name, value);
if (name == "fill-opacity"sv) {
m_fill_opacity = AttributeParser::parse_length(value);
} else if (name == "transform"sv) {
if (name == "transform"sv) {
auto transform_list = AttributeParser::parse_transform(value);
if (transform_list.has_value())
m_transform = transform_from_transform_list(*transform_list);
@ -120,6 +118,12 @@ void SVGGraphicsElement::apply_presentational_hints(CSS::StyleProperties& style)
} else if (name.equals_ignoring_ascii_case("stroke-width"sv)) {
if (auto stroke_width_value = parse_css_value(parsing_context, value, CSS::PropertyID::StrokeWidth).release_value_but_fixme_should_propagate_errors())
style.set_property(CSS::PropertyID::StrokeWidth, stroke_width_value.release_nonnull());
} else if (name.equals_ignoring_ascii_case("fill-opacity"sv)) {
if (auto fill_opacity_value = parse_css_value(parsing_context, value, CSS::PropertyID::FillOpacity).release_value_but_fixme_should_propagate_errors())
style.set_property(CSS::PropertyID::FillOpacity, fill_opacity_value.release_nonnull());
} else if (name.equals_ignoring_ascii_case("stroke-opacity"sv)) {
if (auto stroke_opacity_value = parse_css_value(parsing_context, value, CSS::PropertyID::FillOpacity).release_value_but_fixme_should_propagate_errors())
style.set_property(CSS::PropertyID::StrokeOpacity, stroke_opacity_value.release_nonnull());
}
});
}
@ -133,7 +137,7 @@ Optional<Gfx::Color> SVGGraphicsElement::fill_color() const
return layout_node()->computed_values().fill().map([&](auto& paint) -> Gfx::Color {
if (!paint.is_color())
return Color::Black;
return paint.as_color().with_alpha(m_fill_opacity.value_or(1) * 255);
return paint.as_color();
});
}
@ -150,6 +154,20 @@ Optional<Gfx::Color> SVGGraphicsElement::stroke_color() const
});
}
Optional<float> SVGGraphicsElement::fill_opacity() const
{
if (!layout_node())
return {};
return layout_node()->computed_values().fill_opacity();
}
Optional<float> SVGGraphicsElement::stroke_opacity() const
{
if (!layout_node())
return {};
return layout_node()->computed_values().stroke_opacity();
}
Optional<float> SVGGraphicsElement::stroke_width() const
{
if (!layout_node())

View file

@ -30,6 +30,8 @@ public:
Gfx::Painter::WindingRule fill_rule() const;
Optional<Gfx::Color> stroke_color() const;
Optional<float> stroke_width() const;
Optional<float> fill_opacity() const;
Optional<float> stroke_opacity() const;
float visible_stroke_width() const
{
@ -47,7 +49,6 @@ protected:
virtual JS::ThrowCompletionOr<void> initialize(JS::Realm&) override;
Optional<float> m_fill_opacity = {};
Gfx::AffineTransform m_transform = {};
};

View file

@ -31,11 +31,15 @@ void SVGStopElement::apply_presentational_hints(CSS::StyleProperties& style) con
{
CSS::Parser::ParsingContext parsing_context { document() };
for_each_attribute([&](auto& name, auto& value) {
CSS::Parser::ParsingContext parsing_context { document() };
if (name.equals_ignoring_ascii_case("stop-color"sv)) {
CSS::Parser::ParsingContext parsing_context { document() };
if (auto stop_color = parse_css_value(parsing_context, value, CSS::PropertyID::StopColor).release_value_but_fixme_should_propagate_errors()) {
style.set_property(CSS::PropertyID::StopColor, stop_color.release_nonnull());
}
} else if (name.equals_ignoring_ascii_case("stop-opacity"sv)) {
if (auto stop_opacity = parse_css_value(parsing_context, value, CSS::PropertyID::StopOpacity).release_value_but_fixme_should_propagate_errors()) {
style.set_property(CSS::PropertyID::StopOpacity, stop_opacity.release_nonnull());
}
}
});
}
@ -47,6 +51,13 @@ Gfx::Color SVGStopElement::stop_color() const
return Color::Black;
}
float SVGStopElement::stop_opacity() const
{
if (auto css_values = computed_css_values())
return css_values->stop_opacity();
return 1;
}
JS::NonnullGCPtr<SVGAnimatedNumber> SVGStopElement::offset() const
{
TODO();

View file

@ -27,6 +27,7 @@ public:
NumberPercentage stop_offset() const { return m_offset.value_or(NumberPercentage::create_number(0)); }
Gfx::Color stop_color() const;
float stop_opacity() const;
private:
SVGStopElement(DOM::Document&, DOM::QualifiedName);