Browse Source

LibWeb: Use Gfx::AntiAliasingPainter to draw SVG paths

This is still quite bad, but it's much more pleasing to look at when
drawing random SVGs :^)
Ali Mohammad Pur 3 năm trước cách đây
mục cha
commit
5a2e7d30ce

+ 22 - 3
Userland/Libraries/LibGfx/AntiAliasingPainter.cpp

@@ -16,7 +16,8 @@ static float fractional_part(float x)
 
 // Base algorithm from https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm,
 // because there seems to be no other known method for drawing AA'd lines (?)
-void Gfx::AntiAliasingPainter::draw_line(FloatPoint const& actual_from, FloatPoint const& actual_to, Color color, float thickness, Gfx::Painter::LineStyle style, Color)
+template<Gfx::AntiAliasingPainter::AntiAliasPolicy policy>
+void Gfx::AntiAliasingPainter::draw_anti_aliased_line(FloatPoint const& actual_from, FloatPoint const& actual_to, Color color, float thickness, Gfx::Painter::LineStyle style, Color)
 {
     // FIXME: Implement this :P
     VERIFY(style == Painter::LineStyle::Solid);
@@ -76,10 +77,18 @@ void Gfx::AntiAliasingPainter::draw_line(FloatPoint const& actual_from, FloatPoi
     auto x = first_end_point.x();
     while (x < last_end_point.x()) {
         if (is_steep) {
-            draw_point({ floorf(next_intersection), x }, color_with_alpha(1 - fractional_part(next_intersection)));
+            if constexpr (policy == AntiAliasPolicy::OnlyEnds) {
+                draw_point({ floorf(next_intersection), x }, color);
+            } else {
+                draw_point({ floorf(next_intersection), x }, color_with_alpha(1 - fractional_part(next_intersection)));
+            }
             draw_point({ floorf(next_intersection) + 1, x }, color_with_alpha(fractional_part(next_intersection)));
         } else {
-            draw_point({ x, floorf(next_intersection) }, color_with_alpha(1 - fractional_part(next_intersection)));
+            if constexpr (policy == AntiAliasPolicy::OnlyEnds) {
+                draw_point({ x, floorf(next_intersection) }, color);
+            } else {
+                draw_point({ x, floorf(next_intersection) }, color_with_alpha(1 - fractional_part(next_intersection)));
+            }
             draw_point({ x, floorf(next_intersection) + 1 }, color_with_alpha(fractional_part(next_intersection)));
         }
         next_intersection += delta_y;
@@ -87,6 +96,16 @@ void Gfx::AntiAliasingPainter::draw_line(FloatPoint const& actual_from, FloatPoi
     }
 }
 
+void Gfx::AntiAliasingPainter::draw_aliased_line(FloatPoint const& actual_from, FloatPoint const& actual_to, Color color, float thickness, Gfx::Painter::LineStyle style, Color alternate_color)
+{
+    draw_anti_aliased_line<AntiAliasPolicy::OnlyEnds>(actual_from, actual_to, color, thickness, style, alternate_color);
+}
+
+void Gfx::AntiAliasingPainter::draw_line(FloatPoint const& actual_from, FloatPoint const& actual_to, Color color, float thickness, Gfx::Painter::LineStyle style, Color alternate_color)
+{
+    draw_anti_aliased_line<AntiAliasPolicy::Full>(actual_from, actual_to, color, thickness, style, alternate_color);
+}
+
 void Gfx::AntiAliasingPainter::fill_path(Path& path, Color color, Painter::WindingRule rule)
 {
     Detail::fill_path<Detail::FillPathMode::AllowFloatingPoints>(*this, path, color, rule);

+ 8 - 0
Userland/Libraries/LibGfx/AntiAliasingPainter.h

@@ -18,6 +18,7 @@ public:
     }
 
     void draw_line(FloatPoint const&, FloatPoint const&, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid, Color alternate_color = Color::Transparent);
+    void draw_aliased_line(FloatPoint const&, FloatPoint const&, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid, Color alternate_color = Color::Transparent);
     void fill_path(Path&, Color, Painter::WindingRule rule = Painter::WindingRule::Nonzero);
     void stroke_path(Path const&, Color, float thickness);
     void draw_quadratic_bezier_curve(FloatPoint const& control_point, FloatPoint const&, FloatPoint const&, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid);
@@ -27,6 +28,13 @@ public:
     void translate(FloatPoint const& delta) { m_transform.translate(delta); }
 
 private:
+    enum class AntiAliasPolicy {
+        OnlyEnds,
+        Full,
+    };
+    template<AntiAliasPolicy policy>
+    void draw_anti_aliased_line(FloatPoint const&, FloatPoint const&, Color, float thickness, Painter::LineStyle style, Color alternate_color);
+
     Painter& m_underlying_painter;
     AffineTransform m_transform;
 };

+ 9 - 3
Userland/Libraries/LibGfx/FillPathImplementation.h

@@ -46,6 +46,12 @@ void fill_path(Painter& painter, Path const& path, Color color, Gfx::Painter::Wi
 {
     using GridCoordinateType = Conditional<fill_path_mode == FillPathMode::PlaceOnIntGrid, int, float>;
     using PointType = Point<GridCoordinateType>;
+    auto draw_line = [&](auto... args) {
+        if constexpr (requires { painter.draw_aliased_line(args...); })
+            painter.draw_aliased_line(args...);
+        else
+            painter.draw_line(args...);
+    };
 
     auto const& segments = path.split_lines();
 
@@ -130,7 +136,7 @@ void fill_path(Painter& painter, Path const& path, Color color, Gfx::Painter::Wi
                         // inside the shape
 
                         dbgln_if(FILL_PATH_DEBUG, "y={}: {} at {}: {} -- {}", scanline, winding_number, i, from, to);
-                        painter.draw_line(from, to, color, 1);
+                        draw_line(from, to, color, 1);
                     }
 
                     auto is_passing_through_maxima = scanline == previous.maximum_y
@@ -153,7 +159,7 @@ void fill_path(Painter& painter, Path const& path, Color color, Gfx::Painter::Wi
                 active_list.last().x -= active_list.last().inverse_slope;
             } else {
                 auto point = PointType(active_list[0].x, scanline);
-                painter.draw_line(point, point, color);
+                draw_line(point, point, color);
 
                 // update the x coord
                 active_list.first().x -= active_list.first().inverse_slope;
@@ -183,7 +189,7 @@ void fill_path(Painter& painter, Path const& path, Color color, Gfx::Painter::Wi
     if constexpr (FILL_PATH_DEBUG) {
         size_t i { 0 };
         for (auto& segment : segments) {
-            painter.draw_line(PointType(segment.from), PointType(segment.to), Color::from_hsv(i++ * 360.0 / segments.size(), 1.0, 1.0), 1);
+            draw_line(PointType(segment.from), PointType(segment.to), Color::from_hsv(i++ * 360.0 / segments.size(), 1.0, 1.0), 1);
         }
     }
 }

+ 3 - 2
Userland/Libraries/LibWeb/Layout/SVGPathBox.cpp

@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <LibGfx/AntiAliasingPainter.h>
 #include <LibGfx/Painter.h>
 #include <LibWeb/Layout/SVGPathBox.h>
 #include <LibWeb/SVG/SVGPathElement.h>
@@ -47,10 +48,10 @@ void SVGPathBox::paint(PaintContext& context, PaintPhase phase)
     closed_path.close();
 
     // Fills are computed as though all paths are closed (https://svgwg.org/svg2-draft/painting.html#FillProperties)
-    auto& painter = context.painter();
+    Gfx::AntiAliasingPainter painter { context.painter() };
     auto& svg_context = context.svg_context();
 
-    auto offset = (absolute_position() - effective_offset()).to_type<int>();
+    auto offset = absolute_position() - effective_offset();
 
     painter.translate(offset);