Repository: SerenityOS/serenity
File: Userland/Libraries/LibGfx/AntiAliasingPainter.cpp (C++)

Code before:
/*
 * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
 * Copyright (c) 2022, Ben Maxwell <macdue@dueutil.tech>
 * Copyright (c) 2022, Torsten Engelmann <engelTorsten@gmx.de>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#if defined(AK_COMPILER_GCC)
#    pragma GCC optimize("O3")
#endif

#include <AK/Function.h>
#include <AK/NumericLimits.h>
#include <LibGfx/AntiAliasingPainter.h>
#include <LibGfx/Line.h>
#include <LibGfx/Painter.h>

namespace Gfx {

void AntiAliasingPainter::draw_anti_aliased_line(FloatPoint actual_from, FloatPoint actual_to, Color color, float thickness, LineStyle style, Color, LineLengthMode line_length_mode)
{
    // FIXME: Implement this :P
    VERIFY(style == LineStyle::Solid);

    if (color.alpha() == 0)
        return;

    // FIMXE:
    // This is not a proper line drawing algorithm.
    // It's hack-ish AA rotated rectangle painting.
    // There's probably more optimal ways to achieve this
    // (though this still runs faster than the previous AA-line code)
    //
    // If you, reading this comment, know a better way that:
    //  1. Does not overpaint (i.e. painting a line with transparency looks correct)
    //  2. Has square end points (i.e. the line is a rectangle)
    //  3. Has good anti-aliasing
    //  4. Is less hacky than this
    //
    // Please delete this code and implement it!

    int int_thickness = AK::ceil(thickness);
    auto mapped_from = m_transform.map(actual_from);
    auto mapped_to = m_transform.map(actual_to);
    auto distance = mapped_to.distance_from(mapped_from);
    auto length = distance + (line_length_mode == LineLengthMode::PointToPoint);

    // Axis-aligned lines:

Review comment (suggestion):
(This should be fairly easy now if we actually need it – just pass `.dash_pattern` for StrokeStyle, and set caps to round or not depending on dots or dashed. See LibPDF's Renderer.cpp `Renderer::show_clipping_paths()` for an example.)

Code after:
/*
 * Copyright (c) 2021, Ali Mohammad Pur <mpfard@serenityos.org>
 * Copyright (c) 2022, Ben Maxwell <macdue@dueutil.tech>
 * Copyright (c) 2022, Torsten Engelmann <engelTorsten@gmx.de>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#if defined(AK_COMPILER_GCC)
#    pragma GCC optimize("O3")
#endif

#include <AK/Function.h>
#include <AK/NumericLimits.h>
#include <LibGfx/AntiAliasingPainter.h>
#include <LibGfx/Line.h>
#include <LibGfx/Painter.h>

namespace Gfx {

void AntiAliasingPainter::draw_anti_aliased_line(FloatPoint actual_from, FloatPoint actual_to, Color color, float thickness, LineStyle style, Color)
{
    // FIXME: Implement this :P
    VERIFY(style == LineStyle::Solid);

    if (color.alpha() == 0)
        return;

    Path line;
    line.move_to(actual_from);
    line.line_to(actual_to);

    stroke_path(line, color, Path::StrokeStyle { .thickness = thickness, .cap_style = Path::CapStyle::Square, .join_style = Path::JoinStyle::Miter });
}

void AntiAliasingPainter::draw_dotted_line(IntPoint point1, IntPoint point2, Color color, int thickness)
{
    // AA circles don't really work below a radius of 2px.
    if (thickness < 4)
        return m_underlying_painter.draw_line(point1, point2, color, thickness, LineStyle::Dotted);

    auto draw_spaced_dots = [&](int start, int end, auto to_point) {
        int step = thickness * 2;
        if (start > end)
            swap(start, end);
        int delta = end - start;
        int dots = delta / step;
        if (dots == 0)
            return;