mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibGfx: Make all fill_path() code member functions and move into .cpp
This makes all the code for fill_path() member functions of the painter, and moves them into a new FillPathImplementation.cpp. This allows us to avoid polluting Painter.h with implementation details, and makes the edit, compile, retry loop much shorter.
This commit is contained in:
parent
b1a72d66f6
commit
a425b6f772
Notes:
sideshowbarker
2024-07-17 10:31:19 +09:00
Author: https://github.com/MacDue Commit: https://github.com/SerenityOS/serenity/commit/a425b6f772 Pull-request: https://github.com/SerenityOS/serenity/pull/17780 Reviewed-by: https://github.com/awesomekling
5 changed files with 122 additions and 103 deletions
|
@ -10,7 +10,6 @@
|
||||||
# pragma GCC optimize("O3")
|
# pragma GCC optimize("O3")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "FillPathImplementation.h"
|
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/NumericLimits.h>
|
#include <AK/NumericLimits.h>
|
||||||
#include <LibGfx/AntiAliasingPainter.h>
|
#include <LibGfx/AntiAliasingPainter.h>
|
||||||
|
@ -213,14 +212,12 @@ void AntiAliasingPainter::draw_line(FloatPoint actual_from, FloatPoint actual_to
|
||||||
|
|
||||||
void AntiAliasingPainter::fill_path(Path const& path, Color color, Painter::WindingRule rule)
|
void AntiAliasingPainter::fill_path(Path const& path, Color color, Painter::WindingRule rule)
|
||||||
{
|
{
|
||||||
Detail::fill_path<Detail::FillPathMode::AllowFloatingPoints>(m_underlying_painter, path, color, rule, m_transform.translation());
|
m_underlying_painter.antialiased_fill_path(path, color, rule, m_transform.translation());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AntiAliasingPainter::fill_path(Path const& path, PaintStyle const& paint_style, Painter::WindingRule rule)
|
void AntiAliasingPainter::fill_path(Path const& path, PaintStyle const& paint_style, Painter::WindingRule rule)
|
||||||
{
|
{
|
||||||
paint_style.paint(enclosing_int_rect(path.bounding_box()), [&](PaintStyle::SamplerFunction sampler) {
|
m_underlying_painter.antialiased_fill_path(path, paint_style, rule, m_transform.translation());
|
||||||
Detail::fill_path<Detail::FillPathMode::AllowFloatingPoints>(m_underlying_painter, path, move(sampler), rule, m_transform.translation());
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AntiAliasingPainter::stroke_path(Path const& path, Color color, float thickness)
|
void AntiAliasingPainter::stroke_path(Path const& path, Color color, float thickness)
|
||||||
|
|
|
@ -10,6 +10,7 @@ set(SOURCES
|
||||||
Color.cpp
|
Color.cpp
|
||||||
CursorParams.cpp
|
CursorParams.cpp
|
||||||
DDSLoader.cpp
|
DDSLoader.cpp
|
||||||
|
FillPathImplementation.cpp
|
||||||
Filters/ColorBlindnessFilter.cpp
|
Filters/ColorBlindnessFilter.cpp
|
||||||
Filters/FastBoxBlurFilter.cpp
|
Filters/FastBoxBlurFilter.cpp
|
||||||
Filters/LumaFilter.cpp
|
Filters/LumaFilter.cpp
|
||||||
|
|
|
@ -1,18 +1,87 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
* Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||||
|
* Copyright (c) 2023, MacDue <macdue@dueutil.tech>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/Debug.h>
|
#include <AK/Debug.h>
|
||||||
#include <AK/QuickSort.h>
|
#include <AK/QuickSort.h>
|
||||||
#include <LibGfx/Color.h>
|
#include <LibGfx/Color.h>
|
||||||
#include <LibGfx/Painter.h>
|
#include <LibGfx/Painter.h>
|
||||||
#include <LibGfx/Path.h>
|
#include <LibGfx/Path.h>
|
||||||
|
|
||||||
namespace Gfx::Detail {
|
#if defined(AK_COMPILER_GCC)
|
||||||
|
# pragma GCC optimize("O3")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Gfx {
|
||||||
|
|
||||||
|
template<typename T, typename TColorOrFunction>
|
||||||
|
ALWAYS_INLINE void Painter::draw_scanline_for_fill_path(int y, T x_start, T x_end, TColorOrFunction color)
|
||||||
|
{
|
||||||
|
// Fill path should scale the scanlines before calling this.
|
||||||
|
VERIFY(scale() == 1);
|
||||||
|
|
||||||
|
constexpr bool is_floating_point = IsSameIgnoringCV<T, float>;
|
||||||
|
constexpr bool has_constant_color = IsSameIgnoringCV<TColorOrFunction, Color>;
|
||||||
|
|
||||||
|
int x1 = 0;
|
||||||
|
int x2 = 0;
|
||||||
|
u8 left_subpixel_alpha = 0;
|
||||||
|
u8 right_subpixel_alpha = 0;
|
||||||
|
if constexpr (is_floating_point) {
|
||||||
|
x1 = ceilf(x_start);
|
||||||
|
x2 = floorf(x_end);
|
||||||
|
left_subpixel_alpha = (x1 - x_start) * 255;
|
||||||
|
right_subpixel_alpha = (x_end - x2) * 255;
|
||||||
|
x1 -= left_subpixel_alpha > 0;
|
||||||
|
x2 += right_subpixel_alpha > 0;
|
||||||
|
} else {
|
||||||
|
x1 = x_start;
|
||||||
|
x2 = x_end;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntRect scanline(x1, y, x2 - x1, 1);
|
||||||
|
scanline = scanline.translated(translation());
|
||||||
|
auto clipped = scanline.intersected(clip_rect());
|
||||||
|
if (clipped.is_empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto get_color = [&](int offset) {
|
||||||
|
if constexpr (has_constant_color) {
|
||||||
|
return color;
|
||||||
|
} else {
|
||||||
|
return color(offset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if constexpr (is_floating_point) {
|
||||||
|
// Paint left and right subpixels (then remove them from the scanline).
|
||||||
|
auto get_color_with_alpha = [&](int offset, u8 alpha) {
|
||||||
|
auto color_at_offset = get_color(offset);
|
||||||
|
u8 color_alpha = (alpha * color_at_offset.alpha()) / 255;
|
||||||
|
return color_at_offset.with_alpha(color_alpha);
|
||||||
|
};
|
||||||
|
if (clipped.left() == scanline.left() && left_subpixel_alpha)
|
||||||
|
set_physical_pixel(clipped.top_left(), get_color_with_alpha(0, left_subpixel_alpha), true);
|
||||||
|
if (clipped.right() == scanline.right() && right_subpixel_alpha)
|
||||||
|
set_physical_pixel(clipped.top_right(), get_color_with_alpha(scanline.width(), right_subpixel_alpha), true);
|
||||||
|
clipped.shrink(0, right_subpixel_alpha > 0, 0, left_subpixel_alpha > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if constexpr (has_constant_color) {
|
||||||
|
if (color.alpha() == 255) {
|
||||||
|
// Speedy path: Constant color and no alpha blending.
|
||||||
|
fast_u32_fill(m_target->scanline(clipped.y()) + clipped.x(), color.value(), clipped.width());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int x = clipped.x(); x <= clipped.right(); x++) {
|
||||||
|
set_physical_pixel({ x, clipped.y() }, get_color(x - scanline.x()), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[[maybe_unused]] inline void approximately_place_on_int_grid(FloatPoint ffrom, FloatPoint fto, IntPoint& from, IntPoint& to, Optional<IntPoint> previous_to)
|
[[maybe_unused]] inline void approximately_place_on_int_grid(FloatPoint ffrom, FloatPoint fto, IntPoint& from, IntPoint& to, Optional<IntPoint> previous_to)
|
||||||
{
|
{
|
||||||
|
@ -36,13 +105,8 @@ namespace Gfx::Detail {
|
||||||
from.set_x(previous_to.value().x());
|
from.set_x(previous_to.value().x());
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class FillPathMode {
|
template<Painter::FillPathMode fill_path_mode, typename ColorOrFunction>
|
||||||
PlaceOnIntGrid,
|
void Painter::fill_path_impl(Path const& path, ColorOrFunction color, Gfx::Painter::WindingRule winding_rule, Optional<FloatPoint> offset)
|
||||||
AllowFloatingPoints,
|
|
||||||
};
|
|
||||||
|
|
||||||
template<FillPathMode fill_path_mode, typename ColorOrFunction>
|
|
||||||
void fill_path(Painter& painter, Path const& path, ColorOrFunction color, Gfx::Painter::WindingRule winding_rule, Optional<FloatPoint> offset = {})
|
|
||||||
{
|
{
|
||||||
using GridCoordinateType = Conditional<fill_path_mode == FillPathMode::PlaceOnIntGrid, int, float>;
|
using GridCoordinateType = Conditional<fill_path_mode == FillPathMode::PlaceOnIntGrid, int, float>;
|
||||||
using PointType = Point<GridCoordinateType>;
|
using PointType = Point<GridCoordinateType>;
|
||||||
|
@ -58,9 +122,9 @@ void fill_path(Painter& painter, Path const& path, ColorOrFunction color, Gfx::P
|
||||||
if (x1 > x2)
|
if (x1 > x2)
|
||||||
swap(x1, x2);
|
swap(x1, x2);
|
||||||
if constexpr (IsSameIgnoringCV<ColorOrFunction, Color>) {
|
if constexpr (IsSameIgnoringCV<ColorOrFunction, Color>) {
|
||||||
painter.draw_scanline_for_fill_path(y, x1, x2 + 1, color);
|
draw_scanline_for_fill_path(y, x1, x2 + 1, color);
|
||||||
} else {
|
} else {
|
||||||
painter.draw_scanline_for_fill_path(y, x1, x2 + 1, [&](int offset) {
|
draw_scanline_for_fill_path(y, x1, x2 + 1, [&](int offset) {
|
||||||
return color(IntPoint(x1 + offset, y) - draw_origin);
|
return color(IntPoint(x1 + offset, y) - draw_origin);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -124,7 +188,7 @@ void fill_path(Painter& painter, Path const& path, ColorOrFunction color, Gfx::P
|
||||||
});
|
});
|
||||||
if constexpr (fill_path_mode == FillPathMode::PlaceOnIntGrid && FILL_PATH_DEBUG) {
|
if constexpr (fill_path_mode == FillPathMode::PlaceOnIntGrid && FILL_PATH_DEBUG) {
|
||||||
if ((int)scanline % 10 == 0) {
|
if ((int)scanline % 10 == 0) {
|
||||||
painter.draw_text(Gfx::Rect<GridCoordinateType>(active_list.last().x - 20, scanline, 20, 10), DeprecatedString::number((int)scanline));
|
draw_text(Gfx::Rect<GridCoordinateType>(active_list.last().x - 20, scanline, 20, 10), DeprecatedString::number((int)scanline));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,4 +263,33 @@ void fill_path(Painter& painter, Path const& path, ColorOrFunction color, Gfx::P
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Painter::fill_path(Path const& path, Color color, WindingRule winding_rule)
|
||||||
|
{
|
||||||
|
VERIFY(scale() == 1); // FIXME: Add scaling support.
|
||||||
|
fill_path_impl<FillPathMode::PlaceOnIntGrid>(path, color, winding_rule);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Painter::fill_path(Path const& path, PaintStyle const& paint_style, Painter::WindingRule rule)
|
||||||
|
{
|
||||||
|
VERIFY(scale() == 1); // FIXME: Add scaling support.
|
||||||
|
paint_style.paint(enclosing_int_rect(path.bounding_box()), [&](PaintStyle::SamplerFunction sampler) {
|
||||||
|
fill_path_impl<FillPathMode::PlaceOnIntGrid>(path, move(sampler), rule);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Painter::antialiased_fill_path(Path const& path, Color color, WindingRule rule, FloatPoint translation)
|
||||||
|
{
|
||||||
|
VERIFY(scale() == 1); // FIXME: Add scaling support.
|
||||||
|
fill_path_impl<FillPathMode::AllowFloatingPoints>(path, color, rule, translation);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Painter::antialiased_fill_path(Path const& path, PaintStyle const& paint_style, WindingRule rule, FloatPoint translation)
|
||||||
|
{
|
||||||
|
VERIFY(scale() == 1); // FIXME: Add scaling support.
|
||||||
|
paint_style.paint(enclosing_int_rect(path.bounding_box()), [&](PaintStyle::SamplerFunction sampler) {
|
||||||
|
fill_path_impl<FillPathMode::AllowFloatingPoints>(path, move(sampler), rule, translation);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -27,7 +27,6 @@
|
||||||
#include <AK/Utf32View.h>
|
#include <AK/Utf32View.h>
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf8View.h>
|
||||||
#include <LibGfx/CharacterBitmap.h>
|
#include <LibGfx/CharacterBitmap.h>
|
||||||
#include <LibGfx/FillPathImplementation.h>
|
|
||||||
#include <LibGfx/Palette.h>
|
#include <LibGfx/Palette.h>
|
||||||
#include <LibGfx/Path.h>
|
#include <LibGfx/Path.h>
|
||||||
#include <LibGfx/Quad.h>
|
#include <LibGfx/Quad.h>
|
||||||
|
@ -2390,20 +2389,6 @@ void Painter::stroke_path(Path const& path, Color color, int thickness)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Painter::fill_path(Path const& path, Color color, WindingRule winding_rule)
|
|
||||||
{
|
|
||||||
VERIFY(scale() == 1); // FIXME: Add scaling support.
|
|
||||||
Detail::fill_path<Detail::FillPathMode::PlaceOnIntGrid>(*this, path, color, winding_rule);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Painter::fill_path(Path const& path, PaintStyle const& paint_style, Painter::WindingRule rule)
|
|
||||||
{
|
|
||||||
VERIFY(scale() == 1); // FIXME: Add scaling support.
|
|
||||||
paint_style.paint(enclosing_int_rect(path.bounding_box()), [&](PaintStyle::SamplerFunction sampler) {
|
|
||||||
Detail::fill_path<Detail::FillPathMode::PlaceOnIntGrid>(*this, path, move(sampler), rule);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void Painter::blit_disabled(IntPoint location, Gfx::Bitmap const& bitmap, IntRect const& rect, Palette const& palette)
|
void Painter::blit_disabled(IntPoint location, Gfx::Bitmap const& bitmap, IntRect const& rect, Palette const& palette)
|
||||||
{
|
{
|
||||||
auto bright_color = palette.threed_highlight();
|
auto bright_color = palette.threed_highlight();
|
||||||
|
|
|
@ -141,6 +141,7 @@ public:
|
||||||
Nonzero,
|
Nonzero,
|
||||||
EvenOdd,
|
EvenOdd,
|
||||||
};
|
};
|
||||||
|
|
||||||
void fill_path(Path const&, Color, WindingRule rule = WindingRule::Nonzero);
|
void fill_path(Path const&, Color, WindingRule rule = WindingRule::Nonzero);
|
||||||
void fill_path(Path const&, PaintStyle const& paint_style, WindingRule rule = WindingRule::Nonzero);
|
void fill_path(Path const&, PaintStyle const& paint_style, WindingRule rule = WindingRule::Nonzero);
|
||||||
|
|
||||||
|
@ -181,78 +182,9 @@ public:
|
||||||
|
|
||||||
int scale() const { return state().scale; }
|
int scale() const { return state().scale; }
|
||||||
|
|
||||||
template<typename T, typename TColorOrFunction>
|
|
||||||
ALWAYS_INLINE void draw_scanline_for_fill_path(int y, T x_start, T x_end, TColorOrFunction color)
|
|
||||||
{
|
|
||||||
// Note: This is really an internal function for FillPathImplementation.h to use.
|
|
||||||
// This allows fill path to clip more of the pixels and reduce the number of clipping checks
|
|
||||||
// to the number of scanlines (and allows for a fast fill).
|
|
||||||
|
|
||||||
// Fill path should scale the scanlines before calling this.
|
|
||||||
VERIFY(scale() == 1);
|
|
||||||
|
|
||||||
constexpr bool is_floating_point = IsSameIgnoringCV<T, int>;
|
|
||||||
constexpr bool has_constant_color = IsSameIgnoringCV<TColorOrFunction, Color>;
|
|
||||||
|
|
||||||
int x1 = 0;
|
|
||||||
int x2 = 0;
|
|
||||||
u8 left_subpixel_alpha = 0;
|
|
||||||
u8 right_subpixel_alpha = 0;
|
|
||||||
if constexpr (is_floating_point) {
|
|
||||||
x1 = ceilf(x_start);
|
|
||||||
x2 = floorf(x_end);
|
|
||||||
left_subpixel_alpha = (x1 - x_start) * 255;
|
|
||||||
right_subpixel_alpha = (x_end - x2) * 255;
|
|
||||||
x1 -= left_subpixel_alpha > 0;
|
|
||||||
x2 += right_subpixel_alpha > 0;
|
|
||||||
} else {
|
|
||||||
x1 = x_start;
|
|
||||||
x2 = x_end;
|
|
||||||
}
|
|
||||||
|
|
||||||
IntRect scanline(x1, y, x2 - x1, 1);
|
|
||||||
scanline = scanline.translated(translation());
|
|
||||||
auto clipped = scanline.intersected(clip_rect());
|
|
||||||
if (clipped.is_empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto get_color = [&](int offset) {
|
|
||||||
if constexpr (has_constant_color) {
|
|
||||||
return color;
|
|
||||||
} else {
|
|
||||||
return color(offset);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if constexpr (is_floating_point) {
|
|
||||||
// Paint left and right subpixels (then remove them from the scanline).
|
|
||||||
auto get_color_with_alpha = [&](int offset, u8 alpha) {
|
|
||||||
auto color_at_offset = get_color(offset);
|
|
||||||
u8 color_alpha = (alpha * color_at_offset.alpha()) / 255;
|
|
||||||
return color_at_offset.with_alpha(color_alpha);
|
|
||||||
};
|
|
||||||
if (clipped.left() == scanline.left() && left_subpixel_alpha)
|
|
||||||
set_physical_pixel(clipped.top_left(), get_color_with_alpha(0, left_subpixel_alpha), true);
|
|
||||||
if (clipped.right() == scanline.right() && right_subpixel_alpha)
|
|
||||||
set_physical_pixel(clipped.top_right(), get_color_with_alpha(scanline.width(), right_subpixel_alpha), true);
|
|
||||||
clipped.shrink(0, right_subpixel_alpha > 0, 0, left_subpixel_alpha > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if constexpr (has_constant_color) {
|
|
||||||
if (color.alpha() == 255) {
|
|
||||||
// Speedy path: Constant color and no alpha blending.
|
|
||||||
fast_u32_fill(m_target->scanline(clipped.y()) + clipped.x(), color.value(), clipped.width());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int x = clipped.x(); x <= clipped.right(); x++) {
|
|
||||||
set_physical_pixel({ x, clipped.y() }, get_color(x - scanline.x()), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend GradientLine;
|
friend GradientLine;
|
||||||
|
friend AntiAliasingPainter;
|
||||||
|
|
||||||
IntRect to_physical(IntRect const& r) const { return r.translated(translation()) * scale(); }
|
IntRect to_physical(IntRect const& r) const { return r.translated(translation()) * scale(); }
|
||||||
IntPoint to_physical(IntPoint p) const { return p.translated(translation()) * scale(); }
|
IntPoint to_physical(IntPoint p) const { return p.translated(translation()) * scale(); }
|
||||||
|
@ -285,6 +217,17 @@ private:
|
||||||
bool text_contains_bidirectional_text(Utf8View const&, TextDirection);
|
bool text_contains_bidirectional_text(Utf8View const&, TextDirection);
|
||||||
template<typename DrawGlyphFunction>
|
template<typename DrawGlyphFunction>
|
||||||
void do_draw_text(FloatRect const&, Utf8View const& text, Font const&, TextAlignment, TextElision, TextWrapping, DrawGlyphFunction);
|
void do_draw_text(FloatRect const&, Utf8View const& text, Font const&, TextAlignment, TextElision, TextWrapping, DrawGlyphFunction);
|
||||||
|
|
||||||
|
void antialiased_fill_path(Path const&, Color, WindingRule rule, FloatPoint translation);
|
||||||
|
void antialiased_fill_path(Path const&, PaintStyle const& paint_style, WindingRule rule, FloatPoint translation);
|
||||||
|
enum class FillPathMode {
|
||||||
|
PlaceOnIntGrid,
|
||||||
|
AllowFloatingPoints,
|
||||||
|
};
|
||||||
|
template<typename T, typename TColorOrFunction>
|
||||||
|
void draw_scanline_for_fill_path(int y, T x_start, T x_end, TColorOrFunction color);
|
||||||
|
template<FillPathMode fill_path_mode, typename ColorOrFunction>
|
||||||
|
void fill_path_impl(Path const& path, ColorOrFunction color, Gfx::Painter::WindingRule winding_rule, Optional<FloatPoint> offset = {});
|
||||||
};
|
};
|
||||||
|
|
||||||
class PainterStateSaver {
|
class PainterStateSaver {
|
||||||
|
|
Loading…
Reference in a new issue