diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt index 4b300ae8007..619936626f8 100644 --- a/Userland/Libraries/LibGfx/CMakeLists.txt +++ b/Userland/Libraries/LibGfx/CMakeLists.txt @@ -70,6 +70,7 @@ set(SOURCES Painter.cpp Palette.cpp Path.cpp + PathClipper.cpp Point.cpp Rect.cpp ShareableBitmap.cpp diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPathClipper.cpp b/Userland/Libraries/LibGfx/PathClipper.cpp similarity index 55% rename from Userland/Libraries/LibWeb/HTML/Canvas/CanvasPathClipper.cpp rename to Userland/Libraries/LibGfx/PathClipper.cpp index 0f79c39f918..acd4fa0e32d 100644 --- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPathClipper.cpp +++ b/Userland/Libraries/LibGfx/PathClipper.cpp @@ -5,19 +5,19 @@ */ #include -#include +#include -namespace Web::HTML { +namespace Gfx { // FIXME: This pretty naive, we should be able to cut down the allocations here // (especially for the paint style which is a bit sad). -ErrorOr CanvasPathClipper::create(Gfx::Painter& painter, CanvasClip const& canvas_clip) +ErrorOr PathClipper::create(Painter& painter, ClipPath const& clip_path) { - auto bounding_box = enclosing_int_rect(canvas_clip.path.bounding_box()); - Gfx::IntRect actual_save_rect {}; - auto maybe_bitmap = painter.get_region_bitmap(bounding_box, Gfx::BitmapFormat::BGRA8888, actual_save_rect); - RefPtr saved_clip_region; + auto bounding_box = enclosing_int_rect(clip_path.path.bounding_box()); + IntRect actual_save_rect {}; + auto maybe_bitmap = painter.get_region_bitmap(bounding_box, BitmapFormat::BGRA8888, actual_save_rect); + RefPtr saved_clip_region; if (!maybe_bitmap.is_error()) { saved_clip_region = maybe_bitmap.release_value(); } else if (actual_save_rect.is_empty()) { @@ -27,20 +27,20 @@ ErrorOr CanvasPathClipper::create(Gfx::Painter& painter, Canv } painter.save(); painter.add_clip_rect(bounding_box); - return CanvasPathClipper(move(saved_clip_region), bounding_box, canvas_clip); + return PathClipper(move(saved_clip_region), bounding_box, clip_path); } -ErrorOr CanvasPathClipper::apply_clip(Gfx::Painter& painter) +ErrorOr PathClipper::apply_clip(Painter& painter) { painter.restore(); if (!m_saved_clip_region) return {}; - Gfx::IntRect actual_save_rect {}; - auto clip_area = TRY(painter.get_region_bitmap(m_bounding_box, Gfx::BitmapFormat::BGRA8888, actual_save_rect)); + IntRect actual_save_rect {}; + auto clip_area = TRY(painter.get_region_bitmap(m_bounding_box, BitmapFormat::BGRA8888, actual_save_rect)); painter.blit(actual_save_rect.location(), *m_saved_clip_region, m_saved_clip_region->rect(), 1.0f, false); - Gfx::AntiAliasingPainter aa_painter { painter }; + AntiAliasingPainter aa_painter { painter }; auto fill_offset = m_bounding_box.location() - actual_save_rect.location(); - aa_painter.fill_path(m_canvas_clip.path, TRY(Gfx::BitmapPaintStyle::create(clip_area, fill_offset)), 1.0f, m_canvas_clip.winding_rule); + aa_painter.fill_path(m_clip_path.path, TRY(BitmapPaintStyle::create(clip_area, fill_offset)), 1.0f, m_clip_path.winding_rule); return {}; } } diff --git a/Userland/Libraries/LibGfx/PathClipper.h b/Userland/Libraries/LibGfx/PathClipper.h new file mode 100644 index 00000000000..801c3e48cf0 --- /dev/null +++ b/Userland/Libraries/LibGfx/PathClipper.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2023, MacDue + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Gfx { + +struct ClipPath { + Path path; + Painter::WindingRule winding_rule; +}; + +class PathClipper { +public: + static ErrorOr create(Painter&, ClipPath const& clip_path); + ErrorOr apply_clip(Painter& painter); + +private: + PathClipper(RefPtr saved_clip_region, IntRect bounding_box, ClipPath const& clip_path) + : m_saved_clip_region(saved_clip_region) + , m_bounding_box(bounding_box) + , m_clip_path(clip_path) + { + } + + RefPtr m_saved_clip_region; + IntRect m_bounding_box; + ClipPath const& m_clip_path; +}; + +class ScopedPathClip { + AK_MAKE_NONMOVABLE(ScopedPathClip); + AK_MAKE_NONCOPYABLE(ScopedPathClip); + +public: + ScopedPathClip(Painter& painter, Optional const& clip_path) + : m_painter(painter) + { + if (clip_path.has_value()) { + auto clipper = PathClipper::create(painter, *clip_path); + if (!clipper.is_error()) + m_path_clipper = clipper.release_value(); + else + dbgln("Error: Failed to apply clip path: {}", clipper.error()); + } + } + + ~ScopedPathClip() + { + if (m_path_clipper.has_value()) + m_path_clipper->apply_clip(m_painter).release_value_but_fixme_should_propagate_errors(); + } + +private: + Painter& m_painter; + Optional m_path_clipper; +}; + +} diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index 5af193b81dd..8fec889536c 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -243,7 +243,6 @@ set(SOURCES HTML/BrowsingContextGroup.cpp HTML/Canvas/CanvasDrawImage.cpp HTML/Canvas/CanvasPath.cpp - HTML/Canvas/CanvasPathClipper.cpp HTML/Canvas/CanvasState.cpp HTML/CanvasGradient.cpp HTML/CanvasPattern.cpp diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPathClipper.h b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPathClipper.h deleted file mode 100644 index e9daa29a0d0..00000000000 --- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasPathClipper.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2023, MacDue - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace Web::HTML { - -struct CanvasClip { - Gfx::Path path; - Gfx::Painter::WindingRule winding_rule; -}; - -class CanvasPathClipper { -public: - static ErrorOr create(Gfx::Painter&, CanvasClip const& canvas_clip); - ErrorOr apply_clip(Gfx::Painter& painter); - -private: - CanvasPathClipper(RefPtr saved_clip_region, Gfx::IntRect bounding_box, CanvasClip const& canvas_clip) - : m_saved_clip_region(saved_clip_region) - , m_bounding_box(bounding_box) - , m_canvas_clip(canvas_clip) - { - } - - RefPtr m_saved_clip_region; - Gfx::IntRect m_bounding_box; - CanvasClip const& m_canvas_clip; -}; - -class ScopedCanvasPathClip { - AK_MAKE_NONMOVABLE(ScopedCanvasPathClip); - AK_MAKE_NONCOPYABLE(ScopedCanvasPathClip); - -public: - ScopedCanvasPathClip(Gfx::Painter& painter, Optional const& canvas_clip) - : m_painter(painter) - { - if (canvas_clip.has_value()) { - auto clipper = CanvasPathClipper::create(painter, *canvas_clip); - if (!clipper.is_error()) - m_canvas_clipper = clipper.release_value(); - else - dbgln("CRC2D Error: Failed to apply canvas clip path: {}", clipper.error()); - } - } - - ~ScopedCanvasPathClip() - { - if (m_canvas_clipper.has_value()) - m_canvas_clipper->apply_clip(m_painter).release_value_but_fixme_should_propagate_errors(); - } - -private: - Gfx::Painter& m_painter; - Optional m_canvas_clipper; -}; - -} diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h index 88ee2565884..410ef5bcb54 100644 --- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h +++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h @@ -12,8 +12,8 @@ #include #include #include +#include #include -#include #include #include @@ -79,7 +79,7 @@ public: bool image_smoothing_enabled { true }; Bindings::ImageSmoothingQuality image_smoothing_quality { Bindings::ImageSmoothingQuality::Low }; float global_alpha = { 1 }; - Optional clip; + Optional clip; RefPtr font_style_value { nullptr }; RefPtr current_font { nullptr }; Bindings::CanvasTextAlign text_align { Bindings::CanvasTextAlign::Start }; diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index 229497a2196..b0d7b4820ab 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -592,7 +592,7 @@ void CanvasRenderingContext2D::clip_internal(Gfx::Path& path, Gfx::Painter::Wind if (drawing_state().clip.has_value()) { dbgln("FIXME: CRC2D: Calculate the new clip path by intersecting the given path with the current one."); } - drawing_state().clip = CanvasClip { path, winding_rule }; + drawing_state().clip = Gfx::ClipPath { path, winding_rule }; } void CanvasRenderingContext2D::clip(StringView fill_rule) diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h index 7bfc536a7b5..2707f17af04 100644 --- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h +++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -129,7 +129,7 @@ private: auto painter = this->antialiased_painter(); if (!painter.has_value()) return; - ScopedCanvasPathClip clipper(painter->underlying_painter(), drawing_state().clip); + Gfx::ScopedPathClip clipper(painter->underlying_painter(), drawing_state().clip); auto draw_rect = draw_function(*painter); if (drawing_state().clip.has_value()) draw_rect.intersect(drawing_state().clip->path.bounding_box());