From 6daef6303af8b0e071aca4aafb574f36d033cd4c Mon Sep 17 00:00:00 2001 From: MacDue Date: Wed, 30 Nov 2022 00:10:02 +0000 Subject: [PATCH] LibWeb: Use AntiAliasingPainter for canvas painting --- .../LibWeb/HTML/CanvasRenderingContext2D.cpp | 53 +++++++++++-------- .../LibWeb/HTML/CanvasRenderingContext2D.h | 5 +- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index c1b7c1e994..b243f0dbaa 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -62,14 +62,14 @@ JS::NonnullGCPtr CanvasRenderingContext2D::canvas_for_binding void CanvasRenderingContext2D::fill_rect(float x, float y, float width, float height) { - auto painter = this->painter(); - if (!painter) + auto painter = this->antialiased_painter(); + if (!painter.has_value()) return; auto& drawing_state = this->drawing_state(); auto rect = drawing_state.transform.map(Gfx::FloatRect(x, y, width, height)); - painter->fill_rect(enclosing_int_rect(rect), drawing_state.fill_style); + painter->fill_rect(rect, drawing_state.fill_style); did_draw(rect); } @@ -86,23 +86,26 @@ void CanvasRenderingContext2D::clear_rect(float x, float y, float width, float h void CanvasRenderingContext2D::stroke_rect(float x, float y, float width, float height) { - auto painter = this->painter(); - if (!painter) + auto painter = this->antialiased_painter(); + if (!painter.has_value()) return; auto& drawing_state = this->drawing_state(); auto rect = drawing_state.transform.map(Gfx::FloatRect(x, y, width, height)); + // We could remove the rounding here, but the lines look better when they have whole number pixel endponts. + auto top_left = drawing_state.transform.map(Gfx::FloatPoint(x, y)).to_rounded(); + auto top_right = drawing_state.transform.map(Gfx::FloatPoint(x + width - 1, y)).to_rounded(); + auto bottom_left = drawing_state.transform.map(Gfx::FloatPoint(x, y + height - 1)).to_rounded(); + auto bottom_right = drawing_state.transform.map(Gfx::FloatPoint(x + width - 1, y + height - 1)).to_rounded(); - auto top_left = drawing_state.transform.map(Gfx::FloatPoint(x, y)).to_type(); - auto top_right = drawing_state.transform.map(Gfx::FloatPoint(x + width - 1, y)).to_type(); - auto bottom_left = drawing_state.transform.map(Gfx::FloatPoint(x, y + height - 1)).to_type(); - auto bottom_right = drawing_state.transform.map(Gfx::FloatPoint(x + width - 1, y + height - 1)).to_type(); - - painter->draw_line(top_left, top_right, drawing_state.stroke_style, drawing_state.line_width); - painter->draw_line(top_right, bottom_right, drawing_state.stroke_style, drawing_state.line_width); - painter->draw_line(bottom_right, bottom_left, drawing_state.stroke_style, drawing_state.line_width); - painter->draw_line(bottom_left, top_left, drawing_state.stroke_style, drawing_state.line_width); + Gfx::Path path; + path.move_to(top_left); + path.line_to(top_right); + path.line_to(bottom_right); + path.line_to(bottom_left); + path.line_to(top_left); + painter->stroke_path(path, drawing_state.stroke_style, drawing_state.line_width); did_draw(rect); } @@ -173,14 +176,22 @@ void CanvasRenderingContext2D::did_draw(Gfx::FloatRect const&) canvas_element().layout_node()->set_needs_display(); } -OwnPtr CanvasRenderingContext2D::painter() +Gfx::Painter* CanvasRenderingContext2D::painter() { if (!canvas_element().bitmap()) { if (!canvas_element().create_bitmap()) - return {}; + return nullptr; + m_painter = make(*canvas_element().bitmap()); } + return m_painter.ptr(); +} - return make(*canvas_element().bitmap()); +Optional CanvasRenderingContext2D::antialiased_painter() +{ + auto painter = this->painter(); + if (painter) + return Gfx::AntiAliasingPainter { *painter }; + return {}; } void CanvasRenderingContext2D::fill_text(String const& text, float x, float y, Optional max_width) @@ -214,8 +225,8 @@ void CanvasRenderingContext2D::begin_path() void CanvasRenderingContext2D::stroke_internal(Gfx::Path const& path) { - auto painter = this->painter(); - if (!painter) + auto painter = this->antialiased_painter(); + if (!painter.has_value()) return; auto& drawing_state = this->drawing_state(); @@ -238,8 +249,8 @@ void CanvasRenderingContext2D::stroke(Path2D const& path) void CanvasRenderingContext2D::fill_internal(Gfx::Path& path, String const& fill_rule) { - auto painter = this->painter(); - if (!painter) + auto painter = this->antialiased_painter(); + if (!painter.has_value()) return; path.close_all_subpaths(); diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h index 3c0b63d2e0..132a4695d6 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h +++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -101,7 +102,8 @@ private: void did_draw(Gfx::FloatRect const&); PreparedText prepare_text(String const& text, float max_width = INFINITY); - OwnPtr painter(); + Gfx::Painter* painter(); + Optional antialiased_painter(); HTMLCanvasElement& canvas_element(); HTMLCanvasElement const& canvas_element() const; @@ -110,6 +112,7 @@ private: void fill_internal(Gfx::Path&, String const& fill_rule); JS::NonnullGCPtr m_element; + OwnPtr m_painter; // https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-origin-clean bool m_origin_clean { true };