浏览代码

LibWeb+LibGfx: Keep path properties when cloning and implement fill-rule

Gingeh 9 月之前
父节点
当前提交
3467076dbc

+ 3 - 0
Tests/LibWeb/Screenshot/clip-path-basic-shapes.html

@@ -121,6 +121,9 @@
 <div class="outer">
 <div class="outer">
     <div class="inner" style="clip-path: polygon(nonzero, 65px 0px, 35px 80px, 105px 30px, 25px 30px, 95px 80px)"></div>
     <div class="inner" style="clip-path: polygon(nonzero, 65px 0px, 35px 80px, 105px 30px, 25px 30px, 95px 80px)"></div>
 </div>
 </div>
+<div class="outer">
+    <div class="inner" style="clip-path: polygon(evenodd, 65px 0px, 35px 80px, 105px 30px, 25px 30px, 95px 80px)"></div>
+</div>
 <div class="outer">
 <div class="outer">
     <div class="inner" style="clip-path: polygon(100px 0%, 50% 50px, 100% 100%)"></div>
     <div class="inner" style="clip-path: polygon(100px 0%, 50% 50px, 100% 100%)"></div>
 </div>
 </div>

二进制
Tests/LibWeb/Screenshot/images/clip-path-basic-shapes-ref.png


+ 4 - 4
Tests/LibWeb/Text/expected/css/calc-coverage.txt

@@ -34,10 +34,10 @@ border-top-width: 'calc(2px)' -> 'calc(2px)'
 border-top-width: 'calc(2px * var(--n))' -> 'calc(2px * 2)'
 border-top-width: 'calc(2px * var(--n))' -> 'calc(2px * 2)'
 bottom: 'calc(2px)' -> 'calc(2px)'
 bottom: 'calc(2px)' -> 'calc(2px)'
 bottom: 'calc(2px * var(--n))' -> 'calc(2px * 2)'
 bottom: 'calc(2px * var(--n))' -> 'calc(2px * 2)'
-clip-path: 'polygon(calc(0px) calc(2px), calc(2px) calc(0px), calc(2px) calc(2px))' -> 'polygon(calc(0px) calc(2px),calc(2px) calc(0px),calc(2px) calc(2px))'
-clip-path: 'polygon(calc(0px * var(--n)) calc(2px * var(--n)), calc(2px * var(--n)) calc(0px * var(--n)), calc(2px * var(--n)) calc(2px * var(--n)))' -> 'polygon(calc(0px * 2) calc(2px * 2),calc(2px * 2) calc(0px * 2),calc(2px * 2) calc(2px * 2))'
-clip-path: 'polygon(calc(0%) calc(2%), calc(2%) calc(0%), calc(2%) calc(2%))' -> 'polygon(calc(0%) calc(2%),calc(2%) calc(0%),calc(2%) calc(2%))'
-clip-path: 'polygon(calc(0% * var(--n)) calc(2% * var(--n)), calc(2% * var(--n)) calc(0% * var(--n)), calc(2% * var(--n)) calc(2% * var(--n)))' -> 'polygon(calc(0% * 2) calc(2% * 2),calc(2% * 2) calc(0% * 2),calc(2% * 2) calc(2% * 2))'
+clip-path: 'polygon(calc(0px) calc(2px), calc(2px) calc(0px), calc(2px) calc(2px))' -> 'polygon(nonzero, calc(0px) calc(2px), calc(2px) calc(0px), calc(2px) calc(2px))'
+clip-path: 'polygon(calc(0px * var(--n)) calc(2px * var(--n)), calc(2px * var(--n)) calc(0px * var(--n)), calc(2px * var(--n)) calc(2px * var(--n)))' -> 'polygon(nonzero, calc(0px * 2) calc(2px * 2), calc(2px * 2) calc(0px * 2), calc(2px * 2) calc(2px * 2))'
+clip-path: 'polygon(calc(0%) calc(2%), calc(2%) calc(0%), calc(2%) calc(2%))' -> 'polygon(nonzero, calc(0%) calc(2%), calc(2%) calc(0%), calc(2%) calc(2%))'
+clip-path: 'polygon(calc(0% * var(--n)) calc(2% * var(--n)), calc(2% * var(--n)) calc(0% * var(--n)), calc(2% * var(--n)) calc(2% * var(--n)))' -> 'polygon(nonzero, calc(0% * 2) calc(2% * 2), calc(2% * 2) calc(0% * 2), calc(2% * 2) calc(2% * 2))'
 column-count: 'calc(2)' -> 'calc(2)'
 column-count: 'calc(2)' -> 'calc(2)'
 column-count: 'calc(2 * var(--n))' -> '4'
 column-count: 'calc(2 * var(--n))' -> '4'
 column-gap: 'calc(2px)' -> 'calc(2px)'
 column-gap: 'calc(2px)' -> 'calc(2px)'

+ 2 - 0
Userland/Libraries/LibGfx/Path.h

