Quellcode durchsuchen

LibWeb: Add for CSS `fill/stroke/stroke-color` properties for SVG

In the spec, `fill` and `stroke` are supposed to be a shorthands for
various properties. But since the spec is still a working draft, and
neither Firefox or Chrome support the `fill-color` or `stroke-color`
properties, we'll stick with `fill` and `stroke` as simple colors for
now.

Also, note that SVG expects things in "user units", and we are assuming
that 1px = 1 user unit for now.
Sam Atkins vor 3 Jahren
Ursprung
Commit
3964b81d2b

+ 12 - 0
Userland/Libraries/LibWeb/CSS/ComputedValues.h

@@ -104,6 +104,10 @@ public:
 
     CSS::ListStyleType list_style_type() const { return m_inherited.list_style_type; }
 
+    Optional<Color> fill() const { return m_inherited.fill; }
+    Optional<Color> stroke() const { return m_inherited.stroke; }
+    Optional<Length> 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<Color> fill;
+        Optional<Color> stroke;
+        Optional<Length> stroke_width;
     } m_inherited;
 
     struct {
@@ -210,6 +218,10 @@ public:
     void set_opacity(Optional<float> value) { m_noninherited.opacity = value; }
     void set_justify_content(CSS::JustifyContent value) { m_noninherited.justify_content = value; }
     void set_box_shadow(Optional<BoxShadowData> 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; }
 };
 
 }

+ 8 - 0
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"

+ 13 - 0
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<CSS::NumericStyleValue const&>(*stroke_width.value()).value()));
+        else
+            computed_values.set_stroke_width(stroke_width.value()->to_length());
+    }
 }
 
 void Node::handle_mousedown(Badge<EventHandler>, const Gfx::IntPoint&, unsigned, unsigned)

+ 37 - 1
Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.cpp

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
+ * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
  *
  * 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<Gfx::Color> 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<Gfx::Color> 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<float> 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 {};
+}
+
 }

+ 5 - 4
Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h

@@ -1,5 +1,6 @@
 /*
  * Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
+ * Copyright (c) 2021, Sam Atkins <atkinssj@serenityos.org>
  *
  * 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<Gfx::Color>& fill_color() const { return m_fill_color; }
-    const Optional<Gfx::Color>& stroke_color() const { return m_stroke_color; }
-    const Optional<float>& stroke_width() const { return m_stroke_width; }
+    Optional<Gfx::Color> fill_color() const;
+    Optional<Gfx::Color> stroke_color() const;
+    Optional<float> stroke_width() const;
 
 protected:
     Optional<Gfx::Color> m_fill_color;