فهرست منبع

LibWeb: Add the `clip-path` property and resolve it for SVG elements

MacDue 1 سال پیش
والد
کامیت
03f957dc79

+ 2 - 1
Tests/LibWeb/Text/expected/css/getComputedStyle-print-all.txt

@@ -47,6 +47,7 @@ box-sizing: content-box
 caption-side: top
 clear: none
 clip: auto
+clip-path: none
 color: rgb(0, 0, 0)
 column-count: auto
 column-gap: auto
@@ -83,7 +84,7 @@ grid-row-start: auto
 grid-template-areas: 
 grid-template-columns: 
 grid-template-rows: 
-height: 1445px
+height: 1462px
 image-rendering: auto
 inline-size: auto
 inset-block-end: auto

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

@@ -230,6 +230,21 @@ private:
     URL::URL m_url;
 };
 
+// https://drafts.fxtf.org/css-masking/#the-clip-path
+class ClipPathReference {
+public:
+    // TODO: Support clip sources.
+    ClipPathReference(URL::URL const& url)
+        : m_url(url)
+    {
+    }
+
+    URL::URL const& url() const { return m_url; }
+
+private:
+    URL::URL m_url;
+};
+
 struct BackgroundLayerData {
     RefPtr<CSS::AbstractImageStyleValue const> background_image { nullptr };
     CSS::BackgroundAttachment attachment { CSS::BackgroundAttachment::Scroll };
@@ -414,6 +429,7 @@ public:
     CSS::TextAnchor text_anchor() const { return m_inherited.text_anchor; }
     Optional<MaskReference> const& mask() const { return m_noninherited.mask; }
     CSS::MaskType mask_type() const { return m_noninherited.mask_type; }
+    Optional<ClipPathReference> const& clip_path() const { return m_noninherited.clip_path; }
 
     LengthPercentage const& cx() const { return m_noninherited.cx; }
     LengthPercentage const& cy() const { return m_noninherited.cy; }
@@ -579,6 +595,7 @@ protected:
 
         Optional<MaskReference> mask;
         CSS::MaskType mask_type { InitialValues::mask_type() };
+        Optional<ClipPathReference> clip_path;
 
         LengthPercentage cx { InitialValues::cx() };
         LengthPercentage cy { InitialValues::cy() };
@@ -713,6 +730,7 @@ public:
     void set_outline_width(CSS::Length value) { m_noninherited.outline_width = value; }
     void set_mask(MaskReference value) { m_noninherited.mask = value; }
     void set_mask_type(CSS::MaskType value) { m_noninherited.mask_type = value; }
+    void set_clip_path(ClipPathReference value) { m_noninherited.clip_path = value; }
 
     void set_cx(LengthPercentage cx) { m_noninherited.cx = cx; }
     void set_cy(LengthPercentage cy) { m_noninherited.cy = cy; }

+ 14 - 0
Userland/Libraries/LibWeb/CSS/Properties.json

@@ -702,6 +702,20 @@
       "unitless-length"
     ]
   },
+  "clip-path": {
+    "animation-type": "none",
+    "affects-layout": false,
+    "affects-stacking-context": true,
+    "inherited": false,
+    "valid-identifiers": [
+      "none"
+    ],
+    "__comment": "FIXME: This should be a <clip-source> | [ <basic-shape> || <geometry-box> ]",
+    "valid-types": [
+      "url"
+    ],
+    "initial": "none"
+  },
   "color": {
     "affects-layout": false,
     "animation-type": "by-computed-value",

+ 4 - 1
Userland/Libraries/LibWeb/Layout/Node.cpp

@@ -193,7 +193,7 @@ bool Node::establishes_stacking_context() const
     // - perspective
     // - clip-path
     // - mask / mask-image / mask-border
-    if (computed_values().mask().has_value())
+    if (computed_values().mask().has_value() || computed_values().clip_path().has_value())
         return true;
 
     return computed_values().opacity() < 1.0f;
@@ -796,6 +796,9 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
     if (auto mask = computed_style.property(CSS::PropertyID::Mask); mask->is_url())
         computed_values.set_mask(mask->as_url().url());
 
+    if (auto clip_path = computed_style.property(CSS::PropertyID::ClipPath); clip_path->is_url())
+        computed_values.set_clip_path(clip_path->as_url().url());
+
     if (auto fill_rule = computed_style.fill_rule(); fill_rule.has_value())
         computed_values.set_fill_rule(*fill_rule);
 

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

@@ -13,6 +13,7 @@
 #include <LibWeb/Layout/Node.h>
 #include <LibWeb/SVG/AttributeNames.h>
 #include <LibWeb/SVG/AttributeParser.h>
+#include <LibWeb/SVG/SVGClipPathElement.h>
 #include <LibWeb/SVG/SVGGradientElement.h>
 #include <LibWeb/SVG/SVGGraphicsElement.h>
 #include <LibWeb/SVG/SVGMaskElement.h>
@@ -76,6 +77,14 @@ JS::GCPtr<SVG::SVGMaskElement const> SVGGraphicsElement::mask() const
     return try_resolve_url_to<SVG::SVGMaskElement const>(mask_reference->url());
 }
 
+JS::GCPtr<SVG::SVGClipPathElement const> SVGGraphicsElement::clip_path() const
+{
+    auto const& clip_path_reference = layout_node()->computed_values().clip_path();
+    if (!clip_path_reference.has_value())
+        return {};
+    return try_resolve_url_to<SVG::SVGClipPathElement const>(clip_path_reference->url());
+}
+
 Gfx::AffineTransform transform_from_transform_list(ReadonlySpan<Transform> transform_list)
 {
     Gfx::AffineTransform affine_transform;
@@ -144,7 +153,8 @@ void SVGGraphicsElement::apply_presentational_hints(CSS::StyleProperties& style)
         NamedPropertyID(CSS::PropertyID::TextAnchor),
         NamedPropertyID(CSS::PropertyID::FontSize),
         NamedPropertyID(CSS::PropertyID::Mask),
-        NamedPropertyID(CSS::PropertyID::MaskType)
+        NamedPropertyID(CSS::PropertyID::MaskType),
+        NamedPropertyID(CSS::PropertyID::ClipPath),
     };
 
     CSS::Parser::ParsingContext parsing_context { document(), CSS::Parser::ParsingContext::Mode::SVGPresentationAttribute };

+ 2 - 0
Userland/Libraries/LibWeb/SVG/SVGGraphicsElement.h

@@ -47,6 +47,8 @@ public:
 
     JS::GCPtr<SVG::SVGMaskElement const> mask() const;
 
+    JS::GCPtr<SVG::SVGClipPathElement const> clip_path() const;
+
 protected:
     SVGGraphicsElement(DOM::Document&, DOM::QualifiedName);