@@ -39,6 +39,7 @@ public:
     [[nodiscard]] virtual bool is_empty() const = 0;
     [[nodiscard]] virtual bool is_empty() const = 0;
     virtual Gfx::FloatPoint last_point() const = 0;
     virtual Gfx::FloatPoint last_point() const = 0;
     virtual Gfx::FloatRect bounding_box() const = 0;
     virtual Gfx::FloatRect bounding_box() const = 0;
+    virtual void set_fill_type(Gfx::WindingRule winding_rule) = 0;
     virtual bool contains(FloatPoint point, Gfx::WindingRule) const = 0;
     virtual bool contains(FloatPoint point, Gfx::WindingRule) const = 0;
 
 
     virtual NonnullOwnPtr<PathImpl> clone() const = 0;
     virtual NonnullOwnPtr<PathImpl> clone() const = 0;
@@ -86,6 +87,7 @@ public:
     Gfx::FloatPoint last_point() const { return impl().last_point(); }
     Gfx::FloatPoint last_point() const { return impl().last_point(); }
     Gfx::FloatRect bounding_box() const { return impl().bounding_box(); }
     Gfx::FloatRect bounding_box() const { return impl().bounding_box(); }
     bool contains(FloatPoint point, Gfx::WindingRule winding_rule) const { return impl().contains(point, winding_rule); }
     bool contains(FloatPoint point, Gfx::WindingRule winding_rule) const { return impl().contains(point, winding_rule); }
+    void set_fill_type(Gfx::WindingRule winding_rule) { impl().set_fill_type(winding_rule); }
 
 
     Gfx::Path clone() const { return Gfx::Path { impl().clone() }; }
     Gfx::Path clone() const { return Gfx::Path { impl().clone() }; }
     Gfx::Path copy_transformed(Gfx::AffineTransform const& transform) const { return Gfx::Path { impl().copy_transformed(transform) }; }
     Gfx::Path copy_transformed(Gfx::AffineTransform const& transform) const { return Gfx::Path { impl().copy_transformed(transform) }; }

+ 14 - 5
Userland/Libraries/LibGfx/PathSkia.cpp

@@ -29,6 +29,12 @@ PathImplSkia::PathImplSkia()
 {
 {
 }
 }
 
 
+PathImplSkia::PathImplSkia(PathImplSkia const& other)
+    : m_last_move_to(other.m_last_move_to)
+    , m_path(adopt_own(*new SkPath(other.sk_path())))
+{
+}
+
 PathImplSkia::~PathImplSkia() = default;
 PathImplSkia::~PathImplSkia() = default;
 
 
 void PathImplSkia::clear()
 void PathImplSkia::clear()
@@ -217,21 +223,24 @@ bool PathImplSkia::contains(FloatPoint point, Gfx::WindingRule winding_rule) con
     return temp_path.contains(point.x(), point.y());
     return temp_path.contains(point.x(), point.y());
 }
 }
 
 
+void PathImplSkia::set_fill_type(Gfx::WindingRule winding_rule)
+{
+    m_path->setFillType(to_skia_path_fill_type(winding_rule));
+}
+
 NonnullOwnPtr<PathImpl> PathImplSkia::clone() const
 NonnullOwnPtr<PathImpl> PathImplSkia::clone() const
 {
 {
-    auto new_path = PathImplSkia::create();
-    new_path->sk_path().addPath(*m_path);
-    return new_path;
+    return adopt_own(*new PathImplSkia(*this));
 }
 }
 
 
 NonnullOwnPtr<PathImpl> PathImplSkia::copy_transformed(Gfx::AffineTransform const& transform) const
 NonnullOwnPtr<PathImpl> PathImplSkia::copy_transformed(Gfx::AffineTransform const& transform) const
 {
 {
-    auto new_path = PathImplSkia::create();
+    auto new_path = adopt_own(*new PathImplSkia(*this));
     auto matrix = SkMatrix::MakeAll(
     auto matrix = SkMatrix::MakeAll(
         transform.a(), transform.c(), transform.e(),
         transform.a(), transform.c(), transform.e(),
         transform.b(), transform.d(), transform.f(),
         transform.b(), transform.d(), transform.f(),
         0, 0, 1);
         0, 0, 1);
-    new_path->sk_path().addPath(*m_path, matrix);
+    new_path->sk_path().transform(matrix);
     return new_path;
     return new_path;
 }
 }
 
 

+ 2 - 0
Userland/Libraries/LibGfx/PathSkia.h

@@ -36,6 +36,7 @@ public:
     virtual Gfx::FloatPoint last_point() const override;
     virtual Gfx::FloatPoint last_point() const override;
     virtual Gfx::FloatRect bounding_box() const override;
     virtual Gfx::FloatRect bounding_box() const override;
     virtual bool contains(FloatPoint point, Gfx::WindingRule) const override;
     virtual bool contains(FloatPoint point, Gfx::WindingRule) const override;
+    virtual void set_fill_type(Gfx::WindingRule winding_rule) override;
 
 
     virtual NonnullOwnPtr<PathImpl> clone() const override;
     virtual NonnullOwnPtr<PathImpl> clone() const override;
     virtual NonnullOwnPtr<PathImpl> copy_transformed(Gfx::AffineTransform const&) const override;
     virtual NonnullOwnPtr<PathImpl> copy_transformed(Gfx::AffineTransform const&) const override;
@@ -46,6 +47,7 @@ public:
 
 
 private:
 private:
     PathImplSkia();
     PathImplSkia();
+    PathImplSkia(PathImplSkia const& other);
 
 
     Gfx::FloatPoint m_last_move_to;
     Gfx::FloatPoint m_last_move_to;
     NonnullOwnPtr<SkPath> m_path;
     NonnullOwnPtr<SkPath> m_path;

+ 4 - 4
Userland/Libraries/LibWeb/CSS/Parser/Parser.cpp

@@ -1457,15 +1457,15 @@ RefPtr<CSSStyleValue> Parser::parse_basic_shape_value(TokenStream<ComponentValue
         if (arguments.size() < 1)
         if (arguments.size() < 1)
             return nullptr;
             return nullptr;
 
 
-        Optional<FillRule> fill_rule;
+        Optional<Gfx::WindingRule> fill_rule;
         auto first_argument = arguments[0];
         auto first_argument = arguments[0];
         TokenStream first_argument_tokens { first_argument };
         TokenStream first_argument_tokens { first_argument };
 
 
         first_argument_tokens.discard_whitespace();
         first_argument_tokens.discard_whitespace();
         if (first_argument_tokens.next_token().is_ident("nonzero"sv)) {
         if (first_argument_tokens.next_token().is_ident("nonzero"sv)) {
-            fill_rule = FillRule::Nonzero;
+            fill_rule = Gfx::WindingRule::Nonzero;
         } else if (first_argument_tokens.next_token().is_ident("evenodd"sv)) {
         } else if (first_argument_tokens.next_token().is_ident("evenodd"sv)) {
-            fill_rule = FillRule::Evenodd;
+            fill_rule = Gfx::WindingRule::EvenOdd;
         }
         }
 
 
         if (fill_rule.has_value()) {
         if (fill_rule.has_value()) {
@@ -1475,7 +1475,7 @@ RefPtr<CSSStyleValue> Parser::parse_basic_shape_value(TokenStream<ComponentValue
 
 
             arguments.remove(0);
             arguments.remove(0);
         } else {
         } else {
-            fill_rule = FillRule::Nonzero;
+            fill_rule = Gfx::WindingRule::Nonzero;
         }
         }
 
 
         if (arguments.size() < 1)
         if (arguments.size() < 1)

+ 9 - 5
Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.cpp

@@ -176,6 +176,7 @@ String Ellipse::to_string() const
 Gfx::Path Polygon::to_path(CSSPixelRect reference_box, Layout::Node const& node) const
 Gfx::Path Polygon::to_path(CSSPixelRect reference_box, Layout::Node const& node) const
 {
 {
     Gfx::Path path;
     Gfx::Path path;
+    path.set_fill_type(fill_rule);
     bool first = true;
     bool first = true;
     for (auto const& point : points) {
     for (auto const& point : points) {
         Gfx::FloatPoint resolved_point {
         Gfx::FloatPoint resolved_point {
@@ -196,12 +197,15 @@ String Polygon::to_string() const
 {
 {
     StringBuilder builder;
     StringBuilder builder;
     builder.append("polygon("sv);
     builder.append("polygon("sv);
-    bool first = true;
+    switch (fill_rule) {
+    case Gfx::WindingRule::Nonzero:
+        builder.append("nonzero"sv);
+        break;
+    case Gfx::WindingRule::EvenOdd:
+        builder.append("evenodd"sv);
+    }
     for (auto const& point : points) {
     for (auto const& point : points) {
-        if (!first)
-            builder.append(',');
-        builder.appendff("{} {}", point.x, point.y);
-        first = false;
+        builder.appendff(", {} {}", point.x, point.y);
     }
     }
     builder.append(')');
     builder.append(')');
     return MUST(builder.to_string());
     return MUST(builder.to_string());

+ 2 - 2
Userland/Libraries/LibWeb/CSS/StyleValues/BasicShapeStyleValue.h

@@ -7,6 +7,7 @@
 #pragma once
 #pragma once
 
 
 #include <AK/Variant.h>
 #include <AK/Variant.h>
+#include <LibGfx/WindingRule.h>
 #include <LibWeb/CSS/CSSStyleValue.h>
 #include <LibWeb/CSS/CSSStyleValue.h>
 #include <LibWeb/CSS/LengthBox.h>
 #include <LibWeb/CSS/LengthBox.h>
 #include <LibWeb/CSS/PercentageOr.h>
 #include <LibWeb/CSS/PercentageOr.h>
@@ -84,8 +85,7 @@ struct Polygon {
 
 
     bool operator==(Polygon const&) const = default;
     bool operator==(Polygon const&) const = default;
 
 
-    // FIXME: Actually use the fill rule
-    FillRule fill_rule;
+    Gfx::WindingRule fill_rule;
     Vector<Point> points;
     Vector<Point> points;
 };
 };