mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibGfx: Update fill_path() to support taking a PaintStyle
This means fill_path() now paints the scanlines its self rather than calling draw_line() which easily allows each pixel along the scanline to have a different color.
This commit is contained in:
parent
b31d768e95
commit
223cedc896
Notes:
sideshowbarker
2024-07-17 08:55:54 +09:00
Author: https://github.com/MacDue Commit: https://github.com/SerenityOS/serenity/commit/223cedc896 Pull-request: https://github.com/SerenityOS/serenity/pull/17049 Reviewed-by: https://github.com/awesomekling
5 changed files with 64 additions and 29 deletions
|
@ -50,11 +50,6 @@ void AntiAliasingPainter::draw_anti_aliased_line(FloatPoint actual_from, FloatPo
|
|||
// Axis-aligned lines:
|
||||
if (mapped_from.y() == mapped_to.y()) {
|
||||
auto start_point = (mapped_from.x() < mapped_to.x() ? mapped_from : mapped_to).translated(0, -int_thickness / 2);
|
||||
if constexpr (path_hacks == FixmeEnableHacksForBetterPathPainting::Yes) {
|
||||
// FIXME: SVG fill_path() hack:
|
||||
// SVG asks for 1px scanlines at floating point y values, if they're not snapped to a pixel they look faint.
|
||||
start_point.set_y(floorf(start_point.y()));
|
||||
}
|
||||
return fill_rect(Gfx::FloatRect(start_point, { length, thickness }), color);
|
||||
}
|
||||
if (mapped_from.x() == mapped_to.x()) {
|
||||
|
@ -213,9 +208,20 @@ void AntiAliasingPainter::draw_line(FloatPoint actual_from, FloatPoint actual_to
|
|||
draw_anti_aliased_line<FixmeEnableHacksForBetterPathPainting::No>(actual_from, actual_to, color, thickness, style, alternate_color, line_length_mode);
|
||||
}
|
||||
|
||||
void AntiAliasingPainter::fill_path(Path& path, Color color, Painter::WindingRule rule)
|
||||
// FIXME: In the fill_paths() m_transform.translation() throws away any other transforms
|
||||
// this currently does not matter -- but may in future.
|
||||
|
||||
void AntiAliasingPainter::fill_path(Path const& path, Color color, Painter::WindingRule rule)
|
||||
{
|
||||
Detail::fill_path<Detail::FillPathMode::AllowFloatingPoints>(*this, path, color, rule);
|
||||
Detail::fill_path<Detail::FillPathMode::AllowFloatingPoints>(
|
||||
m_underlying_painter, path, [=](IntPoint) { return color; }, rule, m_transform.translation());
|
||||
}
|
||||
|
||||
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) {
|
||||
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)
|
||||
|
|
|
@ -29,12 +29,10 @@ public:
|
|||
void draw_line(IntPoint, IntPoint, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid, Color alternate_color = Color::Transparent, LineLengthMode line_length_mode = LineLengthMode::PointToPoint);
|
||||
void draw_line(FloatPoint, FloatPoint, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid, Color alternate_color = Color::Transparent, LineLengthMode line_length_mode = LineLengthMode::PointToPoint);
|
||||
void draw_line_for_path(FloatPoint, FloatPoint, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid, Color alternate_color = Color::Transparent, LineLengthMode line_length_mode = LineLengthMode::PointToPoint);
|
||||
void draw_line_for_fill_path(FloatPoint from, FloatPoint to, Color color, float thickness = 1)
|
||||
{
|
||||
draw_line_for_path(from, to, color, thickness, Painter::LineStyle::Solid, Color {}, LineLengthMode::Distance);
|
||||
}
|
||||
|
||||
void fill_path(Path&, Color, Painter::WindingRule rule = Painter::WindingRule::Nonzero);
|
||||
void fill_path(Path const&, Color, Painter::WindingRule rule = Painter::WindingRule::Nonzero);
|
||||
void fill_path(Path const&, PaintStyle const& paint_style, Painter::WindingRule rule = Painter::WindingRule::Nonzero);
|
||||
|
||||
void stroke_path(Path const&, Color, float thickness);
|
||||
void draw_quadratic_bezier_curve(FloatPoint control_point, FloatPoint, FloatPoint, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid);
|
||||
void draw_cubic_bezier_curve(FloatPoint control_point_0, FloatPoint control_point_1, FloatPoint, FloatPoint, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid);
|
||||
|
@ -75,6 +73,8 @@ public:
|
|||
|
||||
void fill_rect_with_rounded_corners(IntRect const&, Color, CornerRadius top_left, CornerRadius top_right, CornerRadius bottom_right, CornerRadius bottom_left, BlendMode blend_mode = BlendMode::Normal);
|
||||
|
||||
Gfx::Painter& underlying_painter() { return m_underlying_painter; }
|
||||
|
||||
private:
|
||||
struct Range {
|
||||
int min;
|
||||
|
|
|
@ -41,16 +41,40 @@ enum class FillPathMode {
|
|||
AllowFloatingPoints,
|
||||
};
|
||||
|
||||
template<FillPathMode fill_path_mode, typename Painter>
|
||||
void fill_path(Painter& painter, Path const& path, Color color, Gfx::Painter::WindingRule winding_rule)
|
||||
template<FillPathMode fill_path_mode, typename ColorFunction>
|
||||
void fill_path(Painter& painter, Path const& path, ColorFunction color_function, Gfx::Painter::WindingRule winding_rule, Optional<FloatPoint> offset = {})
|
||||
{
|
||||
using GridCoordinateType = Conditional<fill_path_mode == FillPathMode::PlaceOnIntGrid, int, float>;
|
||||
using PointType = Point<GridCoordinateType>;
|
||||
auto draw_line = [&](auto... args) {
|
||||
if constexpr (requires { painter.draw_line_for_fill_path(args...); })
|
||||
painter.draw_line_for_fill_path(args...);
|
||||
else
|
||||
painter.draw_line(args...);
|
||||
|
||||
auto draw_scanline = [&](int y, float x1, float x2) {
|
||||
const auto draw_offset = offset.value_or({ 0, 0 });
|
||||
const auto draw_origin = (path.bounding_box().top_left() + draw_offset).to_type<int>();
|
||||
// FIMXE: Offset is added here to handle floating point translations in the AA painter,
|
||||
// really this should be done there but this function is a bit too specialised.
|
||||
y = floorf(y + draw_offset.y());
|
||||
x1 += draw_offset.x();
|
||||
x2 += draw_offset.x();
|
||||
if (x1 > x2)
|
||||
swap(x1, x2);
|
||||
auto set_pixel = [&](int x, int y, Color color) {
|
||||
painter.set_pixel(x, y, color, true);
|
||||
};
|
||||
if constexpr (fill_path_mode == FillPathMode::AllowFloatingPoints) {
|
||||
int int_x1 = ceilf(x1);
|
||||
int int_x2 = floorf(x2);
|
||||
float left_subpixel = int_x1 - x1;
|
||||
float right_subpixel = x2 - int_x2;
|
||||
auto left_color = color_function(IntPoint(int_x1 - 1, y) - draw_origin);
|
||||
auto right_color = color_function(IntPoint(int_x2, y) - draw_origin);
|
||||
set_pixel(int_x1 - 1, y, left_color.with_alpha(left_color.alpha() * left_subpixel));
|
||||
set_pixel(int_x2, y, right_color.with_alpha(right_color.alpha() * right_subpixel));
|
||||
for (int x = int_x1; x < int_x2; x++)
|
||||
set_pixel(x, y, color_function(IntPoint(x, y) - draw_origin));
|
||||
} else {
|
||||
for (int x = x1; x < int(x2); x++)
|
||||
set_pixel(x, y, color_function(IntPoint(x, y) - draw_origin));
|
||||
}
|
||||
};
|
||||
|
||||
auto const& segments = path.split_lines();
|
||||
|
@ -136,7 +160,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);
|
||||
draw_line(from, to, color, 1);
|
||||
draw_scanline(floorf(scanline), from.x(), to.x());
|
||||
}
|
||||
|
||||
auto is_passing_through_maxima = scanline == previous.maximum_y
|
||||
|
@ -159,7 +183,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);
|
||||
draw_line(point, point, color);
|
||||
draw_scanline(floorf(scanline), point.x(), point.x());
|
||||
|
||||
// update the x coord
|
||||
active_list.first().x -= active_list.first().inverse_slope;
|
||||
|
@ -185,12 +209,5 @@ void fill_path(Painter& painter, Path const& path, Color color, Gfx::Painter::Wi
|
|||
active_list.append(segment);
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (FILL_PATH_DEBUG) {
|
||||
size_t i { 0 };
|
||||
for (auto& segment : segments) {
|
||||
draw_line(PointType(segment.from), PointType(segment.to), Color::from_hsv(i++ * 360.0 / segments.size(), 1.0, 1.0), 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2373,7 +2373,16 @@ 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);
|
||||
Detail::fill_path<Detail::FillPathMode::PlaceOnIntGrid>(
|
||||
*this, path, [=](IntPoint) { return 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)
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <LibGfx/Font/FontDatabase.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibGfx/Gradients.h>
|
||||
#include <LibGfx/PaintStyle.h>
|
||||
#include <LibGfx/Point.h>
|
||||
#include <LibGfx/Rect.h>
|
||||
#include <LibGfx/Size.h>
|
||||
|
@ -21,6 +22,7 @@
|
|||
#include <LibGfx/TextDirection.h>
|
||||
#include <LibGfx/TextElision.h>
|
||||
#include <LibGfx/TextWrapping.h>
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
class Painter {
|
||||
|
@ -138,6 +140,7 @@ public:
|
|||
EvenOdd,
|
||||
};
|
||||
void fill_path(Path const&, Color, WindingRule rule = WindingRule::Nonzero);
|
||||
void fill_path(Path const&, PaintStyle const& paint_style, WindingRule rule = WindingRule::Nonzero);
|
||||
|
||||
Font const& font() const
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue