diff --git a/Userland/Libraries/LibWeb/CSS/ComputedValues.h b/Userland/Libraries/LibWeb/CSS/ComputedValues.h index 18a4fe07e9..b19e89f454 100644 --- a/Userland/Libraries/LibWeb/CSS/ComputedValues.h +++ b/Userland/Libraries/LibWeb/CSS/ComputedValues.h @@ -104,6 +104,10 @@ public: CSS::ListStyleType list_style_type() const { return m_inherited.list_style_type; } + Optional fill() const { return m_inherited.fill; } + Optional stroke() const { return m_inherited.stroke; } + Optional stroke_width() const { return m_inherited.stroke_width; } + ComputedValues clone_inherited_values() const { ComputedValues clone; @@ -119,6 +123,10 @@ protected: CSS::TextTransform text_transform { InitialValues::text_transform() }; CSS::WhiteSpace white_space { InitialValues::white_space() }; CSS::ListStyleType list_style_type { InitialValues::list_style_type() }; + + Optional fill; + Optional stroke; + Optional stroke_width; } m_inherited; struct { @@ -210,6 +218,10 @@ public: void set_opacity(Optional value) { m_noninherited.opacity = value; } void set_justify_content(CSS::JustifyContent value) { m_noninherited.justify_content = value; } void set_box_shadow(Optional value) { m_noninherited.box_shadow = move(value); } + + void set_fill(Color value) { m_inherited.fill = value; } + void set_stroke(Color value) { m_inherited.stroke = value; } + void set_stroke_width(Length value) { m_inherited.stroke_width = value; } }; } diff --git a/Userland/Libraries/LibWeb/CSS/Properties.json b/Userland/Libraries/LibWeb/CSS/Properties.json index 2652c9332f..df667629df 100644 --- a/Userland/Libraries/LibWeb/CSS/Properties.json +++ b/Userland/Libraries/LibWeb/CSS/Properties.json @@ -545,6 +545,14 @@ "unitless-length" ] }, + "stroke": { + "inherited": true, + "initial": "transparent" + }, + "stroke-width": { + "inherited": true, + "initial": "1px" + }, "text-align": { "inherited": true, "initial": "left" diff --git a/Userland/Libraries/LibWeb/Layout/Node.cpp b/Userland/Libraries/LibWeb/Layout/Node.cpp index b8205cb667..b1ee4196f7 100644 --- a/Userland/Libraries/LibWeb/Layout/Node.cpp +++ b/Userland/Libraries/LibWeb/Layout/Node.cpp @@ -360,6 +360,19 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& specified_style) do_border_style(computed_values.border_top(), CSS::PropertyID::BorderTopWidth, CSS::PropertyID::BorderTopColor, CSS::PropertyID::BorderTopStyle); do_border_style(computed_values.border_right(), CSS::PropertyID::BorderRightWidth, CSS::PropertyID::BorderRightColor, CSS::PropertyID::BorderRightStyle); do_border_style(computed_values.border_bottom(), CSS::PropertyID::BorderBottomWidth, CSS::PropertyID::BorderBottomColor, CSS::PropertyID::BorderBottomStyle); + + if (auto fill = specified_style.property(CSS::PropertyID::Fill); fill.has_value()) + computed_values.set_fill(fill.value()->to_color(document())); + if (auto stroke = specified_style.property(CSS::PropertyID::Stroke); stroke.has_value()) + computed_values.set_stroke(stroke.value()->to_color(document())); + if (auto stroke_width = specified_style.property(CSS::PropertyID::StrokeWidth); stroke_width.has_value()) { + // FIXME: Converting to pixels isn't really correct - values should be in "user units" + // https://svgwg.org/svg2-draft/coords.html#TermUserUnits + if (stroke_width.value()->is_numeric()) + computed_values.set_stroke_width(CSS::Length::make_px(static_cast(*stroke_width.value()).value())); + else + computed_values.set_stroke_width(stroke_width.value()->to_length()); + } } void Node::handle_mousedown(Badge, const Gfx::IntPoint&, unsigned, unsigned) diff --git a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp index 6a373a2ab5..4fa2c64485 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp +++ b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Matthew Olsson + * Copyright (c) 2021, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -13,7 +14,7 @@ SVGGraphicsElement::SVGGraphicsElement(DOM::Document& document, QualifiedName qu { } -void SVGGraphicsElement::parse_attribute(const FlyString& name, const String& value) +void SVGGraphicsElement::parse_attribute(FlyString const& name, String const& value) { SVGElement::parse_attribute(name, value); @@ -28,4 +29,39 @@ void SVGGraphicsElement::parse_attribute(const FlyString& name, const String& va } } +Optional SVGGraphicsElement::fill_color() const +{ + if (m_fill_color.has_value()) + return m_fill_color; + if (!layout_node()) + return {}; + // FIXME: In the working-draft spec, `fill` is intended to be a shorthand, with `fill-color` + // being what we actually want to use. But that's not final or widely supported yet. + return layout_node()->computed_values().fill(); +} + +Optional SVGGraphicsElement::stroke_color() const +{ + if (m_stroke_color.has_value()) + return m_stroke_color; + if (!layout_node()) + return {}; + // FIXME: In the working-draft spec, `stroke` is intended to be a shorthand, with `stroke-color` + // being what we actually want to use. But that's not final or widely supported yet. + return layout_node()->computed_values().stroke(); +} + +Optional SVGGraphicsElement::stroke_width() const +{ + if (m_stroke_width.has_value()) + return m_stroke_width; + if (!layout_node()) + return {}; + // FIXME: Converting to pixels isn't really correct - values should be in "user units" + // https://svgwg.org/svg2-draft/coords.html#TermUserUnits + if (auto width = layout_node()->computed_values().stroke_width(); width.has_value()) + return width->to_px(*layout_node()); + return {}; +} + } diff --git a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h index cce0b414f2..58019e67a9 100644 --- a/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h +++ b/Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2020, Matthew Olsson + * Copyright (c) 2021, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ @@ -19,11 +20,11 @@ public: SVGGraphicsElement(DOM::Document&, QualifiedName); - virtual void parse_attribute(const FlyString& name, const String& value) override; + virtual void parse_attribute(FlyString const& name, String const& value) override; - const Optional& fill_color() const { return m_fill_color; } - const Optional& stroke_color() const { return m_stroke_color; } - const Optional& stroke_width() const { return m_stroke_width; } + Optional fill_color() const; + Optional stroke_color() const; + Optional stroke_width() const; protected: Optional m_fill_color;