From f9b08272db411f807dd203bab025b5fccbe3f494 Mon Sep 17 00:00:00 2001 From: MacDue Date: Thu, 18 Aug 2022 11:23:07 +0100 Subject: [PATCH] LibGfx: Add AntiAliasingPainter::fill_rect This function is able to draw rectangles of floating-point pixel precision. --- .../Libraries/LibGfx/AntiAliasingPainter.cpp | 47 +++++++++++++++++++ .../Libraries/LibGfx/AntiAliasingPainter.h | 2 + 2 files changed, 49 insertions(+) diff --git a/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp b/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp index 8f0aee5d6a..db42e46db4 100644 --- a/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp +++ b/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp @@ -238,6 +238,53 @@ void AntiAliasingPainter::draw_cubic_bezier_curve(FloatPoint const& control_poin }); } +void AntiAliasingPainter::fill_rect(FloatRect const& float_rect, Color color) +{ + // Draw the integer part of the rectangle: + float right_x = float_rect.x() + float_rect.width(); + float bottom_y = float_rect.y() + float_rect.height(); + int x1 = ceilf(float_rect.x()); + int y1 = ceilf(float_rect.y()); + int x2 = floorf(right_x); + int y2 = floorf(bottom_y); + auto solid_rect = Gfx::IntRect::from_two_points({ x1, y1 }, { x2, y2 }); + m_underlying_painter.fill_rect(solid_rect, color); + + if (float_rect == solid_rect) + return; + + // Draw the rest: + float left_subpixel = x1 - float_rect.x(); + float top_subpixel = y1 - float_rect.y(); + float right_subpixel = right_x - x2; + float bottom_subpixel = bottom_y - y2; + float top_left_subpixel = top_subpixel * left_subpixel; + float top_right_subpixel = top_subpixel * right_subpixel; + float bottom_left_subpixel = bottom_subpixel * left_subpixel; + float bottom_right_subpixel = bottom_subpixel * right_subpixel; + + auto subpixel = [&](float alpha) { + return color.with_alpha(color.alpha() * alpha); + }; + + auto set_pixel = [&](int x, int y, float alpha) { + m_underlying_painter.set_pixel(x, y, subpixel(alpha), true); + }; + + auto line_to_rect = [&](int x1, int y1, int x2, int y2) { + return IntRect::from_two_points({ x1, y1 }, { x2 + 1, y2 + 1 }); + }; + + set_pixel(x1 - 1, y1 - 1, top_left_subpixel); + set_pixel(x2, y1 - 1, top_right_subpixel); + set_pixel(x2, y2, bottom_right_subpixel); + set_pixel(x1 - 1, y2, bottom_left_subpixel); + m_underlying_painter.fill_rect(line_to_rect(x1, y1 - 1, x2 - 1, y1 - 1), subpixel(top_subpixel)); + m_underlying_painter.fill_rect(line_to_rect(x1, y2, x2 - 1, y2), subpixel(bottom_subpixel)); + m_underlying_painter.fill_rect(line_to_rect(x1 - 1, y1, x1 - 1, y2 - 1), subpixel(left_subpixel)); + m_underlying_painter.fill_rect(line_to_rect(x2, y1, x2, y2 - 1), subpixel(right_subpixel)); +} + void AntiAliasingPainter::draw_ellipse(IntRect const& a_rect, Color color, int thickness) { // FIXME: Come up with an allocation-free version of this! diff --git a/Userland/Libraries/LibGfx/AntiAliasingPainter.h b/Userland/Libraries/LibGfx/AntiAliasingPainter.h index 0dad8aab31..86ff9bb6c2 100644 --- a/Userland/Libraries/LibGfx/AntiAliasingPainter.h +++ b/Userland/Libraries/LibGfx/AntiAliasingPainter.h @@ -35,6 +35,8 @@ public: AlphaSubtract }; + void fill_rect(FloatRect const&, Color); + void fill_circle(IntPoint const& center, int radius, Color, BlendMode blend_mode = BlendMode::Normal); void fill_ellipse(IntRect const& a_rect, Color, BlendMode blend_mode = BlendMode::Normal);